about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-06-28 07:13:12 +0000
committerbors <bors@rust-lang.org>2023-06-28 07:13:12 +0000
commit984d29d26069590786b47424c8ca205e4f4560cb (patch)
treea400dcb280046d1e426076bd25df1b468aebe6b5
parent662388e17fe4f3a4252f63fd84c05cfd54cc13a0 (diff)
parentde9dc5916456f441286c35452416a3dec0b4c2c0 (diff)
downloadrust-984d29d26069590786b47424c8ca205e4f4560cb.tar.gz
rust-984d29d26069590786b47424c8ca205e4f4560cb.zip
Auto merge of #2944 - oli-obk:rustup, r=oli-obk
Rustup
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml3
-rw-r--r--.github/workflows/ci.yml24
-rw-r--r--.github/workflows/dependencies.yml3
-rw-r--r--Cargo.lock95
-rw-r--r--README.md15
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs4
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs7
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs8
-rw-r--r--compiler/rustc_borrowck/src/place_ext.rs6
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs27
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs14
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs111
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/locals.rs75
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs43
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs21
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs16
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs12
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs5
-rw-r--r--compiler/rustc_driver_impl/src/args.rs9
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs128
-rw-r--r--compiler/rustc_expand/src/config.rs2
-rw-r--r--compiler/rustc_fluent_macro/src/fluent.rs42
-rw-r--r--compiler/rustc_hir/src/hir.rs5
-rw-r--r--compiler/rustc_hir/src/intravisit.rs1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs66
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs88
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs34
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs57
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl4
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs54
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs132
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs5
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs6
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs4
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs30
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs8
-rw-r--r--compiler/rustc_infer/src/traits/util.rs7
-rw-r--r--compiler/rustc_interface/src/interface.rs33
-rw-r--r--compiler/rustc_interface/src/tests.rs95
-rw-r--r--compiler/rustc_interface/src/util.rs45
-rw-r--r--compiler/rustc_lint/src/builtin.rs24
-rw-r--r--compiler/rustc_lint/src/lints.rs6
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs2
-rw-r--r--compiler/rustc_lint/src/traits.rs3
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs61
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs6
-rw-r--r--compiler/rustc_middle/src/arena.rs4
-rw-r--r--compiler/rustc_middle/src/lint.rs7
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs3
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs11
-rw-r--r--compiler/rustc_middle/src/query/keys.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs8
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs7
-rw-r--r--compiler/rustc_middle/src/thir.rs4
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/traits/chalk.rs2
-rw-r--r--compiler/rustc_middle/src/traits/util.rs4
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs18
-rw-r--r--compiler/rustc_middle/src/ty/context.rs30
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs2
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs7
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs13
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs70
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs40
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs15
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs20
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/category.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs7
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs19
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs6
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs17
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs7
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs19
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs8
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs8
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs30
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs8
-rw-r--r--compiler/rustc_parse/messages.ftl1
-rw-r--r--compiler/rustc_parse/src/errors.rs11
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs17
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs10
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs4
-rw-r--r--compiler/rustc_passes/src/errors.rs8
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs4
-rw-r--r--compiler/rustc_passes/src/liveness.rs7
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs1
-rw-r--r--compiler/rustc_privacy/src/lib.rs22
-rw-r--r--compiler/rustc_resolve/messages.ftl38
-rw-r--r--compiler/rustc_resolve/src/errors.rs81
-rw-r--r--compiler/rustc_resolve/src/imports.rs106
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs7
-rw-r--r--compiler/rustc_session/src/config.rs400
-rw-r--r--compiler/rustc_session/src/options.rs17
-rw-r--r--compiler/rustc_session/src/parse.rs7
-rw-r--r--compiler/rustc_session/src/search_paths.rs6
-rw-r--r--compiler/rustc_session/src/session.rs99
-rw-r--r--compiler/rustc_target/src/spec/aarch64_be_unknown_netbsd.rs17
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs62
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs30
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs2
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs72
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs2
-rw-r--r--compiler/rustc_traits/src/type_op.rs10
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs22
-rw-r--r--library/alloc/Cargo.toml1
-rw-r--r--library/alloc/src/boxed.rs35
-rw-r--r--library/alloc/src/vec/extract_if.rs8
-rw-r--r--library/alloc/src/vec/mod.rs2
-rw-r--r--library/core/benches/iter.rs52
-rw-r--r--library/core/src/default.rs2
-rw-r--r--library/core/src/iter/adapters/step_by.rs411
-rw-r--r--library/core/tests/iter/adapters/step_by.rs55
-rw-r--r--library/std/Cargo.toml1
-rw-r--r--library/std/src/fs.rs10
-rw-r--r--library/std/src/sys/windows/c.rs45
-rw-r--r--library/std/src/sys/windows/c/windows_sys.lst4
-rw-r--r--library/std/src/sys/windows/c/windows_sys.rs45
-rw-r--r--library/sysroot/Cargo.toml1
-rw-r--r--src/bootstrap/bin/main.rs57
-rw-r--r--src/bootstrap/bootstrap.py155
-rw-r--r--src/bootstrap/bootstrap_test.py94
-rw-r--r--src/bootstrap/config.rs8
-rw-r--r--src/bootstrap/config/tests.rs19
-rwxr-xr-xsrc/bootstrap/configure.py8
-rw-r--r--src/bootstrap/defaults/config.dist.toml (renamed from src/bootstrap/defaults/config.user.toml)0
-rw-r--r--src/bootstrap/doc.rs15
-rw-r--r--src/bootstrap/lib.rs9
-rw-r--r--src/bootstrap/setup.rs16
-rw-r--r--src/bootstrap/test.rs19
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh2
-rw-r--r--src/ci/github-actions/ci.yml19
m---------src/doc/book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md13
-rw-r--r--src/doc/rustc/src/platform-support/esp-idf.md10
-rw-r--r--src/doc/rustc/src/platform-support/loongarch-linux.md2
-rw-r--r--src/doc/rustc/src/platform-support/netbsd.md107
-rw-r--r--src/doc/style-guide/src/statements.md105
-rwxr-xr-xsrc/etc/test-float-parse/runtests.py2
-rw-r--r--src/librustdoc/clean/auto_trait.rs10
-rw-r--r--src/librustdoc/clean/mod.rs152
-rw-r--r--src/librustdoc/clean/simplify.rs4
-rw-r--r--src/librustdoc/clean/types.rs3
-rw-r--r--src/librustdoc/config.rs36
-rw-r--r--src/librustdoc/core.rs7
-rw-r--r--src/librustdoc/doctest.rs11
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css2
-rw-r--r--src/librustdoc/html/static/js/search.js4
-rw-r--r--src/librustdoc/lib.rs54
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/eager_or_lazy.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs16
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs1
-rw-r--r--src/tools/clippy/src/driver.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6250.stderr5
-rw-r--r--src/tools/compiletest/src/common.rs90
-rw-r--r--src/tools/compiletest/src/header/needs.rs5
-rw-r--r--src/tools/compiletest/src/runtest.rs2
-rw-r--r--src/tools/error_index_generator/main.rs5
-rw-r--r--src/tools/generate-windows-sys/src/arm_shim.rs20
-rw-r--r--src/tools/generate-windows-sys/src/main.rs4
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/bin/miri.rs25
-rw-r--r--src/tools/rust-installer/Cargo.toml4
-rw-r--r--src/tools/rust-installer/src/combiner.rs30
-rw-r--r--src/tools/rust-installer/src/compression.rs2
-rw-r--r--src/tools/rust-installer/src/generator.rs28
-rw-r--r--src/tools/rust-installer/src/scripter.rs12
-rw-r--r--src/tools/rust-installer/src/tarballer.rs14
-rw-r--r--src/tools/rust-installer/src/util.rs4
-rw-r--r--src/tools/tidy/src/features.rs8
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/codegen/issues/issue-111603.rs12
-rw-r--r--tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir4
-rw-r--r--tests/mir-opt/basic_assignment.main.ElaborateDrops.diff2
-rw-r--r--tests/mir-opt/box_expr.main.ElaborateDrops.before.panic-unwind.mir6
-rw-r--r--tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir2
-rw-r--r--tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir2
-rw-r--r--tests/mir-opt/building/custom/terminators.direct_call.built.after.mir2
-rw-r--r--tests/mir-opt/building/custom/terminators.drop_first.built.after.mir2
-rw-r--r--tests/mir-opt/building/custom/terminators.drop_second.built.after.mir2
-rw-r--r--tests/mir-opt/building/custom/terminators.indirect_call.built.after.mir2
-rw-r--r--tests/mir-opt/combine_array_len.norm2.InstSimplify.panic-unwind.diff4
-rw-r--r--tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstSimplify.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir2
-rw-r--r--tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff4
-rw-r--r--tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/copy-prop/branch.foo.CopyProp.panic-unwind.diff6
-rw-r--r--tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/copy-prop/cycle.main.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff10
-rw-r--r--tests/mir-opt/copy-prop/move_arg.f.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff6
-rw-r--r--tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/copy-prop/reborrow.remut.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff4
-rw-r--r--tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff2
-rw-r--r--tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff6
-rw-r--r--tests/mir-opt/derefer_inline_test.main.Derefer.panic-unwind.diff4
-rw-r--r--tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.panic-unwind.diff8
-rw-r--r--tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff6
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.panic-unwind.diff4
-rw-r--r--tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff2
-rw-r--r--tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff6
-rw-r--r--tests/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir4
-rw-r--r--tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/caller_with_trivial_bound.foo.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff6
-rw-r--r--tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/exponential_runtime.main.Inline.panic-unwind.diff28
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_cycle.one.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/inline_diverging.f.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff4
-rw-r--r--tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_options.main.Inline.after.panic-unwind.mir8
-rw-r--r--tests/mir-opt/inline/inline_shims.clone.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff6
-rw-r--r--tests/mir-opt/inline/inline_specialization.main.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff6
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff8
-rw-r--r--tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff2
-rw-r--r--tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff2
-rw-r--r--tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir6
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff2
-rw-r--r--tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff4
-rw-r--r--tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff4
-rw-r--r--tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.panic-unwind.mir2
-rw-r--r--tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff2
-rw-r--r--tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir4
-rw-r--r--tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir4
-rw-r--r--tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir4
-rw-r--r--tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir4
-rw-r--r--tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir4
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff8
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff8
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff4
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_inclusive_iter_next.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff2
-rw-r--r--tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff2
-rw-r--r--tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff6
-rw-r--r--tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff2
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff20
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff22
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff20
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff20
-rw-r--r--tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff4
-rw-r--r--tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.panic-unwind.diff4
-rw-r--r--tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff2
-rw-r--r--tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff2
-rw-r--r--tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir6
-rw-r--r--tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir2
-rw-r--r--tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir4
-rw-r--r--tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff2
-rw-r--r--tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff2
-rw-r--r--tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.panic-unwind.diff8
-rw-r--r--tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff2
-rw-r--r--tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff2
-rw-r--r--tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff4
-rw-r--r--tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir4
-rw-r--r--tests/run-make-fulldeps/obtain-borrowck/driver.rs3
-rw-r--r--tests/run-make/const_fn_mir/dump.mir6
-rw-r--r--tests/rustdoc-gui/docblock-code-block-line-number.goml6
-rw-r--r--tests/rustdoc-gui/search-result-display.goml3
-rw-r--r--tests/rustdoc-gui/settings.goml60
-rw-r--r--tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html2
-rw-r--r--tests/rustdoc/decl-line-wrapping-empty-arg-list.rs12
-rw-r--r--tests/rustdoc/inline_cross/assoc-const-equality.rs8
-rw-r--r--tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs12
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs7
-rw-r--r--tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs17
-rw-r--r--tests/rustdoc/reexport-doc-hidden-inside-private.rs2
-rw-r--r--tests/ui-fulldeps/session-diagnostic/example.ftl2
-rw-r--r--tests/ui-fulldeps/session-diagnostic/invalid-variable.rs21
-rw-r--r--tests/ui-fulldeps/stable-mir/crate-info.rs3
-rw-r--r--tests/ui/associated-consts/issue-110933.rs20
-rw-r--r--tests/ui/associated-inherent-types/issue-109071.no_gate.stderr35
-rw-r--r--tests/ui/associated-inherent-types/issue-109071.rs18
-rw-r--r--tests/ui/associated-inherent-types/issue-109071.with_gate.stderr26
-rw-r--r--tests/ui/cfg/diagnostics-reexport.rs24
-rw-r--r--tests/ui/cfg/diagnostics-reexport.stderr38
-rw-r--r--tests/ui/codegen/subtyping-impacts-selection-1.rs44
-rw-r--r--tests/ui/codegen/subtyping-impacts-selection-2.rs12
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-109141.rs13
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-109141.stderr26
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-96699.rs87
-rw-r--r--tests/ui/explicit-tail-calls/become-outside.array.stderr9
-rw-r--r--tests/ui/explicit-tail-calls/become-outside.constant.stderr9
-rw-r--r--tests/ui/explicit-tail-calls/become-outside.rs15
-rw-r--r--tests/ui/explicit-tail-calls/return-lifetime-sub.rs13
-rw-r--r--tests/ui/explicit-tail-calls/return-mismatches.rs28
-rw-r--r--tests/ui/explicit-tail-calls/return-mismatches.stderr27
-rw-r--r--tests/ui/higher-ranked/trait-bounds/future.classic.stderr6
-rw-r--r--tests/ui/higher-ranked/trait-bounds/future.rs38
-rw-r--r--tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs12
-rw-r--r--tests/ui/issues/issue-12133-3.rs2
-rw-r--r--tests/ui/issues/issue-51714.rs10
-rw-r--r--tests/ui/issues/issue-51714.stderr6
-rw-r--r--tests/ui/issues/issue-85461.rs1
-rw-r--r--tests/ui/parser/bad-interpolated-block.stderr12
-rw-r--r--tests/ui/parser/labeled-no-colon-expr.stderr4
-rw-r--r--tests/ui/pattern/byte-string-inference.rs15
-rw-r--r--tests/ui/proc-macro/crt-static.rs1
-rw-r--r--tests/ui/return/issue-64620.rs2
-rw-r--r--tests/ui/return/issue-64620.stderr2
-rw-r--r--tests/ui/return/issue-86188-return-not-in-fn-body.rs12
-rw-r--r--tests/ui/return/tail-expr-as-potential-return.rs4
-rw-r--r--tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs4
-rw-r--r--tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr27
-rw-r--r--tests/ui/stability-attribute/auxiliary/default_body.rs4
-rw-r--r--tests/ui/stability-attribute/default-body-stability-err.rs1
-rw-r--r--tests/ui/stability-attribute/default-body-stability-err.stderr14
-rw-r--r--tests/ui/stability-attribute/default-body-stability-ok-impls.rs2
-rw-r--r--tests/ui/suggestions/issue-109991.rs27
-rw-r--r--tests/ui/suggestions/issue-109991.stderr72
-rw-r--r--tests/ui/traits/ice-with-dyn-pointee-errors.rs15
-rw-r--r--tests/ui/traits/ice-with-dyn-pointee-errors.stderr19
-rw-r--r--tests/ui/traits/ice-with-dyn-pointee.rs11
-rw-r--r--tests/ui/traits/new-solver/member-constraints-in-root-universe.rs17
-rw-r--r--tests/ui/traits/new-solver/slice-match-byte-lit.rs2
-rw-r--r--tests/ui/traits/new-solver/slice-match-byte-lit.stderr11
-rw-r--r--tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr55
-rw-r--r--tests/ui/type-alias-impl-trait/normalize-hidden-types.rs60
-rw-r--r--tests/ui/typeck/issue-86721-return-expr-ice.rs2
-rw-r--r--tests/ui/uninhabited/projection.rs32
-rwxr-xr-xx.ps114
-rwxr-xr-xx.py2
491 files changed, 4491 insertions, 2739 deletions
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 7d4cfaece44..a2878a0e012 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -6,3 +6,6 @@ contact_links:
   - name: Feature Request
     url: https://internals.rust-lang.org/
     about: Please discuss language feature requests on the internals forum.
+  - name: Clippy Bug
+    url: https://github.com/rust-lang/rust-clippy/issues/new/choose
+    about: Please report Clippy bugs such as false positives in the Clippy repo.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2f54d2838cf..8d64b5f076e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,10 +30,11 @@ permissions:
 defaults:
   run:
     shell: bash
+concurrency:
+  group: "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}"
+  cancel-in-progress: true
 jobs:
   pr:
-    permissions:
-      actions: write
     name: "PR - ${{ matrix.name }}"
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
@@ -84,11 +85,6 @@ jobs:
       - name: ensure the channel matches the target branch
         run: src/ci/scripts/verify-channel.sh
         if: success() && !env.SKIP_JOB
-      - name: configure GitHub Actions to kill the build when outdated
-        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-        with:
-          github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -162,8 +158,6 @@ jobs:
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
         if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
   auto:
-    permissions:
-      actions: write
     name: "auto - ${{ matrix.name }}"
     env:
       CI_JOB_NAME: "${{ matrix.name }}"
@@ -496,11 +490,6 @@ jobs:
       - name: ensure the channel matches the target branch
         run: src/ci/scripts/verify-channel.sh
         if: success() && !env.SKIP_JOB
-      - name: configure GitHub Actions to kill the build when outdated
-        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-        with:
-          github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -574,8 +563,6 @@ jobs:
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
         if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
   try:
-    permissions:
-      actions: write
     name: "try - ${{ matrix.name }}"
     env:
       DIST_TRY_BUILD: 1
@@ -623,11 +610,6 @@ jobs:
       - name: ensure the channel matches the target branch
         run: src/ci/scripts/verify-channel.sh
         if: success() && !env.SKIP_JOB
-      - name: configure GitHub Actions to kill the build when outdated
-        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-        with:
-          github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 2eccd28e5bb..26d2ba636f3 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -25,6 +25,7 @@ env:
 
 jobs:
   not-waiting-on-bors:
+    if: github.repository_owner == 'rust-lang'
     name: skip if S-waiting-on-bors
     runs-on: ubuntu-latest
     steps:
@@ -43,6 +44,7 @@ jobs:
           fi
 
   update:
+    if: github.repository_owner == 'rust-lang'
     name: update dependencies
     needs: not-waiting-on-bors
     runs-on: ubuntu-latest
@@ -76,6 +78,7 @@ jobs:
           retention-days: 1
 
   pr:
+    if: github.repository_owner == 'rust-lang'
     name: amend PR
     needs: update
     runs-on: ubuntu-latest
diff --git a/Cargo.lock b/Cargo.lock
index 28db4063996..dc2d2e324c9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -482,29 +482,12 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.2.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
-dependencies = [
- "atty",
- "bitflags",
- "clap_derive 3.2.18",
- "clap_lex 0.2.2",
- "indexmap",
- "once_cell",
- "strsim",
- "termcolor",
- "textwrap",
-]
-
-[[package]]
-name = "clap"
 version = "4.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
 dependencies = [
  "clap_builder",
- "clap_derive 4.2.0",
+ "clap_derive",
  "once_cell",
 ]
 
@@ -517,7 +500,7 @@ dependencies = [
  "anstream",
  "anstyle",
  "bitflags",
- "clap_lex 0.4.1",
+ "clap_lex",
  "once_cell",
  "strsim",
  "terminal_size",
@@ -529,20 +512,7 @@ version = "4.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
 dependencies = [
- "clap 4.2.1",
-]
-
-[[package]]
-name = "clap_derive"
-version = "3.2.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
-dependencies = [
- "heck",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 1.0.102",
+ "clap",
 ]
 
 [[package]]
@@ -559,15 +529,6 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5538cd660450ebeb4234cfecf8f2284b844ffc4c50531e66d584ad5b91293613"
-dependencies = [
- "os_str_bytes",
-]
-
-[[package]]
-name = "clap_lex"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
@@ -576,7 +537,7 @@ checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
 name = "clippy"
 version = "0.1.72"
 dependencies = [
- "clap 4.2.1",
+ "clap",
  "clippy_lints",
  "clippy_utils",
  "compiletest_rs",
@@ -605,7 +566,7 @@ name = "clippy_dev"
 version = "0.0.1"
 dependencies = [
  "aho-corasick",
- "clap 4.2.1",
+ "clap",
  "indoc",
  "itertools",
  "opener",
@@ -1749,7 +1710,7 @@ name = "installer"
 version = "0.0.0"
 dependencies = [
  "anyhow",
- "clap 3.2.20",
+ "clap",
  "flate2",
  "num_cpus",
  "rayon",
@@ -1869,7 +1830,7 @@ name = "jsondoclint"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "clap 4.2.1",
+ "clap",
  "fs-err",
  "rustc-hash",
  "rustdoc-json-types",
@@ -2086,7 +2047,7 @@ dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap 4.2.1",
+ "clap",
  "clap_complete",
  "elasticlunr-rs",
  "env_logger 0.10.0",
@@ -2371,12 +2332,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "os_str_bytes"
-version = "6.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
-
-[[package]]
 name = "owo-colors"
 version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2618,30 +2573,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
-name = "proc-macro-error"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
-dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "syn 1.0.102",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
-dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
 name = "proc-macro-hack"
 version = "0.5.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2897,7 +2828,7 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap 4.2.1",
+ "clap",
  "env_logger 0.10.0",
  "mdbook",
 ]
@@ -4346,7 +4277,7 @@ dependencies = [
  "anyhow",
  "bytecount",
  "cargo_metadata",
- "clap 4.2.1",
+ "clap",
  "diff",
  "dirs",
  "env_logger 0.10.0",
@@ -4875,12 +4806,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "textwrap"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
-
-[[package]]
 name = "thin-vec"
 version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/README.md b/README.md
index 41b135972af..901213d2ca9 100644
--- a/README.md
+++ b/README.md
@@ -33,24 +33,13 @@ format:
 ```
 
 This is how the documentation and examples assume you are running `x.py`.
-Some alternative ways are:
-
-```sh
-# On a Unix shell if you don't have the necessary `python3` command
-./x <subcommand> [flags]
-
-# On the Windows Command Prompt (if .py files are configured to run Python)
-x.py <subcommand> [flags]
-
-# You can also run Python yourself, e.g.:
-python x.py <subcommand> [flags]
-```
+See the [rustc dev guide][rustcguidebuild] if this does not work on your platform.
 
 More information about `x.py` can be found by running it with the `--help` flag
 or reading the [rustc dev guide][rustcguidebuild].
 
 [gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
-[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
+[rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#what-is-xpy
 
 ### Dependencies
 
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 225714a1361..29972dd76eb 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -277,9 +277,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::Yeet(sub_expr) => self.lower_expr_yeet(e.span, sub_expr.as_deref()),
                 ExprKind::Become(sub_expr) => {
                     let sub_expr = self.lower_expr(sub_expr);
-
-                    // FIXME(explicit_tail_calls): Use `hir::ExprKind::Become` once we implemented it
-                    hir::ExprKind::Ret(Some(sub_expr))
+                    hir::ExprKind::Become(sub_expr)
                 }
                 ExprKind::InlineAsm(asm) => {
                     hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index a0979bbda54..096cea945b0 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -623,13 +623,12 @@ impl<'a> AstValidator<'a> {
     fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
         // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
         // call site which do not have a macro backtrace. See #61963.
-        let is_macro_callsite = self
+        if self
             .session
             .source_map()
             .span_to_snippet(span)
-            .map(|snippet| snippet.starts_with("#["))
-            .unwrap_or(true);
-        if !is_macro_callsite {
+            .is_ok_and(|snippet| !snippet.starts_with("#["))
+        {
             self.lint_buffer.buffer_lint_with_diagnostic(
                 MISSING_ABI,
                 id,
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 82fe2a21d08..ab8015c4a43 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -78,13 +78,6 @@ pub struct ForbiddenLifetimeBound {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_forbidden_non_lifetime_param)]
-pub struct ForbiddenNonLifetimeParam {
-    #[primary_span]
-    pub spans: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_fn_param_too_many)]
 pub struct FnParamTooMany {
     #[primary_span]
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 5c365e98f0b..39b05829888 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -678,8 +678,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
 
         // Find out if the predicates show that the type is a Fn or FnMut
-        let find_fn_kind_from_did = |(pred, _): (ty::Predicate<'tcx>, _)| {
-            if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = pred.kind().skip_binder()
+        let find_fn_kind_from_did = |(pred, _): (ty::Clause<'tcx>, _)| {
+            if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder()
                 && pred.self_ty() == ty
             {
                 if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
@@ -705,7 +705,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
                 .explicit_item_bounds(def_id)
                 .subst_iter_copied(tcx, substs)
-                .find_map(|(clause, span)| find_fn_kind_from_did((clause.as_predicate(), span))),
+                .find_map(|(clause, span)| find_fn_kind_from_did((clause, span))),
             ty::Closure(_, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
                 ty::ClosureKind::FnMut => Some(hir::Mutability::Mut),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 1ba490e9a01..1f2fefadf65 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -123,13 +123,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     item_msg = access_place_desc;
                     debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref());
                     debug_assert!(is_closure_or_generator(
-                        Place::ty_from(
-                            the_place_err.local,
-                            the_place_err.projection,
-                            self.body,
-                            self.infcx.tcx
-                        )
-                        .ty
+                        the_place_err.ty(self.body, self.infcx.tcx).ty
                     ));
 
                     reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 55c9864af8c..074f37bed13 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -928,7 +928,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
 
     fn any_param_predicate_mentions(
         &self,
-        predicates: &[ty::Predicate<'tcx>],
+        clauses: &[ty::Clause<'tcx>],
         ty: Ty<'tcx>,
         region: ty::EarlyBoundRegion,
     ) -> bool {
@@ -937,10 +937,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             if let ty::GenericArgKind::Type(ty) = arg.unpack()
                 && let ty::Param(_) = ty.kind()
             {
-                predicates.iter().any(|pred| {
+                clauses.iter().any(|pred| {
                     match pred.kind().skip_binder() {
-                        ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) if data.self_ty() == ty => {}
-                        ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) if data.projection_ty.self_ty() == ty => {}
+                        ty::ClauseKind::Trait(data) if data.self_ty() == ty => {}
+                        ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
                         _ => return false,
                     }
                     tcx.any_free_region_meets(pred, |r| {
diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs
index d521d0db213..3d7e8c6ebf3 100644
--- a/compiler/rustc_borrowck/src/place_ext.rs
+++ b/compiler/rustc_borrowck/src/place_ext.rs
@@ -46,11 +46,9 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
             }
         }
 
-        for (i, elem) in self.projection.iter().enumerate() {
-            let proj_base = &self.projection[..i];
-
+        for (i, (proj_base, elem)) in self.iter_projections().enumerate() {
             if elem == ProjectionElem::Deref {
-                let ty = Place::ty_from(self.local, proj_base, body, tcx).ty;
+                let ty = proj_base.ty(body, tcx).ty;
                 match ty.kind() {
                     ty::Ref(_, _, hir::Mutability::Not) if i == 0 => {
                         // For references to thread-local statics, we do need
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index c83d045a94e..1217dcb9c40 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -137,13 +137,11 @@ fn place_components_conflict<'tcx>(
     }
 
     // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
-    for (i, (borrow_c, &access_c)) in
-        iter::zip(borrow_place.projection, access_place.projection).enumerate()
+    for ((borrow_place, borrow_c), &access_c) in
+        iter::zip(borrow_place.iter_projections(), access_place.projection)
     {
         debug!(?borrow_c, ?access_c);
 
-        let borrow_proj_base = &borrow_place.projection[..i];
-
         // Borrow and access path both have more components.
         //
         // Examples:
@@ -156,15 +154,7 @@ fn place_components_conflict<'tcx>(
         // check whether the components being borrowed vs
         // accessed are disjoint (as in the second example,
         // but not the first).
-        match place_projection_conflict(
-            tcx,
-            body,
-            borrow_local,
-            borrow_proj_base,
-            borrow_c,
-            access_c,
-            bias,
-        ) {
+        match place_projection_conflict(tcx, body, borrow_place, borrow_c, access_c, bias) {
             Overlap::Arbitrary => {
                 // We have encountered different fields of potentially
                 // the same union - the borrow now partially overlaps.
@@ -195,8 +185,7 @@ fn place_components_conflict<'tcx>(
     }
 
     if borrow_place.projection.len() > access_place.projection.len() {
-        for (i, elem) in borrow_place.projection[access_place.projection.len()..].iter().enumerate()
-        {
+        for (base, elem) in borrow_place.iter_projections().skip(access_place.projection.len()) {
             // Borrow path is longer than the access path. Examples:
             //
             // - borrow of `a.b.c`, access to `a.b`
@@ -205,8 +194,7 @@ fn place_components_conflict<'tcx>(
             // our place. This is a conflict if that is a part our
             // access cares about.
 
-            let proj_base = &borrow_place.projection[..access_place.projection.len() + i];
-            let base_ty = Place::ty_from(borrow_local, proj_base, body, tcx).ty;
+            let base_ty = base.ty(body, tcx).ty;
 
             match (elem, &base_ty.kind(), access) {
                 (_, _, Shallow(Some(ArtificialField::ArrayLength)))
@@ -310,8 +298,7 @@ fn place_base_conflict(l1: Local, l2: Local) -> Overlap {
 fn place_projection_conflict<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    pi1_local: Local,
-    pi1_proj_base: &[PlaceElem<'tcx>],
+    pi1: PlaceRef<'tcx>,
     pi1_elem: PlaceElem<'tcx>,
     pi2_elem: PlaceElem<'tcx>,
     bias: PlaceConflictBias,
@@ -333,7 +320,7 @@ fn place_projection_conflict<'tcx>(
                 debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
                 Overlap::EqualOrDisjoint
             } else {
-                let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
+                let ty = pi1.ty(body, tcx).ty;
                 if ty.is_union() {
                     // Different fields of a union, we are basically stuck.
                     debug!("place_element_conflict: STUCK-UNION");
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 0a897272d35..23c3b7b7016 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -50,7 +50,6 @@ 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;
 use crate::{
     borrow_set::BorrowSet,
@@ -1040,9 +1039,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             .collect();
 
         let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
-            self.infcx.next_nll_region_var(
+            self.infcx.next_nll_region_var_in_universe(
                 NllRegionVariableOrigin::Existential { from_forall: false },
-                || RegionCtxt::Unknown,
+                ty::UniverseIndex::ROOT,
             )
         });
 
@@ -2503,7 +2502,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             location, borrow_region, borrowed_place
         );
 
-        let mut cursor = borrowed_place.projection.as_ref();
         let tcx = self.infcx.tcx;
         let field = path_utils::is_upvar_field_projection(
             tcx,
@@ -2517,14 +2515,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             ConstraintCategory::Boring
         };
 
-        while let [proj_base @ .., elem] = cursor {
-            cursor = proj_base;
-
+        for (base, elem) in borrowed_place.as_ref().iter_projections().rev() {
             debug!("add_reborrow_constraint - iteration {:?}", elem);
 
             match elem {
                 ProjectionElem::Deref => {
-                    let base_ty = Place::ty_from(borrowed_place.local, proj_base, body, tcx).ty;
+                    let base_ty = base.ty(body, tcx).ty;
 
                     debug!("add_reborrow_constraint - base_ty = {:?}", base_ty);
                     match base_ty.kind() {
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index fe4483104ee..140853db695 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -8,7 +8,7 @@ use rustc_feature::AttributeTemplate;
 use rustc_parse::validate_attr;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 
 pub(crate) struct Expander(pub bool);
 
@@ -22,7 +22,7 @@ impl MultiItemModifier for Expander {
         _: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let sess = ecx.sess;
-        if report_bad_target(sess, &item, span) {
+        if report_bad_target(sess, &item, span).is_err() {
             // We don't want to pass inappropriate targets to derive macros to avoid
             // follow up errors, all other errors below are recoverable.
             return ExpandResult::Ready(vec![item]);
@@ -103,7 +103,11 @@ fn dummy_annotatable() -> Annotatable {
     })
 }
 
-fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
+fn report_bad_target(
+    sess: &Session,
+    item: &Annotatable,
+    span: Span,
+) -> Result<(), ErrorGuaranteed> {
     let item_kind = match item {
         Annotatable::Item(item) => Some(&item.kind),
         Annotatable::Stmt(stmt) => match &stmt.kind {
@@ -116,9 +120,9 @@ fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
     let bad_target =
         !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
     if bad_target {
-        sess.emit_err(errors::BadDeriveTarget { span, item: item.span() });
+        return Err(sess.emit_err(errors::BadDeriveTarget { span, item: item.span() }));
     }
-    bad_target
+    Ok(())
 }
 
 fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index fcc68010a34..d7a92dac50f 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -8,7 +8,7 @@ use rustc_ast_pretty::pprust;
 use rustc_errors::Applicability;
 use rustc_expand::base::*;
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{FileNameDisplayPreference, Span};
+use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
 use std::iter;
 use thin_vec::{thin_vec, ThinVec};
 
@@ -128,12 +128,15 @@ pub fn expand_test_or_bench(
         };
     };
 
-    // has_*_signature will report any errors in the type so compilation
+    // check_*_signature will report any errors in the type so compilation
     // will fail. We shouldn't try to expand in this case because the errors
     // would be spurious.
-    if (!is_bench && !has_test_signature(cx, &item))
-        || (is_bench && !has_bench_signature(cx, &item))
-    {
+    let check_result = if is_bench {
+        check_bench_signature(cx, &item, &fn_)
+    } else {
+        check_test_signature(cx, &item, &fn_)
+    };
+    if check_result.is_err() {
         return if is_stmt {
             vec![Annotatable::Stmt(P(cx.stmt_item(item.span, item)))]
         } else {
@@ -523,72 +526,62 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType {
     }
 }
 
-fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
+fn check_test_signature(
+    cx: &ExtCtxt<'_>,
+    i: &ast::Item,
+    f: &ast::Fn,
+) -> Result<(), ErrorGuaranteed> {
     let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
     let sd = &cx.sess.parse_sess.span_diagnostic;
-    match &i.kind {
-        ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
-            if let ast::Unsafe::Yes(span) = sig.header.unsafety {
-                sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" });
-                return false;
-            }
-            if let ast::Async::Yes { span, .. } = sig.header.asyncness {
-                sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" });
-                return false;
-            }
 
-            // If the termination trait is active, the compiler will check that the output
-            // type implements the `Termination` trait as `libtest` enforces that.
-            let has_output = match &sig.decl.output {
-                ast::FnRetTy::Default(..) => false,
-                ast::FnRetTy::Ty(t) if t.kind.is_unit() => false,
-                _ => true,
-            };
-
-            if !sig.decl.inputs.is_empty() {
-                sd.span_err(i.span, "functions used as tests can not have any arguments");
-                return false;
-            }
+    if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
+        return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
+    }
 
-            if has_should_panic_attr && has_output {
-                sd.span_err(i.span, "functions using `#[should_panic]` must return `()`");
-                return false;
-            }
+    if let ast::Async::Yes { span, .. } = f.sig.header.asyncness {
+        return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" }));
+    }
 
-            if generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime))
-            {
-                sd.span_err(
-                    i.span,
-                    "functions used as tests can not have any non-lifetime generic parameters",
-                );
-                return false;
-            }
+    // If the termination trait is active, the compiler will check that the output
+    // type implements the `Termination` trait as `libtest` enforces that.
+    let has_output = match &f.sig.decl.output {
+        ast::FnRetTy::Default(..) => false,
+        ast::FnRetTy::Ty(t) if t.kind.is_unit() => false,
+        _ => true,
+    };
 
-            true
-        }
-        _ => {
-            // should be unreachable because `is_test_fn_item` should catch all non-fn items
-            debug_assert!(false);
-            false
-        }
+    if !f.sig.decl.inputs.is_empty() {
+        return Err(sd.span_err(i.span, "functions used as tests can not have any arguments"));
     }
-}
 
-fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
-    let has_sig = match &i.kind {
-        // N.B., inadequate check, but we're running
-        // well before resolve, can't get too deep.
-        ast::ItemKind::Fn(box ast::Fn { sig, .. }) => sig.decl.inputs.len() == 1,
-        _ => false,
-    };
+    if has_should_panic_attr && has_output {
+        return Err(sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"));
+    }
+
+    if f.generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) {
+        return Err(sd.span_err(
+            i.span,
+            "functions used as tests can not have any non-lifetime generic parameters",
+        ));
+    }
+
+    Ok(())
+}
 
-    if !has_sig {
-        cx.sess.parse_sess.span_diagnostic.span_err(
+fn check_bench_signature(
+    cx: &ExtCtxt<'_>,
+    i: &ast::Item,
+    f: &ast::Fn,
+) -> Result<(), ErrorGuaranteed> {
+    // N.B., inadequate check, but we're running
+    // well before resolve, can't get too deep.
+    if f.sig.decl.inputs.len() != 1 {
+        return Err(cx.sess.parse_sess.span_diagnostic.span_err(
             i.span,
             "functions used as benches must have \
             signature `fn(&mut Bencher) -> impl Termination`",
-        );
+        ));
     }
 
-    has_sig
+    Ok(())
 }
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index 1007b33eca4..5a4f9e80445 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -225,10 +225,10 @@ pub(crate) fn write_ir_file(
     let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
     if let Err(err) = res {
         // Using early_warn as no Session is available here
-        rustc_session::early_warn(
+        let handler = rustc_session::EarlyErrorHandler::new(
             rustc_session::config::ErrorOutputType::default(),
-            format!("error writing ir file: {}", err),
         );
+        handler.early_warn(format!("error writing ir file: {}", err));
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index b4aa001547c..43258078bd7 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -572,8 +572,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     ) {
         let zero = self.const_usize(0);
         let count = self.const_usize(count);
-        let start = dest.project_index(self, zero).llval;
-        let end = dest.project_index(self, count).llval;
 
         let header_bb = self.append_sibling_block("repeat_loop_header");
         let body_bb = self.append_sibling_block("repeat_loop_body");
@@ -582,24 +580,18 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         self.br(header_bb);
 
         let mut header_bx = Self::build(self.cx, header_bb);
-        let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]);
+        let i = header_bx.phi(self.val_ty(zero), &[zero], &[self.llbb()]);
 
-        let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
+        let keep_going = header_bx.icmp(IntPredicate::IntULT, i, count);
         header_bx.cond_br(keep_going, body_bb, next_bb);
 
         let mut body_bx = Self::build(self.cx, body_bb);
-        let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
-        cg_elem
-            .val
-            .store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align));
-
-        let next = body_bx.inbounds_gep(
-            self.backend_type(cg_elem.layout),
-            current,
-            &[self.const_usize(1)],
-        );
+        let dest_elem = dest.project_index(&mut body_bx, i);
+        cg_elem.val.store(&mut body_bx, dest_elem);
+
+        let next = body_bx.unchecked_uadd(i, self.const_usize(1));
         body_bx.br(header_bb);
-        header_bx.add_incoming_to_phi(current, next, body_bb);
+        header_bx.add_incoming_to_phi(i, next, body_bb);
 
         *self = Self::build(self.cx, next_bb);
     }
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 31854c7f4c4..c26a7422fdd 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -4,6 +4,7 @@
 #![feature(if_let_guard)]
 #![feature(int_roundings)]
 #![feature(let_chains)]
+#![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(strict_provenance)]
 #![feature(try_blocks)]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 0cec560ba45..5e40b672866 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1729,7 +1729,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             IndirectOperand(tmp, index) => {
                 let op = bx.load_operand(tmp);
                 tmp.storage_dead(bx);
-                self.locals[index] = LocalRef::Operand(op);
+                self.overwrite_local(index, LocalRef::Operand(op));
                 self.debug_introduce_local(bx, index);
             }
             DirectOperand(index) => {
@@ -1744,7 +1744,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 } else {
                     OperandRef::from_immediate_or_packed_pair(bx, llval, ret_abi.layout)
                 };
-                self.locals[index] = LocalRef::Operand(op);
+                self.overwrite_local(index, LocalRef::Operand(op));
                 self.debug_introduce_local(bx, index);
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 4f79c6a3d82..c6589a40392 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -248,7 +248,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     }
 
     fn spill_operand_to_stack(
-        operand: &OperandRef<'tcx, Bx::Value>,
+        operand: OperandRef<'tcx, Bx::Value>,
         name: Option<String>,
         bx: &mut Bx,
     ) -> PlaceRef<'tcx, Bx::Value> {
@@ -375,7 +375,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     return;
                 }
 
-                Self::spill_operand_to_stack(operand, name, bx)
+                Self::spill_operand_to_stack(*operand, name, bx)
             }
 
             LocalRef::Place(place) => *place,
@@ -550,7 +550,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
                             self.set_debug_loc(bx, var.source_info);
                             let base = Self::spill_operand_to_stack(
-                                &operand,
+                                operand,
                                 Some(var.name.to_string()),
                                 bx,
                             );
diff --git a/compiler/rustc_codegen_ssa/src/mir/locals.rs b/compiler/rustc_codegen_ssa/src/mir/locals.rs
new file mode 100644
index 00000000000..da8bf5e7916
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/mir/locals.rs
@@ -0,0 +1,75 @@
+//! Locals are in a private module as updating `LocalRef::Operand` has to
+//! be careful wrt to subtyping. To deal with this we only allow updates by using
+//! `FunctionCx::overwrite_local` which handles it automatically.
+use crate::mir::{FunctionCx, LocalRef};
+use crate::traits::BuilderMethods;
+use rustc_index::IndexVec;
+use rustc_middle::mir;
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use std::ops::{Index, IndexMut};
+
+pub(super) struct Locals<'tcx, V> {
+    values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
+}
+
+impl<'tcx, V> Index<mir::Local> for Locals<'tcx, V> {
+    type Output = LocalRef<'tcx, V>;
+    #[inline]
+    fn index(&self, index: mir::Local) -> &LocalRef<'tcx, V> {
+        &self.values[index]
+    }
+}
+
+/// To mutate locals, use `FunctionCx::overwrite_local` instead.
+impl<'tcx, V, Idx: ?Sized> !IndexMut<Idx> for Locals<'tcx, V> {}
+
+impl<'tcx, V> Locals<'tcx, V> {
+    pub(super) fn empty() -> Locals<'tcx, V> {
+        Locals { values: IndexVec::default() }
+    }
+
+    pub(super) fn indices(&self) -> impl DoubleEndedIterator<Item = mir::Local> + Clone + 'tcx {
+        self.values.indices()
+    }
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+    pub(super) fn initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>) {
+        assert!(self.locals.values.is_empty());
+
+        for (local, value) in values.into_iter().enumerate() {
+            match value {
+                LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
+                LocalRef::Operand(op) => {
+                    let local = mir::Local::from_usize(local);
+                    let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
+                    assert_eq!(expected_ty, op.layout.ty, "unexpected initial operand type");
+                }
+            }
+
+            self.locals.values.push(value);
+        }
+    }
+
+    pub(super) fn overwrite_local(
+        &mut self,
+        local: mir::Local,
+        mut value: LocalRef<'tcx, Bx::Value>,
+    ) {
+        match value {
+            LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
+            LocalRef::Operand(ref mut op) => {
+                let local_ty = self.monomorphize(self.mir.local_decls[local].ty);
+                if local_ty != op.layout.ty {
+                    // FIXME(#112651): This can be changed to an ICE afterwards.
+                    debug!("updating type of operand due to subtyping");
+                    with_no_trimmed_paths!(debug!(?op.layout.ty));
+                    with_no_trimmed_paths!(debug!(?local_ty));
+                    op.layout.ty = local_ty;
+                }
+            }
+        };
+
+        self.locals.values[local] = value;
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 2809ec2deb5..15b0e34b8e4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -1,21 +1,31 @@
 use crate::base;
 use crate::traits::*;
+use rustc_index::bit_set::BitSet;
+use rustc_index::IndexVec;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::mir::traversal;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_target::abi::call::{FnAbi, PassMode};
 
 use std::iter;
 
-use rustc_index::bit_set::BitSet;
-use rustc_index::IndexVec;
+mod analyze;
+mod block;
+pub mod constant;
+pub mod coverageinfo;
+pub mod debuginfo;
+mod intrinsic;
+mod locals;
+pub mod operand;
+pub mod place;
+mod rvalue;
+mod statement;
 
 use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
-use self::place::PlaceRef;
-use rustc_middle::mir::traversal;
-
 use self::operand::{OperandRef, OperandValue};
+use self::place::PlaceRef;
 
 // Used for tracking the state of generated basic blocks.
 enum CachedLlbb<T> {
@@ -91,7 +101,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     ///
     /// Avoiding allocs can also be important for certain intrinsics,
     /// notably `expect`.
-    locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
+    locals: locals::Locals<'tcx, Bx::Value>,
 
     /// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
     /// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed.
@@ -192,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         cleanup_kinds,
         landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
         funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
-        locals: IndexVec::new(),
+        locals: locals::Locals::empty(),
         debug_context,
         per_local_var_debug_info: None,
         caller_location: None,
@@ -223,7 +233,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let memory_locals = analyze::non_ssa_locals(&fx);
 
     // Allocate variable and temp allocas
-    fx.locals = {
+    let local_values = {
         let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
 
         let mut allocate_local = |local| {
@@ -256,6 +266,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             .chain(mir.vars_and_temps_iter().map(allocate_local))
             .collect()
     };
+    fx.initialize_locals(local_values);
 
     // Apply debuginfo to the newly allocated locals.
     fx.debug_introduce_locals(&mut start_bx);
@@ -289,14 +300,13 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         .enumerate()
         .map(|(arg_index, local)| {
             let arg_decl = &mir.local_decls[local];
+            let arg_ty = fx.monomorphize(arg_decl.ty);
 
             if Some(local) == mir.spread_arg {
                 // This argument (e.g., the last argument in the "rust-call" ABI)
                 // is a tuple that was spread at the ABI level and now we have
                 // to reconstruct it into a tuple local variable, from multiple
                 // individual LLVM function arguments.
-
-                let arg_ty = fx.monomorphize(arg_decl.ty);
                 let ty::Tuple(tupled_arg_tys) = arg_ty.kind() else {
                     bug!("spread argument isn't a tuple?!");
                 };
@@ -331,8 +341,6 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
             }
 
             if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
-                let arg_ty = fx.monomorphize(arg_decl.ty);
-
                 let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
                 bx.va_start(va_list.llval);
 
@@ -429,14 +437,3 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     args
 }
-
-mod analyze;
-mod block;
-pub mod constant;
-pub mod coverageinfo;
-pub mod debuginfo;
-mod intrinsic;
-pub mod operand;
-pub mod place;
-mod rvalue;
-mod statement;
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 3fd7397ad38..314d364c0c2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -20,7 +20,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                         LocalRef::PendingOperand => {
                             let operand = self.codegen_rvalue_operand(bx, rvalue);
-                            self.locals[index] = LocalRef::Operand(operand);
+                            self.overwrite_local(index, LocalRef::Operand(operand));
                             self.debug_introduce_local(bx, index);
                         }
                         LocalRef::Operand(op) => {
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index c5976a65411..6a3a31a0d60 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -44,6 +44,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     // #[target_feature].
     ("thumb-mode", Some(sym::arm_target_feature)),
     ("thumb2", Some(sym::arm_target_feature)),
+    ("trustzone", Some(sym::arm_target_feature)),
     ("v5te", Some(sym::arm_target_feature)),
     ("v6", Some(sym::arm_target_feature)),
     ("v6k", Some(sym::arm_target_feature)),
@@ -53,6 +54,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("vfp2", Some(sym::arm_target_feature)),
     ("vfp3", Some(sym::arm_target_feature)),
     ("vfp4", Some(sym::arm_target_feature)),
+    ("virtualization", Some(sym::arm_target_feature)),
     // tidy-alphabetical-end
 ];
 
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 8b8e8ff58e9..417ab78fd54 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::source_map::Span;
 use rustc_target::abi::{self, Abi};
 
-use super::{CompileTimeEvalContext, CompileTimeInterpreter};
+use super::{CanAccessStatics, CompileTimeEvalContext, CompileTimeInterpreter};
 use crate::errors;
 use crate::interpret::eval_nullary_intrinsic;
 use crate::interpret::{
@@ -93,7 +93,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
     tcx: TyCtxt<'tcx>,
     root_span: Span,
     param_env: ty::ParamEnv<'tcx>,
-    can_access_statics: bool,
+    can_access_statics: CanAccessStatics,
 ) -> CompileTimeEvalContext<'mir, 'tcx> {
     debug!("mk_eval_cx: {:?}", param_env);
     InterpCx::new(
@@ -207,7 +207,7 @@ pub(crate) fn turn_into_const_value<'tcx>(
         tcx,
         tcx.def_span(key.value.instance.def_id()),
         key.param_env,
-        /*can_access_statics:*/ is_static,
+        CanAccessStatics::from(is_static),
     );
 
     let mplace = ecx.raw_const_to_mplace(constant).expect(
@@ -309,7 +309,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
         // Statics (and promoteds inside statics) may access other statics, because unlike consts
         // they do not have to behave "as if" they were evaluated at runtime.
         CompileTimeInterpreter::new(
-            /*can_access_statics:*/ is_static,
+            CanAccessStatics::from(is_static),
             if tcx.sess.opts.unstable_opts.extra_const_ub_checks {
                 CheckAlignment::Error
             } else {
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 7391f567040..f9f645af41f 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -57,7 +57,7 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> {
     /// * Interning makes everything outside of statics immutable.
     /// * Pointers to allocations inside of statics can never leak outside, to a non-static global.
     /// This boolean here controls the second part.
-    pub(super) can_access_statics: bool,
+    pub(super) can_access_statics: CanAccessStatics,
 
     /// Whether to check alignment during evaluation.
     pub(super) check_alignment: CheckAlignment,
@@ -83,8 +83,23 @@ impl CheckAlignment {
     }
 }
 
+#[derive(Copy, Clone, PartialEq)]
+pub(crate) enum CanAccessStatics {
+    No,
+    Yes,
+}
+
+impl From<bool> for CanAccessStatics {
+    fn from(value: bool) -> Self {
+        if value { Self::Yes } else { Self::No }
+    }
+}
+
 impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> {
-    pub(crate) fn new(can_access_statics: bool, check_alignment: CheckAlignment) -> Self {
+    pub(crate) fn new(
+        can_access_statics: CanAccessStatics,
+        check_alignment: CheckAlignment,
+    ) -> Self {
         CompileTimeInterpreter {
             num_evaluated_steps: 0,
             stack: Vec::new(),
@@ -699,7 +714,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
             }
         } else {
             // Read access. These are usually allowed, with some exceptions.
-            if machine.can_access_statics {
+            if machine.can_access_statics == CanAccessStatics::Yes {
                 // Machine configuration allows us read from anything (e.g., `static` initializer).
                 Ok(())
             } else if static_def_id.is_some() {
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 6e462d3a1e9..b9ab0a4b7c8 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -26,7 +26,7 @@ pub(crate) fn const_caller_location(
     (file, line, col): (Symbol, u32, u32),
 ) -> ConstValue<'_> {
     trace!("const_caller_location: {}:{}:{}", file, line, col);
-    let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
+    let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), CanAccessStatics::No);
 
     let loc_place = ecx.alloc_caller_location(file, line, col);
     if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
@@ -55,10 +55,12 @@ pub(crate) fn eval_to_valtree<'tcx>(
 
     // FIXME Need to provide a span to `eval_to_valtree`
     let ecx = mk_eval_cx(
-        tcx, DUMMY_SP, param_env,
+        tcx,
+        DUMMY_SP,
+        param_env,
         // It is absolutely crucial for soundness that
         // we do not read from static items or other mutable memory.
-        false,
+        CanAccessStatics::No,
     );
     let place = ecx.raw_const_to_mplace(const_alloc).unwrap();
     debug!(?place);
@@ -91,7 +93,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
     val: mir::ConstantKind<'tcx>,
 ) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
     trace!("destructure_mir_constant: {:?}", val);
-    let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
+    let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
     let op = ecx.eval_mir_constant(&val, None, None)?;
 
     // We go to `usize` as we cannot allocate anything bigger anyway.
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index b10f2e9f862..e574df27694 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,6 +1,7 @@
 use super::eval_queries::{mk_eval_cx, op_to_const};
 use super::machine::CompileTimeEvalContext;
 use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES};
+use crate::const_eval::CanAccessStatics;
 use crate::interpret::{
     intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
     MemoryKind, PlaceTy, Scalar,
@@ -263,7 +264,11 @@ pub fn valtree_to_const_value<'tcx>(
     // FIXME Does this need an example?
 
     let (param_env, ty) = param_env_ty.into_parts();
-    let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
+    let mut ecx: crate::interpret::InterpCx<
+        '_,
+        '_,
+        crate::const_eval::CompileTimeInterpreter<'_, '_>,
+    > = mk_eval_cx(tcx, DUMMY_SP, param_env, CanAccessStatics::No);
 
     match ty.kind() {
         ty::FnDef(..) => {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 33c79ad7e55..28cf9daf1c1 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -612,30 +612,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
     }
     fn visit_projection_elem(
         &mut self,
-        place_local: Local,
-        proj_base: &[PlaceElem<'tcx>],
+        place_ref: PlaceRef<'tcx>,
         elem: PlaceElem<'tcx>,
         context: PlaceContext,
         location: Location,
     ) {
         trace!(
-            "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
+            "visit_projection_elem: place_ref={:?} elem={:?} \
             context={:?} location={:?}",
-            place_local,
-            proj_base,
+            place_ref,
             elem,
             context,
             location,
         );
 
-        self.super_projection_elem(place_local, proj_base, elem, context, location);
+        self.super_projection_elem(place_ref, elem, context, location);
 
         match elem {
             ProjectionElem::Deref => {
-                let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
+                let base_ty = place_ref.ty(self.body, self.tcx).ty;
                 if base_ty.is_unsafe_ptr() {
-                    if proj_base.is_empty() {
-                        let decl = &self.body.local_decls[place_local];
+                    if place_ref.projection.is_empty() {
+                        let decl = &self.body.local_decls[place_ref.local];
                         if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
                             let span = decl.source_info.span;
                             self.check_static(def_id, span);
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index f197541da5b..7ed73a3f6fe 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -318,8 +318,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
 
     fn visit_projection_elem(
         &mut self,
-        local: Local,
-        proj_base: &[PlaceElem<'tcx>],
+        place_ref: PlaceRef<'tcx>,
         elem: PlaceElem<'tcx>,
         context: PlaceContext,
         location: Location,
@@ -334,7 +333,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             ProjectionElem::Deref
                 if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
             {
-                let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty;
+                let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
 
                 if base_ty.is_box() {
                     self.fail(
@@ -344,8 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 }
             }
             ProjectionElem::Field(f, ty) => {
-                let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) };
-                let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
+                let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx);
                 let fail_out_of_bounds = |this: &Self, location| {
                     this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
                 };
@@ -355,7 +353,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             location,
                             format!(
                                 "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
-                                parent, f, ty, f_ty
+                                place_ref, f, ty, f_ty
                             )
                         )
                     }
@@ -434,7 +432,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             }
             _ => {}
         }
-        self.super_projection_elem(local, proj_base, elem, context, location);
+        self.super_projection_elem(place_ref, elem, context, location);
     }
 
     fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 29063261ada..f56798d4c32 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -2,7 +2,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val
 use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
 
-use crate::const_eval::{CheckAlignment, CompileTimeInterpreter};
+use crate::const_eval::{CanAccessStatics, CheckAlignment, CompileTimeInterpreter};
 use crate::interpret::{InterpCx, MemoryKind, OpTy};
 
 /// Determines if this type permits "raw" initialization by just transmuting some memory into an
@@ -44,8 +44,7 @@ fn might_permit_raw_init_strict<'tcx>(
     tcx: TyCtxt<'tcx>,
     kind: ValidityRequirement,
 ) -> Result<bool, LayoutError<'tcx>> {
-    let machine =
-        CompileTimeInterpreter::new(/*can_access_statics:*/ false, CheckAlignment::Error);
+    let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error);
 
     let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
 
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
index eb92ccc17b2..654d7636da2 100644
--- a/compiler/rustc_driver_impl/src/args.rs
+++ b/compiler/rustc_driver_impl/src/args.rs
@@ -3,6 +3,8 @@ use std::fmt;
 use std::fs;
 use std::io;
 
+use rustc_session::EarlyErrorHandler;
+
 fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
     if let Some(path) = arg.strip_prefix('@') {
         let file = match fs::read_to_string(path) {
@@ -21,15 +23,12 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
 /// **Note:** This function doesn't interpret argument 0 in any special way.
 /// If this function is intended to be used with command line arguments,
 /// `argv[0]` must be removed prior to calling it manually.
-pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
+pub fn arg_expand_all(handler: &EarlyErrorHandler, at_args: &[String]) -> Vec<String> {
     let mut args = Vec::new();
     for arg in at_args {
         match arg_expand(arg.clone()) {
             Ok(arg) => args.extend(arg),
-            Err(err) => rustc_session::early_error(
-                rustc_session::config::ErrorOutputType::default(),
-                format!("Failed to load argument file: {err}"),
-            ),
+            Err(err) => handler.early_error(format!("Failed to load argument file: {err}")),
         }
     }
     args
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 984cc1557a4..4b4573ec2eb 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -40,8 +40,7 @@ use rustc_session::config::{
 use rustc_session::cstore::MetadataLoader;
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, Session};
-use rustc_session::{early_error, early_error_no_abort, early_warn};
+use rustc_session::{config, EarlyErrorHandler, Session};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
 use rustc_target::json::ToJson;
@@ -174,6 +173,7 @@ pub trait Callbacks {
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
+        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         _queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
@@ -260,6 +260,8 @@ fn run_compiler(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
 ) -> interface::Result<()> {
+    let mut early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -270,22 +272,22 @@ fn run_compiler(
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = args::arg_expand_all(at_args);
+    let args = args::arg_expand_all(&early_error_handler, at_args);
 
-    let Some(matches) = handle_options(&args) else { return Ok(()) };
+    let Some(matches) = handle_options(&early_error_handler, &args) else { return Ok(()) };
 
-    let sopts = config::build_session_options(&matches);
+    let sopts = config::build_session_options(&mut early_error_handler, &matches);
 
     // Set parallel mode before thread pool creation, which will create `Lock`s.
     interface::set_thread_safe_mode(&sopts.unstable_opts);
 
     if let Some(ref code) = matches.opt_str("explain") {
-        handle_explain(diagnostics_registry(), code, sopts.error_format);
+        handle_explain(&early_error_handler, diagnostics_registry(), code);
         return Ok(());
     }
 
-    let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
-    let check_cfg = interface::parse_check_cfg(matches.opt_strs("check-cfg"));
+    let cfg = interface::parse_cfgspecs(&early_error_handler, matches.opt_strs("cfg"));
+    let check_cfg = interface::parse_check_cfg(&early_error_handler, matches.opt_strs("check-cfg"));
     let (odir, ofile) = make_output(&matches);
     let mut config = interface::Config {
         opts: sopts,
@@ -304,7 +306,7 @@ fn run_compiler(
         registry: diagnostics_registry(),
     };
 
-    match make_input(config.opts.error_format, &matches.free) {
+    match make_input(&early_error_handler, &matches.free) {
         Err(reported) => return Err(reported),
         Ok(Some(input)) => {
             config.input = input;
@@ -314,8 +316,13 @@ fn run_compiler(
         Ok(None) => match matches.free.len() {
             0 => {
                 callbacks.config(&mut config);
+
+                early_error_handler.abort_if_errors();
+
                 interface::run_compiler(config, |compiler| {
                     let sopts = &compiler.session().opts;
+                    let handler = EarlyErrorHandler::new(sopts.error_format);
+
                     if sopts.describe_lints {
                         let mut lint_store =
                             rustc_lint::new_lint_store(compiler.session().enable_internal_lints());
@@ -329,31 +336,38 @@ fn run_compiler(
                         describe_lints(compiler.session(), &lint_store, registered_lints);
                         return;
                     }
-                    let should_stop =
-                        print_crate_info(&**compiler.codegen_backend(), compiler.session(), false);
+                    let should_stop = print_crate_info(
+                        &handler,
+                        &**compiler.codegen_backend(),
+                        compiler.session(),
+                        false,
+                    );
 
                     if should_stop == Compilation::Stop {
                         return;
                     }
-                    early_error(sopts.error_format, "no input filename given")
+                    handler.early_error("no input filename given")
                 });
                 return Ok(());
             }
             1 => panic!("make_input should have provided valid inputs"),
-            _ => early_error(
-                config.opts.error_format,
-                format!(
-                    "multiple input filenames provided (first two filenames are `{}` and `{}`)",
-                    matches.free[0], matches.free[1],
-                ),
-            ),
+            _ => early_error_handler.early_error(format!(
+                "multiple input filenames provided (first two filenames are `{}` and `{}`)",
+                matches.free[0], matches.free[1],
+            )),
         },
     };
 
+    early_error_handler.abort_if_errors();
+
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
-        let should_stop = print_crate_info(&**compiler.codegen_backend(), sess, true)
-            .and_then(|| list_metadata(sess, &*compiler.codegen_backend().metadata_loader()))
+        let handler = EarlyErrorHandler::new(sess.opts.error_format);
+
+        let should_stop = print_crate_info(&handler, &**compiler.codegen_backend(), sess, true)
+            .and_then(|| {
+                list_metadata(&handler, sess, &*compiler.codegen_backend().metadata_loader())
+            })
             .and_then(|| try_process_rlink(sess, compiler));
 
         if should_stop == Compilation::Stop {
@@ -421,7 +435,7 @@ fn run_compiler(
 
             queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?;
 
-            if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
+            if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
@@ -475,7 +489,7 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileNa
 
 // Extract input (string or file and optional path) from matches.
 fn make_input(
-    error_format: ErrorOutputType,
+    handler: &EarlyErrorHandler,
     free_matches: &[String],
 ) -> Result<Option<Input>, ErrorGuaranteed> {
     if free_matches.len() == 1 {
@@ -485,8 +499,7 @@ fn make_input(
             if io::stdin().read_to_string(&mut src).is_err() {
                 // Immediately stop compilation if there was an issue reading
                 // the input (for example if the input stream is not UTF-8).
-                let reported = early_error_no_abort(
-                    error_format,
+                let reported = handler.early_error_no_abort(
                     "couldn't read from stdin, as it did not contain valid UTF-8",
                 );
                 return Err(reported);
@@ -527,7 +540,7 @@ impl Compilation {
     }
 }
 
-fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
+fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str) {
     let upper_cased_code = code.to_ascii_uppercase();
     let normalised =
         if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
@@ -557,7 +570,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
             }
         }
         Err(InvalidErrorCode) => {
-            early_error(output, format!("{code} is not a valid error code"));
+            handler.early_error(format!("{code} is not a valid error code"));
         }
     }
 }
@@ -636,7 +649,11 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
     }
 }
 
-pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Compilation {
+pub fn list_metadata(
+    handler: &EarlyErrorHandler,
+    sess: &Session,
+    metadata_loader: &dyn MetadataLoader,
+) -> Compilation {
     if sess.opts.unstable_opts.ls {
         match sess.io.input {
             Input::File(ref ifile) => {
@@ -646,7 +663,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
                 safe_println!("{}", String::from_utf8(v).unwrap());
             }
             Input::Str { .. } => {
-                early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
+                handler.early_error("cannot list metadata for stdin");
             }
         }
         return Compilation::Stop;
@@ -656,6 +673,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
 }
 
 fn print_crate_info(
+    handler: &EarlyErrorHandler,
     codegen_backend: &dyn CodegenBackend,
     sess: &Session,
     parse_attrs: bool,
@@ -787,10 +805,8 @@ fn print_crate_info(
                             .expect("unknown Apple target OS")
                     )
                 } else {
-                    early_error(
-                        ErrorOutputType::default(),
-                        "only Apple targets currently support deployment version info",
-                    )
+                    handler
+                        .early_error("only Apple targets currently support deployment version info")
                 }
             }
         }
@@ -801,11 +817,12 @@ fn print_crate_info(
 /// Prints version information
 ///
 /// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
-pub macro version($binary: literal, $matches: expr) {
+pub macro version($handler: expr, $binary: literal, $matches: expr) {
     fn unw(x: Option<&str>) -> &str {
         x.unwrap_or("unknown")
     }
     $crate::version_at_macro_invocation(
+        $handler,
         $binary,
         $matches,
         unw(option_env!("CFG_VERSION")),
@@ -817,6 +834,7 @@ pub macro version($binary: literal, $matches: expr) {
 
 #[doc(hidden)] // use the macro instead
 pub fn version_at_macro_invocation(
+    handler: &EarlyErrorHandler,
     binary: &str,
     matches: &getopts::Matches,
     version: &str,
@@ -837,7 +855,7 @@ pub fn version_at_macro_invocation(
 
         let debug_flags = matches.opt_strs("Z");
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(&None, backend_name).print_version();
+        get_codegen_backend(handler, &None, backend_name).print_version();
     }
 }
 
@@ -1014,7 +1032,7 @@ Available lint options:
 /// Show help for flag categories shared between rustdoc and rustc.
 ///
 /// Returns whether a help option was printed.
-pub fn describe_flag_categories(matches: &Matches) -> bool {
+pub fn describe_flag_categories(handler: &EarlyErrorHandler, matches: &Matches) -> bool {
     // Handle the special case of -Wall.
     let wall = matches.opt_strs("W");
     if wall.iter().any(|x| *x == "all") {
@@ -1036,15 +1054,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool {
     }
 
     if cg_flags.iter().any(|x| *x == "no-stack-check") {
-        early_warn(
-            ErrorOutputType::default(),
-            "the --no-stack-check flag is deprecated and does nothing",
-        );
+        handler.early_warn("the --no-stack-check flag is deprecated and does nothing");
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(&None, backend_name).print_passes();
+        get_codegen_backend(handler, &None, backend_name).print_passes();
         return true;
     }
 
@@ -1101,7 +1116,7 @@ fn print_flag_list<T>(
 ///
 /// So with all that in mind, the comments below have some more detail about the
 /// contortions done here to get things to work out correctly.
-pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
+pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
     if args.is_empty() {
         // user did not write `-v` nor `-Z unstable-options`, so do not
         // include that extra information.
@@ -1127,7 +1142,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
                 .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
             _ => None,
         };
-        early_error(ErrorOutputType::default(), msg.unwrap_or_else(|| e.to_string()));
+        handler.early_error(msg.unwrap_or_else(|| e.to_string()));
     });
 
     // For all options we just parsed, we check a few aspects:
@@ -1141,7 +1156,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     //   we're good to go.
     // * Otherwise, if we're an unstable option then we generate an error
     //   (unstable option being used on stable)
-    nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
+    nightly_options::check_nightly_options(handler, &matches, &config::rustc_optgroups());
 
     if matches.opt_present("h") || matches.opt_present("help") {
         // Only show unstable options in --help if we accept unstable options.
@@ -1151,12 +1166,12 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
         return None;
     }
 
-    if describe_flag_categories(&matches) {
+    if describe_flag_categories(handler, &matches) {
         return None;
     }
 
     if matches.opt_present("version") {
-        version!("rustc", &matches);
+        version!(handler, "rustc", &matches);
         return None;
     }
 
@@ -1276,7 +1291,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
         if let Some(msg) = info.payload().downcast_ref::<String>() {
             if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
                 // the error code is already going to be reported when the panic unwinds up the stack
-                let _ = early_error_no_abort(ErrorOutputType::default(), msg.clone());
+                let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+                let _ = handler.early_error_no_abort(msg.clone());
                 return;
             }
         };
@@ -1359,16 +1375,16 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
-pub fn init_rustc_env_logger() {
-    init_env_logger("RUSTC_LOG");
+pub fn init_rustc_env_logger(handler: &EarlyErrorHandler) {
+    init_env_logger(handler, "RUSTC_LOG");
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
 /// other than `RUSTC_LOG`.
-pub fn init_env_logger(env: &str) {
+pub fn init_env_logger(handler: &EarlyErrorHandler, env: &str) {
     if let Err(error) = rustc_log::init_env_logger(env) {
-        early_error(ErrorOutputType::default(), error.to_string());
+        handler.early_error(error.to_string());
     }
 }
 
@@ -1424,7 +1440,10 @@ mod signal_handler {
 pub fn main() -> ! {
     let start_time = Instant::now();
     let start_rss = get_resident_set_size();
-    init_rustc_env_logger();
+
+    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
+    init_rustc_env_logger(&handler);
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
     install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
@@ -1433,10 +1452,7 @@ pub fn main() -> ! {
             .enumerate()
             .map(|(i, arg)| {
                 arg.into_string().unwrap_or_else(|arg| {
-                    early_error(
-                        ErrorOutputType::default(),
-                        format!("argument {i} is not valid Unicode: {arg:?}"),
-                    )
+                    handler.early_error(format!("argument {i} is not valid Unicode: {arg:?}"))
                 })
             })
             .collect::<Vec<_>>();
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index bcfa5313bde..3e43eae006f 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -445,7 +445,7 @@ impl<'a> StripUnconfigured<'a> {
     /// If attributes are not allowed on expressions, emit an error for `attr`
     #[instrument(level = "trace", skip(self))]
     pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
-        if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
+        if self.features.is_some_and(|features| !features.stmt_expr_attributes) {
             let mut err = feature_err(
                 &self.sess.parse_sess,
                 sym::stmt_expr_attributes,
diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index 9dffc9a7645..56e23ac2775 100644
--- a/compiler/rustc_fluent_macro/src/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -179,7 +179,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
     let mut previous_defns = HashMap::new();
     let mut message_refs = Vec::new();
     for entry in resource.entries() {
-        if let Entry::Message(Message { id: Identifier { name }, attributes, value, .. }) = entry {
+        if let Entry::Message(msg) = entry {
+            let Message { id: Identifier { name }, attributes, value, .. } = msg;
             let _ = previous_defns.entry(name.to_string()).or_insert(resource_span);
             if name.contains('-') {
                 Diagnostic::spanned(
@@ -229,9 +230,10 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                 continue;
             }
 
-            let msg = format!("Constant referring to Fluent message `{name}` from `{crate_name}`");
+            let docstr =
+                format!("Constant referring to Fluent message `{name}` from `{crate_name}`");
             constants.extend(quote! {
-                #[doc = #msg]
+                #[doc = #docstr]
                 pub const #snake_name: crate::DiagnosticMessage =
                     crate::DiagnosticMessage::FluentIdentifier(
                         std::borrow::Cow::Borrowed(#name),
@@ -269,6 +271,15 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
                         );
                 });
             }
+
+            // Record variables referenced by these messages so we can produce
+            // tests in the derive diagnostics to validate them.
+            let ident = quote::format_ident!("{snake_name}_refs");
+            let vrefs = variable_references(msg);
+            constants.extend(quote! {
+                #[cfg(test)]
+                pub const #ident: &[&str] = &[#(#vrefs),*];
+            })
         }
     }
 
@@ -334,3 +345,28 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
     }
     .into()
 }
+
+fn variable_references<'a>(msg: &Message<&'a str>) -> Vec<&'a str> {
+    let mut refs = vec![];
+    if let Some(Pattern { elements }) = &msg.value {
+        for elt in elements {
+            if let PatternElement::Placeable {
+                expression: Expression::Inline(InlineExpression::VariableReference { id }),
+            } = elt
+            {
+                refs.push(id.name);
+            }
+        }
+    }
+    for attr in &msg.attributes {
+        for elt in &attr.value.elements {
+            if let PatternElement::Placeable {
+                expression: Expression::Inline(InlineExpression::VariableReference { id }),
+            } = elt
+            {
+                refs.push(id.name);
+            }
+        }
+    }
+    refs
+}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 5e5001bc8b4..591831b59a1 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1719,6 +1719,7 @@ impl Expr<'_> {
             ExprKind::Break(..) => ExprPrecedence::Break,
             ExprKind::Continue(..) => ExprPrecedence::Continue,
             ExprKind::Ret(..) => ExprPrecedence::Ret,
+            ExprKind::Become(..) => ExprPrecedence::Become,
             ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
             ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf,
             ExprKind::Struct(..) => ExprPrecedence::Struct,
@@ -1776,6 +1777,7 @@ impl Expr<'_> {
             | ExprKind::Break(..)
             | ExprKind::Continue(..)
             | ExprKind::Ret(..)
+            | ExprKind::Become(..)
             | ExprKind::Let(..)
             | ExprKind::Loop(..)
             | ExprKind::Assign(..)
@@ -1866,6 +1868,7 @@ impl Expr<'_> {
             | ExprKind::Break(..)
             | ExprKind::Continue(..)
             | ExprKind::Ret(..)
+            | ExprKind::Become(..)
             | ExprKind::Let(..)
             | ExprKind::Loop(..)
             | ExprKind::Assign(..)
@@ -2025,6 +2028,8 @@ pub enum ExprKind<'hir> {
     Continue(Destination),
     /// A `return`, with an optional value to be returned.
     Ret(Option<&'hir Expr<'hir>>),
+    /// A `become`, with the value to be returned.
+    Become(&'hir Expr<'hir>),
 
     /// Inline assembly (from `asm!`), with its outputs and inputs.
     InlineAsm(&'hir InlineAsm<'hir>),
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index f84c814bd92..1886a91bda8 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -791,6 +791,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::Ret(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
+        ExprKind::Become(ref expr) => visitor.visit_expr(expr),
         ExprKind::InlineAsm(ref asm) => {
             visitor.visit_inline_asm(asm, expression.hir_id);
         }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index cd6cf36baa4..edc6bcacc68 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -137,7 +137,7 @@ hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snip
 
 hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}`
     .note = default implementation of `{$missing_item_name}` is unstable
-    .some_note = use of unstable library feature '{$feature}': {$r}
+    .some_note = use of unstable library feature '{$feature}': {$reason}
     .none_note = use of unstable library feature '{$feature}'
 
 hir_analysis_missing_type_params =
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 41a6d94b278..6a59aa36ec7 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -945,40 +945,30 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         let mut trait_bounds = vec![];
         let mut projection_bounds = vec![];
-        for (clause, span) in bounds.clauses() {
-            let pred: ty::Predicate<'tcx> = clause.as_predicate();
+        for (pred, span) in bounds.clauses() {
             let bound_pred = pred.kind();
             match bound_pred.skip_binder() {
-                ty::PredicateKind::Clause(clause) => match clause {
-                    ty::ClauseKind::Trait(trait_pred) => {
-                        assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
-                        trait_bounds.push((
-                            bound_pred.rebind(trait_pred.trait_ref),
-                            span,
-                            trait_pred.constness,
-                        ));
-                    }
-                    ty::ClauseKind::Projection(proj) => {
-                        projection_bounds.push((bound_pred.rebind(proj), span));
-                    }
-                    ty::ClauseKind::TypeOutlives(_) => {
-                        // Do nothing, we deal with regions separately
-                    }
-                    ty::ClauseKind::RegionOutlives(_)
-                    | ty::ClauseKind::ConstArgHasType(..)
-                    | ty::ClauseKind::WellFormed(_)
-                    | ty::ClauseKind::ConstEvaluatable(_) => {
-                        bug!()
-                    }
-                },
-                ty::PredicateKind::AliasRelate(..)
-                | ty::PredicateKind::ObjectSafe(_)
-                | ty::PredicateKind::ClosureKind(_, _, _)
-                | ty::PredicateKind::Subtype(_)
-                | ty::PredicateKind::Coerce(_)
-                | ty::PredicateKind::ConstEquate(_, _)
-                | ty::PredicateKind::TypeWellFormedFromEnv(_)
-                | ty::PredicateKind::Ambiguous => bug!(),
+                ty::ClauseKind::Trait(trait_pred) => {
+                    assert_eq!(trait_pred.polarity, ty::ImplPolarity::Positive);
+                    trait_bounds.push((
+                        bound_pred.rebind(trait_pred.trait_ref),
+                        span,
+                        trait_pred.constness,
+                    ));
+                }
+                ty::ClauseKind::Projection(proj) => {
+                    projection_bounds.push((bound_pred.rebind(proj), span));
+                }
+                ty::ClauseKind::TypeOutlives(_) => {
+                    // Do nothing, we deal with regions separately
+                }
+                ty::ClauseKind::RegionOutlives(_)
+                | ty::ClauseKind::ConstArgHasType(..)
+                | ty::ClauseKind::WellFormed(_)
+                | ty::ClauseKind::ConstEvaluatable(_)
+                | ty::ClauseKind::TypeWellFormedFromEnv(_) => {
+                    bug!()
+                }
             }
         }
 
@@ -1425,9 +1415,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             || {
                 traits::transitive_bounds_that_define_assoc_item(
                     tcx,
-                    predicates.iter().filter_map(|(p, _)| {
-                        Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
-                    }),
+                    predicates
+                        .iter()
+                        .filter_map(|(p, _)| Some(p.as_trait_clause()?.map_bound(|t| t.trait_ref))),
                     assoc_name,
                 )
             },
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 b2ba566f60c..3048c175e1e 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -220,7 +220,7 @@ fn compare_method_predicate_entailment<'tcx>(
     // the new hybrid bounds we computed.
     let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id);
     let param_env = ty::ParamEnv::new(
-        tcx.mk_predicates(&hybrid_preds.predicates),
+        tcx.mk_clauses(&hybrid_preds.predicates),
         Reveal::UserFacing,
         hir::Constness::NotConst,
     );
@@ -1835,7 +1835,7 @@ fn compare_type_predicate_entailment<'tcx>(
     let impl_ty_span = tcx.def_span(impl_ty_def_id);
     let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
     let param_env = ty::ParamEnv::new(
-        tcx.mk_predicates(&hybrid_preds.predicates),
+        tcx.mk_clauses(&hybrid_preds.predicates),
         Reveal::UserFacing,
         hir::Constness::NotConst,
     );
@@ -2011,7 +2011,7 @@ pub(super) fn check_type_bounds<'tcx>(
                 .to_predicate(tcx),
             ),
         };
-        ty::ParamEnv::new(tcx.mk_predicates(&predicates), Reveal::UserFacing, param_env.constness())
+        ty::ParamEnv::new(tcx.mk_clauses(&predicates), Reveal::UserFacing, param_env.constness())
     };
     debug!(?normalize_param_env);
 
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 596c5518086..ce2da7cb1a3 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -296,7 +296,7 @@ fn default_body_is_unstable(
 /// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
 fn bounds_from_generic_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
-    predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>,
+    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
 ) -> (String, String) {
     let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
     let mut projections = vec![];
@@ -304,7 +304,7 @@ fn bounds_from_generic_predicates<'tcx>(
         debug!("predicate {:?}", predicate);
         let bound_predicate = predicate.kind();
         match bound_predicate.skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
+            ty::ClauseKind::Trait(trait_predicate) => {
                 let entry = types.entry(trait_predicate.self_ty()).or_default();
                 let def_id = trait_predicate.def_id();
                 if Some(def_id) != tcx.lang_items().sized_trait() {
@@ -313,7 +313,7 @@ fn bounds_from_generic_predicates<'tcx>(
                     entry.push(trait_predicate.def_id());
                 }
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection_pred)) => {
+            ty::ClauseKind::Projection(projection_pred) => {
                 projections.push(bound_predicate.rebind(projection_pred));
             }
             _ => {}
@@ -362,7 +362,7 @@ fn fn_sig_suggestion<'tcx>(
     tcx: TyCtxt<'tcx>,
     sig: ty::FnSig<'tcx>,
     ident: Ident,
-    predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>,
+    predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
     assoc: ty::AssocItem,
 ) -> String {
     let args = sig
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 744eb036933..d34d6f644a7 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use rustc_middle::ty::{GenericArgKind, InternalSubsts};
@@ -322,7 +322,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
             // Gather the bounds with which all other items inside of this trait constrain the GAT.
             // This is calculated by taking the intersection of the bounds that each item
             // constrains the GAT with individually.
-            let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
+            let mut new_required_bounds: Option<FxHashSet<ty::Clause<'_>>> = None;
             for item in associated_items {
                 let item_def_id = item.id.owner_id;
                 // Skip our own GAT, since it does not constrain itself at all.
@@ -419,20 +419,17 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
         let mut unsatisfied_bounds: Vec<_> = required_bounds
             .into_iter()
             .filter(|clause| match clause.kind().skip_binder() {
-                ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
-                    ty::OutlivesPredicate(a, b),
-                )) => !region_known_to_outlive(
-                    tcx,
-                    gat_def_id.def_id,
-                    param_env,
-                    &FxIndexSet::default(),
-                    a,
-                    b,
-                ),
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
-                    a,
-                    b,
-                ))) => !ty_known_to_outlive(
+                ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
+                    !region_known_to_outlive(
+                        tcx,
+                        gat_def_id.def_id,
+                        param_env,
+                        &FxIndexSet::default(),
+                        a,
+                        b,
+                    )
+                }
+                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => !ty_known_to_outlive(
                     tcx,
                     gat_def_id.def_id,
                     param_env,
@@ -440,7 +437,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
                     a,
                     b,
                 ),
-                _ => bug!("Unexpected PredicateKind"),
+                _ => bug!("Unexpected ClauseKind"),
             })
             .map(|clause| clause.to_string())
             .collect();
@@ -488,7 +485,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
 fn augment_param_env<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    new_predicates: Option<&FxHashSet<ty::Predicate<'tcx>>>,
+    new_predicates: Option<&FxHashSet<ty::Clause<'tcx>>>,
 ) -> ty::ParamEnv<'tcx> {
     let Some(new_predicates) = new_predicates else {
         return param_env;
@@ -498,7 +495,7 @@ fn augment_param_env<'tcx>(
         return param_env;
     }
 
-    let bounds = tcx.mk_predicates_from_iter(
+    let bounds = tcx.mk_clauses_from_iter(
         param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()),
     );
     // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
@@ -524,7 +521,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
     wf_tys: &FxIndexSet<Ty<'tcx>>,
     gat_def_id: LocalDefId,
     gat_generics: &'tcx ty::Generics,
-) -> Option<FxHashSet<ty::Predicate<'tcx>>> {
+) -> Option<FxHashSet<ty::Clause<'tcx>>> {
     // The bounds we that we would require from `to_check`
     let mut bounds = FxHashSet::default();
 
@@ -573,11 +570,10 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                 );
                 // The predicate we expect to see. (In our example,
                 // `Self: 'me`.)
-                let clause = ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
-                    ty::OutlivesPredicate(ty_param, region_param),
-                ));
-                let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
-                bounds.insert(clause);
+                bounds.insert(
+                    ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param))
+                        .to_predicate(tcx),
+                );
             }
         }
 
@@ -622,11 +618,13 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
                     },
                 );
                 // The predicate we expect to see.
-                let clause = ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
-                    ty::OutlivesPredicate(region_a_param, region_b_param),
-                ));
-                let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
-                bounds.insert(clause);
+                bounds.insert(
+                    ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
+                        region_a_param,
+                        region_b_param,
+                    ))
+                    .to_predicate(tcx),
+                );
             }
         }
     }
@@ -1406,7 +1404,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
             infcx,
             wfcx.param_env.without_const(),
             wfcx.body_def_id,
-            p,
+            p.as_predicate(),
             sp,
         )
     });
@@ -1549,7 +1547,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
         {
             let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
                 match re.kind() {
-                    ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) => re,
+                    ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) | ty::ReStatic => re,
                     r => bug!("unexpected region: {r:?}"),
                 }
             });
@@ -1875,9 +1873,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
             // We lower empty bounds like `Vec<dyn Copy>:` as
             // `WellFormed(Vec<dyn Copy>)`, which will later get checked by
             // regular WF checking
-            if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) =
-                pred.kind().skip_binder()
-            {
+            if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() {
                 continue;
             }
             // Match the existing behavior.
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index bd6252344b2..3bd2931265c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -140,7 +140,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
         impl1_def_id: DefId,
         impl2_def_id: DefId,
     ) {
-        traits::overlapping_impls(
+        let maybe_overlap = traits::overlapping_impls(
             self.tcx,
             impl1_def_id,
             impl2_def_id,
@@ -148,11 +148,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
             // inherent impls without warning.
             SkipLeakCheck::Yes,
             overlap_mode,
-        )
-        .map_or(true, |overlap| {
+        );
+
+        if let Some(overlap) = maybe_overlap {
             self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id, overlap);
-            false
-        });
+        }
     }
 
     fn check_item(&mut self, id: hir::ItemId) {
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 958313fee6f..44c393bfe82 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -38,16 +38,12 @@ fn associated_type_bounds<'tcx>(
         .iter()
         .copied()
         .filter(|(pred, _)| match pred.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => tr.self_ty() == item_ty,
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
-                proj.projection_ty.self_ty() == item_ty
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
-                outlives.0 == item_ty
-            }
+            ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty,
+            ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
+            ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty,
             _ => false,
         })
-        .map(|(pred, span)| (pred.expect_clause(), span));
+        .map(|(clause, span)| (clause, span));
 
     let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses().chain(bounds_from_parent));
     debug!(
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 3081f0c386a..edb6a4cace3 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -75,7 +75,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
 
     // We use an `IndexSet` to preserve order of insertion.
     // Preserving the order of insertion is important here so as not to break UI tests.
-    let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
+    let mut predicates: FxIndexSet<(ty::Clause<'_>, Span)> = FxIndexSet::default();
 
     let ast_generics = match node {
         Node::TraitItem(item) => item.generics,
@@ -126,8 +126,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
         predicates.extend(
             icx.astconv()
                 .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
-                .clauses()
-                .map(|(clause, span)| (clause.as_predicate(), span)),
+                .clauses(),
         );
     }
 
@@ -176,8 +175,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     param.span,
                 );
                 trace!(?bounds);
-                predicates
-                    .extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)));
+                predicates.extend(bounds.clauses());
                 trace!(?predicates);
             }
             GenericParamKind::Const { .. } => {
@@ -188,11 +186,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
 
                 let ct = tcx.mk_const(param_const, ct_ty);
 
-                let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
-                    ty::ClauseKind::ConstArgHasType(ct, ct_ty),
-                ))
-                .to_predicate(tcx);
-                predicates.insert((predicate, param.span));
+                predicates.insert((
+                    ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx),
+                    param.span,
+                ));
 
                 index += 1;
             }
@@ -221,7 +218,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     } else {
                         let span = bound_pred.bounded_ty.span;
                         let predicate = ty::Binder::bind_with_vars(
-                            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty.into())),
+                            ty::ClauseKind::WellFormed(ty.into()),
                             bound_vars,
                         );
                         predicates.insert((predicate.to_predicate(tcx), span));
@@ -236,8 +233,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     bound_vars,
                     OnlySelfBounds(false),
                 );
-                predicates
-                    .extend(bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)));
+                predicates.extend(bounds.clauses());
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
@@ -249,11 +245,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                         }
                         _ => bug!(),
                     };
-                    let pred = ty::Binder::dummy(ty::PredicateKind::Clause(
-                        ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)),
-                    ))
-                    .to_predicate(icx.tcx);
-
+                    let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
+                        .to_predicate(icx.tcx);
                     (pred, span)
                 }))
             }
@@ -318,17 +311,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                 },
             );
             predicates.push((
-                ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
-                    ty::OutlivesPredicate(orig_region, dup_region),
-                )))
-                .to_predicate(icx.tcx),
+                ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_region, dup_region))
+                    .to_predicate(icx.tcx),
                 duplicate.span,
             ));
             predicates.push((
-                ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
-                    ty::OutlivesPredicate(dup_region, orig_region),
-                )))
-                .to_predicate(icx.tcx),
+                ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_region, orig_region))
+                    .to_predicate(icx.tcx),
                 duplicate.span,
             ));
         }
@@ -344,10 +333,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
 fn const_evaluatable_predicates_of(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
-) -> FxIndexSet<(ty::Predicate<'_>, Span)> {
+) -> FxIndexSet<(ty::Clause<'_>, Span)> {
     struct ConstCollector<'tcx> {
         tcx: TyCtxt<'tcx>,
-        preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
+        preds: FxIndexSet<(ty::Clause<'tcx>, Span)>,
     }
 
     impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
@@ -355,13 +344,8 @@ fn const_evaluatable_predicates_of(
             let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
             if let ty::ConstKind::Unevaluated(_) = ct.kind() {
                 let span = self.tcx.def_span(c.def_id);
-                self.preds.insert((
-                    ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(
-                        ct,
-                    )))
-                    .to_predicate(self.tcx),
-                    span,
-                ));
+                self.preds
+                    .insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span));
             }
         }
 
@@ -449,15 +433,9 @@ pub(super) fn explicit_predicates_of<'tcx>(
             .iter()
             .copied()
             .filter(|(pred, _)| match pred.kind().skip_binder() {
-                ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr)) => {
-                    !is_assoc_item_ty(tr.self_ty())
-                }
-                ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) => {
-                    !is_assoc_item_ty(proj.projection_ty.self_ty())
-                }
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(outlives)) => {
-                    !is_assoc_item_ty(outlives.0)
-                }
+                ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
+                ty::ClauseKind::Projection(proj) => !is_assoc_item_ty(proj.projection_ty.self_ty()),
+                ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
                 _ => true,
             })
             .collect();
@@ -498,9 +476,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
                     .predicates
                     .into_iter()
                     .filter(|(pred, _)| {
-                        if let ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) =
-                            pred.kind().skip_binder()
-                        {
+                        if let ty::ClauseKind::ConstArgHasType(ct, _) = pred.kind().skip_binder() {
                             match ct.kind() {
                                 ty::ConstKind::Param(param_const) => {
                                     let defaulted_param_idx = tcx
@@ -665,12 +641,8 @@ pub(super) fn implied_predicates_with_filter(
     };
 
     // Combine the two lists to form the complete set of superbounds:
-    let implied_bounds = &*tcx.arena.alloc_from_iter(
-        superbounds
-            .clauses()
-            .map(|(clause, span)| (clause.as_predicate(), span))
-            .chain(where_bounds_that_match),
-    );
+    let implied_bounds =
+        &*tcx.arena.alloc_from_iter(superbounds.clauses().chain(where_bounds_that_match));
     debug!(?implied_bounds);
 
     // Now require that immediate supertraits are converted, which will, in
@@ -679,7 +651,7 @@ pub(super) fn implied_predicates_with_filter(
     if matches!(filter, PredicateFilter::SelfOnly) {
         for &(pred, span) in implied_bounds {
             debug!("superbound: {:?}", pred);
-            if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(bound)) = pred.kind().skip_binder()
+            if let ty::ClauseKind::Trait(bound) = pred.kind().skip_binder()
                 && bound.polarity == ty::ImplPolarity::Positive
             {
                 tcx.at(span).super_predicates_of(bound.def_id());
@@ -776,9 +748,7 @@ pub(super) fn type_param_predicates(
         )
         .into_iter()
         .filter(|(predicate, _)| match predicate.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
-                data.self_ty().is_param(index)
-            }
+            ty::ClauseKind::Trait(data) => data.self_ty().is_param(index),
             _ => false,
         }),
     );
@@ -800,7 +770,7 @@ impl<'tcx> ItemCtxt<'tcx> {
         ty: Ty<'tcx>,
         only_self_bounds: OnlySelfBounds,
         assoc_name: Option<Ident>,
-    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+    ) -> Vec<(ty::Clause<'tcx>, Span)> {
         let mut bounds = Bounds::default();
 
         for predicate in ast_generics.predicates {
@@ -829,7 +799,7 @@ impl<'tcx> ItemCtxt<'tcx> {
             );
         }
 
-        bounds.clauses().map(|(clause, span)| (clause.as_predicate(), span)).collect()
+        bounds.clauses().collect()
     }
 
     #[instrument(level = "trace", skip(self))]
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index d20f39e9b05..3d75df8c69f 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -1761,7 +1761,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
                 let bound_predicate = pred.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
+                    ty::ClauseKind::Trait(data) => {
                         // The order here needs to match what we would get from `subst_supertrait`
                         let pred_bound_vars = bound_predicate.bound_vars();
                         let mut all_bound_vars = bound_vars.clone();
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 6aecb95b484..35882ad352b 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -151,7 +151,7 @@ pub fn identify_constrained_generic_params<'tcx>(
 /// think of any.
 pub fn setup_constraining_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
-    predicates: &mut [(ty::Predicate<'tcx>, Span)],
+    predicates: &mut [(ty::Clause<'tcx>, Span)],
     impl_trait_ref: Option<ty::TraitRef<'tcx>>,
     input_parameters: &mut FxHashSet<Parameter>,
 ) {
@@ -187,9 +187,7 @@ pub fn setup_constraining_predicates<'tcx>(
         for j in i..predicates.len() {
             // Note that we don't have to care about binders here,
             // as the impl trait ref never contains any late-bound regions.
-            if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(projection)) =
-                predicates[j].0.kind().skip_binder()
-            {
+            if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() {
                 // Special case: watch out for some kind of sneaky attempt
                 // to project out an associated type defined by this very
                 // trait.
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 97813a291da..383144ce139 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
@@ -235,10 +235,8 @@ fn unconstrained_parent_impl_substs<'tcx>(
     // what we want here. We want only a list of constrained parameters while
     // the functions in `cgp` add the constrained parameters to a list of
     // unconstrained parameters.
-    for (predicate, _) in impl_generic_predicates.predicates.iter() {
-        if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
-            predicate.kind().skip_binder()
-        {
+    for (clause, _) in impl_generic_predicates.predicates.iter() {
+        if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() {
             let projection_ty = proj.projection_ty;
             let projected_ty = proj.term;
 
@@ -340,8 +338,11 @@ fn check_predicates<'tcx>(
     impl2_substs: SubstsRef<'tcx>,
     span: Span,
 ) {
-    let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
-    let impl1_predicates: Vec<_> = traits::elaborate(tcx, instantiated.into_iter()).collect();
+    let impl1_predicates: Vec<_> = traits::elaborate(
+        tcx,
+        tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).into_iter(),
+    )
+    .collect();
 
     let mut impl2_predicates = if impl2_node.is_from_trait() {
         // Always applicable traits have to be always applicable without any
@@ -352,8 +353,8 @@ fn check_predicates<'tcx>(
             tcx,
             tcx.predicates_of(impl2_node.def_id())
                 .instantiate(tcx, impl2_substs)
-                .predicates
-                .into_iter(),
+                .into_iter()
+                .map(|(c, _s)| c.as_predicate()),
         )
         .collect()
     };
@@ -377,13 +378,13 @@ fn check_predicates<'tcx>(
     let always_applicable_traits = impl1_predicates
         .iter()
         .copied()
-        .filter(|&(predicate, _)| {
+        .filter(|(clause, _span)| {
             matches!(
-                trait_predicate_kind(tcx, predicate),
+                trait_predicate_kind(tcx, clause.as_predicate()),
                 Some(TraitSpecializationKind::AlwaysApplicable)
             )
         })
-        .map(|(pred, _span)| pred);
+        .map(|(c, _span)| c.as_predicate());
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().subst_identity().substs {
@@ -398,9 +399,12 @@ fn check_predicates<'tcx>(
     }
     impl2_predicates.extend(traits::elaborate(tcx, always_applicable_traits));
 
-    for (predicate, span) in impl1_predicates {
-        if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(tcx, predicate, *pred2, span)) {
-            check_specialization_on(tcx, predicate, span)
+    for (clause, span) in impl1_predicates {
+        if !impl2_predicates
+            .iter()
+            .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
+        {
+            check_specialization_on(tcx, clause.as_predicate(), span)
         }
     }
 }
@@ -550,6 +554,6 @@ fn trait_predicate_kind<'tcx>(
         | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::Ambiguous
-        | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+        | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => None,
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index e63549998d2..3a04c3336ca 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -30,40 +30,31 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
             // process predicates and convert to `RequiredPredicates` entry, see below
             for &(predicate, span) in predicates.predicates {
                 match predicate.kind().skip_binder() {
-                    ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(OutlivesPredicate(
-                        ty,
-                        reg,
-                    ))) => insert_outlives_predicate(
-                        tcx,
-                        ty.into(),
-                        reg,
-                        span,
-                        &mut required_predicates,
-                    ),
+                    ty::ClauseKind::TypeOutlives(OutlivesPredicate(ty, reg)) => {
+                        insert_outlives_predicate(
+                            tcx,
+                            ty.into(),
+                            reg,
+                            span,
+                            &mut required_predicates,
+                        )
+                    }
 
-                    ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(
-                        OutlivesPredicate(reg1, reg2),
-                    )) => insert_outlives_predicate(
-                        tcx,
-                        reg1.into(),
-                        reg2,
-                        span,
-                        &mut required_predicates,
-                    ),
-
-                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
-                    | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
-                    | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
-                    | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
-                    | ty::PredicateKind::AliasRelate(..)
-                    | ty::PredicateKind::ObjectSafe(..)
-                    | ty::PredicateKind::ClosureKind(..)
-                    | ty::PredicateKind::Subtype(..)
-                    | ty::PredicateKind::Coerce(..)
-                    | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                    | ty::PredicateKind::ConstEquate(..)
-                    | ty::PredicateKind::Ambiguous
-                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
+                    ty::ClauseKind::RegionOutlives(OutlivesPredicate(reg1, reg2)) => {
+                        insert_outlives_predicate(
+                            tcx,
+                            reg1.into(),
+                            reg2,
+                            span,
+                            &mut required_predicates,
+                        )
+                    }
+                    ty::ClauseKind::Trait(_)
+                    | ty::ClauseKind::Projection(_)
+                    | ty::ClauseKind::ConstArgHasType(_, _)
+                    | ty::ClauseKind::WellFormed(_)
+                    | ty::ClauseKind::ConstEvaluatable(_)
+                    | ty::ClauseKind::TypeWellFormedFromEnv(_) => {}
                 }
             }
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index ced46fe426c..a699cd6c942 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1554,6 +1554,11 @@ impl<'a> State<'a> {
                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
                 }
             }
+            hir::ExprKind::Become(result) => {
+                self.word("become");
+                self.word(" ");
+                self.print_expr_maybe_paren(result, parser::PREC_JUMP);
+            }
             hir::ExprKind::InlineAsm(asm) => {
                 self.word("asm!");
                 self.print_inline_asm(asm);
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index c1c58db5764..3d012a15a67 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -78,8 +78,8 @@ hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang
 hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
 
 hir_typeck_return_stmt_outside_of_fn_body =
-    return statement outside of function body
-    .encl_body_label = the return is part of this body...
+    {$statement_kind} statement outside of function body
+    .encl_body_label = the {$statement_kind} is part of this body...
     .encl_fn_label = ...not the enclosing function body
 
 hir_typeck_struct_expr_non_exhaustive =
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 9ce03060e0f..47f3c6b8407 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -83,6 +83,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         self.annotate_expected_due_to_let_ty(err, expr, error);
+
+        if self.is_destruct_assignment_desugaring(expr) {
+            return;
+        }
         self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
@@ -1253,6 +1257,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         false
     }
 
+    // Returns whether the given expression is a destruct assignment desugaring.
+    // For example, `(a, b) = (1, &2);`
+    // Here we try to find the pattern binding of the expression,
+    // `default_binding_modes` is false only for destruct assignment desugaring.
+    pub(crate) fn is_destruct_assignment_desugaring(&self, expr: &hir::Expr<'_>) -> bool {
+        if let hir::ExprKind::Path(hir::QPath::Resolved(
+            _,
+            hir::Path { res: hir::def::Res::Local(bind_hir_id), .. },
+        )) = expr.kind
+        {
+            let bind = self.tcx.hir().find(*bind_hir_id);
+            let parent = self.tcx.hir().find(self.tcx.hir().parent_id(*bind_hir_id));
+            if let Some(hir::Node::Pat(hir::Pat { kind: hir::PatKind::Binding(_, _hir_id, _, _), .. })) = bind &&
+                let Some(hir::Node::Pat(hir::Pat { default_binding_modes: false, .. })) = parent {
+                    return true;
+                }
+        }
+        return false;
+    }
+
     /// This function is used to determine potential "simple" improvements or users' errors and
     /// provide them useful help. For example:
     ///
@@ -1443,6 +1467,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _,
                 &ty::Ref(_, checked, _),
             ) if self.can_sub(self.param_env, checked, expected) => {
+                let make_sugg = |start: Span, end: BytePos| {
+                    // skip `(` for tuples such as `(c) = (&123)`.
+                    // make sure we won't suggest like `(c) = 123)` which is incorrect.
+                    let sp = sm.span_extend_while(start.shrink_to_lo(), |c| c == '(' || c.is_whitespace())
+                                .map_or(start, |s| s.shrink_to_hi());
+                    Some((
+                        vec![(sp.with_hi(end), String::new())],
+                        "consider removing the borrow".to_string(),
+                        Applicability::MachineApplicable,
+                        true,
+                        true,
+                    ))
+                };
+
                 // We have `&T`, check if what was expected was `T`. If so,
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
@@ -1456,24 +1494,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .find(|&s| sp.contains(s))
                         && sm.is_span_accessible(call_span)
                     {
-                        return Some((
-                            vec![(sp.with_hi(call_span.lo()), String::new())],
-                            "consider removing the borrow".to_string(),
-                            Applicability::MachineApplicable,
-                            true,
-                            true,
-                        ));
+                        return make_sugg(sp, call_span.lo())
                     }
                     return None;
                 }
                 if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
-                    return Some((
-                        vec![(sp.with_hi(expr.span.lo()), String::new())],
-                        "consider removing the borrow".to_string(),
-                        Applicability::MachineApplicable,
-                        true,
-                        true,
-                    ));
+                    return make_sugg(sp, expr.span.lo())
                 }
             }
             (
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 6b4168d8944..05906a4b9f5 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -2,7 +2,10 @@
 use std::borrow::Cow;
 
 use crate::fluent_generated as fluent;
-use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
+use rustc_errors::{
+    AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg, MultiSpan,
+    SubdiagnosticMessage,
+};
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{
@@ -31,6 +34,24 @@ pub struct ReturnStmtOutsideOfFnBody {
     pub encl_body_span: Option<Span>,
     #[label(hir_typeck_encl_fn_label)]
     pub encl_fn_span: Option<Span>,
+    pub statement_kind: ReturnLikeStatementKind,
+}
+
+pub enum ReturnLikeStatementKind {
+    Return,
+    Become,
+}
+
+impl IntoDiagnosticArg for ReturnLikeStatementKind {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        let kind = match self {
+            Self::Return => "return",
+            Self::Become => "become",
+        }
+        .into();
+
+        DiagnosticArgValue::Str(kind)
+    }
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index e250e68a7f1..8d621c5a42b 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -5,6 +5,7 @@
 use crate::cast;
 use crate::coercion::CoerceMany;
 use crate::coercion::DynamicCoerceMany;
+use crate::errors::ReturnLikeStatementKind;
 use crate::errors::TypeMismatchFruTypo;
 use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive};
 use crate::errors::{
@@ -324,6 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
+            ExprKind::Become(call) => self.check_expr_become(call, expr),
             ExprKind::Let(let_expr) => self.check_expr_let(let_expr),
             ExprKind::Loop(body, _, source, _) => {
                 self.check_expr_loop(body, source, expected, expr)
@@ -735,47 +737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         if self.ret_coercion.is_none() {
-            let mut err = ReturnStmtOutsideOfFnBody {
-                span: expr.span,
-                encl_body_span: None,
-                encl_fn_span: None,
-            };
-
-            let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
-
-            if let Some(hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Fn(..),
-                span: encl_fn_span,
-                ..
-            }))
-            | Some(hir::Node::TraitItem(hir::TraitItem {
-                kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
-                span: encl_fn_span,
-                ..
-            }))
-            | Some(hir::Node::ImplItem(hir::ImplItem {
-                kind: hir::ImplItemKind::Fn(..),
-                span: encl_fn_span,
-                ..
-            })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
-            {
-                // We are inside a function body, so reporting "return statement
-                // outside of function body" needs an explanation.
-
-                let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
-
-                // If this didn't hold, we would not have to report an error in
-                // the first place.
-                assert_ne!(encl_item_id.def_id, encl_body_owner_id);
-
-                let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
-                let encl_body = self.tcx.hir().body(encl_body_id);
-
-                err.encl_body_span = Some(encl_body.value.span);
-                err.encl_fn_span = Some(*encl_fn_span);
-            }
-
-            self.tcx.sess.emit_err(err);
+            self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Return);
 
             if let Some(e) = expr_opt {
                 // We still have to type-check `e` (issue #86188), but calling
@@ -815,6 +777,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.tcx.types.never
     }
 
+    fn check_expr_become(
+        &self,
+        call: &'tcx hir::Expr<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        match &self.ret_coercion {
+            Some(ret_coercion) => {
+                let ret_ty = ret_coercion.borrow().expected_ty();
+                let call_expr_ty = self.check_expr_with_hint(call, ret_ty);
+
+                // N.B. don't coerce here, as tail calls can't support most/all coercions
+                // FIXME(explicit_tail_calls): add a diagnostic note that `become` doesn't allow coercions
+                self.demand_suptype(expr.span, ret_ty, call_expr_ty);
+            }
+            None => {
+                self.emit_return_outside_of_fn_body(expr, ReturnLikeStatementKind::Become);
+
+                // Fallback to simply type checking `call` without hint/demanding the right types.
+                // Best effort to highlight more errors.
+                self.check_expr(call);
+            }
+        }
+
+        self.tcx.types.never
+    }
+
+    /// Check an expression that _is being returned_.
+    /// For example, this is called with `return_expr: $expr` when `return $expr`
+    /// is encountered.
+    ///
+    /// Note that this function must only be called in function bodies.
+    ///
     /// `explicit_return` is `true` if we're checking an explicit `return expr`,
     /// and `false` if we're checking a trailing expression.
     pub(super) fn check_return_expr(
@@ -831,10 +825,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut span = return_expr.span;
         // Use the span of the trailing expression for our cause,
         // not the span of the entire function
-        if !explicit_return {
-            if let ExprKind::Block(body, _) = return_expr.kind && let Some(last_expr) = body.expr {
+        if !explicit_return
+            && let ExprKind::Block(body, _) = return_expr.kind
+            && let Some(last_expr) = body.expr
+        {
                 span = last_expr.span;
-            }
         }
         ret_coercion.borrow_mut().coerce(
             self,
@@ -854,6 +849,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Emit an error because `return` or `become` is used outside of a function body.
+    ///
+    /// `expr` is the `return` (`become`) "statement", `kind` is the kind of the statement
+    /// either `Return` or `Become`.
+    fn emit_return_outside_of_fn_body(&self, expr: &hir::Expr<'_>, kind: ReturnLikeStatementKind) {
+        let mut err = ReturnStmtOutsideOfFnBody {
+            span: expr.span,
+            encl_body_span: None,
+            encl_fn_span: None,
+            statement_kind: kind,
+        };
+
+        let encl_item_id = self.tcx.hir().get_parent_item(expr.hir_id);
+
+        if let Some(hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::Fn(..),
+            span: encl_fn_span,
+            ..
+        }))
+        | Some(hir::Node::TraitItem(hir::TraitItem {
+            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
+            span: encl_fn_span,
+            ..
+        }))
+        | Some(hir::Node::ImplItem(hir::ImplItem {
+            kind: hir::ImplItemKind::Fn(..),
+            span: encl_fn_span,
+            ..
+        })) = self.tcx.hir().find_by_def_id(encl_item_id.def_id)
+        {
+            // We are inside a function body, so reporting "return statement
+            // outside of function body" needs an explanation.
+
+            let encl_body_owner_id = self.tcx.hir().enclosing_body_owner(expr.hir_id);
+
+            // If this didn't hold, we would not have to report an error in
+            // the first place.
+            assert_ne!(encl_item_id.def_id, encl_body_owner_id);
+
+            let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
+            let encl_body = self.tcx.hir().body(encl_body_id);
+
+            err.encl_body_span = Some(encl_body.value.span);
+            err.encl_fn_span = Some(*encl_fn_span);
+        }
+
+        self.tcx.sess.emit_err(err);
+    }
+
     fn point_at_return_for_opaque_ty_error(
         &self,
         errors: &mut Vec<traits::FulfillmentError<'tcx>>,
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 82d9f03b145..0d2e0602e1c 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -326,6 +326,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 }
             }
 
+            hir::ExprKind::Become(call) => {
+                self.consume_expr(call);
+            }
+
             hir::ExprKind::Assign(lhs, rhs, _) => {
                 self.mutate_expr(lhs);
                 self.consume_expr(rhs);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index b44c51ba945..cf6d9eda321 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -683,7 +683,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // inference variable.
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+                | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => None,
             },
         )
     }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 880437023c8..223aedefea3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -25,16 +25,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let generics = self.tcx.generics_of(def_id);
         let predicate_substs = match unsubstituted_pred.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-                pred.trait_ref.substs.to_vec()
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
-                pred.projection_ty.substs.to_vec()
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(arg, ty)) => {
+            ty::ClauseKind::Trait(pred) => pred.trait_ref.substs.to_vec(),
+            ty::ClauseKind::Projection(pred) => pred.projection_ty.substs.to_vec(),
+            ty::ClauseKind::ConstArgHasType(arg, ty) => {
                 vec![ty.into(), arg.into()]
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(e)) => vec![e.into()],
+            ty::ClauseKind::ConstEvaluatable(e) => vec![e.into()],
             _ => return false,
         };
 
@@ -512,11 +508,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // This shouldn't happen, but since this is only a diagnostic improvement, avoid breaking things.
             return Err(expr);
         }
-        let relevant_broken_predicate: ty::PredicateKind<'tcx> =
-            impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder();
 
-        match relevant_broken_predicate {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(broken_trait)) => {
+        match impl_predicates.predicates[impl_predicate_index].0.kind().skip_binder() {
+            ty::ClauseKind::Trait(broken_trait) => {
                 // ...
                 self.blame_specific_part_of_expr_corresponding_to_generic_param(
                     broken_trait.trait_ref.self_ty().into(),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index f294ff0051d..3c67280e0d4 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -955,9 +955,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         //   - f(0, 1,)
                         //   + f()
                         if only_extras_so_far
-                            && errors
+                            && !errors
                                 .peek()
-                                .map_or(true, |next_error| !matches!(next_error, Error::Extra(_)))
+                                .is_some_and(|next_error| matches!(next_error, Error::Extra(_)))
                         {
                             let next = provided_arg_tys
                                 .get(arg_idx + 1)
@@ -1948,7 +1948,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // do that, so it's OK.
                         for (predicate, span) in instantiated
                         {
-                            if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = predicate.kind().skip_binder()
+                            if let ty::ClauseKind::Trait(pred) = predicate.kind().skip_binder()
                                 && pred.self_ty().peel_refs() == callee_ty
                                 && self.tcx.is_fn_trait(pred.def_id())
                             {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index d311ebe8c32..00a3f47b306 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -226,9 +226,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
             predicates: tcx.arena.alloc_from_iter(
                 self.param_env.caller_bounds().iter().filter_map(|predicate| {
                     match predicate.kind().skip_binder() {
-                        ty::PredicateKind::Clause(ty::ClauseKind::Trait(data))
-                            if data.self_ty().is_param(index) =>
-                        {
+                        ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
                             // HACK(eddyb) should get the original `Span`.
                             let span = tcx.def_span(def_id);
                             Some((predicate, span))
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 786a8c28f99..b84c4918649 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -214,6 +214,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
             | ExprKind::Break(..)
             | ExprKind::Continue(..)
             | ExprKind::Ret(..)
+            | ExprKind::Become(..)
             | ExprKind::InlineAsm(..)
             | ExprKind::OffsetOf(..)
             | ExprKind::Struct(..)
@@ -451,6 +452,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
                 }
             }
 
+            ExprKind::Become(_call) => bug!("encountered a tail-call inside a generator"),
+
             ExprKind::Call(f, args) => {
                 self.visit_expr(f);
                 for arg in args {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 78171e0b20e..6c8589493cb 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -361,6 +361,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             | hir::ExprKind::AssignOp(..)
             | hir::ExprKind::Closure { .. }
             | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Become(..)
             | hir::ExprKind::Unary(..)
             | hir::ExprKind::Yield(..)
             | hir::ExprKind::MethodCall(..)
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 279ff849e3d..31894d25b60 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -606,9 +606,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         traits::elaborate(self.tcx, predicates.predicates.iter().copied())
             // We don't care about regions here.
             .filter_map(|pred| match pred.kind().skip_binder() {
-                ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))
-                    if trait_pred.def_id() == sized_def_id =>
-                {
+                ty::ClauseKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
                     let span = predicates
                         .iter()
                         .find_map(|(p, span)| if p == pred { Some(span) } else { None })
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 762176ecfc7..35d70968ce7 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -834,7 +834,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
             let bound_predicate = predicate.kind();
             match bound_predicate.skip_binder() {
-                ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
+                ty::ClauseKind::Trait(trait_predicate) => {
                     match *trait_predicate.trait_ref.self_ty().kind() {
                         ty::Param(p) if p == param_ty => {
                             Some(bound_predicate.rebind(trait_predicate.trait_ref))
@@ -842,20 +842,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         _ => None,
                     }
                 }
-                ty::PredicateKind::Subtype(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
-                | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
-                | ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::ClosureKind(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasRelate(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+                ty::ClauseKind::RegionOutlives(_)
+                | ty::ClauseKind::TypeOutlives(_)
+                | ty::ClauseKind::Projection(_)
+                | ty::ClauseKind::ConstArgHasType(_, _)
+                | ty::ClauseKind::WellFormed(_)
+                | ty::ClauseKind::ConstEvaluatable(_)
+                | ty::ClauseKind::TypeWellFormedFromEnv(_) => None,
             }
         });
 
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 2f9871a103a..5af955d3134 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -393,8 +393,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // They can denote both statically and dynamically-sized byte arrays.
         let mut pat_ty = ty;
         if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(..), .. }) = lt.kind {
-            if let ty::Ref(_, inner_ty, _) = *self.structurally_resolved_type(span, expected).kind()
-                && self.structurally_resolved_type(span, inner_ty).is_slice()
+            let expected = self.structurally_resolved_type(span, expected);
+            if let ty::Ref(_, inner_ty, _) = expected.kind()
+                && matches!(inner_ty.kind(), ty::Slice(_))
             {
                 let tcx = self.tcx;
                 trace!(?lt.hir_id.local_id, "polymorphic byte string lit");
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 630014e2380..32054e6d125 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -739,10 +739,8 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
         self.obligations.push(Obligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
-            predicate: ty::Binder::dummy(ty::PredicateKind::Clause(
-                ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub)),
-            ))
-            .to_predicate(self.infcx.tcx),
+            predicate: ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(sup, sub))
+                .to_predicate(self.infcx.tcx),
             recursion_depth: 0,
         });
     }
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 2a32f0b5047..7293de4c6c5 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
@@ -139,7 +139,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                     tcx,
                                     generics,
                                     diag,
-                                    &format!("{}", proj.self_ty()),
+                                    &proj.self_ty().to_string(),
                                     &path,
                                     None,
                                     matching_span,
@@ -153,7 +153,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                     tcx,
                                     generics,
                                     diag,
-                                    &format!("{}", proj.self_ty()),
+                                    &proj.self_ty().to_string(),
                                     &path,
                                     None,
                                     matching_span,
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 9526ed144c3..7dbc18908d5 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1474,6 +1474,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// universes. Updates `self.universe` to that new universe.
     pub fn create_next_universe(&self) -> ty::UniverseIndex {
         let u = self.universe.get().next_universe();
+        debug!("create_next_universe {u:?}");
         self.universe.set(u);
         u
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index d926f7f7cbd..c998c923760 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -20,27 +20,19 @@ pub fn explicit_outlives_bounds<'tcx>(
     param_env
         .caller_bounds()
         .into_iter()
-        .map(ty::Predicate::kind)
+        .map(ty::Clause::kind)
         .filter_map(ty::Binder::no_bound_vars)
         .filter_map(move |kind| match kind {
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
-            | ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
-            | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
-            | ty::PredicateKind::AliasRelate(..)
-            | ty::PredicateKind::Coerce(..)
-            | ty::PredicateKind::Subtype(..)
-            | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
-            | ty::PredicateKind::ObjectSafe(..)
-            | ty::PredicateKind::ClosureKind(..)
-            | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
-            | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-            | ty::PredicateKind::ConstEquate(..)
-            | ty::PredicateKind::Ambiguous
-            | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
-            ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
-                r_a,
-                r_b,
-            ))) => Some(OutlivesBound::RegionSubRegion(r_b, r_a)),
+            ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
+                Some(OutlivesBound::RegionSubRegion(r_b, r_a))
+            }
+            ty::ClauseKind::Trait(_)
+            | ty::ClauseKind::TypeOutlives(_)
+            | ty::ClauseKind::Projection(_)
+            | ty::ClauseKind::ConstArgHasType(_, _)
+            | ty::ClauseKind::WellFormed(_)
+            | ty::ClauseKind::ConstEvaluatable(_)
+            | ty::ClauseKind::TypeWellFormedFromEnv(_) => None,
         })
 }
 
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 871171f9447..1a5e2b520b8 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -223,7 +223,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         // parameter environments are already elaborated, so we don't
         // have to worry about that.
         let c_b = self.param_env.caller_bounds();
-        let param_bounds = self.collect_outlives_from_predicate_list(erased_ty, c_b.into_iter());
+        let param_bounds = self.collect_outlives_from_clause_list(erased_ty, c_b.into_iter());
 
         // Next, collect regions we scraped from the well-formedness
         // constraints in the fn signature. To do that, we walk the list
@@ -307,15 +307,15 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     /// when comparing `ty` for equality, so `ty` must be something
     /// that does not involve inference variables and where you
     /// otherwise want a precise match.
-    fn collect_outlives_from_predicate_list(
+    fn collect_outlives_from_clause_list(
         &self,
         erased_ty: Ty<'tcx>,
-        predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
+        clauses: impl Iterator<Item = ty::Clause<'tcx>>,
     ) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>>
     {
         let tcx = self.tcx;
         let param_env = self.param_env;
-        predicates.filter_map(|p| p.to_opt_type_outlives()).filter(move |outlives_predicate| {
+        clauses.filter_map(|p| p.as_type_outlives_clause()).filter(move |outlives_predicate| {
             super::test_type_match::can_match_erased_ty(
                 tcx,
                 param_env,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 26919872952..847b267b614 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -258,7 +258,8 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
                             pred = pred.without_const(tcx);
                         }
                         elaboratable.child_with_derived_cause(
-                            pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
+                            pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref))
+                                .as_predicate(),
                             span,
                             bound_predicate.rebind(data),
                             index,
@@ -367,7 +368,7 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
                         .map(|predicate| elaboratable.child(predicate)),
                 );
             }
-            ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+            ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                 // Nothing to elaborate
             }
             ty::PredicateKind::Ambiguous => {}
@@ -440,7 +441,7 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>(
                     tcx.super_predicates_that_define_assoc_item((trait_ref.def_id(), assoc_name));
                 for (super_predicate, _) in super_predicates.predicates {
                     let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
-                    if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
+                    if let Some(binder) = subst_predicate.as_trait_clause() {
                         stack.push(binder.map_bound(|t| t.trait_ref));
                     }
                 }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 54dabb75764..ab5f64b383d 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -14,12 +14,11 @@ use rustc_middle::{bug, ty};
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_query_system::query::print_query_stack;
-use rustc_session::config::{self, ErrorOutputType, Input, OutFileName, OutputFilenames};
-use rustc_session::config::{CheckCfg, ExpectedValues};
-use rustc_session::lint;
+use rustc_session::config::{self, CheckCfg, ExpectedValues, Input, OutFileName, OutputFilenames};
 use rustc_session::parse::{CrateConfig, ParseSess};
+use rustc_session::CompilerIO;
 use rustc_session::Session;
-use rustc_session::{early_error, CompilerIO};
+use rustc_session::{lint, EarlyErrorHandler};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
 use std::path::PathBuf;
@@ -66,7 +65,10 @@ pub fn set_thread_safe_mode(sopts: &config::UnstableOptions) {
 }
 
 /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
-pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
+pub fn parse_cfgspecs(
+    handler: &EarlyErrorHandler,
+    cfgspecs: Vec<String>,
+) -> FxHashSet<(String, Option<String>)> {
     rustc_span::create_default_session_if_not_set_then(move |_| {
         let cfg = cfgspecs
             .into_iter()
@@ -78,10 +80,10 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
 
                 macro_rules! error {
                     ($reason: expr) => {
-                        early_error(
-                            ErrorOutputType::default(),
-                            format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
-                        );
+                        handler.early_error(format!(
+                            concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
+                            s
+                        ));
                     };
                 }
 
@@ -125,7 +127,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
 }
 
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
-pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
+pub fn parse_check_cfg(handler: &EarlyErrorHandler, specs: Vec<String>) -> CheckCfg {
     rustc_span::create_default_session_if_not_set_then(move |_| {
         let mut check_cfg = CheckCfg::default();
 
@@ -137,10 +139,10 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
 
             macro_rules! error {
                 ($reason: expr) => {
-                    early_error(
-                        ErrorOutputType::default(),
-                        format!(concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s),
-                    )
+                    handler.early_error(format!(
+                        concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+                        s
+                    ))
                 };
             }
 
@@ -294,8 +296,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
             let registry = &config.registry;
 
+            let handler = EarlyErrorHandler::new(config.opts.error_format);
+
             let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
             let (mut sess, codegen_backend) = util::create_session(
+                &handler,
                 config.opts,
                 config.crate_cfg,
                 config.crate_check_cfg,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 9d0c9ec9742..6054b48b0b5 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -21,8 +21,8 @@ use rustc_session::config::{InstrumentCoverage, Passes};
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use rustc_session::CompilerIO;
 use rustc_session::{build_session, getopts, Session};
+use rustc_session::{CompilerIO, EarlyErrorHandler};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
@@ -36,15 +36,18 @@ use std::path::{Path, PathBuf};
 
 type CfgSpecs = FxHashSet<(String, Option<String>)>;
 
-fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options, CfgSpecs) {
-    let sessopts = build_session_options(&matches);
-    let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
+fn build_session_options_and_crate_config(
+    handler: &mut EarlyErrorHandler,
+    matches: getopts::Matches,
+) -> (Options, CfgSpecs) {
+    let sessopts = build_session_options(handler, &matches);
+    let cfg = parse_cfgspecs(handler, matches.opt_strs("cfg"));
     (sessopts, cfg)
 }
 
-fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
+fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Session, CfgSpecs) {
     let registry = registry::Registry::new(&[]);
-    let (sessopts, cfg) = build_session_options_and_crate_config(matches);
+    let (sessopts, cfg) = build_session_options_and_crate_config(handler, matches);
     let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
     let io = CompilerIO {
         input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@@ -52,8 +55,18 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
         output_file: None,
         temps_dir,
     };
-    let sess =
-        build_session(sessopts, io, None, registry, vec![], Default::default(), None, None, "");
+    let sess = build_session(
+        handler,
+        sessopts,
+        io,
+        None,
+        registry,
+        vec![],
+        Default::default(),
+        None,
+        None,
+        "",
+    );
     (sess, cfg)
 }
 
@@ -120,7 +133,8 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) {
 fn test_switch_implies_cfg_test() {
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["--test".to_string()]).unwrap();
-        let (sess, cfg) = mk_session(matches);
+        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+        let (sess, cfg) = mk_session(&mut handler, matches);
         let cfg = build_configuration(&sess, to_crate_config(cfg));
         assert!(cfg.contains(&(sym::test, None)));
     });
@@ -131,7 +145,8 @@ fn test_switch_implies_cfg_test() {
 fn test_switch_implies_cfg_test_unless_cfg_test() {
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
-        let (sess, cfg) = mk_session(matches);
+        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+        let (sess, cfg) = mk_session(&mut handler, matches);
         let cfg = build_configuration(&sess, to_crate_config(cfg));
         let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
         assert!(test_items.next().is_some());
@@ -143,20 +158,23 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
 fn test_can_print_warnings() {
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
-        let (sess, _) = mk_session(matches);
+        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+        let (sess, _) = mk_session(&mut handler, matches);
         assert!(!sess.diagnostic().can_emit_warnings());
     });
 
     rustc_span::create_default_session_globals_then(|| {
         let matches =
             optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
-        let (sess, _) = mk_session(matches);
+        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+        let (sess, _) = mk_session(&mut handler, matches);
         assert!(sess.diagnostic().can_emit_warnings());
     });
 
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
-        let (sess, _) = mk_session(matches);
+        let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+        let (sess, _) = mk_session(&mut handler, matches);
         assert!(sess.diagnostic().can_emit_warnings());
     });
 }
@@ -302,35 +320,36 @@ fn test_search_paths_tracking_hash_different_order() {
     let mut v3 = Options::default();
     let mut v4 = Options::default();
 
+    let handler = EarlyErrorHandler::new(JSON);
     const JSON: ErrorOutputType = ErrorOutputType::Json {
         pretty: false,
         json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
     };
 
     // Reference
-    v1.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
-    v1.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
-    v1.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-    v1.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
-    v1.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
-
-    v2.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
-    v2.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-    v2.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
-    v2.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
-    v2.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
-
-    v3.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
-    v3.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
-    v3.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
-    v3.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-    v3.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
-
-    v4.search_paths.push(SearchPath::from_cli_opt("all=mno", JSON));
-    v4.search_paths.push(SearchPath::from_cli_opt("native=abc", JSON));
-    v4.search_paths.push(SearchPath::from_cli_opt("crate=def", JSON));
-    v4.search_paths.push(SearchPath::from_cli_opt("dependency=ghi", JSON));
-    v4.search_paths.push(SearchPath::from_cli_opt("framework=jkl", JSON));
+    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+
+    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+
+    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+
+    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
 
     assert_same_hash(&v1, &v2);
     assert_same_hash(&v1, &v3);
@@ -851,7 +870,9 @@ fn test_edition_parsing() {
     let options = Options::default();
     assert!(options.edition == DEFAULT_EDITION);
 
+    let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     let matches = optgroups().parse(&["--edition=2018".to_string()]).unwrap();
-    let (sessopts, _) = build_session_options_and_crate_config(matches);
+    let (sessopts, _) = build_session_options_and_crate_config(&mut handler, matches);
     assert!(sessopts.edition == Edition::Edition2018)
 }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 87252fefb1e..035ea2414f7 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -11,16 +11,16 @@ use rustc_parse::validate_attr;
 use rustc_session as session;
 use rustc_session::config::CheckCfg;
 use rustc_session::config::{self, CrateType};
-use rustc_session::config::{ErrorOutputType, OutFileName, OutputFilenames, OutputTypes};
+use rustc_session::config::{OutFileName, OutputFilenames, OutputTypes};
 use rustc_session::filesearch::sysroot_candidates;
 use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::CrateConfig;
-use rustc_session::{early_error, filesearch, output, Session};
+use rustc_session::{filesearch, output, Session};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::FileLoader;
 use rustc_span::symbol::{sym, Symbol};
-use session::CompilerIO;
+use session::{CompilerIO, EarlyErrorHandler};
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::mem;
@@ -58,6 +58,7 @@ pub fn add_configuration(
 }
 
 pub fn create_session(
+    handler: &EarlyErrorHandler,
     sopts: config::Options,
     cfg: FxHashSet<(String, Option<String>)>,
     check_cfg: CheckCfg,
@@ -73,7 +74,11 @@ pub fn create_session(
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
         make_codegen_backend(&sopts)
     } else {
-        get_codegen_backend(&sopts.maybe_sysroot, sopts.unstable_opts.codegen_backend.as_deref())
+        get_codegen_backend(
+            handler,
+            &sopts.maybe_sysroot,
+            sopts.unstable_opts.codegen_backend.as_deref(),
+        )
     };
 
     // target_override is documented to be called before init(), so this is okay
@@ -88,7 +93,7 @@ pub fn create_session(
     ) {
         Ok(bundle) => bundle,
         Err(e) => {
-            early_error(sopts.error_format, format!("failed to load fluent bundle: {e}"));
+            handler.early_error(format!("failed to load fluent bundle: {e}"));
         }
     };
 
@@ -96,6 +101,7 @@ pub fn create_session(
     locale_resources.push(codegen_backend.locale_resource());
 
     let mut sess = session::build_session(
+        handler,
         sopts,
         io,
         bundle,
@@ -218,16 +224,16 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     })
 }
 
-fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
+fn load_backend_from_dylib(handler: &EarlyErrorHandler, path: &Path) -> MakeBackendFn {
     let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
         let err = format!("couldn't load codegen backend {path:?}: {err}");
-        early_error(ErrorOutputType::default(), err);
+        handler.early_error(err);
     });
 
     let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
         .unwrap_or_else(|e| {
             let err = format!("couldn't load codegen backend: {e}");
-            early_error(ErrorOutputType::default(), err);
+            handler.early_error(err);
         });
 
     // Intentionally leak the dynamic library. We can't ever unload it
@@ -242,6 +248,7 @@ fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
 ///
 /// A name of `None` indicates that the default backend should be used.
 pub fn get_codegen_backend(
+    handler: &EarlyErrorHandler,
     maybe_sysroot: &Option<PathBuf>,
     backend_name: Option<&str>,
 ) -> Box<dyn CodegenBackend> {
@@ -251,10 +258,12 @@ pub fn get_codegen_backend(
         let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm");
 
         match backend_name.unwrap_or(default_codegen_backend) {
-            filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()),
+            filename if filename.contains('.') => {
+                load_backend_from_dylib(handler, filename.as_ref())
+            }
             #[cfg(feature = "llvm")]
             "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
-            backend_name => get_codegen_sysroot(maybe_sysroot, backend_name),
+            backend_name => get_codegen_sysroot(handler, maybe_sysroot, backend_name),
         }
     });
 
@@ -286,7 +295,11 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
     })
 }
 
-fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
+fn get_codegen_sysroot(
+    handler: &EarlyErrorHandler,
+    maybe_sysroot: &Option<PathBuf>,
+    backend_name: &str,
+) -> MakeBackendFn {
     // For now we only allow this function to be called once as it'll dlopen a
     // few things, which seems to work best if we only do that once. In
     // general this assertion never trips due to the once guard in `get_codegen_backend`,
@@ -321,7 +334,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
             "failed to find a `codegen-backends` folder \
                            in the sysroot candidates:\n* {candidates}"
         );
-        early_error(ErrorOutputType::default(), err);
+        handler.early_error(err);
     });
     info!("probing {} for a codegen backend", sysroot.display());
 
@@ -332,7 +345,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
             sysroot.display(),
             e
         );
-        early_error(ErrorOutputType::default(), err);
+        handler.early_error(err);
     });
 
     let mut file: Option<PathBuf> = None;
@@ -360,16 +373,16 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
                 prev.display(),
                 path.display()
             );
-            early_error(ErrorOutputType::default(), err);
+            handler.early_error(err);
         }
         file = Some(path.clone());
     }
 
     match file {
-        Some(ref s) => load_backend_from_dylib(s),
+        Some(ref s) => load_backend_from_dylib(handler, s),
         None => {
             let err = format!("unsupported builtin codegen backend `{backend_name}`");
-            early_error(ErrorOutputType::default(), err);
+            handler.early_error(err);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5c5ec452850..53aad6d8b31 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1593,33 +1593,25 @@ declare_lint_pass!(
 impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         use rustc_middle::ty::ClauseKind;
-        use rustc_middle::ty::PredicateKind::*;
 
         if cx.tcx.features().trivial_bounds {
             let predicates = cx.tcx.predicates_of(item.owner_id);
             for &(predicate, span) in predicates.predicates {
                 let predicate_kind_name = match predicate.kind().skip_binder() {
-                    Clause(ClauseKind::Trait(..)) => "trait",
-                    Clause(ClauseKind::TypeOutlives(..)) |
-                    Clause(ClauseKind::RegionOutlives(..)) => "lifetime",
+                    ClauseKind::Trait(..) => "trait",
+                    ClauseKind::TypeOutlives(..) |
+                    ClauseKind::RegionOutlives(..) => "lifetime",
 
                     // `ConstArgHasType` is never global as `ct` is always a param
-                    Clause(ClauseKind::ConstArgHasType(..)) |
+                    ClauseKind::ConstArgHasType(..)
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
-                    Clause(ClauseKind::Projection(..)) |
+                    | ClauseKind::Projection(..)
                     // Ignore bounds that a user can't type
-                    Clause(ClauseKind::WellFormed(..)) |
+                    | ClauseKind::WellFormed(..)
                     // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
-                    Clause(ClauseKind::ConstEvaluatable(..)) |
-                    AliasRelate(..) |
-                    ObjectSafe(..) |
-                    ClosureKind(..) |
-                    Subtype(..) |
-                    Coerce(..) |
-                    ConstEquate(..) |
-                    Ambiguous |
-                    TypeWellFormedFromEnv(..) => continue,
+                    | ClauseKind::ConstEvaluatable(..)
+                    | ClauseKind::TypeWellFormedFromEnv(_)  => continue,
                 };
                 if predicate.is_global() {
                     cx.emit_spanned_lint(
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 49597516b36..0613ef2c5e9 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -10,7 +10,7 @@ use rustc_errors::{
 use rustc_hir::def_id::DefId;
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{
-    inhabitedness::InhabitedPredicate, PolyExistentialTraitRef, Predicate, Ty, TyCtxt,
+    inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
 };
 use rustc_session::parse::ParseSess;
 use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
@@ -352,7 +352,7 @@ impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
 #[diag(lint_builtin_trivial_bounds)]
 pub struct BuiltinTrivialBounds<'a> {
     pub predicate_kind_name: &'a str,
-    pub predicate: Predicate<'a>,
+    pub predicate: Clause<'a>,
 }
 
 #[derive(LintDiagnostic)]
@@ -1262,7 +1262,7 @@ pub struct RedundantSemicolonsDiag {
 
 // traits.rs
 pub struct DropTraitConstraintsDiag<'a> {
-    pub predicate: Predicate<'a>,
+    pub predicate: Clause<'a>,
     pub tcx: TyCtxt<'a>,
     pub def_id: DefId,
 }
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index c2ed0e19f40..53fe0ceb234 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
                     .super_predicates_of(def_id)
                     .predicates
                     .into_iter()
-                    .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred());
+                    .filter_map(|(pred, _)| pred.as_trait_clause());
             if direct_super_traits_iter.count() > 1 {
                 cx.emit_spanned_lint(
                     MULTIPLE_SUPERTRAIT_UPCASTABLE,
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 8aba5349578..de11208062d 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -88,11 +88,10 @@ declare_lint_pass!(
 impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         use rustc_middle::ty::ClauseKind;
-        use rustc_middle::ty::PredicateKind::*;
 
         let predicates = cx.tcx.explicit_predicates_of(item.owner_id);
         for &(predicate, span) in predicates.predicates {
-            let Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder() else {
+            let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
                 continue
             };
             let def_id = trait_predicate.trait_ref.def_id;
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 12a954258d1..04b7c5feebe 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -1,5 +1,7 @@
 #![deny(unused_must_use)]
 
+use std::cell::RefCell;
+
 use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
 use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
 use crate::diagnostics::utils::SetOnce;
@@ -28,6 +30,7 @@ impl<'a> DiagnosticDerive<'a> {
     pub(crate) fn into_tokens(self) -> TokenStream {
         let DiagnosticDerive { mut structure, mut builder } = self;
 
+        let slugs = RefCell::new(Vec::new());
         let implementation = builder.each_variant(&mut structure, |mut builder, variant| {
             let preamble = builder.preamble(variant);
             let body = builder.body(variant);
@@ -56,6 +59,7 @@ impl<'a> DiagnosticDerive<'a> {
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                 }
                 Some(slug) => {
+                    slugs.borrow_mut().push(slug.clone());
                     quote! {
                         let mut #diag = #handler.struct_diagnostic(crate::fluent_generated::#slug);
                     }
@@ -73,7 +77,8 @@ impl<'a> DiagnosticDerive<'a> {
         });
 
         let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() };
-        structure.gen_impl(quote! {
+
+        let mut imp = structure.gen_impl(quote! {
             gen impl<'__diagnostic_handler_sess, G>
                     rustc_errors::IntoDiagnostic<'__diagnostic_handler_sess, G>
                     for @Self
@@ -89,7 +94,11 @@ impl<'a> DiagnosticDerive<'a> {
                     #implementation
                 }
             }
-        })
+        });
+        for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) {
+            imp.extend(test);
+        }
+        imp
     }
 }
 
@@ -124,6 +133,7 @@ impl<'a> LintDiagnosticDerive<'a> {
             }
         });
 
+        let slugs = RefCell::new(Vec::new());
         let msg = builder.each_variant(&mut structure, |mut builder, variant| {
             // Collect the slug by generating the preamble.
             let _ = builder.preamble(variant);
@@ -148,6 +158,7 @@ impl<'a> LintDiagnosticDerive<'a> {
                     DiagnosticDeriveError::ErrorHandled.to_compile_error()
                 }
                 Some(slug) => {
+                    slugs.borrow_mut().push(slug.clone());
                     quote! {
                         crate::fluent_generated::#slug.into()
                     }
@@ -156,7 +167,7 @@ impl<'a> LintDiagnosticDerive<'a> {
         });
 
         let diag = &builder.diag;
-        structure.gen_impl(quote! {
+        let mut imp = structure.gen_impl(quote! {
             gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
                 #[track_caller]
                 fn decorate_lint<'__b>(
@@ -171,7 +182,12 @@ impl<'a> LintDiagnosticDerive<'a> {
                     #msg
                 }
             }
-        })
+        });
+        for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) {
+            imp.extend(test);
+        }
+
+        imp
     }
 }
 
@@ -198,3 +214,40 @@ impl Mismatch {
         }
     }
 }
+
+/// Generates a `#[test]` that verifies that all referenced variables
+/// exist on this structure.
+fn generate_test(slug: &syn::Path, structure: &Structure<'_>) -> TokenStream {
+    // FIXME: We can't identify variables in a subdiagnostic
+    for field in structure.variants().iter().flat_map(|v| v.ast().fields.iter()) {
+        for attr_name in field.attrs.iter().filter_map(|at| at.path().get_ident()) {
+            if attr_name == "subdiagnostic" {
+                return quote!();
+            }
+        }
+    }
+    use std::sync::atomic::{AtomicUsize, Ordering};
+    // We need to make sure that the same diagnostic slug can be used multiple times without causing an
+    // error, so just have a global counter here.
+    static COUNTER: AtomicUsize = AtomicUsize::new(0);
+    let slug = slug.get_ident().unwrap();
+    let ident = quote::format_ident!("verify_{slug}_{}", COUNTER.fetch_add(1, Ordering::Relaxed));
+    let ref_slug = quote::format_ident!("{slug}_refs");
+    let struct_name = &structure.ast().ident;
+    let variables: Vec<_> = structure
+        .variants()
+        .iter()
+        .flat_map(|v| v.ast().fields.iter().filter_map(|f| f.ident.as_ref().map(|i| i.to_string())))
+        .collect();
+    // tidy errors on `#[test]` outside of test files, so we use `#[test ]` to work around this
+    quote! {
+        #[cfg(test)]
+        #[test ]
+        fn #ident() {
+            let variables = [#(#variables),*];
+            for vref in crate::fluent_generated::#ref_slug {
+                assert!(variables.contains(vref), "{}: variable `{vref}` not found ({})", stringify!(#struct_name), stringify!(#slug));
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 90014bd9267..b9318aee581 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -636,12 +636,6 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol {
     }
 }
 
-impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
-    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
-        ty::codec::RefDecodable::decode(d)
-    }
-}
-
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
     fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
         ty::codec::RefDecodable::decode(d)
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index ac4cef34fdd..5a320865c95 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -83,9 +83,9 @@ macro_rules! arena_types {
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::FnSig<'tcx>>
                 >,
-            [] type_op_normalize_predicate:
+            [] type_op_normalize_clause:
                 rustc_middle::infer::canonical::Canonical<'tcx,
-                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Predicate<'tcx>>
+                    rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Clause<'tcx>>
                 >,
             [] type_op_normalize_ty:
                 rustc_middle::infer::canonical::Canonical<'tcx,
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index caf3fc26039..81c1ae4f630 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -388,10 +388,11 @@ pub fn struct_lint_level(
             // it'll become a hard error, so we have to emit *something*. Also,
             // if this lint occurs in the expansion of a macro from an external crate,
             // allow individual lints to opt-out from being reported.
-            let not_future_incompatible =
-                future_incompatible.map(|f| f.reason.edition().is_some()).unwrap_or(true);
-            if not_future_incompatible && !lint.report_in_external_macro {
+            let incompatible = future_incompatible.is_some_and(|f| f.reason.edition().is_none());
+
+            if !incompatible && !lint.report_in_external_macro {
                 err.cancel();
+
                 // Don't continue further, since we don't want to have
                 // `diag_span_note_once` called for a diagnostic that isn't emitted.
                 return;
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 561ef371b09..1b9c1438f40 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -272,7 +272,8 @@ impl<'tcx> Debug for TerminatorKind<'tcx> {
 
         let unwind = match self.unwind() {
             // Not needed or included in successors
-            None | Some(UnwindAction::Continue) | Some(UnwindAction::Cleanup(_)) => None,
+            None | Some(UnwindAction::Cleanup(_)) => None,
+            Some(UnwindAction::Continue) => Some("unwind continue"),
             Some(UnwindAction::Unreachable) => Some("unwind unreachable"),
             Some(UnwindAction::Terminate) => Some("unwind terminate"),
         };
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index b030d1e6c3e..205dc9ec746 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1133,13 +1133,12 @@ macro_rules! visit_place_fns {
 
         fn visit_projection_elem(
             &mut self,
-            local: Local,
-            proj_base: &[PlaceElem<'tcx>],
+            place_ref: PlaceRef<'tcx>,
             elem: PlaceElem<'tcx>,
             context: PlaceContext,
             location: Location,
         ) {
-            self.super_projection_elem(local, proj_base, elem, context, location);
+            self.super_projection_elem(place_ref, elem, context, location);
         }
 
         fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
@@ -1168,15 +1167,13 @@ macro_rules! visit_place_fns {
             location: Location,
         ) {
             for (base, elem) in place_ref.iter_projections().rev() {
-                let base_proj = base.projection;
-                self.visit_projection_elem(place_ref.local, base_proj, elem, context, location);
+                self.visit_projection_elem(base, elem, context, location);
             }
         }
 
         fn super_projection_elem(
             &mut self,
-            _local: Local,
-            _proj_base: &[PlaceElem<'tcx>],
+            _place_ref: PlaceRef<'tcx>,
             elem: PlaceElem<'tcx>,
             _context: PlaceContext,
             location: Location,
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index fa62b7f32b1..4006a6cd1cc 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -420,7 +420,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
     }
 }
 
-impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
+impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> {
     type CacheSelector = DefaultCacheSelector<Self>;
 
     fn default_span(&self, _: TyCtxt<'_>) -> Span {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5d6a477b9ad..15215552f52 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2031,10 +2031,10 @@ rustc_queries! {
     }
 
     /// Do not call this query directly: part of the `Normalize` type-op
-    query type_op_normalize_predicate(
-        goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>
+    query type_op_normalize_clause(
+        goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Clause<'tcx>>
     ) -> Result<
-        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
+        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Clause<'tcx>>>,
         NoSolution,
     > {
         desc { "normalizing `{:?}`", goal.value.value.value }
@@ -2125,7 +2125,7 @@ rustc_queries! {
         desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
     }
 
-    query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+    query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Clause<'tcx>>) -> &'tcx ty::List<ty::Clause<'tcx>> {
         desc { "revealing opaque types in `{:?}`", key }
     }
 
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 220118ae5cc..8751d3b7890 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -791,13 +791,6 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
-    #[inline]
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
-        RefDecodable::decode(d)
-    }
-}
-
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
     #[inline]
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 813e109c41e..0f3ad6d0151 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -410,6 +410,10 @@ pub enum ExprKind<'tcx> {
     Return {
         value: Option<ExprId>,
     },
+    /// A `become` expression.
+    Become {
+        value: ExprId,
+    },
     /// An inline `const` block, e.g. `const {}`.
     ConstBlock {
         did: DefId,
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 5c7ec31cf93..9cc07677e0e 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -100,6 +100,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
                 visitor.visit_expr(&visitor.thir()[value])
             }
         }
+        Become { value } => visitor.visit_expr(&visitor.thir()[value]),
         ConstBlock { did: _, substs: _ } => {}
         Repeat { value, count: _ } => {
             visitor.visit_expr(&visitor.thir()[value]);
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
index fcc8f457a8b..6e3d2d91ae9 100644
--- a/compiler/rustc_middle/src/traits/chalk.rs
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -385,7 +385,7 @@ impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> {
 /// A chalk environment and goal.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct ChalkEnvironmentAndGoal<'tcx> {
-    pub environment: &'tcx ty::List<ty::Predicate<'tcx>>,
+    pub environment: &'tcx ty::List<ty::Clause<'tcx>>,
     pub goal: ty::Predicate<'tcx>,
 }
 
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
index d54b8c599d9..05c06efaf16 100644
--- a/compiler/rustc_middle/src/traits/util.rs
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -25,9 +25,7 @@ impl<'tcx> Elaborator<'tcx> {
             .super_predicates_of(trait_ref.def_id())
             .predicates
             .into_iter()
-            .flat_map(|(pred, _)| {
-                pred.subst_supertrait(self.tcx, &trait_ref).to_opt_poly_trait_pred()
-            })
+            .flat_map(|(pred, _)| pred.subst_supertrait(self.tcx, &trait_ref).as_trait_clause())
             .map(|t| t.map_bound(|pred| pred.trait_ref))
             .filter(|supertrait_ref| self.visited.insert(*supertrait_ref));
 
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 248251e1ef5..22bed6ad1c5 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -368,16 +368,6 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for AdtDef<'tcx> {
     }
 }
 
-impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
-    for [(ty::Predicate<'tcx>, Span)]
-{
-    fn decode(decoder: &mut D) -> &'tcx Self {
-        decoder.interner().arena.alloc_from_iter(
-            (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
-        )
-    }
-}
-
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] {
     fn decode(decoder: &mut D) -> &'tcx Self {
         decoder.interner().arena.alloc_from_iter(
@@ -406,11 +396,11 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty
     }
 }
 
-impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Predicate<'tcx>> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Clause<'tcx>> {
     fn decode(decoder: &mut D) -> &'tcx Self {
         let len = decoder.read_usize();
-        decoder.interner().mk_predicates_from_iter(
-            (0..len).map::<ty::Predicate<'tcx>, _>(|_| Decodable::decode(decoder)),
+        decoder.interner().mk_clauses_from_iter(
+            (0..len).map::<ty::Clause<'tcx>, _>(|_| Decodable::decode(decoder)),
         )
     }
 }
@@ -434,7 +424,7 @@ impl_decodable_via_ref! {
     &'tcx mir::BorrowCheckResult<'tcx>,
     &'tcx mir::coverage::CodeRegion,
     &'tcx ty::List<ty::BoundVariableKind>,
-    &'tcx ty::List<ty::Predicate<'tcx>>,
+    &'tcx ty::List<ty::Clause<'tcx>>,
     &'tcx ty::List<FieldIdx>,
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1f9cf2c6448..1c610d6891b 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -141,8 +141,6 @@ pub struct CtxtInterners<'tcx> {
     region: InternedSet<'tcx, RegionKind<'tcx>>,
     poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
     predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
-    // FIXME(clause): remove this when all usages are moved to predicate
-    predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
@@ -168,7 +166,6 @@ impl<'tcx> CtxtInterners<'tcx> {
             poly_existential_predicates: Default::default(),
             canonical_var_infos: Default::default(),
             predicate: Default::default(),
-            predicates: Default::default(),
             clauses: Default::default(),
             projs: Default::default(),
             place_elems: Default::default(),
@@ -1260,10 +1257,11 @@ nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; Const<'a> => Const<'tcx>}
 nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
 nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
+nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
 
 nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>}
 nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>}
-nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>}
+nop_list_lift! {clauses; Clause<'a> => Clause<'tcx>}
 nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
 nop_list_lift! {projs; ProjectionKind => ProjectionKind}
 nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind}
@@ -1541,7 +1539,6 @@ slice_interners!(
     type_lists: pub mk_type_list(Ty<'tcx>),
     canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
     poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
-    predicates: intern_predicates(Predicate<'tcx>),
     clauses: intern_clauses(Clause<'tcx>),
     projs: pub mk_projs(ProjectionKind),
     place_elems: pub mk_place_elems(PlaceElem<'tcx>),
@@ -1597,9 +1594,7 @@ impl<'tcx> TyCtxt<'tcx> {
             let generic_predicates = self.super_predicates_of(trait_did);
 
             for (predicate, _) in generic_predicates.predicates {
-                if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) =
-                    predicate.kind().skip_binder()
-                {
+                if let ty::ClauseKind::Trait(data) = predicate.kind().skip_binder() {
                     if set.insert(data.def_id()) {
                         stack.push(data.def_id());
                     }
@@ -2087,18 +2082,11 @@ impl<'tcx> TyCtxt<'tcx> {
         self.intern_poly_existential_predicates(eps)
     }
 
-    pub fn mk_predicates(self, preds: &[Predicate<'tcx>]) -> &'tcx List<Predicate<'tcx>> {
+    pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> {
         // FIXME consider asking the input slice to be sorted to avoid
         // re-interning permutations, in which case that would be asserted
         // here.
-        self.intern_predicates(preds)
-    }
-
-    pub fn mk_clauses(self, preds: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> {
-        // FIXME consider asking the input slice to be sorted to avoid
-        // re-interning permutations, in which case that would be asserted
-        // here.
-        self.intern_clauses(preds)
+        self.intern_clauses(clauses)
     }
 
     pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
@@ -2144,14 +2132,6 @@ impl<'tcx> TyCtxt<'tcx> {
         T::collect_and_apply(iter, |xs| self.mk_poly_existential_predicates(xs))
     }
 
-    pub fn mk_predicates_from_iter<I, T>(self, iter: I) -> T::Output
-    where
-        I: Iterator<Item = T>,
-        T: CollectAndApply<Predicate<'tcx>, &'tcx List<Predicate<'tcx>>>,
-    {
-        T::collect_and_apply(iter, |xs| self.mk_predicates(xs))
-    }
-
     pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index cc982045c46..06a8e34cbab 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -287,7 +287,7 @@ impl FlagComputation {
                 self.add_const(expected);
                 self.add_const(found);
             }
-            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+            ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(ty)) => {
                 self.add_ty(ty);
             }
             ty::PredicateKind::Ambiguous => {}
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 30f92b91cb7..58fd6e1aa27 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -6,7 +6,7 @@ use rustc_hir::def_id::DefId;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
-use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
+use super::{Clause, EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, TyCtxt};
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum GenericParamDefKind {
@@ -323,7 +323,7 @@ impl<'tcx> Generics {
 #[derive(Copy, Clone, Default, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct GenericPredicates<'tcx> {
     pub parent: Option<DefId>,
-    pub predicates: &'tcx [(Predicate<'tcx>, Span)],
+    pub predicates: &'tcx [(Clause<'tcx>, Span)],
 }
 
 impl<'tcx> GenericPredicates<'tcx> {
@@ -341,8 +341,7 @@ impl<'tcx> GenericPredicates<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
         substs: SubstsRef<'tcx>,
-    ) -> impl Iterator<Item = (Predicate<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator
-    {
+    ) -> impl Iterator<Item = (Clause<'tcx>, Span)> + DoubleEndedIterator + ExactSizeIterator {
         EarlyBinder::bind(self.predicates).subst_iter_copied(tcx, substs)
     }
 
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
index d48672b2baa..018fa227154 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -62,7 +62,18 @@ impl<'tcx> InhabitedPredicate<'tcx> {
                 Some(1..) => Ok(false),
             },
             Self::NotInModule(id) => in_module(id).map(|in_mod| !in_mod),
-            Self::GenericType(_) => Ok(true),
+            // `t` may be a projection, for which `inhabited_predicate` returns a `GenericType`. As
+            // we have a param_env available, we can do better.
+            Self::GenericType(t) => {
+                let normalized_pred = tcx
+                    .try_normalize_erasing_regions(param_env, t)
+                    .map_or(self, |t| t.inhabited_predicate(tcx));
+                match normalized_pred {
+                    // We don't have more information than we started with, so consider inhabited.
+                    Self::GenericType(_) => Ok(true),
+                    pred => pred.apply_inner(tcx, param_env, in_module),
+                }
+            }
             Self::And([a, b]) => try_and(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
             Self::Or([a, b]) => try_or(a, b, |x| x.apply_inner(tcx, param_env, in_module)),
         }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 0e604fdf6f4..7bd49ad07ea 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -555,7 +555,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_))
             | PredicateKind::ConstEquate(_, _)
             | PredicateKind::Ambiguous
-            | PredicateKind::TypeWellFormedFromEnv(_) => true,
+            | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(_)) => true,
         }
     }
 }
@@ -566,6 +566,12 @@ impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
     }
 }
 
+impl rustc_errors::IntoDiagnosticArg for Clause<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
+    }
+}
+
 /// A subset of predicates which can be assumed by the trait solver. They show up in
 /// an item's where clauses, hence the name `Clause`, and may either be user-written
 /// (such as traits) or may be inserted during lowering.
@@ -620,6 +626,10 @@ impl<'tcx> Clause<'tcx> {
             None
         }
     }
+
+    pub fn without_const(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
+        self.as_predicate().without_const(tcx).expect_clause()
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
@@ -651,6 +661,11 @@ pub enum ClauseKind<'tcx> {
 
     /// Constant initializer must evaluate successfully.
     ConstEvaluatable(ty::Const<'tcx>),
+
+    /// Represents a type found in the environment that we can use for implied bounds.
+    ///
+    /// Only used for Chalk.
+    TypeWellFormedFromEnv(Ty<'tcx>),
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
@@ -687,11 +702,6 @@ pub enum PredicateKind<'tcx> {
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(Const<'tcx>, Const<'tcx>),
 
-    /// Represents a type found in the environment that we can use for implied bounds.
-    ///
-    /// Only used for Chalk.
-    TypeWellFormedFromEnv(Ty<'tcx>),
-
     /// A marker predicate that is always ambiguous.
     /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
     Ambiguous,
@@ -730,11 +740,10 @@ pub struct CratePredicatesMap<'tcx> {
     /// For each struct with outlive bounds, maps to a vector of the
     /// predicate of its outlive bounds. If an item has no outlives
     /// bounds, it will have no entry.
-    // FIXME(clause): should this be a `Clause`?
     pub predicates: FxHashMap<DefId, &'tcx [(Clause<'tcx>, Span)]>,
 }
 
-impl<'tcx> Predicate<'tcx> {
+impl<'tcx> Clause<'tcx> {
     /// Performs a substitution 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
@@ -744,7 +753,7 @@ impl<'tcx> Predicate<'tcx> {
         self,
         tcx: TyCtxt<'tcx>,
         trait_ref: &ty::PolyTraitRef<'tcx>,
-    ) -> Predicate<'tcx> {
+    ) -> Clause<'tcx> {
         // The interaction between HRTB and supertraits is not entirely
         // obvious. Let me walk you (and myself) through an example.
         //
@@ -830,7 +839,13 @@ impl<'tcx> Predicate<'tcx> {
         // 3) ['x] + ['b] -> ['x, 'b]
         let bound_vars =
             tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(pred_bound_vars));
-        tcx.reuse_or_mk_predicate(self, ty::Binder::bind_with_vars(new, bound_vars))
+
+        // FIXME: Is it really perf sensitive to use reuse_or_mk_predicate here?
+        tcx.reuse_or_mk_predicate(
+            self.as_predicate(),
+            ty::Binder::bind_with_vars(PredicateKind::Clause(new), bound_vars),
+        )
+        .expect_clause()
     }
 }
 
@@ -1301,6 +1316,14 @@ impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> {
     }
 }
 
+impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> {
+    #[inline(always)]
+    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
+        let p: Predicate<'tcx> = self.to_predicate(tcx);
+        p.expect_clause()
+    }
+}
+
 impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
     #[inline(always)]
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
@@ -1402,7 +1425,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
             | PredicateKind::ConstEquate(..)
             | PredicateKind::Ambiguous
-            | PredicateKind::TypeWellFormedFromEnv(..) => None,
+            | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None,
         }
     }
 
@@ -1423,7 +1446,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
             | PredicateKind::ConstEquate(..)
             | PredicateKind::Ambiguous
-            | PredicateKind::TypeWellFormedFromEnv(..) => None,
+            | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None,
         }
     }
 
@@ -1444,7 +1467,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..))
             | PredicateKind::ConstEquate(..)
             | PredicateKind::Ambiguous
-            | PredicateKind::TypeWellFormedFromEnv(..) => None,
+            | PredicateKind::Clause(ClauseKind::TypeWellFormedFromEnv(..)) => None,
         }
     }
 
@@ -1456,12 +1479,11 @@ impl<'tcx> Predicate<'tcx> {
         }
     }
 
-    /// Turns a predicate into a clause without checking that it is a `PredicateKind::Clause`
-    /// first. This will ICE when methods are called on `Clause`.
+    /// Assert that the predicate is a clause.
     pub fn expect_clause(self) -> Clause<'tcx> {
         match self.kind().skip_binder() {
             PredicateKind::Clause(..) => Clause(self.0),
-            _ => bug!(),
+            _ => bug!("{self} is not a clause"),
         }
     }
 }
@@ -1487,7 +1509,7 @@ impl<'tcx> Predicate<'tcx> {
 /// [usize:Bar<isize>]]`.
 #[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct InstantiatedPredicates<'tcx> {
-    pub predicates: Vec<Predicate<'tcx>>,
+    pub predicates: Vec<Clause<'tcx>>,
     pub spans: Vec<Span>,
 }
 
@@ -1506,9 +1528,9 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
 }
 
 impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
-    type Item = (Predicate<'tcx>, Span);
+    type Item = (Clause<'tcx>, Span);
 
-    type IntoIter = std::iter::Zip<std::vec::IntoIter<Predicate<'tcx>>, std::vec::IntoIter<Span>>;
+    type IntoIter = std::iter::Zip<std::vec::IntoIter<Clause<'tcx>>, std::vec::IntoIter<Span>>;
 
     fn into_iter(self) -> Self::IntoIter {
         debug_assert_eq!(self.predicates.len(), self.spans.len());
@@ -1517,10 +1539,10 @@ impl<'tcx> IntoIterator for InstantiatedPredicates<'tcx> {
 }
 
 impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> {
-    type Item = (Predicate<'tcx>, Span);
+    type Item = (Clause<'tcx>, Span);
 
     type IntoIter = std::iter::Zip<
-        std::iter::Copied<std::slice::Iter<'a, Predicate<'tcx>>>,
+        std::iter::Copied<std::slice::Iter<'a, Clause<'tcx>>>,
         std::iter::Copied<std::slice::Iter<'a, Span>>,
     >;
 
@@ -1670,7 +1692,7 @@ pub struct ParamEnv<'tcx> {
     /// want `Reveal::All`.
     ///
     /// Note: This is packed, use the reveal() method to access it.
-    packed: CopyTaggedPtr<&'tcx List<Predicate<'tcx>>, ParamTag, true>,
+    packed: CopyTaggedPtr<&'tcx List<Clause<'tcx>>, ParamTag, true>,
 }
 
 #[derive(Copy, Clone)]
@@ -1736,7 +1758,7 @@ impl<'tcx> ParamEnv<'tcx> {
     }
 
     #[inline]
-    pub fn caller_bounds(self) -> &'tcx List<Predicate<'tcx>> {
+    pub fn caller_bounds(self) -> &'tcx List<Clause<'tcx>> {
         self.packed.pointer()
     }
 
@@ -1770,7 +1792,7 @@ impl<'tcx> ParamEnv<'tcx> {
     /// Construct a trait environment with the given set of predicates.
     #[inline]
     pub fn new(
-        caller_bounds: &'tcx List<Predicate<'tcx>>,
+        caller_bounds: &'tcx List<Clause<'tcx>>,
         reveal: Reveal,
         constness: hir::Constness,
     ) -> Self {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 7afda73862d..a5848b98da0 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2864,20 +2864,38 @@ define_print_and_forward_display! {
         p!(print(binder))
     }
 
+    ty::Clause<'tcx> {
+        p!(print(self.kind()))
+    }
+
+    ty::ClauseKind<'tcx> {
+        match *self {
+            ty::ClauseKind::Trait(ref data) => {
+                p!(print(data))
+            }
+            ty::ClauseKind::RegionOutlives(predicate) => p!(print(predicate)),
+            ty::ClauseKind::TypeOutlives(predicate) => p!(print(predicate)),
+            ty::ClauseKind::Projection(predicate) => p!(print(predicate)),
+            ty::ClauseKind::ConstArgHasType(ct, ty) => {
+                p!("the constant `", print(ct), "` has type `", print(ty), "`")
+            },
+            ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+            ty::ClauseKind::ConstEvaluatable(ct) => {
+                p!("the constant `", print(ct), "` can be evaluated")
+            }
+            ty::ClauseKind::TypeWellFormedFromEnv(ty) => {
+                p!("the type `", print(ty), "` is found in the environment")
+            }
+        }
+    }
+
     ty::PredicateKind<'tcx> {
         match *self {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref data)) => {
+            ty::PredicateKind::Clause(data) => {
                 p!(print(data))
             }
             ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
             ty::PredicateKind::Coerce(predicate) => p!(print(predicate)),
-            ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => p!(print(predicate)),
-            ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => p!(print(predicate)),
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => p!(print(predicate)),
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
-                p!("the constant `", print(ct), "` has type `", print(ty), "`")
-            },
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => p!(print(arg), " well-formed"),
             ty::PredicateKind::ObjectSafe(trait_def_id) => {
                 p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
             }
@@ -2886,15 +2904,9 @@ define_print_and_forward_display! {
                 print_value_path(closure_def_id, &[]),
                 write("` implements the trait `{}`", kind)
             ),
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
-                p!("the constant `", print(ct), "` can be evaluated")
-            }
             ty::PredicateKind::ConstEquate(c1, c2) => {
                 p!("the constant `", print(c1), "` equals `", print(c2), "`")
             }
-            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
-                p!("the type `", print(ty), "` is found in the environment")
-            }
             ty::PredicateKind::Ambiguous => p!("ambiguous"),
             ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
         }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 959bf032a83..113328de176 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -189,6 +189,9 @@ impl<'tcx> fmt::Debug for ty::ClauseKind<'tcx> {
             ty::ClauseKind::ConstEvaluatable(ct) => {
                 write!(f, "ConstEvaluatable({ct:?})")
             }
+            ty::ClauseKind::TypeWellFormedFromEnv(ty) => {
+                write!(f, "TypeWellFormedFromEnv({:?})", ty)
+            }
         }
     }
 }
@@ -206,9 +209,6 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
             ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
-            ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
-                write!(f, "TypeWellFormedFromEnv({:?})", ty)
-            }
             ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
             ty::PredicateKind::AliasRelate(t1, t2, dir) => {
                 write!(f, "AliasRelate({t1:?}, {dir:?}, {t2:?})")
@@ -701,15 +701,6 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Predicate<'tcx>> {
-    fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        ty::util::fold_list(self, folder, |tcx, v| tcx.mk_predicates(v))
-    }
-}
-
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
         self,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index c0627ab5c01..bb6d49e1773 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -715,7 +715,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
     /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
     /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
     /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
-    pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
+    pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> {
         use crate::ty::ToPredicate;
         match self.skip_binder() {
             ExistentialPredicate::Trait(tr) => {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index fcd624b3fef..bb08deff294 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1419,8 +1419,8 @@ pub struct AlwaysRequiresDrop;
 /// with their underlying types.
 pub fn reveal_opaque_types_in_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
-    val: &'tcx ty::List<ty::Predicate<'tcx>>,
-) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+    val: &'tcx ty::List<ty::Clause<'tcx>>,
+) -> &'tcx ty::List<ty::Clause<'tcx>> {
     let mut visitor = OpaqueTypeExpander {
         seen_opaque_tys: FxHashSet::default(),
         expanded_cache: FxHashMap::default(),
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 32c618828c9..e5c2cc6c7bb 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -118,7 +118,11 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
                 phase = Some(value);
             }
             other => {
-                panic!("Unexpected key {}", other);
+                span_bug!(
+                    nested.span(),
+                    "Unexpected key while parsing custom_mir attribute: '{}'",
+                    other
+                );
             }
         }
     }
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 7ec57add66b..783f6e2085c 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -549,6 +549,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Break { .. }
             | ExprKind::Continue { .. }
             | ExprKind::Return { .. }
+            | ExprKind::Become { .. }
             | ExprKind::Literal { .. }
             | ExprKind::NamedConst { .. }
             | ExprKind::NonHirLiteral { .. }
@@ -677,21 +678,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             // check that we just did stays valid. Since we can't assign to
             // unsized values, we only need to ensure that none of the
             // pointers in the base place are modified.
-            for (idx, elem) in base_place.projection.iter().enumerate().rev() {
+            for (base_place, elem) in base_place.iter_projections().rev() {
                 match elem {
                     ProjectionElem::Deref => {
-                        let fake_borrow_deref_ty = Place::ty_from(
-                            base_place.local,
-                            &base_place.projection[..idx],
-                            &self.local_decls,
-                            tcx,
-                        )
-                        .ty;
+                        let fake_borrow_deref_ty = base_place.ty(&self.local_decls, tcx).ty;
                         let fake_borrow_ty =
                             tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty);
                         let fake_borrow_temp =
                             self.local_decls.push(LocalDecl::new(fake_borrow_ty, expr_span));
-                        let projection = tcx.mk_place_elems(&base_place.projection[..idx]);
+                        let projection = tcx.mk_place_elems(&base_place.projection);
                         self.cfg.push_assign(
                             block,
                             source_info,
@@ -705,12 +700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         fake_borrow_temps.push(fake_borrow_temp);
                     }
                     ProjectionElem::Index(_) => {
-                        let index_ty = Place::ty_from(
-                            base_place.local,
-                            &base_place.projection[..idx],
-                            &self.local_decls,
-                            tcx,
-                        );
+                        let index_ty = base_place.ty(&self.local_decls, tcx);
                         match index_ty.ty.kind() {
                             // The previous index expression has already
                             // done any index expressions needed here.
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index ec00f9a96be..27b1b58d2e9 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -532,6 +532,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Break { .. }
             | ExprKind::Continue { .. }
             | ExprKind::Return { .. }
+            | ExprKind::Become { .. }
             | ExprKind::InlineAsm { .. }
             | ExprKind::PlaceTypeAscription { .. }
             | ExprKind::ValueTypeAscription { .. } => {
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index d9aa461c19d..2fe9cac6378 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -82,7 +82,8 @@ impl Category {
             | ExprKind::Block { .. }
             | ExprKind::Break { .. }
             | ExprKind::Continue { .. }
-            | ExprKind::Return { .. } =>
+            | ExprKind::Return { .. }
+            | ExprKind::Become { .. } =>
             // FIXME(#27840) these probably want their own
             // category, like "nonterminating"
             {
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 731f3996244..91c464252f1 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -493,7 +493,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.unit()
             }
 
-            ExprKind::Continue { .. } | ExprKind::Break { .. } | ExprKind::Return { .. } => {
+            ExprKind::Continue { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::Return { .. }
+            | ExprKind::Become { .. } => {
                 unpack!(block = this.stmt_expr(block, expr, None));
                 // No assign, as these have type `!`.
                 block.unit()
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index ea5aeb67d85..396f82c27cd 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -99,6 +99,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 BreakableTarget::Return,
                 source_info,
             ),
+            // FIXME(explicit_tail_calls): properly lower tail calls here
+            ExprKind::Become { value } => this.break_scope(
+                block,
+                Some(&this.thir[value]),
+                BreakableTarget::Return,
+                source_info,
+            ),
             _ => {
                 assert!(
                     statement_scope.is_some(),
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 4f3a574031d..105564b7874 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -316,6 +316,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             | ExprKind::Closure { .. }
             | ExprKind::Continue { .. }
             | ExprKind::Return { .. }
+            | ExprKind::Become { .. }
             | ExprKind::Yield { .. }
             | ExprKind::Loop { .. }
             | ExprKind::Let { .. }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 7f0c2e9ca3f..791c10c1748 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -694,7 +694,8 @@ impl<'tcx> Cx<'tcx> {
 
                 ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
             }
-            hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
+            hir::ExprKind::Ret(v) => ExprKind::Return { value: v.map(|v| self.mirror_expr(v)) },
+            hir::ExprKind::Become(call) => ExprKind::Become { value: self.mirror_expr(call) },
             hir::ExprKind::Break(dest, ref value) => match dest.target_id {
                 Ok(target_id) => ExprKind::Break {
                     label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index b2f2a64e29c..0b6029bf388 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -421,6 +421,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
 
                 print_indented!(self, "}", depth_lvl);
             }
+            Become { value } => {
+                print_indented!(self, "Become {", depth_lvl);
+                print_indented!(self, "value:", depth_lvl + 1);
+                self.print_expr(*value, depth_lvl + 2);
+                print_indented!(self, "}", depth_lvl);
+            }
             ConstBlock { did, substs } => {
                 print_indented!(self, "ConstBlock {", depth_lvl);
                 print_indented!(self, format!("did: {:?}", did), depth_lvl + 1);
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index e5e9c1507ba..58df9b9a768 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -45,7 +45,7 @@ pub mod graphviz;
 pub mod lattice;
 mod visitor;
 
-pub use self::cursor::{ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
+pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor};
 pub use self::direction::{Backward, Direction, Forward};
 pub use self::engine::{Engine, EntrySets, Results, ResultsCloned};
 pub use self::lattice::{JoinSemiLattice, MeetSemiLattice};
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 3494a37c3cf..900d438f8d5 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -27,10 +27,10 @@ pub use self::drop_flag_effects::{
     on_lookup_result_bits,
 };
 pub use self::framework::{
-    fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, CallReturnPlaces,
-    CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results,
-    ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, ResultsVisitable,
-    ResultsVisitor, SwitchIntEdgeEffects,
+    fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, AnalysisResults, Backward,
+    CallReturnPlaces, CloneAnalysis, Direction, Engine, Forward, GenKill, GenKillAnalysis,
+    JoinSemiLattice, Results, ResultsCloned, ResultsClonedCursor, ResultsCursor, ResultsRefCursor,
+    ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
 };
 
 use self::move_paths::MoveData;
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index fe9631653ea..2b37b55d278 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -113,22 +113,16 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
         // from `*(u.f: &_)` isn't allowed.
         let mut union_path = None;
 
-        for (i, elem) in place.projection.iter().enumerate() {
-            let proj_base = &place.projection[..i];
+        for (place_ref, elem) in place.as_ref().iter_projections() {
             let body = self.builder.body;
             let tcx = self.builder.tcx;
-            let place_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
+            let place_ty = place_ref.ty(body, tcx).ty;
+
             match place_ty.kind() {
                 ty::Ref(..) | ty::RawPtr(..) => {
-                    let proj = &place.projection[..i + 1];
                     return Err(MoveError::cannot_move_out_of(
                         self.loc,
-                        BorrowedContent {
-                            target_place: Place {
-                                local: place.local,
-                                projection: tcx.mk_place_elems(proj),
-                            },
-                        },
+                        BorrowedContent { target_place: place_ref.project_deeper(&[elem], tcx) },
                     ));
                 }
                 ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
@@ -163,10 +157,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
             };
 
             if union_path.is_none() {
-                base = self.add_move_path(base, elem, |tcx| Place {
-                    local: place.local,
-                    projection: tcx.mk_place_elems(&place.projection[..i + 1]),
-                });
+                base = self.add_move_path(base, elem, |tcx| place_ref.project_deeper(&[elem], tcx));
             }
         }
 
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index 856327e6ce6..05c54ab3097 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -240,9 +240,9 @@ fn insert_alignment_check<'tcx>(
                 required: Operand::Copy(alignment),
                 found: Operand::Copy(addr),
             }),
-            // The panic symbol that this calls is #[rustc_nounwind]. We never want to insert an
-            // unwind into unsafe code, because unwinding could make a failing UB check turn into
-            // much worse UB when we start unwinding.
+            // This calls panic_misaligned_pointer_dereference, which is #[rustc_nounwind].
+            // We never want to insert an unwind into unsafe code, because unwinding could
+            // make a failing UB check turn into much worse UB when we start unwinding.
             unwind: UnwindAction::Unreachable,
         },
     });
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index 6a3d42511ac..7ad98144159 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -277,14 +277,7 @@ impl DebugCounters {
 
     pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option<String>) {
         if let Some(counters) = &mut self.some_counters {
-            let id: ExpressionOperandId = match *counter_kind {
-                CoverageKind::Counter { id, .. } => id.into(),
-                CoverageKind::Expression { id, .. } => id.into(),
-                _ => bug!(
-                    "the given `CoverageKind` is not an counter or expression: {:?}",
-                    counter_kind
-                ),
-            };
+            let id = counter_kind.as_operand_id();
             counters
                 .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
                 .expect("attempt to add the same counter_kind to DebugCounters more than once");
@@ -330,13 +323,7 @@ impl DebugCounters {
             }
         }
 
-        let id: ExpressionOperandId = match *counter_kind {
-            CoverageKind::Counter { id, .. } => id.into(),
-            CoverageKind::Expression { id, .. } => id.into(),
-            _ => {
-                bug!("the given `CoverageKind` is not an counter or expression: {:?}", counter_kind)
-            }
-        };
+        let id = counter_kind.as_operand_id();
         if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
             let counters = self.some_counters.as_ref().unwrap();
             if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index ea1223fbca6..d2a854b2675 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -387,7 +387,7 @@ impl BasicCoverageBlockData {
             // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
             // have an expression (to be injected into an existing `BasicBlock` represented by this
             // `BasicCoverageBlock`).
-            if !self.counter_kind.as_ref().map_or(true, |c| c.is_expression()) {
+            if self.counter_kind.as_ref().is_some_and(|c| !c.is_expression()) {
                 return Error::from_string(format!(
                     "attempt to add an incoming edge counter from {:?} when the target BCB already \
                     has a `Counter`",
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index d27200419e2..35cf9ea5f91 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -480,9 +480,10 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
 
     fn check_invoked_macro_name_span(&mut self) {
         if let Some(visible_macro) = self.curr().visible_macro(self.body_span) {
-            if self.prev_expn_span.map_or(true, |prev_expn_span| {
-                self.curr().expn_span.ctxt() != prev_expn_span.ctxt()
-            }) {
+            if !self
+                .prev_expn_span
+                .is_some_and(|prev_expn_span| self.curr().expn_span.ctxt() == prev_expn_span.ctxt())
+            {
                 let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo();
                 let after_macro_bang =
                     merged_prefix_len + BytePos(visible_macro.as_str().len() as u32 + 1);
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 78758e2db28..a31551cf619 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -37,6 +37,10 @@
 //!   if they do not consistently refer to the same place in memory. This is satisfied if they do
 //!   not contain any indirection through a pointer or any indexing projections.
 //!
+//! * `p` and `q` must have the **same type**. If we replace a local with a subtype or supertype,
+//!   we may end up with a differnet vtable for that local. See the `subtyping-impacts-selection`
+//!   tests for an example where that causes issues.
+//!
 //! * We need to make sure that the goal of "merging the memory" is actually structurally possible
 //!   in MIR. For example, even if all the other conditions are satisfied, there is no way to
 //!   "merge" `_5.foo` and `_6.bar`. For now, we ensure this by requiring that both `p` and `q` are
@@ -134,6 +138,7 @@ use crate::MirPass;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
+use rustc_middle::mir::HasLocalDecls;
 use rustc_middle::mir::{dump_mir, PassWhere};
 use rustc_middle::mir::{
     traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, Rvalue,
@@ -763,12 +768,22 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> {
                 return;
             };
 
-            // As described at the top of the file, we do not go near things that have their address
-            // taken.
+            // As described at the top of the file, we do not go near things that have
+            // their address taken.
             if self.borrowed.contains(src) || self.borrowed.contains(dest) {
                 return;
             }
 
+            // As described at the top of this file, we do not touch locals which have
+            // different types.
+            let src_ty = self.body.local_decls()[src].ty;
+            let dest_ty = self.body.local_decls()[dest].ty;
+            if src_ty != dest_ty {
+                // FIXME(#112651): This can be removed afterwards. Also update the module description.
+                trace!("skipped `{src:?} = {dest:?}` due to subtyping: {src_ty} != {dest_ty}");
+                return;
+            }
+
             // Also, we need to make sure that MIR actually allows the `src` to be removed
             if is_local_required(src, self.body) {
                 return;
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 502f367dcb6..0b41e57be3b 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -2,7 +2,7 @@ use itertools::Itertools;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, EarlyBinder, PredicateKind, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt};
 use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
 use rustc_span::{symbol::sym, Span};
 use rustc_target::spec::abi::Abi;
@@ -74,7 +74,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
         let param_env = self.tcx.param_env(def_id);
         let bounds = param_env.caller_bounds();
         for bound in bounds {
-            if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) {
+            if let Some(bound_ty) = self.is_pointer_trait(bound) {
                 // Get the argument types as they appear in the function signature.
                 let arg_defs = self.tcx.fn_sig(def_id).subst_identity().skip_binder().inputs();
                 for (arg_num, arg_def) in arg_defs.iter().enumerate() {
@@ -104,8 +104,8 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
     }
 
     /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
-    fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option<Ty<'tcx>> {
-        if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) = bound {
+    fn is_pointer_trait(&self, bound: ty::Clause<'tcx>) -> Option<Ty<'tcx>> {
+        if let ty::ClauseKind::Trait(predicate) = bound.kind().skip_binder() {
             self.tcx
                 .is_diagnostic_item(sym::Pointer, predicate.def_id())
                 .then(|| predicate.trait_ref.self_ty())
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 703824f5bda..240beabfc1a 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -839,15 +839,13 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
     /// to normalization failure.
     fn visit_projection_elem(
         &mut self,
-        local: Local,
-        proj_base: &[PlaceElem<'tcx>],
+        place_ref: PlaceRef<'tcx>,
         elem: PlaceElem<'tcx>,
         context: PlaceContext,
         location: Location,
     ) {
         if let ProjectionElem::Field(f, ty) = elem {
-            let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) };
-            let parent_ty = parent.ty(&self.callee_body.local_decls, self.tcx);
+            let parent_ty = place_ref.ty(&self.callee_body.local_decls, self.tcx);
             let check_equal = |this: &mut Self, f_ty| {
                 if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
                     trace!(?ty, ?f_ty);
@@ -926,7 +924,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
             }
         }
 
-        self.super_projection_elem(local, proj_base, elem, context, location);
+        self.super_projection_elem(place_ref, elem, context, location);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 2ae5ec4d9e6..500595e9f50 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -32,13 +32,15 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
     let mut result = match instance {
         ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
         ty::InstanceDef::VTableShim(def_id) => {
-            build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id))
+            let adjustment = Adjustment::Deref { source: DerefSource::MutPtr };
+            build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id))
         }
         ty::InstanceDef::FnPtrShim(def_id, ty) => {
             let trait_ = tcx.trait_of_item(def_id).unwrap();
             let adjustment = match tcx.fn_trait_kind_from_def_id(trait_) {
                 Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
-                Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref,
+                Some(ty::ClosureKind::Fn) => Adjustment::Deref { source: DerefSource::ImmRef },
+                Some(ty::ClosureKind::FnMut) => Adjustment::Deref { source: DerefSource::MutRef },
                 None => bug!("fn pointer {:?} is not an fn", ty),
             };
 
@@ -108,15 +110,25 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
+enum DerefSource {
+    /// `fn shim(&self) { inner(*self )}`.
+    ImmRef,
+    /// `fn shim(&mut self) { inner(*self )}`.
+    MutRef,
+    /// `fn shim(*mut self) { inner(*self )}`.
+    MutPtr,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
 enum Adjustment {
     /// Pass the receiver as-is.
     Identity,
 
-    /// We get passed `&[mut] self` and call the target with `*self`.
+    /// We get passed a reference or a raw pointer to `self` and call the target with `*self`.
     ///
     /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
     /// (for `VTableShim`, which effectively is passed `&own Self`).
-    Deref,
+    Deref { source: DerefSource },
 
     /// We get passed `self: Self` and call the target with `&mut self`.
     ///
@@ -667,8 +679,12 @@ fn build_call_shim<'tcx>(
         let self_arg = &mut inputs_and_output[0];
         *self_arg = match rcvr_adjustment.unwrap() {
             Adjustment::Identity => fnty,
-            Adjustment::Deref => tcx.mk_imm_ptr(fnty),
-            Adjustment::RefMut => tcx.mk_mut_ptr(fnty),
+            Adjustment::Deref { source } => match source {
+                DerefSource::ImmRef => tcx.mk_imm_ref(tcx.lifetimes.re_erased, fnty),
+                DerefSource::MutRef => tcx.mk_mut_ref(tcx.lifetimes.re_erased, fnty),
+                DerefSource::MutPtr => tcx.mk_mut_ptr(fnty),
+            },
+            Adjustment::RefMut => bug!("`RefMut` is never used with indirect calls: {instance:?}"),
         };
         sig.inputs_and_output = tcx.mk_type_list(&inputs_and_output);
     }
@@ -699,7 +715,7 @@ fn build_call_shim<'tcx>(
 
     let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
         Adjustment::Identity => Operand::Move(rcvr_place()),
-        Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())),
+        Adjustment::Deref { source: _ } => Operand::Move(tcx.mk_place_deref(rcvr_place())),
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
             let ref_rcvr = local_decls.push(
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index 7a0d3a025f3..8dc2dfe13bd 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -271,6 +271,14 @@ fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
         else { continue };
 
         let Some(rhs) = place.as_local() else { continue };
+        let local_ty = body.local_decls()[local].ty;
+        let rhs_ty = body.local_decls()[rhs].ty;
+        if local_ty != rhs_ty {
+            // FIXME(#112651): This can be removed afterwards.
+            trace!("skipped `{local:?} = {rhs:?}` due to subtyping: {local_ty} != {rhs_ty}");
+            continue;
+        }
+
         if !ssa.is_ssa(rhs) {
             continue;
         }
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 35eec2c8e1b..9787d98c1a4 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -353,6 +353,7 @@ parse_int_literal_too_large = integer literal is too large
 
 parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
     .label = the `block` fragment is within this context
+    .suggestion = wrap this in another block
 
 parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
     .label = {parse_invalid_char_in_escape_msg}
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 84494eab855..96e1c0e3c6d 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -333,6 +333,17 @@ pub(crate) struct InvalidBlockMacroSegment {
     pub span: Span,
     #[label]
     pub context: Span,
+    #[subdiagnostic]
+    pub wrap: WrapInExplicitBlock,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
+pub(crate) struct WrapInExplicitBlock {
+    #[suggestion_part(code = "{{ ")]
+    pub lo: Span,
+    #[suggestion_part(code = " }}")]
+    pub hi: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index e1db19557cf..ee0abba1c17 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -422,15 +422,12 @@ impl<'a> Parser<'a> {
     }
 }
 
-pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
-    // One of the attributes may either itself be a macro,
-    // or expand to macro attributes (`cfg_attr`).
-    attrs.iter().any(|attr| {
-        if attr.is_doc_comment() {
-            return false;
-        }
-        attr.ident().map_or(true, |ident| {
-            ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name)
-        })
+/// The attributes are complete if all attributes are either a doc comment or a builtin attribute other than `cfg_attr`
+pub fn is_complete(attrs: &[ast::Attribute]) -> bool {
+    attrs.iter().all(|attr| {
+        attr.is_doc_comment()
+            || attr.ident().is_some_and(|ident| {
+                ident.name != sym::cfg_attr && rustc_feature::is_builtin_attr_name(ident.name)
+            })
     })
 }
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 1e6ac54964f..b579da098d8 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -61,8 +61,8 @@ impl AttrWrapper {
         self.attrs.is_empty()
     }
 
-    pub fn maybe_needs_tokens(&self) -> bool {
-        crate::parser::attr::maybe_needs_tokens(&self.attrs)
+    pub fn is_complete(&self) -> bool {
+        crate::parser::attr::is_complete(&self.attrs)
     }
 }
 
@@ -201,7 +201,7 @@ impl<'a> Parser<'a> {
         //    by definition
         if matches!(force_collect, ForceCollect::No)
             // None of our outer attributes can require tokens (e.g. a proc-macro)
-            && !attrs.maybe_needs_tokens()
+            && attrs.is_complete()
             // If our target supports custom inner attributes, then we cannot bail
             // out early, since we may need to capture tokens for a custom inner attribute
             // invocation.
@@ -244,9 +244,9 @@ impl<'a> Parser<'a> {
         // Now that we've parsed an AST node, we have more information available.
         if matches!(force_collect, ForceCollect::No)
             // We now have inner attributes available, so this check is more precise
-            // than `attrs.maybe_needs_tokens()` at the start of the function.
+            // than `attrs.is_complete()` at the start of the function.
             // As a result, we don't need to check `R::SUPPORTS_CUSTOM_INNER_ATTRS`
-            && !crate::parser::attr::maybe_needs_tokens(ret.attrs())
+            && crate::parser::attr::is_complete(ret.attrs())
             // Subtle: We call `has_cfg_or_cfg_attr` with the attrs from `ret`.
             // This ensures that we consider inner attributes (e.g. `#![cfg]`),
             // which require us to have tokens available
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 5f2f86e8113..7ede4fbc3d9 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2192,6 +2192,10 @@ impl<'a> Parser<'a> {
             self.sess.emit_err(errors::InvalidBlockMacroSegment {
                 span: self.token.span,
                 context: lo.to(self.token.span),
+                wrap: errors::WrapInExplicitBlock {
+                    lo: self.token.span.shrink_to_lo(),
+                    hi: self.token.span.shrink_to_hi(),
+                },
             });
         }
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 7890c93d5ff..3fe7feb9dfa 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1150,14 +1150,6 @@ pub struct UnixSigpipeValues {
     pub span: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(passes_no_main_function, code = "E0601")]
-pub struct NoMainFunction {
-    #[primary_span]
-    pub span: Span,
-    pub crate_name: String,
-}
-
 pub struct NoMainErr {
     pub sp: Span,
     pub crate_name: Symbol,
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 90809270118..6c748147abe 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -302,8 +302,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             [
                 ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
                 DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index,
-                Path, AddrOf, Break, Continue, Ret, InlineAsm, OffsetOf, Struct, Repeat, Yield,
-                Err
+                Path, AddrOf, Break, Continue, Ret, Become, InlineAsm, OffsetOf, Struct, Repeat,
+                Yield, Err
             ]
         );
         hir_visit::walk_expr(self, e)
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 63b1578d43f..803ca05b202 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -463,6 +463,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
             | hir::ExprKind::Lit(_)
             | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Become(..)
             | hir::ExprKind::Block(..)
             | hir::ExprKind::Assign(..)
             | hir::ExprKind::AssignOp(..)
@@ -967,6 +968,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
                 self.propagate_through_opt_expr(o_e.as_deref(), self.exit_ln)
             }
 
+            hir::ExprKind::Become(ref e) => {
+                // Ignore succ and subst exit_ln.
+                self.propagate_through_expr(e, self.exit_ln)
+            }
+
             hir::ExprKind::Break(label, ref opt_expr) => {
                 // Find which label this break jumps to
                 let target = match label.target_id {
@@ -1408,6 +1414,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
         | hir::ExprKind::DropTemps(..)
         | hir::ExprKind::Unary(..)
         | hir::ExprKind::Ret(..)
+        | hir::ExprKind::Become(..)
         | hir::ExprKind::Break(..)
         | hir::ExprKind::Continue(..)
         | hir::ExprKind::Lit(_)
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index a849d61edfe..769b389009b 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -204,6 +204,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             | ExprKind::Continue(..)
             | ExprKind::Ret(..)
             | ExprKind::OffsetOf(..)
+            | ExprKind::Become(..)
             | ExprKind::Struct(..)
             | ExprKind::Repeat(..)
             | ExprKind::Yield(..) => {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 8a848e5db62..5f7313dcca6 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -112,13 +112,13 @@ trait DefIdVisitor<'tcx> {
         &mut self,
         predicates: ty::GenericPredicates<'tcx>,
     ) -> ControlFlow<Self::BreakTy> {
-        self.skeleton().visit_predicates(predicates)
+        self.skeleton().visit_clauses(predicates.predicates)
     }
     fn visit_clauses(
         &mut self,
-        predicates: &[(ty::Clause<'tcx>, Span)],
+        clauses: &[(ty::Clause<'tcx>, Span)],
     ) -> ControlFlow<Self::BreakTy> {
-        self.skeleton().visit_clauses(predicates)
+        self.skeleton().visit_clauses(clauses)
     }
 }
 
@@ -182,24 +182,12 @@ where
             }
             ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
             ty::ClauseKind::WellFormed(arg) => arg.visit_with(self),
+            ty::ClauseKind::TypeWellFormedFromEnv(_) => bug!("unexpected clause: {clause}"),
         }
     }
 
-    fn visit_predicates(
-        &mut self,
-        predicates: ty::GenericPredicates<'tcx>,
-    ) -> ControlFlow<V::BreakTy> {
-        let ty::GenericPredicates { parent: _, predicates } = predicates;
-        predicates.iter().try_for_each(|&(predicate, _span)| {
-            let clause = predicate
-                .as_clause()
-                .unwrap_or_else(|| bug!("unexpected predicate: {:?}", predicate));
-            self.visit_clause(clause)
-        })
-    }
-
     fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> ControlFlow<V::BreakTy> {
-        clauses.iter().try_for_each(|&(clause, _span)| self.visit_clause(clause))
+        clauses.into_iter().try_for_each(|&(clause, _span)| self.visit_clause(clause))
     }
 }
 
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 60b6d74da7b..f98918cba88 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -44,13 +44,26 @@ resolve_binding_shadows_something_unacceptable =
 resolve_binding_shadows_something_unacceptable_suggestion =
     try specify the pattern arguments
 
+resolve_cannot_be_reexported_crate_public =
+    `{$ident}` is only public within the crate, and cannot be re-exported outside
+
+resolve_cannot_be_reexported_private =
+    `{$ident}` is private, and cannot be re-exported
+
 resolve_cannot_capture_dynamic_environment_in_fn_item =
     can't capture dynamic environment in a fn item
     .help = use the `|| {"{"} ... {"}"}` closure form instead
 
+resolve_cannot_determine_import_resolution =
+    cannot determine resolution for the import
+    .note = import resolution is stuck, try simplifying other imports
+
 resolve_cannot_find_ident_in_this_scope =
     cannot find {$expected} `{$ident}` in this scope
 
+resolve_cannot_glob_import_possible_crates =
+    cannot glob-import all possible crates
+
 resolve_cannot_use_self_type_here =
     can't use `Self` here
 
@@ -60,6 +73,15 @@ resolve_change_import_binding =
 resolve_consider_adding_a_derive =
     consider adding a derive
 
+resolve_consider_adding_macro_export =
+    consider adding a `#[macro_export]` to the macro in the imported module
+
+resolve_consider_declaring_with_pub =
+    consider declaring type or module `{$ident}` with `pub`
+
+resolve_consider_marking_as_pub =
+    consider marking `{$ident}` as `pub` in the imported module
+
 resolve_const_not_member_of_trait =
     const `{$const_}` is not a member of trait `{$trait_}`
     .label = not a member of trait `{$trait_}`
@@ -98,6 +120,9 @@ resolve_generic_params_from_outer_function =
     .label = use of generic parameter from outer function
     .suggestion = try using a local generic parameter instead
 
+resolve_glob_import_doesnt_reexport =
+    glob import doesn't reexport anything because no candidate is public enough
+
 resolve_help_try_using_local_generic_param =
     try using a local generic parameter instead
 
@@ -122,6 +147,13 @@ resolve_invalid_asm_sym =
     .label = is a local variable
     .help = `sym` operands must refer to either a function or a static
 
+resolve_is_not_directly_importable =
+    `{$target}` is not directly importable
+    .label = cannot be imported directly
+
+resolve_items_in_traits_are_not_importable =
+    items in traits are not importable
+
 resolve_label_with_similar_name_reachable =
     a label with a similar name is reachable
 
@@ -176,6 +208,12 @@ resolve_parent_module_reset_for_binding =
 resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
     .help = you can define integration tests in a directory named `tests`
 
+resolve_reexport_of_crate_public =
+    re-export of crate public `{$ident}`
+
+resolve_reexport_of_private =
+    re-export of private `{$ident}`
+
 resolve_relative_2018 =
     relative paths are not supported in visibilities in 2018 edition or later
     .suggestion = try
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 93b626c7794..e4b89c65853 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -646,3 +646,84 @@ pub(crate) struct ConsiderAddingADerive {
     pub(crate) span: Span,
     pub(crate) suggestion: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_determine_import_resolution)]
+pub(crate) struct CannotDetermineImportResolution {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_be_reexported_private, code = "E0364")]
+pub(crate) struct CannotBeReexportedPrivate {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_be_reexported_crate_public, code = "E0364")]
+pub(crate) struct CannotBeReexportedCratePublic {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_be_reexported_private, code = "E0365")]
+#[note(resolve_consider_declaring_with_pub)]
+pub(crate) struct CannotBeReexportedPrivateNS {
+    #[primary_span]
+    #[label(resolve_reexport_of_private)]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_be_reexported_crate_public, code = "E0365")]
+#[note(resolve_consider_declaring_with_pub)]
+pub(crate) struct CannotBeReexportedCratePublicNS {
+    #[primary_span]
+    #[label(resolve_reexport_of_crate_public)]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Subdiagnostic)]
+#[help(resolve_consider_adding_macro_export)]
+pub(crate) struct ConsiderAddingMacroExport {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[note(resolve_consider_marking_as_pub)]
+pub(crate) struct ConsiderMarkingAsPub {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) ident: Ident,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_cannot_glob_import_possible_crates)]
+pub(crate) struct CannotGlobImportAllCrates {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_items_in_traits_are_not_importable)]
+pub(crate) struct ItemsInTraitsAreNotImportable {
+    #[primary_span]
+    pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_is_not_directly_importable, code = "E0253")]
+pub(crate) struct IsNotDirectlyImportable {
+    #[primary_span]
+    #[label]
+    pub(crate) span: Span,
+    pub(crate) target: Ident,
+}
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 44453309920..35491ebe10c 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1,8 +1,14 @@
 //! A bunch of methods and structures more or less related to resolving imports.
 
 use crate::diagnostics::{import_candidates, DiagnosticMode, Suggestion};
+use crate::errors::{
+    CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate,
+    CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
+    ConsiderAddingMacroExport, ConsiderMarkingAsPub, IsNotDirectlyImportable,
+    ItemsInTraitsAreNotImportable,
+};
 use crate::Determinacy::{self, *};
-use crate::Namespace::*;
+use crate::{fluent_generated as fluent, Namespace::*};
 use crate::{module_to_string, names_to_string, ImportSuggestion};
 use crate::{
     AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, ModuleKind, ResolutionError,
@@ -609,7 +615,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
     }
 
-    fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
+    fn throw_unresolved_import_error(&mut self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
         if errors.is_empty() {
             return;
         }
@@ -679,6 +685,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     _ => {}
                 }
             }
+
+            match &import.kind {
+                ImportKind::Single { source, .. } => {
+                    if let Some(ModuleOrUniformRoot::Module(module)) = import.imported_module.get()
+                     && let Some(module) = module.opt_def_id()
+                    {
+                        self.find_cfg_stripped(&mut diag, &source.name, module)
+                    }
+                },
+                _ => {}
+            }
         }
 
         diag.emit();
@@ -763,9 +780,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                     source_binding @ (Ok(..) | Err(Determined)) => {
                         if source_binding.is_ok() {
-                            let msg = format!("`{}` is not directly importable", target);
-                            struct_span_err!(this.tcx.sess, import.span, E0253, "{}", &msg)
-                                .span_label(import.span, "cannot be imported directly")
+                            this.tcx
+                                .sess
+                                .create_err(IsNotDirectlyImportable { span: import.span, target })
                                 .emit();
                         }
                         let key = BindingKey::new(target, ns);
@@ -814,9 +831,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         span_bug!(import.span, "inconsistent resolution for an import");
                     }
                 } else if self.privacy_errors.is_empty() {
-                    let msg = "cannot determine resolution for the import";
-                    let msg_note = "import resolution is stuck, try simplifying other imports";
-                    self.tcx.sess.struct_span_err(import.span, msg).note(msg_note).emit();
+                    self.tcx
+                        .sess
+                        .create_err(CannotDetermineImportResolution { span: import.span })
+                        .emit();
                 }
 
                 module
@@ -927,8 +945,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     && let Some(max_vis) = max_vis.get()
                     && !max_vis.is_at_least(import.expect_vis(), self.tcx)
                 {
-                    let msg = "glob import doesn't reexport anything because no candidate is public enough";
-                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
+                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, fluent::resolve_glob_import_doesnt_reexport);
                 }
                     return None;
                 }
@@ -1000,10 +1017,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             && this.ambiguity_errors.is_empty()
                             && this.privacy_errors.is_empty()
                         {
-                            let msg = "cannot determine resolution for the import";
-                            let msg_note =
-                                "import resolution is stuck, try simplifying other imports";
-                            this.tcx.sess.struct_span_err(import.span, msg).note(msg_note).emit();
+                            this.tcx
+                                .sess
+                                .create_err(CannotDetermineImportResolution { span: import.span })
+                                .emit();
                         }
                     }
                     Err(..) => {
@@ -1161,46 +1178,43 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     msg,
                 );
             } else {
-                let error_msg = if crate_private_reexport {
-                    format!(
-                        "`{}` is only public within the crate, and cannot be re-exported outside",
-                        ident
-                    )
-                } else {
-                    format!("`{}` is private, and cannot be re-exported", ident)
-                };
-
                 if ns == TypeNS {
-                    let label_msg = if crate_private_reexport {
-                        format!("re-export of crate public `{}`", ident)
+                    let mut err = if crate_private_reexport {
+                        self.tcx.sess.create_err(CannotBeReexportedCratePublicNS {
+                            span: import.span,
+                            ident,
+                        })
                     } else {
-                        format!("re-export of private `{}`", ident)
+                        self.tcx
+                            .sess
+                            .create_err(CannotBeReexportedPrivateNS { span: import.span, ident })
                     };
-
-                    struct_span_err!(self.tcx.sess, import.span, E0365, "{}", error_msg)
-                        .span_label(import.span, label_msg)
-                        .note(format!("consider declaring type or module `{}` with `pub`", ident))
-                        .emit();
+                    err.emit();
                 } else {
-                    let mut err =
-                        struct_span_err!(self.tcx.sess, import.span, E0364, "{error_msg}");
+                    let mut err = if crate_private_reexport {
+                        self.tcx
+                            .sess
+                            .create_err(CannotBeReexportedCratePublic { span: import.span, ident })
+                    } else {
+                        self.tcx
+                            .sess
+                            .create_err(CannotBeReexportedPrivate { span: import.span, ident })
+                    };
+
                     match binding.kind {
                         NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id))
                             // exclude decl_macro
                             if self.get_macro_by_def_id(def_id).macro_rules =>
                         {
-                            err.span_help(
-                                binding.span,
-                                "consider adding a `#[macro_export]` to the macro in the imported module",
-                            );
+                            err.subdiagnostic(ConsiderAddingMacroExport {
+                                span: binding.span,
+                            });
                         }
                         _ => {
-                            err.span_note(
-                                import.span,
-                                format!(
-                                    "consider marking `{ident}` as `pub` in the imported module"
-                                ),
-                            );
+                            err.subdiagnostic(ConsiderMarkingAsPub {
+                                span: import.span,
+                                ident,
+                            });
                         }
                     }
                     err.emit();
@@ -1306,12 +1320,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
 
         let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
-            self.tcx.sess.span_err(import.span, "cannot glob-import all possible crates");
+            self.tcx.sess.create_err(CannotGlobImportAllCrates {
+                span: import.span,
+            }).emit();
             return;
         };
 
         if module.is_trait() {
-            self.tcx.sess.span_err(import.span, "items in traits are not importable");
+            self.tcx.sess.create_err(ItemsInTraitsAreNotImportable { span: import.span }).emit();
             return;
         } else if ptr::eq(module, import.parent_scope.module) {
             return;
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 475772734ff..c62fc031a16 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2183,10 +2183,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 None => {
                     debug!(?param.ident, ?param.ident.span);
                     let deletion_span = deletion_span();
-                    // the give lifetime originates from expanded code so we won't be able to remove it #104432
-                    let lifetime_only_in_expanded_code =
-                        deletion_span.map(|sp| sp.in_derive_expansion()).unwrap_or(true);
-                    if !lifetime_only_in_expanded_code {
+
+                    // if the lifetime originates from expanded code, we won't be able to remove it #104432
+                    if deletion_span.is_some_and(|sp| !sp.in_derive_expansion()) {
                         self.r.lint_buffer.buffer_lint_with_diagnostic(
                             lint::builtin::UNUSED_LIFETIMES,
                             param.id,
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index a9668ae4828..480d2478e81 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -5,8 +5,8 @@ pub use crate::options::*;
 
 use crate::search_paths::SearchPath;
 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use crate::{early_error, early_warn, Session};
 use crate::{lint, HashStableContext};
+use crate::{EarlyErrorHandler, Session};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
@@ -1389,6 +1389,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
 }
 
 pub(super) fn build_target_config(
+    handler: &EarlyErrorHandler,
     opts: &Options,
     target_override: Option<Target>,
     sysroot: &Path,
@@ -1398,27 +1399,21 @@ pub(super) fn build_target_config(
         |t| Ok((t, TargetWarnings::empty())),
     );
     let (target, target_warnings) = target_result.unwrap_or_else(|e| {
-        early_error(
-            opts.error_format,
-            format!(
-                "Error loading target specification: {}. \
+        handler.early_error(format!(
+            "Error loading target specification: {}. \
                  Run `rustc --print target-list` for a list of built-in targets",
-                e
-            ),
-        )
+            e
+        ))
     });
     for warning in target_warnings.warning_messages() {
-        early_warn(opts.error_format, warning)
+        handler.early_warn(warning)
     }
 
     if !matches!(target.pointer_width, 16 | 32 | 64) {
-        early_error(
-            opts.error_format,
-            format!(
-                "target specification was invalid: unrecognized target-pointer-width {}",
-                target.pointer_width
-            ),
-        )
+        handler.early_error(format!(
+            "target specification was invalid: unrecognized target-pointer-width {}",
+            target.pointer_width
+        ))
     }
 
     target
@@ -1654,8 +1649,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
 }
 
 pub fn get_cmd_lint_options(
+    handler: &EarlyErrorHandler,
     matches: &getopts::Matches,
-    error_format: ErrorOutputType,
 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
     let mut lint_opts_with_position = vec![];
     let mut describe_lints = false;
@@ -1679,14 +1674,14 @@ pub fn get_cmd_lint_options(
 
     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
         lint::Level::from_str(&cap)
-            .unwrap_or_else(|| early_error(error_format, format!("unknown lint level: `{cap}`")))
+            .unwrap_or_else(|| handler.early_error(format!("unknown lint level: `{cap}`")))
     });
 
     (lint_opts, describe_lints, lint_cap)
 }
 
 /// Parses the `--color` flag.
-pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
+pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> ColorConfig {
     match matches.opt_str("color").as_deref() {
         Some("auto") => ColorConfig::Auto,
         Some("always") => ColorConfig::Always,
@@ -1694,13 +1689,10 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
 
         None => ColorConfig::Auto,
 
-        Some(arg) => early_error(
-            ErrorOutputType::default(),
-            format!(
-                "argument for `--color` must be auto, \
+        Some(arg) => handler.early_error(format!(
+            "argument for `--color` must be auto, \
                  always or never (instead was `{arg}`)"
-            ),
-        ),
+        )),
     }
 }
 
@@ -1743,7 +1735,7 @@ impl JsonUnusedExterns {
 ///
 /// The first value returned is how to render JSON diagnostics, and the second
 /// is whether or not artifact notifications are enabled.
-pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
+pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> JsonConfig {
     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
         HumanReadableErrorType::Default;
     let mut json_color = ColorConfig::Never;
@@ -1755,10 +1747,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
         // won't actually be emitting any colors and anything colorized is
         // embedded in a diagnostic message anyway.
         if matches.opt_str("color").is_some() {
-            early_error(
-                ErrorOutputType::default(),
-                "cannot specify the `--color` option with `--json`",
-            );
+            handler.early_error("cannot specify the `--color` option with `--json`");
         }
 
         for sub_option in option.split(',') {
@@ -1769,10 +1758,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
                 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
                 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
                 "future-incompat" => json_future_incompat = true,
-                s => early_error(
-                    ErrorOutputType::default(),
-                    format!("unknown `--json` option `{s}`"),
-                ),
+                s => handler.early_error(format!("unknown `--json` option `{s}`")),
             }
         }
     }
@@ -1787,6 +1773,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
 
 /// Parses the `--error-format` flag.
 pub fn parse_error_format(
+    handler: &mut EarlyErrorHandler,
     matches: &getopts::Matches,
     color: ColorConfig,
     json_rendered: HumanReadableErrorType,
@@ -1807,13 +1794,15 @@ pub fn parse_error_format(
             Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
 
-            Some(arg) => early_error(
-                ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
-                format!(
+            Some(arg) => {
+                handler.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
+                    HumanReadableErrorType::Default(color),
+                ));
+                handler.early_error(format!(
                     "argument for `--error-format` must be `human`, `json` or \
                      `short` (instead was `{arg}`)"
-                ),
-            ),
+                ))
+            }
         }
     } else {
         ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
@@ -1826,10 +1815,7 @@ pub fn parse_error_format(
         // `--error-format=json`. This means that `--json` is specified we
         // should actually be emitting JSON blobs.
         _ if !matches.opt_strs("json").is_empty() => {
-            early_error(
-                ErrorOutputType::default(),
-                "using `--json` requires also using `--error-format=json`",
-            );
+            handler.early_error("using `--json` requires also using `--error-format=json`");
         }
 
         _ => {}
@@ -1838,16 +1824,13 @@ pub fn parse_error_format(
     error_format
 }
 
-pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
+pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Edition {
     let edition = match matches.opt_str("edition") {
         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
-            early_error(
-                ErrorOutputType::default(),
-                format!(
-                    "argument for `--edition` must be one of: \
+            handler.early_error(format!(
+                "argument for `--edition` must be one of: \
                      {EDITION_NAME_LIST}. (instead was `{arg}`)"
-                ),
-            )
+            ))
         }),
         None => DEFAULT_EDITION,
     };
@@ -1862,39 +1845,42 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
         } else {
             format!("edition {edition} is unstable and only available with -Z unstable-options")
         };
-        early_error(ErrorOutputType::default(), msg)
+        handler.early_error(msg)
     }
 
     edition
 }
 
 fn check_error_format_stability(
+    handler: &mut EarlyErrorHandler,
     unstable_opts: &UnstableOptions,
     error_format: ErrorOutputType,
     json_rendered: HumanReadableErrorType,
 ) {
     if !unstable_opts.unstable_options {
         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
-            early_error(
-                ErrorOutputType::Json { pretty: false, json_rendered },
-                "`--error-format=pretty-json` is unstable",
-            );
+            handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
+                pretty: false,
+                json_rendered,
+            });
+            handler.early_error("`--error-format=pretty-json` is unstable");
         }
         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
             error_format
         {
-            early_error(
-                ErrorOutputType::Json { pretty: false, json_rendered },
-                "`--error-format=human-annotate-rs` is unstable",
-            );
+            handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
+                pretty: false,
+                json_rendered,
+            });
+            handler.early_error("`--error-format=human-annotate-rs` is unstable");
         }
     }
 }
 
 fn parse_output_types(
+    handler: &EarlyErrorHandler,
     unstable_opts: &UnstableOptions,
     matches: &getopts::Matches,
-    error_format: ErrorOutputType,
 ) -> OutputTypes {
     let mut output_types = BTreeMap::new();
     if !unstable_opts.parse_only {
@@ -1908,13 +1894,10 @@ fn parse_output_types(
                     }
                 };
                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
-                    early_error(
-                        error_format,
-                        format!(
-                            "unknown emission type: `{shorthand}` - expected one of: {display}",
-                            display = OutputType::shorthands_display(),
-                        ),
-                    )
+                    handler.early_error(format!(
+                        "unknown emission type: `{shorthand}` - expected one of: {display}",
+                        display = OutputType::shorthands_display(),
+                    ))
                 });
                 output_types.insert(output_type, path);
             }
@@ -1927,9 +1910,9 @@ fn parse_output_types(
 }
 
 fn should_override_cgus_and_disable_thinlto(
+    handler: &EarlyErrorHandler,
     output_types: &OutputTypes,
     matches: &getopts::Matches,
-    error_format: ErrorOutputType,
     mut codegen_units: Option<usize>,
 ) -> (bool, Option<usize>) {
     let mut disable_local_thinlto = false;
@@ -1947,15 +1930,12 @@ fn should_override_cgus_and_disable_thinlto(
             Some(n) if n > 1 => {
                 if matches.opt_present("o") {
                     for ot in &incompatible {
-                        early_warn(
-                            error_format,
-                            format!(
-                                "`--emit={ot}` with `-o` incompatible with \
+                        handler.early_warn(format!(
+                            "`--emit={ot}` with `-o` incompatible with \
                                  `-C codegen-units=N` for N > 1",
-                            ),
-                        );
+                        ));
                     }
-                    early_warn(error_format, "resetting to default -C codegen-units=1");
+                    handler.early_warn("resetting to default -C codegen-units=1");
                     codegen_units = Some(1);
                     disable_local_thinlto = true;
                 }
@@ -1968,27 +1948,27 @@ fn should_override_cgus_and_disable_thinlto(
     }
 
     if codegen_units == Some(0) {
-        early_error(error_format, "value for codegen units must be a positive non-zero integer");
+        handler.early_error("value for codegen units must be a positive non-zero integer");
     }
 
     (disable_local_thinlto, codegen_units)
 }
 
-fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
+fn check_thread_count(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) {
     if unstable_opts.threads == 0 {
-        early_error(error_format, "value for threads must be a positive non-zero integer");
+        handler.early_error("value for threads must be a positive non-zero integer");
     }
 
     if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
-        early_error(error_format, "optimization fuel is incompatible with multiple threads");
+        handler.early_error("optimization fuel is incompatible with multiple threads");
     }
 }
 
 fn collect_print_requests(
+    handler: &EarlyErrorHandler,
     cg: &mut CodegenOptions,
     unstable_opts: &mut UnstableOptions,
     matches: &getopts::Matches,
-    error_format: ErrorOutputType,
 ) -> Vec<PrintRequest> {
     let mut prints = Vec::<PrintRequest>::new();
     if cg.target_cpu.as_ref().is_some_and(|s| s == "help") {
@@ -2028,8 +2008,7 @@ fn collect_print_requests(
                 if unstable_opts.unstable_options {
                     PrintRequest::TargetSpec
                 } else {
-                    early_error(
-                        error_format,
+                    handler.early_error(
                         "the `-Z unstable-options` flag must also be passed to \
                          enable the target-spec-json print option",
                     );
@@ -2039,8 +2018,7 @@ fn collect_print_requests(
                 if unstable_opts.unstable_options {
                     PrintRequest::AllTargetSpecs
                 } else {
-                    early_error(
-                        error_format,
+                    handler.early_error(
                         "the `-Z unstable-options` flag must also be passed to \
                          enable the all-target-specs-json print option",
                     );
@@ -2051,10 +2029,9 @@ fn collect_print_requests(
                 let prints =
                     PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
                 let prints = prints.join(", ");
-                early_error(
-                    error_format,
-                    format!("unknown print request `{req}`. Valid print requests are: {prints}"),
-                );
+                handler.early_error(format!(
+                    "unknown print request `{req}`. Valid print requests are: {prints}"
+                ));
             }
         }
     }));
@@ -2063,14 +2040,14 @@ fn collect_print_requests(
 }
 
 pub fn parse_target_triple(
+    handler: &EarlyErrorHandler,
     matches: &getopts::Matches,
-    error_format: ErrorOutputType,
 ) -> TargetTriple {
     match matches.opt_str("target") {
         Some(target) if target.ends_with(".json") => {
             let path = Path::new(&target);
             TargetTriple::from_path(path).unwrap_or_else(|_| {
-                early_error(error_format, format!("target file {path:?} does not exist"))
+                handler.early_error(format!("target file {path:?} does not exist"))
             })
         }
         Some(target) => TargetTriple::TargetTriple(target),
@@ -2079,9 +2056,9 @@ pub fn parse_target_triple(
 }
 
 fn parse_opt_level(
+    handler: &EarlyErrorHandler,
     matches: &getopts::Matches,
     cg: &CodegenOptions,
-    error_format: ErrorOutputType,
 ) -> OptLevel {
     // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
     // to use them interchangeably. However, because they're technically different flags,
@@ -2109,13 +2086,10 @@ fn parse_opt_level(
             "s" => OptLevel::Size,
             "z" => OptLevel::SizeMin,
             arg => {
-                early_error(
-                    error_format,
-                    format!(
-                        "optimization level needs to be \
+                handler.early_error(format!(
+                    "optimization level needs to be \
                             between 0-3, s or z (instead was `{arg}`)"
-                    ),
-                );
+                ));
             }
         }
     }
@@ -2135,23 +2109,23 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
 }
 
 pub(crate) fn parse_assert_incr_state(
+    handler: &EarlyErrorHandler,
     opt_assertion: &Option<String>,
-    error_format: ErrorOutputType,
 ) -> Option<IncrementalStateAssertion> {
     match opt_assertion {
         Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
         Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
         Some(s) => {
-            early_error(error_format, format!("unexpected incremental state assertion value: {s}"))
+            handler.early_error(format!("unexpected incremental state assertion value: {s}"))
         }
         None => None,
     }
 }
 
 fn parse_native_lib_kind(
+    handler: &EarlyErrorHandler,
     matches: &getopts::Matches,
     kind: &str,
-    error_format: ErrorOutputType,
 ) -> (NativeLibKind, Option<bool>) {
     let (kind, modifiers) = match kind.split_once(':') {
         None => (kind, None),
@@ -2169,35 +2143,31 @@ fn parse_native_lib_kind(
                 } else {
                     ", the `-Z unstable-options` flag must also be passed to use it"
                 };
-                early_error(error_format, format!("library kind `link-arg` is unstable{why}"))
+                handler.early_error(format!("library kind `link-arg` is unstable{why}"))
             }
             NativeLibKind::LinkArg
         }
-        _ => early_error(
-            error_format,
-            format!(
-                "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
-            ),
-        ),
+        _ => handler.early_error(format!(
+            "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
+        )),
     };
     match modifiers {
         None => (kind, None),
-        Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
+        Some(modifiers) => parse_native_lib_modifiers(handler, kind, modifiers, matches),
     }
 }
 
 fn parse_native_lib_modifiers(
+    handler: &EarlyErrorHandler,
     mut kind: NativeLibKind,
     modifiers: &str,
-    error_format: ErrorOutputType,
     matches: &getopts::Matches,
 ) -> (NativeLibKind, Option<bool>) {
     let mut verbatim = None;
     for modifier in modifiers.split(',') {
         let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
             Some(m) => (m, modifier.starts_with('+')),
-            None => early_error(
-                error_format,
+            None => handler.early_error(
                 "invalid linking modifier syntax, expected '+' or '-' prefix \
                  before one of: bundle, verbatim, whole-archive, as-needed",
             ),
@@ -2210,21 +2180,20 @@ fn parse_native_lib_modifiers(
                 } else {
                     ", the `-Z unstable-options` flag must also be passed to use it"
                 };
-                early_error(error_format, format!("linking modifier `{modifier}` is unstable{why}"))
+                handler.early_error(format!("linking modifier `{modifier}` is unstable{why}"))
             }
         };
         let assign_modifier = |dst: &mut Option<bool>| {
             if dst.is_some() {
                 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
-                early_error(error_format, msg)
+                handler.early_error(msg)
             } else {
                 *dst = Some(value);
             }
         };
         match (modifier, &mut kind) {
             ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
-            ("bundle", _) => early_error(
-                error_format,
+            ("bundle", _) => handler.early_error(
                 "linking modifier `bundle` is only compatible with `static` linking kind",
             ),
 
@@ -2233,8 +2202,7 @@ fn parse_native_lib_modifiers(
             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
                 assign_modifier(whole_archive)
             }
-            ("whole-archive", _) => early_error(
-                error_format,
+            ("whole-archive", _) => handler.early_error(
                 "linking modifier `whole-archive` is only compatible with `static` linking kind",
             ),
 
@@ -2243,28 +2211,24 @@ fn parse_native_lib_modifiers(
                 report_unstable_modifier();
                 assign_modifier(as_needed)
             }
-            ("as-needed", _) => early_error(
-                error_format,
+            ("as-needed", _) => handler.early_error(
                 "linking modifier `as-needed` is only compatible with \
                  `dylib` and `framework` linking kinds",
             ),
 
             // Note: this error also excludes the case with empty modifier
             // string, like `modifiers = ""`.
-            _ => early_error(
-                error_format,
-                format!(
-                    "unknown linking modifier `{modifier}`, expected one \
+            _ => handler.early_error(format!(
+                "unknown linking modifier `{modifier}`, expected one \
                      of: bundle, verbatim, whole-archive, as-needed"
-                ),
-            ),
+            )),
         }
     }
 
     (kind, verbatim)
 }
 
-fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
+fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<NativeLib> {
     matches
         .opt_strs("l")
         .into_iter()
@@ -2278,7 +2242,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
             let (name, kind, verbatim) = match s.split_once('=') {
                 None => (s, NativeLibKind::Unspecified, None),
                 Some((kind, name)) => {
-                    let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
+                    let (kind, verbatim) = parse_native_lib_kind(handler, matches, kind);
                     (name.to_string(), kind, verbatim)
                 }
             };
@@ -2288,7 +2252,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
             };
             if name.is_empty() {
-                early_error(error_format, "library name must not be empty");
+                handler.early_error("library name must not be empty");
             }
             NativeLib { name, new_name, kind, verbatim }
         })
@@ -2296,9 +2260,9 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
 }
 
 pub fn parse_externs(
+    handler: &EarlyErrorHandler,
     matches: &getopts::Matches,
     unstable_opts: &UnstableOptions,
-    error_format: ErrorOutputType,
 ) -> Externs {
     let is_unstable_enabled = unstable_opts.unstable_options;
     let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
@@ -2362,8 +2326,7 @@ pub fn parse_externs(
         let mut force = false;
         if let Some(opts) = options {
             if !is_unstable_enabled {
-                early_error(
-                    error_format,
+                handler.early_error(
                     "the `-Z unstable-options` flag must also be passed to \
                      enable `--extern` options",
                 );
@@ -2375,15 +2338,14 @@ pub fn parse_externs(
                         if let ExternLocation::ExactPaths(_) = &entry.location {
                             add_prelude = false;
                         } else {
-                            early_error(
-                                error_format,
+                            handler.early_error(
                                 "the `noprelude` --extern option requires a file path",
                             );
                         }
                     }
                     "nounused" => nounused_dep = true,
                     "force" => force = true,
-                    _ => early_error(error_format, format!("unknown --extern option `{opt}`")),
+                    _ => handler.early_error(format!("unknown --extern option `{opt}`")),
                 }
             }
         }
@@ -2402,18 +2364,15 @@ pub fn parse_externs(
 }
 
 fn parse_remap_path_prefix(
+    handler: &EarlyErrorHandler,
     matches: &getopts::Matches,
     unstable_opts: &UnstableOptions,
-    error_format: ErrorOutputType,
 ) -> Vec<(PathBuf, PathBuf)> {
     let mut mapping: Vec<(PathBuf, PathBuf)> = matches
         .opt_strs("remap-path-prefix")
         .into_iter()
         .map(|remap| match remap.rsplit_once('=') {
-            None => early_error(
-                error_format,
-                "--remap-path-prefix must contain '=' between FROM and TO",
-            ),
+            None => handler.early_error("--remap-path-prefix must contain '=' between FROM and TO"),
             Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
         })
         .collect();
@@ -2429,86 +2388,75 @@ fn parse_remap_path_prefix(
 
 // JUSTIFICATION: before wrapper fn is available
 #[allow(rustc::bad_opt_access)]
-pub fn build_session_options(matches: &getopts::Matches) -> Options {
-    let color = parse_color(matches);
+pub fn build_session_options(
+    handler: &mut EarlyErrorHandler,
+    matches: &getopts::Matches,
+) -> Options {
+    let color = parse_color(handler, matches);
 
-    let edition = parse_crate_edition(matches);
+    let edition = parse_crate_edition(handler, matches);
 
     let JsonConfig {
         json_rendered,
         json_artifact_notifications,
         json_unused_externs,
         json_future_incompat,
-    } = parse_json(matches);
+    } = parse_json(handler, matches);
 
-    let error_format = parse_error_format(matches, color, json_rendered);
+    let error_format = parse_error_format(handler, matches, color, json_rendered);
 
     let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
-        early_error(error_format, "`--diagnostic-width` must be an positive integer");
+        handler.early_error("`--diagnostic-width` must be an positive integer");
     });
 
     let unparsed_crate_types = matches.opt_strs("crate-type");
     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
-        .unwrap_or_else(|e| early_error(error_format, e));
+        .unwrap_or_else(|e| handler.early_error(e));
 
-    let mut unstable_opts = UnstableOptions::build(matches, error_format);
-    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+    let mut unstable_opts = UnstableOptions::build(handler, matches);
+    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
 
-    check_error_format_stability(&unstable_opts, error_format, json_rendered);
+    check_error_format_stability(handler, &unstable_opts, error_format, json_rendered);
 
     if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
-        early_error(
-            error_format,
+        handler.early_error(
             "the `-Z unstable-options` flag must also be passed to enable \
             the flag `--json=unused-externs`",
         );
     }
 
-    let output_types = parse_output_types(&unstable_opts, matches, error_format);
+    let output_types = parse_output_types(handler, &unstable_opts, matches);
 
-    let mut cg = CodegenOptions::build(matches, error_format);
-    let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
-        &output_types,
-        matches,
-        error_format,
-        cg.codegen_units,
-    );
+    let mut cg = CodegenOptions::build(handler, matches);
+    let (disable_local_thinlto, mut codegen_units) =
+        should_override_cgus_and_disable_thinlto(handler, &output_types, matches, cg.codegen_units);
 
-    check_thread_count(&unstable_opts, error_format);
+    check_thread_count(handler, &unstable_opts);
 
     let incremental = cg.incremental.as_ref().map(PathBuf::from);
 
-    let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
+    let assert_incr_state = parse_assert_incr_state(handler, &unstable_opts.assert_incr_state);
 
     if unstable_opts.profile && incremental.is_some() {
-        early_error(
-            error_format,
-            "can't instrument with gcov profiling when compiling incrementally",
-        );
+        handler.early_error("can't instrument with gcov profiling when compiling incrementally");
     }
     if unstable_opts.profile {
         match codegen_units {
             Some(1) => {}
             None => codegen_units = Some(1),
-            Some(_) => early_error(
-                error_format,
-                "can't instrument with gcov profiling with multiple codegen units",
-            ),
+            Some(_) => handler
+                .early_error("can't instrument with gcov profiling with multiple codegen units"),
         }
     }
 
     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
-        early_error(
-            error_format,
-            "options `-C profile-generate` and `-C profile-use` are exclusive",
-        );
+        handler.early_error("options `-C profile-generate` and `-C profile-use` are exclusive");
     }
 
     if unstable_opts.profile_sample_use.is_some()
         && (cg.profile_generate.enabled() || cg.profile_use.is_some())
     {
-        early_error(
-            error_format,
+        handler.early_error(
             "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
         );
     }
@@ -2517,23 +2465,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     // precedence.
     match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
         (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
-            early_error(
-                error_format,
+            handler.early_error(
                 "incompatible values passed for `-C symbol-mangling-version` \
                 and `-Z symbol-mangling-version`",
             );
         }
         (Some(SymbolManglingVersion::V0), _) => {}
         (Some(_), _) if !unstable_opts.unstable_options => {
-            early_error(
-                error_format,
-                "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
-            );
+            handler
+                .early_error("`-C symbol-mangling-version=legacy` requires `-Z unstable-options`");
         }
         (None, None) => {}
         (None, smv) => {
-            early_warn(
-                error_format,
+            handler.early_warn(
                 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
             );
             cg.symbol_mangling_version = smv;
@@ -2545,25 +2489,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     // precedence.
     match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
         (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
-            early_error(
-                error_format,
+            handler.early_error(
                 "incompatible values passed for `-C instrument-coverage` \
                 and `-Z instrument-coverage`",
             );
         }
         (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
         (Some(_), _) if !unstable_opts.unstable_options => {
-            early_error(
-                error_format,
-                "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
-            );
+            handler.early_error("`-C instrument-coverage=except-*` requires `-Z unstable-options`");
         }
         (None, None) => {}
         (None, ic) => {
-            early_warn(
-                error_format,
-                "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
-            );
+            handler
+                .early_warn("`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`");
             cg.instrument_coverage = ic;
         }
         _ => {}
@@ -2571,8 +2509,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
-            early_error(
-                error_format,
+            handler.early_error(
                 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
                 or `-C profile-generate`",
             );
@@ -2585,8 +2522,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         match cg.symbol_mangling_version {
             None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
             Some(SymbolManglingVersion::Legacy) => {
-                early_warn(
-                    error_format,
+                handler.early_warn(
                     "-C instrument-coverage requires symbol mangling version `v0`, \
                     but `-C symbol-mangling-version=legacy` was specified",
                 );
@@ -2602,10 +2538,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     if !cg.embed_bitcode {
         match cg.lto {
             LtoCli::No | LtoCli::Unspecified => {}
-            LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
-                error_format,
-                "options `-C embed-bitcode=no` and `-C lto` are incompatible",
-            ),
+            LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
+                handler.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible")
+            }
         }
     }
 
@@ -2618,17 +2553,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
                  flag must also be passed to explicitly use it",
                 flavor.desc()
             );
-            early_error(error_format, msg);
+            handler.early_error(msg);
         }
     }
 
-    let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
+    let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches);
 
     let cg = cg;
 
     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
-    let target_triple = parse_target_triple(matches, error_format);
-    let opt_level = parse_opt_level(matches, &cg, error_format);
+    let target_triple = parse_target_triple(handler, matches);
+    let opt_level = parse_opt_level(handler, matches, &cg);
     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
     // for more details.
@@ -2637,28 +2572,28 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let mut search_paths = vec![];
     for s in &matches.opt_strs("L") {
-        search_paths.push(SearchPath::from_cli_opt(s, error_format));
+        search_paths.push(SearchPath::from_cli_opt(handler, s));
     }
 
-    let libs = parse_libs(matches, error_format);
+    let libs = parse_libs(handler, matches);
 
     let test = matches.opt_present("test");
 
     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
-        early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
+        handler.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
     }
 
-    let externs = parse_externs(matches, &unstable_opts, error_format);
+    let externs = parse_externs(handler, matches, &unstable_opts);
 
     let crate_name = matches.opt_str("crate-name");
 
-    let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
+    let remap_path_prefix = parse_remap_path_prefix(handler, matches, &unstable_opts);
 
-    let pretty = parse_pretty(&unstable_opts, error_format);
+    let pretty = parse_pretty(handler, &unstable_opts);
 
     // query-dep-graph is required if dump-dep-graph is given #106736
     if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
-        early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`");
+        handler.early_error("can't dump dependency graph without `-Z query-dep-graph`");
     }
 
     // Try to find a directory containing the Rust `src`, for more details see
@@ -2690,7 +2625,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     };
 
     let working_dir = std::env::current_dir().unwrap_or_else(|e| {
-        early_error(error_format, format!("Current directory is invalid: {e}"));
+        handler.early_error(format!("Current directory is invalid: {e}"));
     });
 
     let remap = FilePathMapping::new(remap_path_prefix.clone());
@@ -2741,7 +2676,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     }
 }
 
-fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
+fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> Option<PpMode> {
     use PpMode::*;
 
     let first = match unstable_opts.unpretty.as_deref()? {
@@ -2760,16 +2695,13 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
         "thir-flat" => ThirFlat,
         "mir" => Mir,
         "mir-cfg" => MirCFG,
-        name => early_error(
-            efmt,
-            format!(
-                "argument to `unpretty` must be one of `normal`, `identified`, \
+        name => handler.early_error(format!(
+            "argument to `unpretty` must be one of `normal`, `identified`, \
                             `expanded`, `expanded,identified`, `expanded,hygiene`, \
                             `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
                             `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \
                             `mir-cfg`; got {name}"
-            ),
-        ),
+        )),
     };
     debug!("got unpretty option: {first:?}");
     Some(first)
@@ -2809,8 +2741,8 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
 }
 
 pub mod nightly_options {
-    use super::{ErrorOutputType, OptionStability, RustcOptGroup};
-    use crate::early_error;
+    use super::{OptionStability, RustcOptGroup};
+    use crate::EarlyErrorHandler;
     use rustc_feature::UnstableFeatures;
 
     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
@@ -2826,7 +2758,11 @@ pub mod nightly_options {
         UnstableFeatures::from_environment(krate).is_nightly_build()
     }
 
-    pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
+    pub fn check_nightly_options(
+        handler: &EarlyErrorHandler,
+        matches: &getopts::Matches,
+        flags: &[RustcOptGroup],
+    ) {
         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
         let really_allows_unstable_options = match_is_nightly_build(matches);
 
@@ -2838,14 +2774,11 @@ pub mod nightly_options {
                 continue;
             }
             if opt.name != "Z" && !has_z_unstable_option {
-                early_error(
-                    ErrorOutputType::default(),
-                    format!(
-                        "the `-Z unstable-options` flag must also be passed to enable \
+                handler.early_error(format!(
+                    "the `-Z unstable-options` flag must also be passed to enable \
                          the flag `{}`",
-                        opt.name
-                    ),
-                );
+                    opt.name
+                ));
             }
             if really_allows_unstable_options {
                 continue;
@@ -2856,7 +2789,12 @@ pub mod nightly_options {
                         "the option `{}` is only accepted on the nightly compiler",
                         opt.name
                     );
-                    early_error(ErrorOutputType::default(), msg);
+                    let _ = handler.early_error_no_abort(msg);
+                    handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
+                    handler.early_help(
+                        "consider switching to a nightly toolchain: `rustup default nightly`",
+                    );
+                    handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
                 }
                 OptionStability::Stable => {}
             }
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 270d8331602..e5063eef47a 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1,9 +1,8 @@
 use crate::config::*;
 
-use crate::early_error;
-use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
+use crate::{lint, EarlyErrorHandler};
 use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_errors::{LanguageIdentifier, TerminalUrl};
 use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
@@ -245,10 +244,10 @@ macro_rules! options {
 
     impl $struct_name {
         pub fn build(
+            handler: &EarlyErrorHandler,
             matches: &getopts::Matches,
-            error_format: ErrorOutputType,
         ) -> $struct_name {
-            build_options(matches, $stat, $prefix, $outputname, error_format)
+            build_options(handler, matches, $stat, $prefix, $outputname)
         }
 
         fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
@@ -309,11 +308,11 @@ type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
 type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)];
 
 fn build_options<O: Default>(
+    handler: &EarlyErrorHandler,
     matches: &getopts::Matches,
     descrs: OptionDescrs<O>,
     prefix: &str,
     outputname: &str,
-    error_format: ErrorOutputType,
 ) -> O {
     let mut op = O::default();
     for option in matches.opt_strs(prefix) {
@@ -327,15 +326,13 @@ fn build_options<O: Default>(
             Some((_, setter, type_desc, _)) => {
                 if !setter(&mut op, value) {
                     match value {
-                        None => early_error(
-                            error_format,
+                        None => handler.early_error(
                             format!(
                                 "{0} option `{1}` requires {2} ({3} {1}=<value>)",
                                 outputname, key, type_desc, prefix
                             ),
                         ),
-                        Some(value) => early_error(
-                            error_format,
+                        Some(value) => handler.early_error(
                             format!(
                                 "incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected"
                             ),
@@ -343,7 +340,7 @@ fn build_options<O: Default>(
                     }
                 }
             }
-            None => early_error(error_format, format!("unknown {outputname} option: `{key}`")),
+            None => handler.early_error(format!("unknown {outputname} option: `{key}`")),
         }
     }
     return op;
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index a433e2371c9..194f7201ff3 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -51,13 +51,6 @@ impl GatedSpans {
         debug_assert_eq!(span, removed_span);
     }
 
-    /// Is the provided `feature` gate ungated currently?
-    ///
-    /// Using this is discouraged unless you have a really good reason to.
-    pub fn is_ungated(&self, feature: Symbol) -> bool {
-        self.spans.borrow().get(&feature).map_or(true, |spans| spans.is_empty())
-    }
-
     /// Prepend the given set of `spans` onto the set in `self`.
     pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
         let mut inner = self.spans.borrow_mut();
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index 56a6b6f3b03..07e78d1760e 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -1,5 +1,5 @@
 use crate::filesearch::make_target_lib_path;
-use crate::{config, early_error};
+use crate::EarlyErrorHandler;
 use std::path::{Path, PathBuf};
 
 #[derive(Clone, Debug)]
@@ -46,7 +46,7 @@ impl PathKind {
 }
 
 impl SearchPath {
-    pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self {
+    pub fn from_cli_opt(handler: &EarlyErrorHandler, path: &str) -> Self {
         let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
             (PathKind::Native, stripped)
         } else if let Some(stripped) = path.strip_prefix("crate=") {
@@ -61,7 +61,7 @@ impl SearchPath {
             (PathKind::All, path)
         };
         if path.is_empty() {
-            early_error(output, "empty search path given via `-L`");
+            handler.early_error("empty search path given via `-L`");
         }
 
         let dir = PathBuf::from(path);
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index ea5beb6f8be..5be122ffbde 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1,10 +1,10 @@
 use crate::cgu_reuse_tracker::CguReuseTracker;
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
-use crate::config::Input;
 use crate::config::{
     self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
 };
+use crate::config::{ErrorOutputType, Input};
 use crate::errors;
 use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
@@ -25,7 +25,7 @@ use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
     error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
+    ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
     TerminalUrl,
 };
 use rustc_macros::HashStable_Generic;
@@ -1382,6 +1382,7 @@ fn default_emitter(
 // JUSTIFICATION: literally session construction
 #[allow(rustc::bad_opt_access)]
 pub fn build_session(
+    handler: &EarlyErrorHandler,
     sopts: config::Options,
     io: CompilerIO,
     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
@@ -1408,13 +1409,12 @@ pub fn build_session(
         None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
     };
 
-    let target_cfg = config::build_target_config(&sopts, target_override, &sysroot);
+    let target_cfg = config::build_target_config(handler, &sopts, target_override, &sysroot);
     let host_triple = TargetTriple::from_triple(config::host_triple());
-    let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
-        early_error(sopts.error_format, format!("Error loading host specification: {e}"))
-    });
+    let (host, target_warnings) = Target::search(&host_triple, &sysroot)
+        .unwrap_or_else(|e| handler.early_error(format!("Error loading host specification: {e}")));
     for warning in target_warnings.warning_messages() {
-        early_warn(sopts.error_format, warning)
+        handler.early_warn(warning)
     }
 
     let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
@@ -1456,7 +1456,7 @@ pub fn build_session(
         match profiler {
             Ok(profiler) => Some(Arc::new(profiler)),
             Err(e) => {
-                early_warn(sopts.error_format, format!("failed to create profiler: {e}"));
+                handler.early_warn(format!("failed to create profiler: {e}"));
                 None
             }
         }
@@ -1723,7 +1723,64 @@ pub enum IncrCompSession {
     InvalidBecauseOfErrors { session_directory: PathBuf },
 }
 
-fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler {
+/// A wrapper around an [`Handler`] that is used for early error emissions.
+pub struct EarlyErrorHandler {
+    handler: Handler,
+}
+
+impl EarlyErrorHandler {
+    pub fn new(output: ErrorOutputType) -> Self {
+        let emitter = mk_emitter(output);
+        Self { handler: rustc_errors::Handler::with_emitter(true, None, emitter) }
+    }
+
+    pub fn abort_if_errors(&self) {
+        self.handler.abort_if_errors()
+    }
+
+    /// Swap out the underlying handler once we acquire the user's preference on error emission
+    /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
+    /// previous handler will be emitted.
+    pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) {
+        self.handler.abort_if_errors();
+
+        let emitter = mk_emitter(output);
+        self.handler = Handler::with_emitter(true, None, emitter);
+    }
+
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    pub fn early_note(&self, msg: impl Into<DiagnosticMessage>) {
+        self.handler.struct_note_without_error(msg).emit()
+    }
+
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    pub fn early_help(&self, msg: impl Into<DiagnosticMessage>) {
+        self.handler.struct_help(msg).emit()
+    }
+
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
+    pub fn early_error_no_abort(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
+        self.handler.struct_err(msg).emit()
+    }
+
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    pub fn early_error(&self, msg: impl Into<DiagnosticMessage>) -> ! {
+        self.handler.struct_fatal(msg).emit()
+    }
+
+    #[allow(rustc::untranslatable_diagnostic)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) {
+        self.handler.struct_warn(msg).emit()
+    }
+}
+
+fn mk_emitter(output: ErrorOutputType) -> Box<dyn Emitter + sync::Send + 'static> {
     // FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will
     // need to reference every crate that might emit an early error for translation to work.
     let fallback_bundle =
@@ -1755,27 +1812,5 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
             TerminalUrl::No,
         )),
     };
-    rustc_errors::Handler::with_emitter(true, None, emitter)
-}
-
-#[allow(rustc::untranslatable_diagnostic)]
-#[allow(rustc::diagnostic_outside_of_impl)]
-#[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
-pub fn early_error_no_abort(
-    output: config::ErrorOutputType,
-    msg: impl Into<DiagnosticMessage>,
-) -> ErrorGuaranteed {
-    early_error_handler(output).struct_err(msg).emit()
-}
-
-#[allow(rustc::untranslatable_diagnostic)]
-#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_error(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) -> ! {
-    early_error_handler(output).struct_fatal(msg).emit()
-}
-
-#[allow(rustc::untranslatable_diagnostic)]
-#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_warn(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) {
-    early_error_handler(output).struct_warn(msg).emit()
+    emitter
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_netbsd.rs
new file mode 100644
index 00000000000..98ae05974aa
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_netbsd.rs
@@ -0,0 +1,17 @@
+use crate::abi::Endian;
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "aarch64_be-unknown-netbsd".into(),
+        pointer_width: 64,
+        data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            mcount: "__mcount".into(),
+            max_atomic_width: Some(128),
+            endian: Endian::Big,
+            ..super::netbsd_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index c15a330ee74..88fbe2a8be1 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1194,6 +1194,7 @@ supported_targets! {
     ("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
 
     ("aarch64-unknown-netbsd", aarch64_unknown_netbsd),
+    ("aarch64_be-unknown-netbsd", aarch64_be_unknown_netbsd),
     ("armv6-unknown-netbsd-eabihf", armv6_unknown_netbsd_eabihf),
     ("armv7-unknown-netbsd-eabihf", armv7_unknown_netbsd_eabihf),
     ("i686-unknown-netbsd", i686_unknown_netbsd),
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index cde8a52cdec..9e8dbd0cde2 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -469,13 +469,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
         for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() {
-            if let Some(clause) = assumption.as_clause() {
-                match G::consider_implied_clause(self, goal, clause, []) {
-                    Ok(result) => {
-                        candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
-                    }
-                    Err(NoSolution) => (),
+            match G::consider_implied_clause(self, goal, assumption, []) {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result })
                 }
+                Err(NoSolution) => (),
             }
         }
     }
@@ -685,19 +683,15 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             // since that'll cause ambiguity.
             //
             // We can remove this when we have implemented lifetime intersections in responses.
-            if assumption.to_opt_poly_projection_pred().is_some()
-                && !own_bounds.contains(&assumption)
-            {
+            if assumption.as_projection_clause().is_some() && !own_bounds.contains(&assumption) {
                 continue;
             }
 
-            if let Some(clause) = assumption.as_clause() {
-                match G::consider_object_bound_candidate(self, goal, clause) {
-                    Ok(result) => {
-                        candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
-                    }
-                    Err(NoSolution) => (),
+            match G::consider_object_bound_candidate(self, goal, assumption) {
+                Ok(result) => {
+                    candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
                 }
+                Err(NoSolution) => (),
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 439cf788ab4..9eac53c3983 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -343,7 +343,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
-) -> Vec<ty::Predicate<'tcx>> {
+) -> Vec<ty::Clause<'tcx>> {
     let tcx = ecx.tcx();
     let mut requirements = vec![];
     requirements.extend(
@@ -353,11 +353,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
         // FIXME(associated_const_equality): Also add associated consts to
         // the requirements here.
         if item.kind == ty::AssocKind::Type {
-            requirements.extend(
-                tcx.item_bounds(item.def_id)
-                    .subst_iter(tcx, trait_ref.substs)
-                    .map(|clause| clause.as_predicate()),
-            );
+            requirements.extend(tcx.item_bounds(item.def_id).subst_iter(tcx, trait_ref.substs));
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index b42bbf91e90..6aca40b8dbd 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -395,7 +395,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 ty::PredicateKind::ConstEquate(_, _) => {
                     bug!("ConstEquate should not be emitted when `-Ztrait-solver=next` is active")
                 }
-                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
                 ty::PredicateKind::AliasRelate(lhs, rhs, direction) => self
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index f8f1239d5b4..5c62ea64f99 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -132,8 +132,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
                                             SelectionError::Unimplemented,
                                         )
                                     }
-                                    ty::PredicateKind::ConstEquate(..)
-                                    | ty::PredicateKind::TypeWellFormedFromEnv(_) => {
+                                    ty::PredicateKind::ConstEquate(..) => {
                                         bug!("unexpected goal: {goal:?}")
                                     }
                                 },
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 71557e8930d..fb6bf7211b9 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -255,7 +255,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         // that are already in the `ParamEnv` (modulo regions): we already
         // know that they must hold.
         for predicate in param_env.caller_bounds() {
-            fresh_preds.insert(self.clean_pred(infcx, predicate));
+            fresh_preds.insert(self.clean_pred(infcx, predicate.as_predicate()));
         }
 
         let mut select = SelectionContext::new(&infcx);
@@ -270,8 +270,9 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             polarity: ty::ImplPolarity::Positive,
         }));
 
-        let computed_preds = param_env.caller_bounds().iter();
-        let mut user_computed_preds: FxIndexSet<_> = user_env.caller_bounds().iter().collect();
+        let computed_preds = param_env.caller_bounds().iter().map(|c| c.as_predicate());
+        let mut user_computed_preds: FxIndexSet<_> =
+            user_env.caller_bounds().iter().map(|c| c.as_predicate()).collect();
 
         let mut new_env = param_env;
         let dummy_cause = ObligationCause::dummy();
@@ -349,14 +350,14 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             let normalized_preds =
                 elaborate(tcx, computed_preds.clone().chain(user_computed_preds.iter().cloned()));
             new_env = ty::ParamEnv::new(
-                tcx.mk_predicates_from_iter(normalized_preds),
+                tcx.mk_clauses_from_iter(normalized_preds.filter_map(|p| p.as_clause())),
                 param_env.reveal(),
                 param_env.constness(),
             );
         }
 
         let final_user_env = ty::ParamEnv::new(
-            tcx.mk_predicates_from_iter(user_computed_preds.into_iter()),
+            tcx.mk_clauses_from_iter(user_computed_preds.into_iter().filter_map(|p| p.as_clause())),
             user_env.reveal(),
             user_env.constness(),
         );
@@ -835,7 +836,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 // FIXME(generic_const_exprs): you can absolutely add this as a where clauses
                 | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
                 | ty::PredicateKind::Coerce(..) => {}
-                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                     bug!("predicate should only exist in the environment: {bound_predicate:?}")
                 }
                 ty::PredicateKind::Ambiguous => return false,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 0065c7fc253..9e1332c1c81 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -148,7 +148,12 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
         impl_def_id,
         self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs),
         trait_ref: tcx.impl_trait_ref(impl_def_id).map(|i| i.subst(tcx, impl_substs)),
-        predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates,
+        predicates: tcx
+            .predicates_of(impl_def_id)
+            .instantiate(tcx, impl_substs)
+            .iter()
+            .map(|(c, _)| c.as_predicate())
+            .collect(),
     };
 
     let InferOk { value: mut header, obligations } =
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index f9f242d29f6..ab4727b8697 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -207,7 +207,7 @@ fn satisfied_from_param_env<'tcx>(
 
     for pred in param_env.caller_bounds() {
         match pred.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ce)) => {
+            ty::ClauseKind::ConstEvaluatable(ce) => {
                 let b_ct = tcx.expand_abstract_consts(ce);
                 let mut v = Visitor { ct, infcx, param_env, single_match };
                 let _ = b_ct.visit_with(&mut v);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
index 1351d9bb257..96c183f9a58 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -84,7 +84,7 @@ pub fn recompute_applicable_impls<'tcx>(
         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::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = kind.skip_binder()
+        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())) {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 557341f7ac8..f93d6b1ce88 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1094,10 +1094,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                     ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"),
 
-                    ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
-                        span,
-                        "TypeWellFormedFromEnv predicate should only exist in the environment"
-                    ),
+                    ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
+                        span_bug!(
+                            span,
+                            "TypeWellFormedFromEnv predicate should only exist in the environment"
+                        )
+                    }
 
                     ty::PredicateKind::AliasRelate(..) => span_bug!(
                         span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 71d2380f234..43b63762ba3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1201,7 +1201,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         DefIdOrName::Name("type parameter")
                     };
                     param_env.caller_bounds().iter().find_map(|pred| {
-                        if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = pred.kind().skip_binder()
+                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
                         && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
                         && proj.projection_ty.self_ty() == found
                         // args tuple will always be substs[1]
@@ -2001,7 +2001,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause
             && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
             && let Some(pred) = predicates.predicates.get(*idx)
-            && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) = pred.kind().skip_binder()
+            && let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
             && self.tcx.is_fn_trait(trait_pred.def_id())
         {
             let expected_self =
@@ -2015,7 +2015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             let other_pred = predicates.into_iter()
                 .enumerate()
                 .find(|(other_idx, (pred, _))| match pred.kind().skip_binder() {
-                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred))
+                    ty::ClauseKind::Trait(trait_pred)
                         if self.tcx.is_fn_trait(trait_pred.def_id())
                             && other_idx != idx
                             // Make sure that the self type matches
@@ -3526,7 +3526,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
                 && let Some(where_pred) = where_clauses.predicates.get(*idx)
             {
-                if let Some(where_pred) = where_pred.to_opt_poly_trait_pred()
+                if let Some(where_pred) = where_pred.as_trait_clause()
                     && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
                 {
                     let where_pred = self.instantiate_binder_with_placeholders(where_pred);
@@ -3549,7 +3549,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             }
                         })
                     };
-                } else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred()
+                } else if let Some(where_pred) = where_pred.as_projection_clause()
                     && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
                     && let Some(found) = failed_pred.skip_binder().term.ty()
                 {
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 7c5260fc67b..f2f99eb60e4 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -366,7 +366,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     ProcessResult::Changed(mk_pending(vec![obligation.with(infcx.tcx, pred)]))
                 }
                 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
-                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
                 ty::PredicateKind::AliasRelate(..) => {
@@ -634,7 +634,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     }
                 }
                 ty::PredicateKind::Ambiguous => ProcessResult::Unchanged,
-                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
                 ty::PredicateKind::AliasRelate(..) => {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index a5481714e3e..ae76651c336 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -114,11 +114,11 @@ pub fn predicates_for_generics<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     generic_bounds: ty::InstantiatedPredicates<'tcx>,
 ) -> impl Iterator<Item = PredicateObligation<'tcx>> {
-    generic_bounds.into_iter().enumerate().map(move |(idx, (predicate, span))| Obligation {
+    generic_bounds.into_iter().enumerate().map(move |(idx, (clause, span))| Obligation {
         cause: cause(idx, span),
         recursion_depth: 0,
         param_env,
-        predicate,
+        predicate: clause.as_predicate(),
     })
 }
 
@@ -185,8 +185,8 @@ fn do_normalize_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     cause: ObligationCause<'tcx>,
     elaborated_env: ty::ParamEnv<'tcx>,
-    predicates: Vec<ty::Predicate<'tcx>>,
-) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> {
+    predicates: Vec<ty::Clause<'tcx>>,
+) -> Result<Vec<ty::Clause<'tcx>>, ErrorGuaranteed> {
     let span = cause.span;
     // FIXME. We should really... do something with these region
     // obligations. But this call just continues the older
@@ -330,7 +330,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
 
     let elaborated_env = ty::ParamEnv::new(
-        tcx.mk_predicates(&predicates),
+        tcx.mk_clauses(&predicates),
         unnormalized_env.reveal(),
         unnormalized_env.constness(),
     );
@@ -355,10 +355,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     // TypeOutlives predicates - these are normally used by regionck.
     let outlives_predicates: Vec<_> = predicates
         .extract_if(|predicate| {
-            matches!(
-                predicate.kind().skip_binder(),
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
-            )
+            matches!(predicate.kind().skip_binder(), ty::ClauseKind::TypeOutlives(..))
         })
         .collect();
 
@@ -384,7 +381,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     // predicates here anyway. Keeping them here anyway because it seems safer.
     let outlives_env = non_outlives_predicates.iter().chain(&outlives_predicates).cloned();
     let outlives_env = ty::ParamEnv::new(
-        tcx.mk_predicates_from_iter(outlives_env),
+        tcx.mk_clauses_from_iter(outlives_env),
         unnormalized_env.reveal(),
         unnormalized_env.constness(),
     );
@@ -404,7 +401,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     predicates.extend(outlives_predicates);
     debug!("normalize_param_env_or_error: final predicates={:?}", predicates);
     ty::ParamEnv::new(
-        tcx.mk_predicates(&predicates),
+        tcx.mk_clauses(&predicates),
         unnormalized_env.reveal(),
         unnormalized_env.constness(),
     )
@@ -439,10 +436,7 @@ where
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
 /// hold. Used when creating vtables to check for unsatisfiable methods.
-pub fn impossible_predicates<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    predicates: Vec<ty::Predicate<'tcx>>,
-) -> bool {
+pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool {
     debug!("impossible_predicates(predicates={:?})", predicates);
 
     let infcx = tcx.infer_ctxt().build();
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index df93c4d45dc..78270b7d535 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -271,22 +271,22 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
         .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied())
-        .filter_map(|(clause, span)| predicate_references_self(tcx, (clause.as_predicate(), span)))
+        .filter_map(|c| predicate_references_self(tcx, c))
         .collect()
 }
 
 fn predicate_references_self<'tcx>(
     tcx: TyCtxt<'tcx>,
-    (predicate, sp): (ty::Predicate<'tcx>, Span),
+    (predicate, sp): (ty::Clause<'tcx>, Span),
 ) -> Option<Span> {
     let self_ty = tcx.types.self_param;
     let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk().any(|arg| arg == self_ty.into());
     match predicate.kind().skip_binder() {
-        ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref data)) => {
+        ty::ClauseKind::Trait(ref data) => {
             // In the case of a trait predicate, we can skip the "self" type.
             data.trait_ref.substs[1..].iter().any(has_self_ty).then_some(sp)
         }
-        ty::PredicateKind::Clause(ty::ClauseKind::Projection(ref data)) => {
+        ty::ClauseKind::Projection(ref data) => {
             // And similarly for projections. This should be redundant with
             // the previous check because any projection should have a
             // matching `Trait` predicate with the same inputs, but we do
@@ -304,24 +304,14 @@ fn predicate_references_self<'tcx>(
             // possible alternatives.
             data.projection_ty.substs[1..].iter().any(has_self_ty).then_some(sp)
         }
-        ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(_ct, ty)) => {
-            has_self_ty(&ty.into()).then_some(sp)
-        }
-
-        ty::PredicateKind::AliasRelate(..) => bug!("`AliasRelate` not allowed as assumption"),
+        ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp),
 
-        ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
-        | ty::PredicateKind::ObjectSafe(..)
-        | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
-        | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
-        | ty::PredicateKind::ClosureKind(..)
-        | ty::PredicateKind::Subtype(..)
-        | ty::PredicateKind::Coerce(..)
+        ty::ClauseKind::WellFormed(..)
+        | ty::ClauseKind::TypeOutlives(..)
+        | ty::ClauseKind::RegionOutlives(..)
         // FIXME(generic_const_exprs): this can mention `Self`
-        | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-        | ty::PredicateKind::ConstEquate(..)
-        | ty::PredicateKind::Ambiguous
-        | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+        | ty::ClauseKind::ConstEvaluatable(..)
+        | ty::ClauseKind::TypeWellFormedFromEnv(_) => None,
     }
 }
 
@@ -353,23 +343,16 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     let predicates = tcx.predicates_of(def_id);
     let predicates = predicates.instantiate_identity(tcx).predicates;
     elaborate(tcx, predicates.into_iter()).any(|pred| match pred.kind().skip_binder() {
-        ty::PredicateKind::Clause(ty::ClauseKind::Trait(ref trait_pred)) => {
+        ty::ClauseKind::Trait(ref trait_pred) => {
             trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
         }
-        ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
-        | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
-        | ty::PredicateKind::Subtype(..)
-        | ty::PredicateKind::Coerce(..)
-        | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
-        | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
-        | ty::PredicateKind::ObjectSafe(..)
-        | ty::PredicateKind::ClosureKind(..)
-        | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..))
-        | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-        | ty::PredicateKind::ConstEquate(..)
-        | ty::PredicateKind::AliasRelate(..)
-        | ty::PredicateKind::Ambiguous
-        | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
+        ty::ClauseKind::RegionOutlives(_)
+        | ty::ClauseKind::TypeOutlives(_)
+        | ty::ClauseKind::Projection(_)
+        | ty::ClauseKind::ConstArgHasType(_, _)
+        | ty::ClauseKind::WellFormed(_)
+        | ty::ClauseKind::ConstEvaluatable(_)
+        | ty::ClauseKind::TypeWellFormedFromEnv(_) => false,
     })
 }
 
@@ -575,7 +558,7 @@ fn virtual_call_violation_for_method<'tcx>(
         // because a trait object can't claim to live longer than the concrete
         // type. If the lifetime bound holds on dyn Trait then it's guaranteed
         // to hold as well on the concrete type.
-        if pred.to_opt_type_outlives().is_some() {
+        if pred.as_type_outlives_clause().is_some() {
             return false;
         }
 
@@ -592,11 +575,11 @@ fn virtual_call_violation_for_method<'tcx>(
         // only if the autotrait is one of the trait object's trait bounds, like
         // in `dyn Trait + AutoTrait`. This guarantees that trait objects only
         // implement auto traits if the underlying type does as well.
-        if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(ty::TraitPredicate {
+        if let ty::ClauseKind::Trait(ty::TraitPredicate {
             trait_ref: pred_trait_ref,
             constness: ty::BoundConstness::NotConst,
             polarity: ty::ImplPolarity::Positive,
-        })) = pred.kind().skip_binder()
+        }) = pred.kind().skip_binder()
             && pred_trait_ref.self_ty() == tcx.types.self_param
             && tcx.trait_is_auto(pred_trait_ref.def_id)
         {
@@ -764,7 +747,6 @@ fn receiver_is_dispatchable<'tcx>(
         // Self: Unsize<U>
         let unsize_predicate =
             ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty])
-                .without_const()
                 .to_predicate(tcx);
 
         // U: Trait<Arg1, ..., ArgN>
@@ -781,7 +763,7 @@ fn receiver_is_dispatchable<'tcx>(
             param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]);
 
         ty::ParamEnv::new(
-            tcx.mk_predicates_from_iter(caller_bounds),
+            tcx.mk_clauses_from_iter(caller_bounds),
             param_env.reveal(),
             param_env.constness(),
         )
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 2a78c5befa4..c84c75cecdf 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1585,7 +1585,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
         obligation,
         candidate_set,
         ProjectionCandidate::TraitDef,
-        bounds.iter().map(|clause| clause.as_predicate()),
+        bounds.iter(),
         true,
     );
 }
@@ -1648,15 +1648,13 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
     ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>,
-    env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
+    env_predicates: impl Iterator<Item = ty::Clause<'tcx>>,
     potentially_unnormalized_candidates: bool,
 ) {
     let infcx = selcx.infcx;
     for predicate in env_predicates {
         let bound_predicate = predicate.kind();
-        if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
-            predicate.kind().skip_binder()
-        {
+        if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() {
             let data = bound_predicate.rebind(data);
             if data.projection_def_id() != obligation.predicate.def_id {
                 continue;
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 7d0dc740cf5..83d536c9ca5 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
@@ -134,7 +134,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
                 | ty::PredicateKind::AliasRelate(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+                | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {}
 
                 // We need to search through *all* WellFormed predicates
                 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index 57ca14aa492..9559f5002f6 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -50,12 +50,12 @@ impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
     }
 }
 
-impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> {
+impl<'tcx> Normalizable<'tcx> for ty::Clause<'tcx> {
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
     ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
-        tcx.type_op_normalize_predicate(canonicalized)
+        tcx.type_op_normalize_clause(canonicalized)
     }
 }
 
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 8eef7d5d63f..412b601c966 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -181,7 +181,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .caller_bounds()
             .iter()
             .filter(|p| !p.references_error())
-            .filter_map(|p| p.to_opt_poly_trait_pred());
+            .filter_map(|p| p.as_trait_clause());
 
         // Micro-optimization: filter out predicates relating to different traits.
         let matching_bounds =
@@ -402,7 +402,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         };
 
         for &(predicate, _) in self.tcx().predicates_of(impl_def_id).predicates {
-            let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
+            let ty::ClauseKind::Trait(pred)
                 = predicate.kind().skip_binder() else { continue };
             if fn_ptr_trait != pred.trait_ref.def_id {
                 continue;
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index a50af417a44..c94fddc124f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -1108,12 +1108,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     obligation.cause.span,
                     [source],
                 );
-                nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
+                nested.push(predicate_to_obligation(tr.to_predicate(tcx)));
 
                 // If the type is `Foo + 'a`, ensure that the type
                 // being cast to `Foo + 'a` outlives `'a`:
                 let outlives = ty::OutlivesPredicate(source, r);
-                nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate(tcx)));
+                nested.push(predicate_to_obligation(
+                    ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx),
+                ));
             }
 
             // `[T; n]` -> `[T]`
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0a8b7b688e7..7406b47e327 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -967,7 +967,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         }
                     }
                 }
-                ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+                ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
                 ty::PredicateKind::AliasRelate(..) => {
@@ -2657,7 +2657,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                         }))
                     })
                 };
-            let predicate = normalize_with_depth_to(
+            let clause = normalize_with_depth_to(
                 self,
                 param_env,
                 cause.clone(),
@@ -2665,7 +2665,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 predicate,
                 &mut obligations,
             );
-            obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
+            obligations.push(Obligation {
+                cause,
+                recursion_depth,
+                param_env,
+                predicate: clause.as_predicate(),
+            });
         }
 
         obligations
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 68ba8ceaa43..fee38aed0e2 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -508,22 +508,14 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
         Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
 
     for (mut p, _) in predicates {
-        if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
+        if let Some(poly_trait_ref) = p.as_trait_clause() {
             if Some(poly_trait_ref.def_id()) == sized_trait {
                 types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder());
                 continue;
             }
 
             if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness {
-                let new_trait_pred = poly_trait_ref.map_bound(|mut trait_pred| {
-                    trait_pred.constness = ty::BoundConstness::NotConst;
-                    trait_pred
-                });
-
-                p = tcx.mk_predicate(
-                    new_trait_pred
-                        .map_bound(|p| ty::PredicateKind::Clause(ty::ClauseKind::Trait(p))),
-                )
+                p = p.without_const(tcx);
             }
         }
         pretty_predicates.push(p.to_string());
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 05a7f3e3b02..72adf3106ab 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -125,7 +125,7 @@ impl<'tcx> TraitAliasExpander<'tcx> {
 
         let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| {
             pred.subst_supertrait(tcx, &trait_ref)
-                .to_opt_poly_trait_pred()
+                .as_trait_clause()
                 .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span))
         });
         debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>());
@@ -182,7 +182,7 @@ impl Iterator for SupertraitDefIds<'_> {
             predicates
                 .predicates
                 .iter()
-                .filter_map(|(pred, _)| pred.to_opt_poly_trait_pred())
+                .filter_map(|(pred, _)| pred.as_trait_clause())
                 .map(|trait_ref| trait_ref.def_id())
                 .filter(|&super_def_id| visited.insert(super_def_id)),
         );
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 96b8e0b82b6..c05d557b774 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -115,7 +115,7 @@ pub fn prepare_vtable_segments<'tcx, T>(
                     .predicates
                     .into_iter()
                     .filter_map(move |(pred, _)| {
-                        pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_pred()
+                        pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause()
                     });
 
                 'diving_in_skip_visited_traits: loop {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index e96e89ce73c..8bb4288f80d 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -185,7 +185,7 @@ pub fn predicate_obligations<'tcx>(
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::Ambiguous
         | ty::PredicateKind::AliasRelate(..)
-        | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+        | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
             bug!("We should only wf check where clauses, unexpected predicate: {predicate:?}")
         }
     }
@@ -976,7 +976,7 @@ pub fn object_region_bounds<'tcx>(
 pub(crate) fn required_region_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     erased_self_ty: Ty<'tcx>,
-    predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
+    predicates: impl Iterator<Item = ty::Clause<'tcx>>,
 ) -> Vec<ty::Region<'tcx>> {
     assert!(!erased_self_ty.has_escaping_bound_vars());
 
@@ -984,24 +984,7 @@ pub(crate) fn required_region_bounds<'tcx>(
         .filter_map(|pred| {
             debug!(?pred);
             match pred.kind().skip_binder() {
-                ty::PredicateKind::Clause(ty::ClauseKind::Projection(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::Trait(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
-                | ty::PredicateKind::Subtype(..)
-                | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..))
-                | ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::ClosureKind(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..))
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::AliasRelate(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
-                    ref t,
-                    ref r,
-                ))) => {
+                ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
                     // Search for a bound of the form `erased_self_ty
                     // : 'a`, but be wary of something like `for<'a>
                     // erased_self_ty : 'a` (we interpret a
@@ -1017,6 +1000,13 @@ pub(crate) fn required_region_bounds<'tcx>(
                         None
                     }
                 }
+                ty::ClauseKind::Trait(_)
+                | ty::ClauseKind::RegionOutlives(_)
+                | ty::ClauseKind::Projection(_)
+                | ty::ClauseKind::ConstArgHasType(_, _)
+                | ty::ClauseKind::WellFormed(_)
+                | ty::ClauseKind::ConstEvaluatable(_)
+                | ty::ClauseKind::TypeWellFormedFromEnv(_) => None,
             }
         })
         .collect()
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 7e64cbdf54a..6948151c644 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -42,7 +42,7 @@ impl<'tcx> RustIrDatabase<'tcx> {
             .tcx
             .predicates_defined_on(def_id)
             .instantiate_own(self.interner.tcx, bound_vars)
-            .filter_map(|(wc, _)| LowerInto::lower_into(wc, self.interner))
+            .filter_map(|(wc, _)| LowerInto::lower_into(wc.as_predicate(), self.interner))
             .collect()
     }
 
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index aefe57e0ddf..b7db56d3db8 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -93,36 +93,28 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
             let (predicate, binders, _named_regions) =
                 collect_bound_vars(interner, interner.tcx, predicate.kind());
             let consequence = match predicate {
-                ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+                ty::ClauseKind::TypeWellFormedFromEnv(ty) => {
                     chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner)))
                 }
-                ty::PredicateKind::Clause(ty::ClauseKind::Trait(predicate)) => {
-                    chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Trait(
-                        predicate.trait_ref.lower_into(interner),
-                    ))
-                }
-                ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(predicate)) => {
-                    chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::LifetimeOutlives(
-                        chalk_ir::LifetimeOutlives {
-                            a: predicate.0.lower_into(interner),
-                            b: predicate.1.lower_into(interner),
-                        },
-                    ))
-                }
-                ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(predicate)) => {
-                    chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::TypeOutlives(
-                        chalk_ir::TypeOutlives {
-                            ty: predicate.0.lower_into(interner),
-                            lifetime: predicate.1.lower_into(interner),
-                        },
-                    ))
-                }
-                ty::PredicateKind::Clause(ty::ClauseKind::Projection(predicate)) => {
-                    chalk_ir::DomainGoal::Holds(chalk_ir::WhereClause::AliasEq(
-                        predicate.lower_into(interner),
-                    ))
-                }
-                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => match arg.unpack() {
+                ty::ClauseKind::Trait(predicate) => chalk_ir::DomainGoal::FromEnv(
+                    chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)),
+                ),
+                ty::ClauseKind::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+                    chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
+                        a: predicate.0.lower_into(interner),
+                        b: predicate.1.lower_into(interner),
+                    }),
+                ),
+                ty::ClauseKind::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+                    chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
+                        ty: predicate.0.lower_into(interner),
+                        lifetime: predicate.1.lower_into(interner),
+                    }),
+                ),
+                ty::ClauseKind::Projection(predicate) => chalk_ir::DomainGoal::Holds(
+                    chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
+                ),
+                ty::ClauseKind::WellFormed(arg) => match arg.unpack() {
                     ty::GenericArgKind::Type(ty) => chalk_ir::DomainGoal::WellFormed(
                         chalk_ir::WellFormed::Ty(ty.lower_into(interner)),
                     ),
@@ -131,15 +123,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                         interner.tcx.types.unit.lower_into(interner),
                     )),
                 },
-                ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
-                | ty::PredicateKind::AliasRelate(..)
-                | ty::PredicateKind::ClosureKind(..)
-                | ty::PredicateKind::Subtype(..)
-                | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::Ambiguous
-                | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
+                ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::ConstEvaluatable(_) => {
+                    bug!("unexpected predicate {}", predicate)
+                }
             };
             let value = chalk_ir::ProgramClauseImplication {
                 consequence,
@@ -236,9 +222,11 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             | ty::PredicateKind::ConstEquate(..) => {
                 chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
             }
-            ty::PredicateKind::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal(
-                chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))),
-            ),
+            ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(ty)) => {
+                chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::FromEnv(
+                    chalk_ir::FromEnv::Ty(ty.lower_into(interner)),
+                ))
+            }
         };
 
         chalk_ir::GoalData::Quantified(
@@ -683,7 +671,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::Ambiguous
-            | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+            | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                 bug!("unexpected predicate {self}")
             }
         };
@@ -819,7 +807,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
             | ty::PredicateKind::ConstEquate(..)
             | ty::PredicateKind::Ambiguous
-            | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+            | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => {
                 bug!("unexpected predicate {}", &self)
             }
         }
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 96896526a12..b83abf98592 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -70,6 +70,6 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
         | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::Ambiguous
-        | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
+        | ty::PredicateKind::Clause(ty::ClauseKind::TypeWellFormedFromEnv(..)) => true,
     }
 }
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 98d814d54f2..01b9a5640b8 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.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::traits::query::NoSolution;
+use rustc_middle::ty::{Clause, ParamEnvAnd};
 use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
-use rustc_middle::ty::{ParamEnvAnd, Predicate};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
@@ -23,7 +23,7 @@ pub(crate) fn provide(p: &mut Providers) {
         type_op_prove_predicate,
         type_op_subtype,
         type_op_normalize_ty,
-        type_op_normalize_predicate,
+        type_op_normalize_clause,
         type_op_normalize_fn_sig,
         type_op_normalize_poly_fn_sig,
         ..*p
@@ -70,10 +70,10 @@ fn type_op_normalize_ty<'tcx>(
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
 
-fn type_op_normalize_predicate<'tcx>(
+fn type_op_normalize_clause<'tcx>(
     tcx: TyCtxt<'tcx>,
-    canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Predicate<'tcx>>>>,
-) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Predicate<'tcx>>>, NoSolution> {
+    canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Clause<'tcx>>>>,
+) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Clause<'tcx>>>, NoSolution> {
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
 
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index 387adda8f57..d79ed220570 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -241,7 +241,8 @@ fn recurse_build<'tcx>(
         ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
             error(GenericConstantTooComplexSub::AssignNotSupported(node.span))?
         }
-        ExprKind::Closure { .. } | ExprKind::Return { .. } => {
+        // FIXME(explicit_tail_calls): maybe get `become` a new error
+        ExprKind::Closure { .. } | ExprKind::Return { .. } | ExprKind::Become { .. } => {
             error(GenericConstantTooComplexSub::ClosureAndReturnNotSupported(node.span))?
         }
         // let expressions imply control flow
@@ -337,6 +338,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
             | thir::ExprKind::Break { .. }
             | thir::ExprKind::Continue { .. }
             | thir::ExprKind::Return { .. }
+            | thir::ExprKind::Become { .. }
             | thir::ExprKind::Array { .. }
             | thir::ExprKind::Tuple { .. }
             | thir::ExprKind::Adt(_)
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index fe2d1fba7fe..2daab520a2f 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -4,8 +4,8 @@ use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, Binder, EarlyBinder, ImplTraitInTraitData, Predicate, PredicateKind, ToPredicate, Ty,
-    TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, EarlyBinder, ImplTraitInTraitData, ToPredicate, Ty, TyCtxt, TypeSuperVisitable,
+    TypeVisitable, TypeVisitor,
 };
 use rustc_session::config::TraitSolver;
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
@@ -245,7 +245,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     };
 
     let unnormalized_env =
-        ty::ParamEnv::new(tcx.mk_predicates(&predicates), traits::Reveal::UserFacing, constness);
+        ty::ParamEnv::new(tcx.mk_clauses(&predicates), traits::Reveal::UserFacing, constness);
 
     let body_id = local_did.unwrap_or(CRATE_DEF_ID);
     let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
@@ -258,7 +258,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
 /// its corresponding opaque within the body of a default-body trait method.
 struct ImplTraitInTraitFinder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    predicates: &'a mut Vec<Predicate<'tcx>>,
+    predicates: &'a mut Vec<ty::Clause<'tcx>>,
     fn_def_id: DefId,
     bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
     seen: FxHashSet<DefId>,
@@ -340,9 +340,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
 /// that are assumed to be well-formed (because they come from the environment).
 ///
 /// Used only in chalk mode.
-fn well_formed_types_in_env(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Predicate<'_>> {
+fn well_formed_types_in_env(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<ty::Clause<'_>> {
     use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
-    use rustc_middle::ty::subst::GenericArgKind;
 
     debug!("environment(def_id = {:?})", def_id);
 
@@ -430,20 +429,19 @@ fn well_formed_types_in_env(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Predica
     }
     let input_clauses = inputs.into_iter().filter_map(|arg| {
         match arg.unpack() {
-            GenericArgKind::Type(ty) => {
-                let binder = Binder::dummy(PredicateKind::TypeWellFormedFromEnv(ty));
-                Some(tcx.mk_predicate(binder))
+            ty::GenericArgKind::Type(ty) => {
+                Some(ty::ClauseKind::TypeWellFormedFromEnv(ty).to_predicate(tcx))
             }
 
             // FIXME(eddyb) no WF conditions from lifetimes?
-            GenericArgKind::Lifetime(_) => None,
+            ty::GenericArgKind::Lifetime(_) => None,
 
             // FIXME(eddyb) support const generics in Chalk
-            GenericArgKind::Const(_) => None,
+            ty::GenericArgKind::Const(_) => None,
         }
     });
 
-    tcx.mk_predicates_from_iter(clauses.chain(input_clauses))
+    tcx.mk_clauses_from_iter(clauses.chain(input_clauses))
 }
 
 fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index 95c07abf731..e5f828c4c0b 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -35,3 +35,4 @@ compiler-builtins-mem = ['compiler_builtins/mem']
 compiler-builtins-c = ["compiler_builtins/c"]
 compiler-builtins-no-asm = ["compiler_builtins/no-asm"]
 compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
+compiler-builtins-weak-intrinsics = ["compiler_builtins/weak-intrinsics"]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 8ef2bac9282..fa23367593d 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1319,39 +1319,56 @@ impl Clone for Box<str> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized + PartialEq, A: Allocator> PartialEq for Box<T, A> {
+impl<T, A1, A2> PartialEq<Box<T, A2>> for Box<T, A1>
+where
+    T: ?Sized + PartialEq,
+    A1: Allocator,
+    A2: Allocator,
+{
     #[inline]
-    fn eq(&self, other: &Self) -> bool {
+    fn eq(&self, other: &Box<T, A2>) -> bool {
         PartialEq::eq(&**self, &**other)
     }
+
     #[inline]
-    fn ne(&self, other: &Self) -> bool {
+    fn ne(&self, other: &Box<T, A2>) -> bool {
         PartialEq::ne(&**self, &**other)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for Box<T, A> {
+impl<T, A1, A2> PartialOrd<Box<T, A2>> for Box<T, A1>
+where
+    T: ?Sized + PartialOrd,
+    A1: Allocator,
+    A2: Allocator,
+{
     #[inline]
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+    fn partial_cmp(&self, other: &Box<T, A2>) -> Option<Ordering> {
         PartialOrd::partial_cmp(&**self, &**other)
     }
+
     #[inline]
-    fn lt(&self, other: &Self) -> bool {
+    fn lt(&self, other: &Box<T, A2>) -> bool {
         PartialOrd::lt(&**self, &**other)
     }
+
     #[inline]
-    fn le(&self, other: &Self) -> bool {
+    fn le(&self, other: &Box<T, A2>) -> bool {
         PartialOrd::le(&**self, &**other)
     }
+
     #[inline]
-    fn ge(&self, other: &Self) -> bool {
+    fn ge(&self, other: &Box<T, A2>) -> bool {
         PartialOrd::ge(&**self, &**other)
     }
+
     #[inline]
-    fn gt(&self, other: &Self) -> bool {
+    fn gt(&self, other: &Box<T, A2>) -> bool {
         PartialOrd::gt(&**self, &**other)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Ord, A: Allocator> Ord for Box<T, A> {
     #[inline]
diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs
index e8e6bd56d21..118cfdb36b9 100644
--- a/library/alloc/src/vec/extract_if.rs
+++ b/library/alloc/src/vec/extract_if.rs
@@ -37,12 +37,6 @@ pub struct ExtractIf<
     pub(super) old_len: usize,
     /// The filter test predicate.
     pub(super) pred: F,
-    /// A flag that indicates a panic has occurred in the filter test predicate.
-    /// This is used as a hint in the drop implementation to prevent consumption
-    /// of the remainder of the `ExtractIf`. Any unprocessed items will be
-    /// backshifted in the `vec`, but no further items will be dropped or
-    /// tested by the filter predicate.
-    pub(super) panic_flag: bool,
 }
 
 impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
@@ -69,9 +63,7 @@ where
             while self.idx < self.old_len {
                 let i = self.idx;
                 let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
-                self.panic_flag = true;
                 let drained = (self.pred)(&mut v[i]);
-                self.panic_flag = false;
                 // Update the index *after* the predicate is called. If the index
                 // is updated prior and the predicate panics, the element at this
                 // index would be leaked.
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index a30c6a44e07..ef4f8be6f19 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2948,7 +2948,7 @@ impl<T, A: Allocator> Vec<T, A> {
             self.set_len(0);
         }
 
-        ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
+        ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter }
     }
 }
 
diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs
index 60ef83223d1..5ec22e5147b 100644
--- a/library/core/benches/iter.rs
+++ b/library/core/benches/iter.rs
@@ -2,6 +2,7 @@ use core::borrow::Borrow;
 use core::iter::*;
 use core::mem;
 use core::num::Wrapping;
+use core::ops::Range;
 use test::{black_box, Bencher};
 
 #[bench]
@@ -69,6 +70,57 @@ fn bench_max(b: &mut Bencher) {
     })
 }
 
+#[bench]
+fn bench_range_step_by_sum_reducible(b: &mut Bencher) {
+    let r = 0u32..1024;
+    b.iter(|| {
+        let r = black_box(r.clone()).step_by(8);
+
+        let mut sum: u32 = 0;
+        for i in r {
+            sum += i;
+        }
+
+        sum
+    })
+}
+
+#[bench]
+fn bench_range_step_by_loop_u32(b: &mut Bencher) {
+    let r = 0..(u16::MAX as u32);
+    b.iter(|| {
+        let r = black_box(r.clone()).step_by(64);
+
+        let mut sum: u32 = 0;
+        for i in r {
+            let i = i ^ i.wrapping_sub(1);
+            sum = sum.wrapping_add(i);
+        }
+
+        sum
+    })
+}
+
+#[bench]
+fn bench_range_step_by_fold_usize(b: &mut Bencher) {
+    let r: Range<usize> = 0..(u16::MAX as usize);
+    b.iter(|| {
+        let r = black_box(r.clone());
+        r.step_by(64)
+            .map(|x: usize| x ^ (x.wrapping_sub(1)))
+            .fold(0usize, |acc, i| acc.wrapping_add(i))
+    })
+}
+
+#[bench]
+fn bench_range_step_by_fold_u16(b: &mut Bencher) {
+    let r: Range<u16> = 0..u16::MAX;
+    b.iter(|| {
+        let r = black_box(r.clone());
+        r.step_by(64).map(|x: u16| x ^ (x.wrapping_sub(1))).fold(0u16, |acc, i| acc.wrapping_add(i))
+    })
+}
+
 pub fn copy_zip(xs: &[u8], ys: &mut [u8]) {
     for (a, b) in ys.iter_mut().zip(xs) {
         *a = *b;
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index 09dbc95810f..1f7be85d38a 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -190,7 +190,7 @@ macro_rules! default_impl {
     ($t:ty, $v:expr, $doc:tt) => {
         #[stable(feature = "rust1", since = "1.0.0")]
         impl Default for $t {
-            #[inline]
+            #[inline(always)]
             #[doc = $doc]
             fn default() -> $t {
                 $v
diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs
index 4252c34a0e0..7f58f7d1775 100644
--- a/library/core/src/iter/adapters/step_by.rs
+++ b/library/core/src/iter/adapters/step_by.rs
@@ -1,4 +1,9 @@
-use crate::{intrinsics, iter::from_fn, ops::Try};
+use crate::convert::TryFrom;
+use crate::{
+    intrinsics,
+    iter::{from_fn, TrustedLen},
+    ops::{Range, Try},
+};
 
 /// An iterator for stepping iterators by a custom amount.
 ///
@@ -11,14 +16,22 @@ use crate::{intrinsics, iter::from_fn, ops::Try};
 #[stable(feature = "iterator_step_by", since = "1.28.0")]
 #[derive(Clone, Debug)]
 pub struct StepBy<I> {
+    /// This field is guaranteed to be preprocessed by the specialized `SpecRangeSetup::setup`
+    /// in the constructor.
+    /// For most iterators that processing is a no-op, but for Range<{integer}> types it is lossy
+    /// which means the inner iterator cannot be returned to user code.
+    /// Additionally this type-dependent preprocessing means specialized implementations
+    /// cannot be used interchangeably.
     iter: I,
     step: usize,
     first_take: bool,
 }
 
 impl<I> StepBy<I> {
+    #[inline]
     pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> {
         assert!(step != 0);
+        let iter = <I as SpecRangeSetup<I>>::setup(iter, step);
         StepBy { iter, step: step - 1, first_take: true }
     }
 }
@@ -32,16 +45,174 @@ where
 
     #[inline]
     fn next(&mut self) -> Option<Self::Item> {
+        self.spec_next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.spec_size_hint()
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<Self::Item> {
+        self.spec_nth(n)
+    }
+
+    fn try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R
+    where
+        F: FnMut(Acc, Self::Item) -> R,
+        R: Try<Output = Acc>,
+    {
+        self.spec_try_fold(acc, f)
+    }
+
+    #[inline]
+    fn fold<Acc, F>(self, acc: Acc, f: F) -> Acc
+    where
+        F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.spec_fold(acc, f)
+    }
+}
+
+impl<I> StepBy<I>
+where
+    I: ExactSizeIterator,
+{
+    // The zero-based index starting from the end of the iterator of the
+    // last element. Used in the `DoubleEndedIterator` implementation.
+    fn next_back_index(&self) -> usize {
+        let rem = self.iter.len() % (self.step + 1);
         if self.first_take {
-            self.first_take = false;
-            self.iter.next()
+            if rem == 0 { self.step } else { rem - 1 }
         } else {
-            self.iter.nth(self.step)
+            rem
         }
     }
+}
 
+#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
+impl<I> DoubleEndedIterator for StepBy<I>
+where
+    I: DoubleEndedIterator + ExactSizeIterator,
+{
     #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.spec_next_back()
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        self.spec_nth_back(n)
+    }
+
+    fn try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R
+    where
+        F: FnMut(Acc, Self::Item) -> R,
+        R: Try<Output = Acc>,
+    {
+        self.spec_try_rfold(init, f)
+    }
+
+    #[inline]
+    fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
+    where
+        Self: Sized,
+        F: FnMut(Acc, Self::Item) -> Acc,
+    {
+        self.spec_rfold(init, f)
+    }
+}
+
+// StepBy can only make the iterator shorter, so the len will still fit.
+#[stable(feature = "iterator_step_by", since = "1.28.0")]
+impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
+
+trait SpecRangeSetup<T> {
+    fn setup(inner: T, step: usize) -> T;
+}
+
+impl<T> SpecRangeSetup<T> for T {
+    #[inline]
+    default fn setup(inner: T, _step: usize) -> T {
+        inner
+    }
+}
+
+/// Specialization trait to optimize `StepBy<Range<{integer}>>` iteration.
+///
+/// # Safety
+///
+/// Technically this is safe to implement (look ma, no unsafe!), but in reality
+/// a lot of unsafe code relies on ranges over integers being correct.
+///
+/// For correctness *all* public StepBy methods must be specialized
+/// because `setup` drastically alters the meaning of the struct fields so that mixing
+/// different implementations would lead to incorrect results.
+unsafe trait StepByImpl<I> {
+    type Item;
+
+    fn spec_next(&mut self) -> Option<Self::Item>;
+
+    fn spec_size_hint(&self) -> (usize, Option<usize>);
+
+    fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
+
+    fn spec_try_fold<Acc, F, R>(&mut self, acc: Acc, f: F) -> R
+    where
+        F: FnMut(Acc, Self::Item) -> R,
+        R: Try<Output = Acc>;
+
+    fn spec_fold<Acc, F>(self, acc: Acc, f: F) -> Acc
+    where
+        F: FnMut(Acc, Self::Item) -> Acc;
+}
+
+/// Specialization trait for double-ended iteration.
+///
+/// See also: `StepByImpl`
+///
+/// # Safety
+///
+/// The specializations must be implemented together with `StepByImpl`
+/// where applicable. I.e. if `StepBy` does support backwards iteration
+/// for a given iterator and that is specialized for forward iteration then
+/// it must also be specialized for backwards iteration.
+unsafe trait StepByBackImpl<I> {
+    type Item;
+
+    fn spec_next_back(&mut self) -> Option<Self::Item>
+    where
+        I: DoubleEndedIterator + ExactSizeIterator;
+
+    fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>
+    where
+        I: DoubleEndedIterator + ExactSizeIterator;
+
+    fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, f: F) -> R
+    where
+        I: DoubleEndedIterator + ExactSizeIterator,
+        F: FnMut(Acc, Self::Item) -> R,
+        R: Try<Output = Acc>;
+
+    fn spec_rfold<Acc, F>(self, init: Acc, f: F) -> Acc
+    where
+        I: DoubleEndedIterator + ExactSizeIterator,
+        F: FnMut(Acc, Self::Item) -> Acc;
+}
+
+unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
+    type Item = I::Item;
+
+    #[inline]
+    default fn spec_next(&mut self) -> Option<I::Item> {
+        let step_size = if self.first_take { 0 } else { self.step };
+        self.first_take = false;
+        self.iter.nth(step_size)
+    }
+
+    #[inline]
+    default fn spec_size_hint(&self) -> (usize, Option<usize>) {
         #[inline]
         fn first_size(step: usize) -> impl Fn(usize) -> usize {
             move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) }
@@ -64,7 +235,7 @@ where
     }
 
     #[inline]
-    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
+    default fn spec_nth(&mut self, mut n: usize) -> Option<I::Item> {
         if self.first_take {
             self.first_take = false;
             let first = self.iter.next();
@@ -108,7 +279,7 @@ where
         }
     }
 
-    fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
+    default fn spec_try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
     where
         F: FnMut(Acc, Self::Item) -> R,
         R: Try<Output = Acc>,
@@ -128,7 +299,7 @@ where
         from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f)
     }
 
-    fn fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
+    default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
     where
         F: FnMut(Acc, Self::Item) -> Acc,
     {
@@ -148,34 +319,16 @@ where
     }
 }
 
-impl<I> StepBy<I>
-where
-    I: ExactSizeIterator,
-{
-    // The zero-based index starting from the end of the iterator of the
-    // last element. Used in the `DoubleEndedIterator` implementation.
-    fn next_back_index(&self) -> usize {
-        let rem = self.iter.len() % (self.step + 1);
-        if self.first_take {
-            if rem == 0 { self.step } else { rem - 1 }
-        } else {
-            rem
-        }
-    }
-}
+unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for StepBy<I> {
+    type Item = I::Item;
 
-#[stable(feature = "double_ended_step_by_iterator", since = "1.38.0")]
-impl<I> DoubleEndedIterator for StepBy<I>
-where
-    I: DoubleEndedIterator + ExactSizeIterator,
-{
     #[inline]
-    fn next_back(&mut self) -> Option<Self::Item> {
+    default fn spec_next_back(&mut self) -> Option<Self::Item> {
         self.iter.nth_back(self.next_back_index())
     }
 
     #[inline]
-    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+    default fn spec_nth_back(&mut self, n: usize) -> Option<I::Item> {
         // `self.iter.nth_back(usize::MAX)` does the right thing here when `n`
         // is out of bounds because the length of `self.iter` does not exceed
         // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
@@ -184,7 +337,7 @@ where
         self.iter.nth_back(n)
     }
 
-    fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
+    default fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
     where
         F: FnMut(Acc, Self::Item) -> R,
         R: Try<Output = Acc>,
@@ -207,10 +360,10 @@ where
     }
 
     #[inline]
-    fn rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
+    default fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
     where
         Self: Sized,
-        F: FnMut(Acc, Self::Item) -> Acc,
+        F: FnMut(Acc, I::Item) -> Acc,
     {
         #[inline]
         fn nth_back<I: DoubleEndedIterator>(
@@ -230,6 +383,192 @@ where
     }
 }
 
-// StepBy can only make the iterator shorter, so the len will still fit.
-#[stable(feature = "iterator_step_by", since = "1.28.0")]
-impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
+/// For these implementations, `SpecRangeSetup` calculates the number
+/// of iterations that will be needed and stores that in `iter.end`.
+///
+/// The various iterator implementations then rely on that to not need
+/// overflow checking, letting loops just be counted instead.
+///
+/// These only work for unsigned types, and will need to be reworked
+/// if you want to use it to specialize on signed types.
+///
+/// Currently these are only implemented for integers up to usize due to
+/// correctness issues around ExactSizeIterator impls on 16bit platforms.
+/// And since ExactSizeIterator is a prerequisite for backwards iteration
+/// and we must consistently specialize backwards and forwards iteration
+/// that makes the situation complicated enough that it's not covered
+/// for now.
+macro_rules! spec_int_ranges {
+    ($($t:ty)*) => ($(
+
+        const _: () = assert!(usize::BITS >= <$t>::BITS);
+
+        impl SpecRangeSetup<Range<$t>> for Range<$t> {
+            #[inline]
+            fn setup(mut r: Range<$t>, step: usize) -> Range<$t> {
+                let inner_len = r.size_hint().0;
+                // If step exceeds $t::MAX, then the count will be at most 1 and
+                // thus always fit into $t.
+                let yield_count = inner_len.div_ceil(step);
+                // Turn the range end into an iteration counter
+                r.end = yield_count as $t;
+                r
+            }
+        }
+
+        unsafe impl StepByImpl<Range<$t>> for StepBy<Range<$t>> {
+            #[inline]
+            fn spec_next(&mut self) -> Option<$t> {
+                // if a step size larger than the type has been specified fall back to
+                // t::MAX, in which case remaining will be at most 1.
+                // The `+ 1` can't overflow since the constructor substracted 1 from the original value.
+                let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX);
+                let remaining = self.iter.end;
+                if remaining > 0 {
+                    let val = self.iter.start;
+                    // this can only overflow during the last step, after which the value
+                    // will not be used
+                    self.iter.start = val.wrapping_add(step);
+                    self.iter.end = remaining - 1;
+                    Some(val)
+                } else {
+                    None
+                }
+            }
+
+            #[inline]
+            fn spec_size_hint(&self) -> (usize, Option<usize>) {
+                let remaining = self.iter.end as usize;
+                (remaining, Some(remaining))
+            }
+
+            // The methods below are all copied from the Iterator trait default impls.
+            // We have to repeat them here so that the specialization overrides the StepByImpl defaults
+
+            #[inline]
+            fn spec_nth(&mut self, n: usize) -> Option<Self::Item> {
+                self.advance_by(n).ok()?;
+                self.next()
+            }
+
+            #[inline]
+            fn spec_try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
+                where
+                    F: FnMut(Acc, Self::Item) -> R,
+                    R: Try<Output = Acc>
+            {
+                let mut accum = init;
+                while let Some(x) = self.next() {
+                    accum = f(accum, x)?;
+                }
+                try { accum }
+            }
+
+            #[inline]
+            fn spec_fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
+                where
+                    F: FnMut(Acc, Self::Item) -> Acc
+            {
+                // if a step size larger than the type has been specified fall back to
+                // t::MAX, in which case remaining will be at most 1.
+                let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX);
+                let remaining = self.iter.end;
+                let mut acc = init;
+                let mut val = self.iter.start;
+                for _ in 0..remaining {
+                    acc = f(acc, val);
+                    // this can only overflow during the last step, after which the value
+                    // will no longer be used
+                    val = val.wrapping_add(step);
+                }
+                acc
+            }
+        }
+
+        /// Safety: This macro is only applied to ranges over types <= usize
+        /// which means the inner length is guaranteed to fit into a usize and so
+        /// the outer length calculation won't encounter clamped values
+        #[unstable(feature = "trusted_len", issue = "37572")]
+        unsafe impl TrustedLen for StepBy<Range<$t>> {}
+    )*)
+}
+
+macro_rules! spec_int_ranges_r {
+    ($($t:ty)*) => ($(
+        const _: () = assert!(usize::BITS >= <$t>::BITS);
+
+        unsafe impl StepByBackImpl<Range<$t>> for StepBy<Range<$t>> {
+
+            #[inline]
+            fn spec_next_back(&mut self) -> Option<Self::Item>
+                where Range<$t>: DoubleEndedIterator + ExactSizeIterator,
+            {
+                let step = (self.step + 1) as $t;
+                let remaining = self.iter.end;
+                if remaining > 0 {
+                    let start = self.iter.start;
+                    self.iter.end = remaining - 1;
+                    Some(start + step * (remaining - 1))
+                } else {
+                    None
+                }
+            }
+
+            // The methods below are all copied from the Iterator trait default impls.
+            // We have to repeat them here so that the specialization overrides the StepByImplBack defaults
+
+            #[inline]
+            fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>
+                where Self: DoubleEndedIterator,
+            {
+                if self.advance_back_by(n).is_err() {
+                    return None;
+                }
+                self.next_back()
+            }
+
+            #[inline]
+            fn spec_try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
+                where
+                    Self: DoubleEndedIterator,
+                    F: FnMut(Acc, Self::Item) -> R,
+                    R: Try<Output = Acc>
+            {
+                let mut accum = init;
+                while let Some(x) = self.next_back() {
+                    accum = f(accum, x)?;
+                }
+                try { accum }
+            }
+
+            #[inline]
+            fn spec_rfold<Acc, F>(mut self, init: Acc, mut f: F) -> Acc
+                where
+                    Self: DoubleEndedIterator,
+                    F: FnMut(Acc, Self::Item) -> Acc
+            {
+                let mut accum = init;
+                while let Some(x) = self.next_back() {
+                    accum = f(accum, x);
+                }
+                accum
+            }
+        }
+    )*)
+}
+
+#[cfg(target_pointer_width = "64")]
+spec_int_ranges!(u8 u16 u32 u64 usize);
+// DoubleEndedIterator requires ExactSizeIterator, which isn't implemented for Range<u64>
+#[cfg(target_pointer_width = "64")]
+spec_int_ranges_r!(u8 u16 u32 usize);
+
+#[cfg(target_pointer_width = "32")]
+spec_int_ranges!(u8 u16 u32 usize);
+#[cfg(target_pointer_width = "32")]
+spec_int_ranges_r!(u8 u16 u32 usize);
+
+#[cfg(target_pointer_width = "16")]
+spec_int_ranges!(u8 u16 usize);
+#[cfg(target_pointer_width = "16")]
+spec_int_ranges_r!(u8 u16 usize);
diff --git a/library/core/tests/iter/adapters/step_by.rs b/library/core/tests/iter/adapters/step_by.rs
index 94f2fa8c25e..4c5b1dd9a6b 100644
--- a/library/core/tests/iter/adapters/step_by.rs
+++ b/library/core/tests/iter/adapters/step_by.rs
@@ -244,3 +244,58 @@ fn test_step_by_skip() {
     assert_eq!((0..=50).step_by(10).nth(3), Some(30));
     assert_eq!((200..=255u8).step_by(10).nth(3), Some(230));
 }
+
+
+struct DeOpt<I: Iterator>(I);
+
+impl<I: Iterator> Iterator for DeOpt<I> {
+    type Item = I::Item;
+
+    fn next(&mut self) -> core::option::Option<Self::Item> {
+        self.0.next()
+    }
+}
+
+impl<I: DoubleEndedIterator> DoubleEndedIterator for DeOpt<I> {
+    fn next_back(&mut self) -> core::option::Option<Self::Item> {
+        self.0.next_back()
+    }
+}
+
+#[test]
+fn test_step_by_fold_range_specialization() {
+    macro_rules! t {
+        ($range:expr, $var: ident, $body:tt) => {
+            {
+                // run the same tests for the non-optimized version
+                let mut $var = DeOpt($range);
+                $body
+            }
+            {
+                let mut $var = $range;
+                $body
+            }
+        }
+    }
+
+    t!((1usize..5).step_by(1), r, {
+        assert_eq!(r.next_back(), Some(4));
+        assert_eq!(r.sum::<usize>(), 6);
+    });
+
+    t!((0usize..4).step_by(2), r, {
+        assert_eq!(r.next(), Some(0));
+        assert_eq!(r.sum::<usize>(), 2);
+    });
+
+
+    t!((0usize..5).step_by(2), r, {
+        assert_eq!(r.next(), Some(0));
+        assert_eq!(r.sum::<usize>(), 6);
+    });
+
+    t!((usize::MAX - 6 .. usize::MAX).step_by(5), r, {
+        assert_eq!(r.next(), Some(usize::MAX - 6));
+        assert_eq!(r.sum::<usize>(), usize::MAX - 1);
+    });
+}
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index aaaa88624f0..151809b2df5 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -65,6 +65,7 @@ compiler-builtins-c = ["alloc/compiler-builtins-c"]
 compiler-builtins-mem = ["alloc/compiler-builtins-mem"]
 compiler-builtins-no-asm = ["alloc/compiler-builtins-no-asm"]
 compiler-builtins-mangled-names = ["alloc/compiler-builtins-mangled-names"]
+compiler-builtins-weak-intrinsics = ["alloc/compiler-builtins-weak-intrinsics"]
 llvm-libunwind = ["unwind/llvm-libunwind"]
 system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
 
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 89dfdfafdb1..c2d82169dc3 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1755,8 +1755,14 @@ impl DirEntry {
         self.0.file_type().map(FileType)
     }
 
-    /// Returns the bare file name of this directory entry without any other
-    /// leading path component.
+    /// Returns the file name of this directory entry without any
+    /// leading path component(s).
+    ///
+    /// As an example,
+    /// the output of the function will result in "foo" for all the following paths:
+    /// - "./foo"
+    /// - "/the/foo"
+    /// - "../../foo"
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 5fc6136ba1f..b1b9e84fce9 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -12,7 +12,6 @@ use crate::os::windows::io::{AsRawHandle, BorrowedHandle};
 use crate::ptr;
 use core::ffi::NonZero_c_ulong;
 
-#[path = "c/windows_sys.rs"] // c.rs is included from two places so we need to specify this
 mod windows_sys;
 pub use windows_sys::*;
 
@@ -432,3 +431,47 @@ compat_fn_with_fallback! {
         Status as u32
     }
 }
+
+// # Arm32 shim
+//
+// AddVectoredExceptionHandler and WSAStartup use platform-specific types.
+// However, Microsoft no longer supports thumbv7a so definitions for those targets
+// are not included in the win32 metadata. We work around that by defining them here.
+//
+// Where possible, these definitions should be kept in sync with https://docs.rs/windows-sys
+cfg_if::cfg_if! {
+if #[cfg(not(target_vendor = "uwp"))] {
+    #[link(name = "kernel32")]
+    extern "system" {
+        pub fn AddVectoredExceptionHandler(
+            first: u32,
+            handler: PVECTORED_EXCEPTION_HANDLER,
+        ) -> *mut c_void;
+    }
+    pub type PVECTORED_EXCEPTION_HANDLER = Option<
+        unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32,
+    >;
+    #[repr(C)]
+    pub struct EXCEPTION_POINTERS {
+        pub ExceptionRecord: *mut EXCEPTION_RECORD,
+        pub ContextRecord: *mut CONTEXT,
+    }
+    #[cfg(target_arch = "arm")]
+    pub enum CONTEXT {}
+}}
+
+#[link(name = "ws2_32")]
+extern "system" {
+    pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32;
+}
+#[cfg(target_arch = "arm")]
+#[repr(C)]
+pub struct WSADATA {
+    pub wVersion: u16,
+    pub wHighVersion: u16,
+    pub szDescription: [u8; 257],
+    pub szSystemStatus: [u8; 129],
+    pub iMaxSockets: u16,
+    pub iMaxUdpDg: u16,
+    pub lpVendorInfo: PSTR,
+}
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index 2cf1ade99ce..631aedd26b4 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -2171,7 +2171,6 @@ Windows.Win32.Networking.WinSock.WSARecv
 Windows.Win32.Networking.WinSock.WSASend
 Windows.Win32.Networking.WinSock.WSASERVICE_NOT_FOUND
 Windows.Win32.Networking.WinSock.WSASocketW
-Windows.Win32.Networking.WinSock.WSAStartup
 Windows.Win32.Networking.WinSock.WSASYSCALLFAILURE
 Windows.Win32.Networking.WinSock.WSASYSNOTREADY
 Windows.Win32.Networking.WinSock.WSATRY_AGAIN
@@ -2419,12 +2418,10 @@ Windows.Win32.System.Console.STD_HANDLE
 Windows.Win32.System.Console.STD_INPUT_HANDLE
 Windows.Win32.System.Console.STD_OUTPUT_HANDLE
 Windows.Win32.System.Console.WriteConsoleW
-Windows.Win32.System.Diagnostics.Debug.AddVectoredExceptionHandler
 Windows.Win32.System.Diagnostics.Debug.ARM64_NT_NEON128
 Windows.Win32.System.Diagnostics.Debug.CONTEXT
 Windows.Win32.System.Diagnostics.Debug.CONTEXT
 Windows.Win32.System.Diagnostics.Debug.CONTEXT
-Windows.Win32.System.Diagnostics.Debug.EXCEPTION_POINTERS
 Windows.Win32.System.Diagnostics.Debug.EXCEPTION_RECORD
 Windows.Win32.System.Diagnostics.Debug.FACILITY_CODE
 Windows.Win32.System.Diagnostics.Debug.FACILITY_NT_BIT
@@ -2437,7 +2434,6 @@ Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_IGNORE_INSERTS
 Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_OPTIONS
 Windows.Win32.System.Diagnostics.Debug.FormatMessageW
 Windows.Win32.System.Diagnostics.Debug.M128A
-Windows.Win32.System.Diagnostics.Debug.PVECTORED_EXCEPTION_HANDLER
 Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT
 Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT
 Windows.Win32.System.Environment.FreeEnvironmentStringsW
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index a4294f336fe..02377087173 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -40,13 +40,6 @@ extern "system" {
 }
 #[link(name = "kernel32")]
 extern "system" {
-    pub fn AddVectoredExceptionHandler(
-        first: u32,
-        handler: PVECTORED_EXCEPTION_HANDLER,
-    ) -> *mut ::core::ffi::c_void;
-}
-#[link(name = "kernel32")]
-extern "system" {
     pub fn CancelIo(hfile: HANDLE) -> BOOL;
 }
 #[link(name = "kernel32")]
@@ -712,10 +705,6 @@ extern "system" {
 }
 #[link(name = "ws2_32")]
 extern "system" {
-    pub fn WSAStartup(wversionrequested: u16, lpwsadata: *mut WSADATA) -> i32;
-}
-#[link(name = "ws2_32")]
-extern "system" {
     pub fn accept(s: SOCKET, addr: *mut SOCKADDR, addrlen: *mut i32) -> SOCKET;
 }
 #[link(name = "ws2_32")]
@@ -3029,17 +3018,6 @@ pub const ERROR_XML_PARSE_ERROR: WIN32_ERROR = 1465u32;
 pub type EXCEPTION_DISPOSITION = i32;
 pub const EXCEPTION_MAXIMUM_PARAMETERS: u32 = 15u32;
 #[repr(C)]
-pub struct EXCEPTION_POINTERS {
-    pub ExceptionRecord: *mut EXCEPTION_RECORD,
-    pub ContextRecord: *mut CONTEXT,
-}
-impl ::core::marker::Copy for EXCEPTION_POINTERS {}
-impl ::core::clone::Clone for EXCEPTION_POINTERS {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-#[repr(C)]
 pub struct EXCEPTION_RECORD {
     pub ExceptionCode: NTSTATUS,
     pub ExceptionFlags: u32,
@@ -3748,9 +3726,6 @@ pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32;
 pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32;
 pub const PROGRESS_CONTINUE: u32 = 0u32;
 pub type PSTR = *mut u8;
-pub type PVECTORED_EXCEPTION_HANDLER = ::core::option::Option<
-    unsafe extern "system" fn(exceptioninfo: *mut EXCEPTION_POINTERS) -> i32,
->;
 pub type PWSTR = *mut u16;
 pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
 pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32;
@@ -4275,23 +4250,3 @@ impl ::core::clone::Clone for XSAVE_FORMAT {
         *self
     }
 }
-// Begin of ARM32 shim
-// The raw content of this file should be processed by `generate-windows-sys`
-// to be merged with the generated binding. It is not supposed to be used as
-// a normal Rust module.
-cfg_if::cfg_if! {
-if #[cfg(target_arch = "arm")] {
-#[repr(C)]
-pub struct WSADATA {
-    pub wVersion: u16,
-    pub wHighVersion: u16,
-    pub szDescription: [u8; 257],
-    pub szSystemStatus: [u8; 129],
-    pub iMaxSockets: u16,
-    pub iMaxUdpDg: u16,
-    pub lpVendorInfo: PSTR,
-}
-pub enum CONTEXT {}
-}
-}
-// End of ARM32 shim
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 5356ee277cc..6ff24a8db59 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -17,6 +17,7 @@ compiler-builtins-c = ["std/compiler-builtins-c"]
 compiler-builtins-mem = ["std/compiler-builtins-mem"]
 compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"]
 compiler-builtins-mangled-names = ["std/compiler-builtins-mangled-names"]
+compiler-builtins-weak-intrinsics = ["std/compiler-builtins-weak-intrinsics"]
 llvm-libunwind = ["std/llvm-libunwind"]
 system-llvm-libunwind = ["std/system-llvm-libunwind"]
 panic-unwind = ["std/panic_unwind"]
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs
index a80379e85c1..7ce4599c424 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/bin/main.rs
@@ -5,7 +5,9 @@
 //! parent directory, and otherwise documentation can be found throughout the `build`
 //! directory in each respective module.
 
-use std::env;
+use std::fs::OpenOptions;
+use std::io::Write;
+use std::{env, fs, process};
 
 #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
 use bootstrap::t;
@@ -20,22 +22,32 @@ fn main() {
     #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
     let _build_lock_guard;
     #[cfg(all(any(unix, windows), not(target_os = "solaris")))]
+    // Display PID of process holding the lock
+    // PID will be stored in a lock file
     {
         let path = config.out.join("lock");
-        build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path)));
+        let pid = match fs::read_to_string(&path) {
+            Ok(contents) => contents,
+            Err(_) => String::new(),
+        };
+
+        build_lock =
+            fd_lock::RwLock::new(t!(OpenOptions::new().write(true).create(true).open(&path)));
         _build_lock_guard = match build_lock.try_write() {
-            Ok(lock) => lock,
+            Ok(mut lock) => {
+                t!(lock.write(&process::id().to_string().as_ref()));
+                lock
+            }
             err => {
                 drop(err);
-                if let Some(pid) = get_lock_owner(&path) {
-                    println!("warning: build directory locked by process {pid}, waiting for lock");
-                } else {
-                    println!("warning: build directory locked, waiting for lock");
-                }
-                t!(build_lock.write())
+                println!("warning: build directory locked by process {pid}, waiting for lock");
+                let mut lock = t!(build_lock.write());
+                t!(lock.write(&process::id().to_string().as_ref()));
+                lock
             }
         };
     }
+
     #[cfg(any(not(any(unix, windows)), target_os = "solaris"))]
     println!("warning: file locking not supported for target, not locking build directory");
 
@@ -108,30 +120,3 @@ fn check_version(config: &Config) -> Option<String> {
 
     Some(msg)
 }
-
-/// Get the PID of the process which took the write lock by
-/// parsing `/proc/locks`.
-#[cfg(target_os = "linux")]
-fn get_lock_owner(f: &std::path::Path) -> Option<u64> {
-    use std::fs::File;
-    use std::io::{BufRead, BufReader};
-    use std::os::unix::fs::MetadataExt;
-
-    let lock_inode = std::fs::metadata(f).ok()?.ino();
-    let lockfile = File::open("/proc/locks").ok()?;
-    BufReader::new(lockfile).lines().find_map(|line| {
-        //                       pid--vvvvvv       vvvvvvv--- inode
-        // 21: FLOCK  ADVISORY  WRITE 359238 08:02:3719774 0 EOF
-        let line = line.ok()?;
-        let parts = line.split_whitespace().collect::<Vec<_>>();
-        let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]);
-        let inode = inode.rsplit_once(':')?.1.parse::<u64>().ok()?;
-        if inode == lock_inode { Some(pid) } else { None }
-    })
-}
-
-#[cfg(not(any(target_os = "linux", target_os = "solaris")))]
-fn get_lock_owner(_: &std::path::Path) -> Option<u64> {
-    // FIXME: Implement on other OS's
-    None
-}
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5714613cdf5..149350e62a0 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -323,6 +323,7 @@ def default_build_triple(verbose):
     cputype_mapper = {
         'BePC': 'i686',
         'aarch64': 'aarch64',
+        'aarch64eb': 'aarch64',
         'amd64': 'x86_64',
         'arm64': 'aarch64',
         'i386': 'i686',
@@ -458,23 +459,51 @@ def unpack_component(download_info):
         verbose=download_info.verbose,
     )
 
-class RustBuild(object):
-    """Provide all the methods required to build Rust"""
+class FakeArgs:
+    """Used for unit tests to avoid updating all call sites"""
     def __init__(self):
-        self.checksums_sha256 = {}
-        self.stage0_compiler = None
-        self.download_url = ''
         self.build = ''
         self.build_dir = ''
         self.clean = False
-        self.config_toml = ''
-        self.rust_root = ''
-        self.use_locked_deps = False
-        self.use_vendored_sources = False
         self.verbose = False
+        self.json_output = False
+        self.color = 'auto'
+        self.warnings = 'default'
+
+class RustBuild(object):
+    """Provide all the methods required to build Rust"""
+    def __init__(self, config_toml="", args=FakeArgs()):
         self.git_version = None
         self.nix_deps_dir = None
         self._should_fix_bins_and_dylibs = None
+        self.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
+
+        self.config_toml = config_toml
+
+        self.clean = args.clean
+        self.json_output = args.json_output
+        self.verbose = args.verbose
+        self.color = args.color
+        self.warnings = args.warnings
+
+        config_verbose_count = self.get_toml('verbose', 'build')
+        if config_verbose_count is not None:
+            self.verbose = max(self.verbose, int(config_verbose_count))
+
+        self.use_vendored_sources = self.get_toml('vendor', 'build') == 'true'
+        self.use_locked_deps = self.get_toml('locked-deps', 'build') == 'true'
+
+        build_dir = args.build_dir or self.get_toml('build-dir', 'build') or 'build'
+        self.build_dir = os.path.abspath(build_dir)
+
+        with open(os.path.join(self.rust_root, "src", "stage0.json")) as f:
+            data = json.load(f)
+        self.checksums_sha256 = data["checksums_sha256"]
+        self.stage0_compiler = Stage0Toolchain(data["compiler"])
+        self.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
+
+        self.build = args.build or self.build_triple()
+
 
     def download_toolchain(self):
         """Fetch the build system for Rust, written in Rust
@@ -704,9 +733,10 @@ class RustBuild(object):
         """Return the path for .rustc-stamp at the given stage
 
         >>> rb = RustBuild()
+        >>> rb.build = "host"
         >>> rb.build_dir = "build"
-        >>> rb.rustc_stamp() == os.path.join("build", "stage0", ".rustc-stamp")
-        True
+        >>> expected = os.path.join("build", "host", "stage0", ".rustc-stamp")
+        >>> assert rb.rustc_stamp() == expected, rb.rustc_stamp()
         """
         return os.path.join(self.bin_root(), '.rustc-stamp')
 
@@ -721,15 +751,9 @@ class RustBuild(object):
         """Return the binary root directory for the given stage
 
         >>> rb = RustBuild()
-        >>> rb.build_dir = "build"
-        >>> rb.bin_root() == os.path.join("build", "stage0")
-        True
-
-        When the 'build' property is given should be a nested directory:
-
         >>> rb.build = "devel"
-        >>> rb.bin_root() == os.path.join("build", "devel", "stage0")
-        True
+        >>> expected = os.path.abspath(os.path.join("build", "devel", "stage0"))
+        >>> assert rb.bin_root() == expected, rb.bin_root()
         """
         subdir = "stage0"
         return os.path.join(self.build_dir, self.build, subdir)
@@ -761,9 +785,12 @@ class RustBuild(object):
         >>> rb.get_toml("key1")
         'true'
         """
+        return RustBuild.get_toml_static(self.config_toml, key, section)
 
+    @staticmethod
+    def get_toml_static(config_toml, key, section=None):
         cur_section = None
-        for line in self.config_toml.splitlines():
+        for line in config_toml.splitlines():
             section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
             if section_match is not None:
                 cur_section = section_match.group(1)
@@ -772,7 +799,7 @@ class RustBuild(object):
             if match is not None:
                 value = match.group(1)
                 if section is None or section == cur_section:
-                    return self.get_string(value) or value.strip()
+                    return RustBuild.get_string(value) or value.strip()
         return None
 
     def cargo(self):
@@ -835,13 +862,23 @@ class RustBuild(object):
         """
         return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap")
 
-    def build_bootstrap(self, color, warnings, verbose_count):
+    def build_bootstrap(self):
         """Build bootstrap"""
         env = os.environ.copy()
         if "GITHUB_ACTIONS" in env:
             print("::group::Building bootstrap")
         else:
             print("Building bootstrap", file=sys.stderr)
+
+        args = self.build_bootstrap_cmd(env)
+        # Run this from the source directory so cargo finds .cargo/config
+        run(args, env=env, verbose=self.verbose, cwd=self.rust_root)
+
+        if "GITHUB_ACTIONS" in env:
+            print("::endgroup::")
+
+    def build_bootstrap_cmd(self, env):
+        """For tests."""
         build_dir = os.path.join(self.build_dir, "bootstrap")
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
@@ -894,10 +931,10 @@ class RustBuild(object):
         if target_linker is not None:
             env["RUSTFLAGS"] += " -C linker=" + target_linker
         env["RUSTFLAGS"] += " -Wrust_2018_idioms -Wunused_lifetimes"
-        if warnings == "default":
+        if self.warnings == "default":
             deny_warnings = self.get_toml("deny-warnings", "rust") != "false"
         else:
-            deny_warnings = warnings == "deny"
+            deny_warnings = self.warnings == "deny"
         if deny_warnings:
             env["RUSTFLAGS"] += " -Dwarnings"
 
@@ -908,7 +945,7 @@ class RustBuild(object):
                 self.cargo()))
         args = [self.cargo(), "build", "--manifest-path",
                 os.path.join(self.rust_root, "src/bootstrap/Cargo.toml")]
-        args.extend("--verbose" for _ in range(verbose_count))
+        args.extend("--verbose" for _ in range(self.verbose))
         if self.use_locked_deps:
             args.append("--locked")
         if self.use_vendored_sources:
@@ -918,20 +955,16 @@ class RustBuild(object):
             args.append("build-metrics")
         if self.json_output:
             args.append("--message-format=json")
-        if color == "always":
+        if self.color == "always":
             args.append("--color=always")
-        elif color == "never":
+        elif self.color == "never":
             args.append("--color=never")
         try:
             args += env["CARGOFLAGS"].split()
         except KeyError:
             pass
 
-        # Run this from the source directory so cargo finds .cargo/config
-        run(args, env=env, verbose=self.verbose, cwd=self.rust_root)
-
-        if "GITHUB_ACTIONS" in env:
-            print("::endgroup::")
+        return args
 
     def build_triple(self):
         """Build triple as in LLVM
@@ -981,7 +1014,7 @@ class RustBuild(object):
             if os.path.exists(cargo_dir):
                 shutil.rmtree(cargo_dir)
 
-def parse_args():
+def parse_args(args):
     """Parse the command line arguments that the python script needs."""
     parser = argparse.ArgumentParser(add_help=False)
     parser.add_argument('-h', '--help', action='store_true')
@@ -994,16 +1027,11 @@ def parse_args():
     parser.add_argument('--warnings', choices=['deny', 'warn', 'default'], default='default')
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
-    return parser.parse_known_args(sys.argv)[0]
+    return parser.parse_known_args(args)[0]
 
 def bootstrap(args):
     """Configure, fetch, build and run the initial bootstrap"""
-    # Configure initial bootstrap
-    build = RustBuild()
-    build.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
-    build.verbose = args.verbose != 0
-    build.clean = args.clean
-    build.json_output = args.json_output
+    rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
 
     # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
     # then `config.toml` in the root directory.
@@ -1012,52 +1040,43 @@ def bootstrap(args):
     if using_default_path:
         toml_path = 'config.toml'
         if not os.path.exists(toml_path):
-            toml_path = os.path.join(build.rust_root, toml_path)
+            toml_path = os.path.join(rust_root, toml_path)
 
     # Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
     # but not if `config.toml` hasn't been created.
     if not using_default_path or os.path.exists(toml_path):
         with open(toml_path) as config:
-            build.config_toml = config.read()
+            config_toml = config.read()
+    else:
+        config_toml = ''
 
-    profile = build.get_toml('profile')
+    profile = RustBuild.get_toml_static(config_toml, 'profile')
     if profile is not None:
-        include_file = 'config.{}.toml'.format(profile)
-        include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults')
+        # Allows creating alias for profile names, allowing
+        # profiles to be renamed while maintaining back compatibility
+        # Keep in sync with `profile_aliases` in config.rs
+        profile_aliases = {
+            "user": "dist"
+        }
+        include_file = 'config.{}.toml'.format(profile_aliases.get(profile) or profile)
+        include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults')
         include_path = os.path.join(include_dir, include_file)
-        # HACK: This works because `build.get_toml()` returns the first match it finds for a
+        # HACK: This works because `self.get_toml()` returns the first match it finds for a
         # specific key, so appending our defaults at the end allows the user to override them
         with open(include_path) as included_toml:
-            build.config_toml += os.linesep + included_toml.read()
-
-    verbose_count = args.verbose
-    config_verbose_count = build.get_toml('verbose', 'build')
-    if config_verbose_count is not None:
-        verbose_count = max(args.verbose, int(config_verbose_count))
-
-    build.use_vendored_sources = build.get_toml('vendor', 'build') == 'true'
-    build.use_locked_deps = build.get_toml('locked-deps', 'build') == 'true'
+            config_toml += os.linesep + included_toml.read()
 
+    # Configure initial bootstrap
+    build = RustBuild(config_toml, args)
     build.check_vendored_status()
 
-    build_dir = args.build_dir or build.get_toml('build-dir', 'build') or 'build'
-    build.build_dir = os.path.abspath(build_dir)
-
-    with open(os.path.join(build.rust_root, "src", "stage0.json")) as f:
-        data = json.load(f)
-    build.checksums_sha256 = data["checksums_sha256"]
-    build.stage0_compiler = Stage0Toolchain(data["compiler"])
-    build.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
-
-    build.build = args.build or build.build_triple()
-
     if not os.path.exists(build.build_dir):
         os.makedirs(build.build_dir)
 
     # Fetch/build the bootstrap
     build.download_toolchain()
     sys.stdout.flush()
-    build.build_bootstrap(args.color, args.warnings, verbose_count)
+    build.build_bootstrap()
     sys.stdout.flush()
 
     # Run the bootstrap
@@ -1077,7 +1096,7 @@ def main():
     if len(sys.argv) > 1 and sys.argv[1] == 'help':
         sys.argv[1] = '-h'
 
-    args = parse_args()
+    args = parse_args(sys.argv)
     help_triggered = args.help or len(sys.argv) == 1
 
     # If the user is asking for help, let them know that the whole download-and-build
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 5ecda83ee66..1294ca9df0d 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -1,4 +1,6 @@
-"""Bootstrap tests"""
+"""Bootstrap tests
+
+Run these with `x test bootstrap`, or `python -m unittest bootstrap_test.py`."""
 
 from __future__ import absolute_import, division, print_function
 import os
@@ -13,6 +15,22 @@ from shutil import rmtree
 import bootstrap
 import configure
 
+def serialize_and_parse(configure_args, bootstrap_args=bootstrap.FakeArgs()):
+    from io import StringIO
+
+    section_order, sections, targets = configure.parse_args(configure_args)
+    buffer = StringIO()
+    configure.write_config_toml(buffer, section_order, targets, sections)
+    build = bootstrap.RustBuild(config_toml=buffer.getvalue(), args=bootstrap_args)
+
+    try:
+        import tomllib
+        # Verify this is actually valid TOML.
+        tomllib.loads(build.config_toml)
+    except ImportError:
+        print("warning: skipping TOML validation, need at least python 3.11", file=sys.stderr)
+    return build
+
 
 class VerifyTestCase(unittest.TestCase):
     """Test Case for verify"""
@@ -77,58 +95,58 @@ class ProgramOutOfDate(unittest.TestCase):
 
 class GenerateAndParseConfig(unittest.TestCase):
     """Test that we can serialize and deserialize a config.toml file"""
-    def serialize_and_parse(self, args):
-        from io import StringIO
-
-        section_order, sections, targets = configure.parse_args(args)
-        buffer = StringIO()
-        configure.write_config_toml(buffer, section_order, targets, sections)
-        build = bootstrap.RustBuild()
-        build.config_toml = buffer.getvalue()
-
-        try:
-            import tomllib
-            # Verify this is actually valid TOML.
-            tomllib.loads(build.config_toml)
-        except ImportError:
-            print("warning: skipping TOML validation, need at least python 3.11", file=sys.stderr)
-        return build
-
     def test_no_args(self):
-        build = self.serialize_and_parse([])
+        build = serialize_and_parse([])
         self.assertEqual(build.get_toml("changelog-seen"), '2')
-        self.assertEqual(build.get_toml("profile"), 'user')
+        self.assertEqual(build.get_toml("profile"), 'dist')
         self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))
 
     def test_set_section(self):
-        build = self.serialize_and_parse(["--set", "llvm.download-ci-llvm"])
+        build = serialize_and_parse(["--set", "llvm.download-ci-llvm"])
         self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), 'true')
 
     def test_set_target(self):
-        build = self.serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"])
+        build = serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"])
         self.assertEqual(build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), 'gcc')
 
     def test_set_top_level(self):
-        build = self.serialize_and_parse(["--set", "profile=compiler"])
+        build = serialize_and_parse(["--set", "profile=compiler"])
         self.assertEqual(build.get_toml("profile"), 'compiler')
 
     def test_set_codegen_backends(self):
-        build = self.serialize_and_parse(["--set", "rust.codegen-backends=cranelift"])
+        build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift"])
         self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift']"), -1)
-        build = self.serialize_and_parse(["--set", "rust.codegen-backends=cranelift,llvm"])
+        build = serialize_and_parse(["--set", "rust.codegen-backends=cranelift,llvm"])
         self.assertNotEqual(build.config_toml.find("codegen-backends = ['cranelift', 'llvm']"), -1)
-        build = self.serialize_and_parse(["--enable-full-tools"])
+        build = serialize_and_parse(["--enable-full-tools"])
         self.assertNotEqual(build.config_toml.find("codegen-backends = ['llvm']"), -1)
 
-if __name__ == '__main__':
-    SUITE = unittest.TestSuite()
-    TEST_LOADER = unittest.TestLoader()
-    SUITE.addTest(doctest.DocTestSuite(bootstrap))
-    SUITE.addTests([
-        TEST_LOADER.loadTestsFromTestCase(VerifyTestCase),
-        TEST_LOADER.loadTestsFromTestCase(GenerateAndParseConfig),
-        TEST_LOADER.loadTestsFromTestCase(ProgramOutOfDate)])
-
-    RUNNER = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
-    result = RUNNER.run(SUITE)
-    sys.exit(0 if result.wasSuccessful() else 1)
+
+class BuildBootstrap(unittest.TestCase):
+    """Test that we generate the appropriate arguments when building bootstrap"""
+
+    def build_args(self, configure_args=[], args=[], env={}):
+        env = env.copy()
+        env["PATH"] = os.environ["PATH"]
+
+        parsed = bootstrap.parse_args(args)
+        build = serialize_and_parse(configure_args, parsed)
+        build.build_dir = os.environ["BUILD_DIR"]
+        build.build = os.environ["BUILD_PLATFORM"]
+        return build.build_bootstrap_cmd(env), env
+
+    def test_cargoflags(self):
+        args, _ = self.build_args(env={"CARGOFLAGS": "--timings"})
+        self.assertTrue("--timings" in args)
+
+    def test_warnings(self):
+        for toml_warnings in ['false', 'true', None]:
+            configure_args = []
+            if toml_warnings is not None:
+                configure_args = ["--set", "rust.deny-warnings=" + toml_warnings]
+
+            _, env = self.build_args(configure_args, args=["--warnings=warn"])
+            self.assertFalse("-Dwarnings" in env["RUSTFLAGS"])
+
+            _, env = self.build_args(configure_args, args=["--warnings=deny"])
+            self.assertTrue("-Dwarnings" in env["RUSTFLAGS"])
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 8ee63e561ba..b91275e73e9 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -1129,6 +1129,14 @@ impl Config {
         };
 
         if let Some(include) = &toml.profile {
+            // Allows creating alias for profile names, allowing
+            // profiles to be renamed while maintaining back compatibility
+            // Keep in sync with `profile_aliases` in bootstrap.py
+            let profile_aliases = HashMap::from([("user", "dist")]);
+            let include = match profile_aliases.get(include.as_str()) {
+                Some(alias) => alias,
+                None => include.as_str(),
+            };
             let mut include_path = config.src.clone();
             include_path.push("src");
             include_path.push("bootstrap");
diff --git a/src/bootstrap/config/tests.rs b/src/bootstrap/config/tests.rs
index 4de84b543ed..3bee659abd1 100644
--- a/src/bootstrap/config/tests.rs
+++ b/src/bootstrap/config/tests.rs
@@ -1,5 +1,8 @@
+use crate::config::TomlConfig;
+
 use super::{Config, Flags};
 use clap::CommandFactory;
+use serde::Deserialize;
 use std::{env, path::Path};
 
 fn parse(config: &str) -> Config {
@@ -159,3 +162,19 @@ fn override_toml_duplicate() {
         |&_| toml::from_str("changelog-seen = 0").unwrap(),
     );
 }
+
+#[test]
+fn profile_user_dist() {
+    fn get_toml(file: &Path) -> TomlConfig {
+        let contents = if file.ends_with("config.toml") {
+            "profile = \"user\"".to_owned()
+        } else {
+            assert!(file.ends_with("config.dist.toml"));
+            std::fs::read_to_string(dbg!(file)).unwrap()
+        };
+        toml::from_str(&contents)
+            .and_then(|table: toml::Value| TomlConfig::deserialize(table))
+            .unwrap()
+    }
+    Config::parse_inner(&["check".to_owned()], get_toml);
+}
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index a16f77317c8..e8eebdfb5a5 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -280,7 +280,7 @@ def parse_args(args):
 
     config = {}
 
-    set('build.configure-args', sys.argv[1:], config)
+    set('build.configure-args', args, config)
     apply_args(known_args, option_checking, config)
     return parse_example_config(known_args, config)
 
@@ -400,7 +400,9 @@ def parse_example_config(known_args, config):
     targets = {}
     top_level_keys = []
 
-    for line in open(rust_dir + '/config.example.toml').read().split("\n"):
+    with open(rust_dir + '/config.example.toml') as example_config:
+        example_lines = example_config.read().split("\n")
+    for line in example_lines:
         if cur_section is None:
             if line.count('=') == 1:
                 top_level_key = line.split('=')[0]
@@ -435,7 +437,7 @@ def parse_example_config(known_args, config):
         targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
 
     if 'profile' not in config:
-        set('profile', 'user', config)
+        set('profile', 'dist', config)
     configure_file(sections, top_level_keys, targets, config)
     return section_order, sections, targets
 
diff --git a/src/bootstrap/defaults/config.user.toml b/src/bootstrap/defaults/config.dist.toml
index 25d9e649f23..25d9e649f23 100644
--- a/src/bootstrap/defaults/config.user.toml
+++ b/src/bootstrap/defaults/config.dist.toml
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 8592895423e..1ac52dffe58 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -222,7 +222,7 @@ impl Step for TheBook {
         let shared_assets = builder.ensure(SharedAssets { target });
 
         // build the redirect pages
-        builder.info(&format!("Documenting book redirect pages ({})", target));
+        builder.msg_doc(compiler, "book redirect pages", target);
         for file in t!(fs::read_dir(builder.src.join(&relative_path).join("redirects"))) {
             let file = t!(file);
             let path = file.path();
@@ -306,7 +306,7 @@ impl Step for Standalone {
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
         let compiler = self.compiler;
-        builder.info(&format!("Documenting standalone ({})", target));
+        builder.msg_doc(compiler, "standalone", target);
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
 
@@ -562,7 +562,7 @@ fn doc_std(
 
     let description =
         format!("library{} in {} format", crate_description(&requested_crates), format.as_str());
-    let _guard = builder.msg(Kind::Doc, stage, &description, compiler.host, target);
+    let _guard = builder.msg_doc(compiler, &description, target);
 
     let target_doc_dir_name = if format == DocumentationFormat::JSON { "json-doc" } else { "doc" };
     let target_dir =
@@ -804,14 +804,7 @@ macro_rules! tool_doc {
                     SourceType::Submodule
                 };
 
-                builder.info(
-                    &format!(
-                        "Documenting stage{} {} ({})",
-                        stage,
-                        stringify!($tool).to_lowercase(),
-                        target,
-                    ),
-                );
+                builder.msg_doc(compiler, stringify!($tool).to_lowercase(), target);
 
                 // Symlink compiler docs to the output directory of rustdoc documentation.
                 let out_dirs = [
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index d389b568f56..c960053d7a0 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1009,6 +1009,15 @@ impl Build {
         self.msg(Kind::Check, self.config.stage, what, self.config.build, target)
     }
 
+    fn msg_doc(
+        &self,
+        compiler: Compiler,
+        what: impl Display,
+        target: impl Into<Option<TargetSelection>> + Copy,
+    ) -> Option<gha::Group> {
+        self.msg(Kind::Doc, compiler.stage, what, compiler.host, target.into())
+    }
+
     fn msg_build(
         &self,
         compiler: Compiler,
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 7eb70de91f8..34c6ccf1365 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -20,7 +20,7 @@ pub enum Profile {
     Codegen,
     Library,
     Tools,
-    User,
+    Dist,
     None,
 }
 
@@ -43,7 +43,7 @@ impl Profile {
     pub fn all() -> impl Iterator<Item = Self> {
         use Profile::*;
         // N.B. these are ordered by how they are displayed, not alphabetically
-        [Library, Compiler, Codegen, Tools, User, None].iter().copied()
+        [Library, Compiler, Codegen, Tools, Dist, None].iter().copied()
     }
 
     pub fn purpose(&self) -> String {
@@ -53,7 +53,7 @@ impl Profile {
             Compiler => "Contribute to the compiler itself",
             Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
             Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)",
-            User => "Install Rust from source",
+            Dist => "Install Rust from source",
             None => "Do not modify `config.toml`"
         }
         .to_string()
@@ -73,7 +73,7 @@ impl Profile {
             Profile::Codegen => "codegen",
             Profile::Library => "library",
             Profile::Tools => "tools",
-            Profile::User => "user",
+            Profile::Dist => "dist",
             Profile::None => "none",
         }
     }
@@ -87,7 +87,7 @@ impl FromStr for Profile {
             "lib" | "library" => Ok(Profile::Library),
             "compiler" => Ok(Profile::Compiler),
             "llvm" | "codegen" => Ok(Profile::Codegen),
-            "maintainer" | "user" => Ok(Profile::User),
+            "maintainer" | "dist" | "user" => Ok(Profile::Dist),
             "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => {
                 Ok(Profile::Tools)
             }
@@ -160,7 +160,7 @@ pub fn setup(config: &Config, profile: Profile) {
             "test src/tools/rustfmt",
         ],
         Profile::Library => &["check", "build", "test library/std", "doc"],
-        Profile::User => &["dist", "build"],
+        Profile::Dist => &["dist", "build"],
     };
 
     println!();
@@ -170,7 +170,7 @@ pub fn setup(config: &Config, profile: Profile) {
         println!("- `x.py {}`", cmd);
     }
 
-    if profile != Profile::User {
+    if profile != Profile::Dist {
         println!(
             "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
         );
@@ -582,7 +582,7 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
             Some(false) => {
                 // exists and is not current version or outdated, so back it up
                 let mut backup = vscode_settings.clone();
-                backup.set_extension("bak");
+                backup.set_extension("json.bak");
                 eprintln!("warning: copying `settings.json` to `settings.json.bak`");
                 fs::copy(&vscode_settings, &backup)?;
                 "Updated"
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 873ed61daf3..ec447a1cd73 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1832,11 +1832,13 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             builder,
         );
 
-        builder.info(&format!(
-            "Check compiletest suite={} mode={} ({} -> {})",
-            suite, mode, &compiler.host, target
-        ));
-        let _time = util::timeit(&builder);
+        let _group = builder.msg(
+            Kind::Test,
+            compiler.stage,
+            &format!("compiletest suite={suite} mode={mode}"),
+            compiler.host,
+            target,
+        );
         crate::render_tests::try_run_tests(builder, &mut cmd, false);
 
         if let Some(compare_mode) = compare_mode {
@@ -2664,7 +2666,12 @@ impl Step for Bootstrap {
     /// Tests the build system itself.
     fn run(self, builder: &Builder<'_>) {
         let mut check_bootstrap = Command::new(&builder.python());
-        check_bootstrap.arg("bootstrap_test.py").current_dir(builder.src.join("src/bootstrap/"));
+        check_bootstrap
+            .args(["-m", "unittest", "bootstrap_test.py"])
+            .env("BUILD_DIR", &builder.out)
+            .env("BUILD_PLATFORM", &builder.build.build.triple)
+            .current_dir(builder.src.join("src/bootstrap/"))
+            .args(builder.config.test_args());
         try_run(builder, &mut check_bootstrap).unwrap();
 
         let host = builder.config.build;
diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
index 5fbce36c39d..b867db6a1b5 100755
--- a/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-various-2/build-wasi-toolchain.sh
@@ -10,7 +10,7 @@ bin="$PWD/clang+llvm-15.0.6-x86_64-linux-gnu-ubuntu-18.04/bin"
 git clone https://github.com/WebAssembly/wasi-libc
 
 cd wasi-libc
-git reset --hard 4362b1885fd369e042a7c0ecd8df3b6cd47fb4e8
+git reset --hard 7018e24d8fe248596819d2e884761676f3542a04
 make -j$(nproc) \
     CC="$bin/clang" \
     NM="$bin/llvm-nm" \
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index a9e42e4a0a0..8907d643182 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -147,13 +147,6 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/verify-channel.sh
         <<: *step
 
-      - name: configure GitHub Actions to kill the build when outdated
-        uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
-        with:
-          github_token: "${{ secrets.github_token }}"
-        if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'
-        <<: *step
-
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         <<: *step
@@ -305,10 +298,14 @@ defaults:
     # shell is PowerShell.)
     shell: bash
 
+concurrency:
+  # For a given workflow, if we push to the same PR, cancel all previous builds on that PR.
+  # If the push is not attached to a PR, we will cancel all builds related to the same commit SHA.
+  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+  cancel-in-progress: true
+
 jobs:
   pr:
-    permissions:
-      actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds
     <<: *base-ci-job
     name: PR - ${{ matrix.name }}
     env:
@@ -331,8 +328,6 @@ jobs:
             <<: *job-linux-16c
 
   auto:
-    permissions:
-      actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds
     <<: *base-ci-job
     name: auto - ${{ matrix.name }}
     env:
@@ -734,8 +729,6 @@ jobs:
             <<: *job-windows-8c
 
   try:
-    permissions:
-      actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds
     <<: *base-ci-job
     name: try - ${{ matrix.name }}
     env:
diff --git a/src/doc/book b/src/doc/book
-Subproject 8fa6b854d515506d825390fe0d817f5ef0c8935
+Subproject 21cf840842bdf768a798869f06373c96c1cc512
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject b5f018fb5930cb733b0a8aaf2eed975d4771e74
+Subproject c369e4b489332f8721fbae630354fa83385d457
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 553d99b02a53b4133a40d5bd2e19958c67487c0
+Subproject 5ca365eac678cb0d41a20b3204546d6ed70c717
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 8ee9528b72b927cff8fd32346db8bbd1198816f
+Subproject 57636d6926762861f34e030d52ca25a71e95e5b
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject f1e637883fafeb83bdd5906ee7f467e4d35b733
+Subproject 17fe3e948498c50e208047a750f17d6a8d89669
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 1e17a90a842..f8af26326a7 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -40,6 +40,7 @@
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
     - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
     - [\*-nto-qnx-\*](platform-support/nto-qnx.md)
+    - [\*-unknown-netbsd\*](platform-support/netbsd.md)
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [\*-unknown-uefi](platform-support/unknown-uefi.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 62f628f8229..6d1729e57b1 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -224,13 +224,14 @@ target | std | host | notes
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ✓ |  | ARM64 HermitCore
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
-`aarch64-unknown-netbsd` | ✓ | ✓ |
+[`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD
 [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
 `aarch64-unknown-redox` | ? |  | ARM64 Redox OS
 `aarch64-uwp-windows-msvc` | ? |  |
 `aarch64-wrs-vxworks` | ? |  |
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
+[`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
 [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers
 [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en).
 `armv4t-none-eabi` | * |  | ARMv4T A32
@@ -238,7 +239,7 @@ target | std | host | notes
 [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE A32
 `armv5te-unknown-linux-uclibceabi` | ? |  | ARMv5TE Linux with uClibc
 `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD
-`armv6-unknown-netbsd-eabihf` | ? |  |
+[`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 `armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
 [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? |  | ARM Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
@@ -246,7 +247,7 @@ target | std | host | notes
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7 Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux with uClibc, hardfloat
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
-`armv7-unknown-netbsd-eabihf` | ✓ | ✓ |
+[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv7 NetBSD w/hard-float
 `armv7-wrs-vxworks-eabihf` | ? |  |
 [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
@@ -262,7 +263,7 @@ target | std | host | notes
 `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | * |  | 32-bit Windows XP support
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
-`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
+[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2
 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
@@ -283,7 +284,7 @@ target | std | host | notes
 `msp430-none-elf` | * |  | 16-bit MSP430 microcontrollers
 `powerpc-unknown-linux-gnuspe` | ✓ |  | PowerPC SPE Linux
 `powerpc-unknown-linux-musl` | ? |  |
-`powerpc-unknown-netbsd` | ✓ | ✓ |
+[`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems
 `powerpc-unknown-openbsd` | ? |  |
 `powerpc-wrs-vxworks-spe` | ? |  |
 `powerpc-wrs-vxworks` | ? |  |
@@ -307,7 +308,7 @@ target | std | host | notes
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
-`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
+[`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
 `thumbv4t-none-eabi` | * |  | ARMv4T T32
 [`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE T32
diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md
index 4bbe35709b0..8f630fa152c 100644
--- a/src/doc/rustc/src/platform-support/esp-idf.md
+++ b/src/doc/rustc/src/platform-support/esp-idf.md
@@ -13,10 +13,12 @@ Targets for the [ESP-IDF](https://github.com/espressif/esp-idf) development fram
 
 The target names follow this format: `$ARCH-esp-espidf`, where `$ARCH` specifies the target processor architecture. The following targets are currently defined:
 
-|          Target name           | Target CPU(s)         | Minimum ESP-IDF version |
-|--------------------------------|-----------------------|-------------------------|
-| `riscv32imc-esp-espidf`        |  [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3)             | `v4.3`                |
-| `riscv32imac-esp-espidf`       |  [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6)             | `v5.1`                |
+| Target name              | Target CPU(s)                                                   | Minimum ESP-IDF version |
+| ------------------------ | --------------------------------------------------------------- | ----------------------- |
+| `riscv32imc-esp-espidf`  | [ESP32-C2](https://www.espressif.com/en/products/socs/esp32-c2) | `v5.0`                  |
+| `riscv32imc-esp-espidf`  | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | `v4.3`                  |
+| `riscv32imac-esp-espidf` | [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6) | `v5.1`                  |
+| `riscv32imac-esp-espidf` | [ESP32-H2](https://www.espressif.com/en/products/socs/esp32-h2) | `v5.1`                  |
 
 It is recommended to use the latest ESP-IDF stable release if possible.
 
diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md
index 999e71f8028..17e85590f2c 100644
--- a/src/doc/rustc/src/platform-support/loongarch-linux.md
+++ b/src/doc/rustc/src/platform-support/loongarch-linux.md
@@ -28,9 +28,9 @@ While the integer base ABI is implied by the machine field, the floating po
 
 ## Target maintainers
 
-- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn`
 - [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn`
 - [ZHAI Xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn`
+- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn`
 - [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name`
 
 ## Requirements
diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md
new file mode 100644
index 00000000000..a1969524a20
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/netbsd.md
@@ -0,0 +1,107 @@
+# \*-unknown-netbsd
+
+**Tier: 3**
+
+[NetBSD] multi-platform 4.4BSD-based UNIX-like operating system.
+
+[NetBSD]: https://www.NetBSD.org/
+
+The target names follow this format: `$ARCH-unknown-netbsd{-$SUFFIX}`,
+where `$ARCH` specifies the target processor architecture and
+`-$SUFFIX` (optional) might indicate the ABI. The following targets
+are currently defined running NetBSD:
+
+|          Target name           | NetBSD Platform |
+|--------------------------------|-----------------|
+| `amd64-unknown-netbsd`         | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) |
+| `armv7-unknown-netbsd-eabihf`  | [32-bit ARMv7 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
+| `armv6-unknown-netbsd-eabihf`  | [32-bit ARMv6 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) |
+| `aarch64-unknown-netbsd`       | [64-bit ARM systems, little-endian](https://wiki.netbsd.org/ports/evbarm/) |
+| `aarch64_be-unknown-netbsd`    | [64-bit ARM systems, big-endian](https://wiki.netbsd.org/ports/evbarm/) |
+| `i586-unknown-netbsd`          | [32-bit i386, restricted to Pentium](https://wiki.netbsd.org/ports/i386/) |
+| `i686-unknown-netbsd`          | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) |
+| `mipsel-unknown-netbsd`        | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) |
+| `powerpc-unknown-netbsd`       | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) |
+| `sparc64-unknown-netbsd`       | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) |
+
+All use the "native" `stdc++` library which goes along with the natively
+supplied GNU C++ compiler for the given OS version.  Many of the bootstraps
+are built for NetBSD 9.x, although some exceptions exist (some
+are built for NetBSD 8.x but also work on newer OS versions).
+
+
+## Designated Developers
+
+- [@he32](https://github.com/he32), `he@NetBSD.org`
+- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust
+- [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc.
+- [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself
+
+Fallback to pkgsrc-users@NetBSD.org, or fault reporting via NetBSD's
+bug reporting system.
+
+## Requirements
+
+The `amd64-unknown-netbsd` artifacts is being distributed by the
+rust project.
+
+The other targets are built by the designated developers (see above),
+and the targets are initially cross-compiled, but many if not most
+of them are also built natively as part of testing.
+
+
+## Building
+
+The default build mode for the packages is a native build.
+
+
+## Cross-compilation
+
+These targets can be cross-compiled, and we do that via the pkgsrc
+package(s).
+
+Cross-compilation typically requires the "tools" and "dest" trees
+resulting from a normal cross-build of NetBSD itself, ref. our main
+build script, `build.sh`.
+
+See e.g. [do-cross.mk
+Makefile](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust/do-cross.mk)
+for the Makefile used to cross-build all the above NetBSD targets
+(except for the `amd64` target).
+
+The major option for the rust build is whether to build rust with
+the LLVM rust carries in its distribution, or use the LLVM package
+installed from pkgsrc.  The `PKG_OPTIONS.rust` option is
+`rust-internal-llvm`, ref.  [the rust package's options.mk make
+fragment](https://github.com/NetBSD/pkgsrc/blob/trunk/lang/rust/options.mk).
+It defaults to being set for a few of the above platforms, for
+various reasons (see comments), but is otherwise unset and therefore
+indicates use of the pkgsrc LLVM.
+
+
+## Testing
+
+The Rust testsuite could presumably be run natively.
+
+For the systems where the maintainer can build natively, the rust
+compiler itself is re-built natively.  This involves the rust compiler
+being re-built with the newly self-built rust compiler, so excercises
+the result quite extensively.
+
+Additionally, for some systems we build `librsvg`, and for the more
+capable systems we build and test `firefox` (amd64, i386, aarch64).
+
+
+## Building Rust programs
+
+Rust ships pre-compiled artifacts for the `amd64-unknown-netbsd`
+target.
+
+For the other systems mentioned above, using the `pkgsrc` route is
+probably the easiest, possibly via the `rust-bin` package to save
+time, see the `RUST_TYPE` variable from the `rust.mk` Makefile
+fragment.
+
+The pkgsrc rust package has a few files to assist with building
+pkgsrc packages written in rust, ref. the `rust.mk` and `cargo.mk`
+Makefile fragments in the `lang/rust` package.
diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md
index 62a5a032f07..9bc521e1c7b 100644
--- a/src/doc/style-guide/src/statements.md
+++ b/src/doc/style-guide/src/statements.md
@@ -103,22 +103,69 @@ let Foo {
 
 #### else blocks (let-else statements)
 
-If a let statement contains an `else` component, also known as a let-else statement,
-then the `else` component should be formatted according to the same rules as the `else` block
-in [control flow expressions (i.e. if-else, and if-let-else expressions)](./expressions.md#control-flow-expressions).
-Apply the same formatting rules to the components preceding
-the `else` block (i.e. the `let pattern: Type = initializer_expr ...` portion)
-as described [above](#let-statements)
-
-Similarly to if-else expressions, if the initializer
-expression is multi-lined, then the `else` keyword and opening brace of the block (i.e. `else {`)
-should be put on the same line as the end of the initializer
-expression with a preceding space if all the following are true:
+A let statement can contain an `else` component, making it a let-else statement.
+In this case, always apply the same formatting rules to the components preceding
+the `else` block (i.e. the `let pattern: Type = initializer_expr` portion)
+as described [for other let statements](#let-statements).
+
+The entire let-else statement may be formatted on a single line if all the
+following are true:
+
+* the entire statement is *short*
+* the `else` block contains only a single-line expression and no statements
+* the `else` block contains no comments
+* the let statement components preceding the `else` block can be formatted on a single line
+
+```rust
+let Some(1) = opt else { return };
+```
+
+Formatters may allow users to configure the value of the threshold
+used to determine whether a let-else statement is *short*.
+
+Otherwise, the let-else statement requires some line breaks.
+
+If breaking a let-else statement across multiple lines, never break between the
+`else` and the `{`, and always break before the `}`.
+
+If the let statement components preceding the `else` can be formatted on a
+single line, but the let-else does not qualify to be placed entirely on a
+single line, put the `else {` on the same line as the initializer expression,
+with a space between them, then break the line after the `{`. Indent the
+closing `}` to match the `let`, and indent the contained block one step
+further.
+
+```rust
+let Some(1) = opt else {
+    return;
+};
+
+let Some(1) = opt else {
+    // nope
+    return
+};
+```
+
+If the let statement components preceding the `else` can be formatted on a
+single line, but the `else {` does not fit on the same line, break the line
+before the `else`.
+
+```rust
+    let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name
+    else {
+        return;
+    };
+```
+
+If the initializer expression is multi-line, the `else` keyword and opening
+brace of the block (i.e. `else {`) should be put on the same line as the end of
+the initializer expression, with a space between them, if all the following are
+true:
 
 * The initializer expression ends with one or more closing
   parentheses, square brackets, and/or braces
 * There is nothing else on that line
-* That line is not indented beyond the indent of the first line containing the `let` keyword
+* That line has the same indentation level as the initial `let` keyword.
 
 For example:
 
@@ -135,7 +182,9 @@ let Some(x) = y.foo(
 }
 ```
 
-Otherwise, the `else` keyword and opening brace should be placed on the next line after the end of the initializer expression, and should not be indented (the `else` keyword should be aligned with the `let` keyword).
+Otherwise, the `else` keyword and opening brace should be placed on the next
+line after the end of the initializer expression, and the `else` keyword should
+have the same indentation level as the `let` keyword.
 
 For example:
 
@@ -155,11 +204,6 @@ fn main() {
         return
     };
 
-    let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name
-    else {
-        return;
-    };
-
     let Some(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =
         bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
     else {
@@ -168,31 +212,6 @@ fn main() {
 }
 ```
 
-##### Single line let-else statements
-
-The entire let-else statement may be formatted on a single line if all the following are true:
-
-* the entire statement is *short*
-* the `else` block contains a single-line expression and no statements
-* the `else` block contains no comments
-* the let statement components preceding the `else` block can be formatted on a single line
-
-```rust
-let Some(1) = opt else { return };
-
-let Some(1) = opt else {
-    return;
-};
-
-let Some(1) = opt else {
-    // nope
-    return
-};
-```
-
-Formatters may allow users to configure the value of the threshold
-used to determine whether a let-else statement is *short*.
-
 ### Macros in statement position
 
 A macro use in statement position should use parentheses or square brackets as
diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py
index cf7279534dc..cc5e31a051f 100755
--- a/src/etc/test-float-parse/runtests.py
+++ b/src/etc/test-float-parse/runtests.py
@@ -127,7 +127,7 @@ def write_errors():
         if not have_seen_error:
             have_seen_error = True
             msg("Something is broken:", *args)
-            msg("Future errors logged to errors.txt")
+            msg("Future errors will be logged to errors.txt")
             exit_status = 101
 
 
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 492b0b79557..92bae551644 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -317,14 +317,14 @@ where
         lifetime_predicates
     }
 
-    fn extract_for_generics(&self, pred: ty::Predicate<'tcx>) -> FxHashSet<GenericParamDef> {
+    fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet<GenericParamDef> {
         let bound_predicate = pred.kind();
         let tcx = self.cx.tcx;
         let regions = match bound_predicate.skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_pred)) => {
+            ty::ClauseKind::Trait(poly_trait_pred) => {
                 tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred))
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(poly_proj_pred)) => {
+            ty::ClauseKind::Projection(poly_proj_pred) => {
                 tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred))
             }
             _ => return FxHashSet::default(),
@@ -449,9 +449,7 @@ where
             .filter(|p| {
                 !orig_bounds.contains(p)
                     || match p.kind().skip_binder() {
-                        ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-                            pred.def_id() == sized_trait
-                        }
+                        ty::ClauseKind::Trait(pred) => pred.def_id() == sized_trait,
                         _ => false,
                     }
             })
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f86c32158e0..b2f9c0bccea 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -326,36 +326,24 @@ fn clean_where_predicate<'tcx>(
 }
 
 pub(crate) fn clean_predicate<'tcx>(
-    predicate: ty::Predicate<'tcx>,
+    predicate: ty::Clause<'tcx>,
     cx: &mut DocContext<'tcx>,
 ) -> Option<WherePredicate> {
     let bound_predicate = predicate.kind();
     match bound_predicate.skip_binder() {
-        ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
-            clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
-        }
-        ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(pred)) => {
-            clean_region_outlives_predicate(pred)
-        }
-        ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(pred)) => {
+        ty::ClauseKind::Trait(pred) => clean_poly_trait_predicate(bound_predicate.rebind(pred), cx),
+        ty::ClauseKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
+        ty::ClauseKind::TypeOutlives(pred) => {
             clean_type_outlives_predicate(bound_predicate.rebind(pred), cx)
         }
-        ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
+        ty::ClauseKind::Projection(pred) => {
             Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
         }
         // FIXME(generic_const_exprs): should this do something?
-        ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => None,
-        ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) => None,
-        ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) => None,
-
-        ty::PredicateKind::Subtype(..)
-        | ty::PredicateKind::AliasRelate(..)
-        | ty::PredicateKind::Coerce(..)
-        | ty::PredicateKind::ObjectSafe(..)
-        | ty::PredicateKind::ClosureKind(..)
-        | ty::PredicateKind::ConstEquate(..)
-        | ty::PredicateKind::Ambiguous
-        | ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
+        ty::ClauseKind::ConstEvaluatable(..)
+        | ty::ClauseKind::WellFormed(..)
+        | ty::ClauseKind::ConstArgHasType(..)
+        | ty::ClauseKind::TypeWellFormedFromEnv(..) => None,
     }
 }
 
@@ -791,10 +779,10 @@ fn clean_ty_generics<'tcx>(
         })
         .collect::<ThinVec<GenericParamDef>>();
 
-    // param index -> [(trait DefId, associated type name & generics, type, higher-ranked params)]
+    // param index -> [(trait DefId, associated type name & generics, term, higher-ranked params)]
     let mut impl_trait_proj = FxHashMap::<
         u32,
-        Vec<(DefId, PathSegment, ty::Binder<'_, Ty<'_>>, Vec<GenericParamDef>)>,
+        Vec<(DefId, PathSegment, ty::Binder<'_, ty::Term<'_>>, Vec<GenericParamDef>)>,
     >::default();
 
     let where_predicates = preds
@@ -805,19 +793,17 @@ fn clean_ty_generics<'tcx>(
             let param_idx = (|| {
                 let bound_p = p.kind();
                 match bound_p.skip_binder() {
-                    ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
+                    ty::ClauseKind::Trait(pred) => {
                         if let ty::Param(param) = pred.self_ty().kind() {
                             return Some(param.index);
                         }
                     }
-                    ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(
-                        ty::OutlivesPredicate(ty, _reg),
-                    )) => {
+                    ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
                         if let ty::Param(param) = ty.kind() {
                             return Some(param.index);
                         }
                     }
-                    ty::PredicateKind::Clause(ty::ClauseKind::Projection(p)) => {
+                    ty::ClauseKind::Projection(p) => {
                         if let ty::Param(param) = p.projection_ty.self_ty().kind() {
                             projection = Some(bound_p.rebind(p));
                             return Some(param.index);
@@ -852,11 +838,10 @@ fn clean_ty_generics<'tcx>(
                     .as_ref()
                     .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
                 {
-                    // FIXME(...): Remove this unwrap()
                     impl_trait_proj.entry(param_idx).or_default().push((
                         trait_did,
                         name,
-                        rhs.map_bound(|rhs| rhs.ty().unwrap()),
+                        *rhs,
                         p.get_bound_params()
                             .into_iter()
                             .flatten()
@@ -879,15 +864,8 @@ fn clean_ty_generics<'tcx>(
         let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() };
         if let Some(proj) = impl_trait_proj.remove(&idx) {
             for (trait_did, name, rhs, bound_params) in proj {
-                let rhs = clean_middle_ty(rhs, cx, None, None);
-                simplify::merge_bounds(
-                    cx,
-                    &mut bounds,
-                    bound_params,
-                    trait_did,
-                    name,
-                    &Term::Type(rhs),
-                );
+                let rhs = clean_middle_term(rhs, cx);
+                simplify::merge_bounds(cx, &mut bounds, bound_params, trait_did, name, &rhs);
             }
         }
 
@@ -1360,21 +1338,51 @@ 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)
-                    .subst_identity_iter_copied()
-                    .map(|(c, s)| (c.as_predicate(), s));
-                let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
-                let predicates =
-                    tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
-                let mut generics = clean_ty_generics(
-                    cx,
-                    tcx.generics_of(assoc_item.def_id),
-                    ty::GenericPredicates { parent: None, predicates },
-                );
-                // Filter out the bounds that are (likely?) directly attached to the associated type,
-                // as opposed to being located in the where clause.
+                let bounds =
+                    tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied();
+                predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
+            }
+            let mut generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(assoc_item.def_id),
+                ty::GenericPredicates { parent: None, predicates },
+            );
+            // Move bounds that are (likely) directly attached to the parameters of the
+            // (generic) associated type from the where clause to the respective parameter.
+            // There is no guarantee that this is what the user actually wrote but we have
+            // no way of knowing.
+            let mut where_predicates = ThinVec::new();
+            for mut pred in generics.where_predicates {
+                if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
+                {
+                    param_bounds.append(bounds);
+                } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
+                    && let Some(GenericParamDef {
+                        kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
+                        ..
+                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
+                {
+                    param_bounds.extend(bounds.drain(..).map(|bound| match bound {
+                        GenericBound::Outlives(lifetime) => lifetime,
+                        _ => unreachable!(),
+                    }));
+                } else {
+                    where_predicates.push(pred);
+                }
+            }
+            generics.where_predicates = where_predicates;
+
+            if let ty::TraitContainer = assoc_item.container {
+                // Move bounds that are (likely) directly attached to the associated type
+                // from the where-clause to the associated type.
+                // There is no guarantee that this is what the user actually wrote but we have
+                // no way of knowing.
                 let mut bounds: Vec<GenericBound> = Vec::new();
                 generics.where_predicates.retain_mut(|pred| match *pred {
                     WherePredicate::BoundPredicate {
@@ -1431,33 +1439,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     }
                     None => bounds.push(GenericBound::maybe_sized(cx)),
                 }
-                // Move bounds that are (likely) directly attached to the parameters of the
-                // (generic) associated type from the where clause to the respective parameter.
-                // There is no guarantee that this is what the user actually wrote but we have
-                // no way of knowing.
-                let mut where_predicates = ThinVec::new();
-                for mut pred in generics.where_predicates {
-                    if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
-                    && let Some(GenericParamDef {
-                        kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
-                        ..
-                    }) = generics.params.iter_mut().find(|param| &param.name == arg)
-                    {
-                        param_bounds.append(bounds);
-                    } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
-                    && let Some(GenericParamDef {
-                        kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
-                        ..
-                    }) = generics.params.iter_mut().find(|param| &param.name == arg) {
-                        param_bounds.extend(bounds.drain(..).map(|bound| match bound {
-                            GenericBound::Outlives(lifetime) => lifetime,
-                            _ => unreachable!(),
-                        }));
-                    } else {
-                        where_predicates.push(pred);
-                    }
-                }
-                generics.where_predicates = where_predicates;
 
                 if tcx.defaultness(assoc_item.def_id).has_value() {
                     AssocTypeItem(
@@ -1469,7 +1450,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                                 None,
                             ),
                             generics,
-                            // FIXME: should we obtain the Type from HIR and pass it on here?
                             item_type: None,
                         }),
                         bounds,
@@ -1478,7 +1458,6 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                     TyAssocTypeItem(generics, bounds)
                 }
             } else {
-                // FIXME: when could this happen? Associated items in inherent impls?
                 AssocTypeItem(
                     Box::new(Typedef {
                         type_: clean_middle_ty(
@@ -1487,12 +1466,11 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
                             Some(assoc_item.def_id),
                             None,
                         ),
-                        generics: Generics {
-                            params: ThinVec::new(),
-                            where_predicates: ThinVec::new(),
-                        },
+                        generics,
                         item_type: None,
                     }),
+                    // Associated types inside trait or inherent impls are not allowed to have
+                    // item bounds. Thus we don't attempt to move any bounds there.
                     Vec::new(),
                 )
             }
@@ -2377,7 +2355,7 @@ fn filter_tokens_from_list(
     tokens
 }
 
-/// When inlining items, we merge its attributes (and all the reexports attributes too) with the
+/// When inlining items, we merge their attributes (and all the reexports attributes too) with the
 /// final reexport. For example:
 ///
 /// ```ignore (just an example)
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index a8221cc9449..65b1b72adc1 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -128,9 +128,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
         .predicates
         .iter()
         .filter_map(|(pred, _)| {
-            if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
-                pred.kind().skip_binder()
-            {
+            if let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() {
                 if pred.trait_ref.self_ty() == self_ty { Some(pred.def_id()) } else { None }
             } else {
                 None
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 5f5cade67a2..26139d52769 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -956,6 +956,8 @@ pub(crate) trait AttributesExt {
                     .filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
                     .fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
             } else if doc_auto_cfg_active {
+                // If there is no `doc(cfg())`, then we retrieve the `cfg()` attributes (because
+                // `doc(cfg())` overrides `cfg()`).
                 self.iter()
                     .filter(|attr| attr.has_name(sym::cfg))
                     .filter_map(|attr| single(attr.meta_item_list()?))
@@ -2387,6 +2389,7 @@ impl ImplKind {
 #[derive(Clone, Debug)]
 pub(crate) struct Import {
     pub(crate) kind: ImportKind,
+    /// The item being re-exported.
     pub(crate) source: ImportSource,
     pub(crate) should_be_displayed: bool,
 }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 9f08609a6d1..217f1a6ee6b 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -15,6 +15,7 @@ use rustc_session::config::{
 use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
+use rustc_session::EarlyErrorHandler;
 use rustc_span::edition::Edition;
 use rustc_target::spec::TargetTriple;
 
@@ -311,32 +312,33 @@ impl Options {
     /// Parses the given command-line for options. If an error message or other early-return has
     /// been printed, returns `Err` with the exit code.
     pub(crate) fn from_matches(
+        handler: &mut EarlyErrorHandler,
         matches: &getopts::Matches,
         args: Vec<String>,
     ) -> Result<(Options, RenderOptions), i32> {
         // Check for unstable options.
-        nightly_options::check_nightly_options(matches, &opts());
+        nightly_options::check_nightly_options(handler, matches, &opts());
 
         if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") {
             crate::usage("rustdoc");
             return Err(0);
         } else if matches.opt_present("version") {
-            rustc_driver::version!("rustdoc", matches);
+            rustc_driver::version!(&handler, "rustdoc", matches);
             return Err(0);
         }
 
-        if rustc_driver::describe_flag_categories(&matches) {
+        if rustc_driver::describe_flag_categories(handler, &matches) {
             return Err(0);
         }
 
-        let color = config::parse_color(matches);
+        let color = config::parse_color(handler, matches);
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
-            config::parse_json(matches);
-        let error_format = config::parse_error_format(matches, color, json_rendered);
+            config::parse_json(handler, matches);
+        let error_format = config::parse_error_format(handler, matches, color, json_rendered);
         let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
-        let codegen_options = CodegenOptions::build(matches, error_format);
-        let unstable_opts = UnstableOptions::build(matches, error_format);
+        let codegen_options = CodegenOptions::build(handler, matches);
+        let unstable_opts = UnstableOptions::build(handler, matches);
 
         let diag = new_handler(error_format, None, diagnostic_width, &unstable_opts);
 
@@ -393,8 +395,7 @@ impl Options {
             && !matches.opt_present("show-coverage")
             && !nightly_options::is_unstable_enabled(matches)
         {
-            rustc_session::early_error(
-                error_format,
+            handler.early_error(
                 "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)",
             );
         }
@@ -432,7 +433,7 @@ impl Options {
             return Err(0);
         }
 
-        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
 
         let input = PathBuf::from(if describe_lints {
             "" // dummy, this won't be used
@@ -446,12 +447,9 @@ impl Options {
             &matches.free[0]
         });
 
-        let libs = matches
-            .opt_strs("L")
-            .iter()
-            .map(|s| SearchPath::from_cli_opt(s, error_format))
-            .collect();
-        let externs = parse_externs(matches, &unstable_opts, error_format);
+        let libs =
+            matches.opt_strs("L").iter().map(|s| SearchPath::from_cli_opt(handler, s)).collect();
+        let externs = parse_externs(handler, matches, &unstable_opts);
         let extern_html_root_urls = match parse_extern_html_roots(matches) {
             Ok(ex) => ex,
             Err(err) => {
@@ -589,7 +587,7 @@ impl Options {
             }
         }
 
-        let edition = config::parse_crate_edition(matches);
+        let edition = config::parse_crate_edition(handler, matches);
 
         let mut id_map = html::markdown::IdMap::new();
         let Some(external_html) = ExternalHtml::load(
@@ -623,7 +621,7 @@ impl Options {
             }
         }
 
-        let target = parse_target_triple(matches, error_format);
+        let target = parse_target_triple(handler, matches);
 
         let show_coverage = matches.opt_present("show-coverage");
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index e10a6297775..9687b8b1887 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -13,8 +13,8 @@ use rustc_interface::interface;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_session::config::{self, CrateType, ErrorOutputType, ResolveDocLinks};
-use rustc_session::lint;
 use rustc_session::Session;
+use rustc_session::{lint, EarlyErrorHandler};
 use rustc_span::symbol::sym;
 use rustc_span::{source_map, Span};
 
@@ -181,6 +181,7 @@ pub(crate) fn new_handler(
 
 /// Parse, resolve, and typecheck the given crate.
 pub(crate) fn create_config(
+    handler: &EarlyErrorHandler,
     RustdocOptions {
         input,
         crate_name,
@@ -258,8 +259,8 @@ pub(crate) fn create_config(
 
     interface::Config {
         opts: sessopts,
-        crate_cfg: interface::parse_cfgspecs(cfgs),
-        crate_check_cfg: interface::parse_check_cfg(check_cfgs),
+        crate_cfg: interface::parse_cfgspecs(handler, cfgs),
+        crate_check_cfg: interface::parse_check_cfg(handler, check_cfgs),
         input,
         output_file: None,
         output_dir: None,
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index f6631b66f5b..217257316c8 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -12,7 +12,7 @@ use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::attr::InnerAttrPolicy;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::parse::ParseSess;
-use rustc_session::{lint, Session};
+use rustc_session::{lint, EarlyErrorHandler, Session};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
@@ -85,13 +85,18 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
         ..config::Options::default()
     };
 
+    let early_error_handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     let mut cfgs = options.cfgs.clone();
     cfgs.push("doc".to_owned());
     cfgs.push("doctest".to_owned());
     let config = interface::Config {
         opts: sessopts,
-        crate_cfg: interface::parse_cfgspecs(cfgs),
-        crate_check_cfg: interface::parse_check_cfg(options.check_cfgs.clone()),
+        crate_cfg: interface::parse_cfgspecs(&early_error_handler, cfgs),
+        crate_check_cfg: interface::parse_check_cfg(
+            &early_error_handler,
+            options.check_cfgs.clone(),
+        ),
         input,
         output_file: None,
         output_dir: None,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index b710311c858..b4aba2993c7 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1408,7 +1408,7 @@ impl clean::FnDecl {
         let amp = if f.alternate() { "&" } else { "&amp;" };
 
         write!(f, "(")?;
-        if let Some(n) = line_wrapping_indent {
+        if let Some(n) = line_wrapping_indent && !self.inputs.values.is_empty() {
             write!(f, "\n{}", Indent(n + 4))?;
         }
         for (i, input) in self.inputs.values.iter().enumerate() {
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 21c1eb631e0..b6d90091bba 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -891,8 +891,10 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	color: var(--search-results-grey-color);
 }
 .search-results .result-name .typename {
+	display: inline-block;
 	color: var(--search-results-grey-color);
 	font-size: 0.875rem;
+	width: 6.25rem;
 }
 
 .popover {
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 452348dc865..b8cc0a6db71 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -52,9 +52,9 @@ const longItemTypes = [
     "enum variant",
     "macro",
     "primitive type",
-    "associated type",
+    "assoc type",
     "constant",
-    "associated constant",
+    "assoc const",
     "union",
     "foreign type",
     "keyword",
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index a8cd0ec453e..f28deae791a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -79,8 +79,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_interface::interface;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
-use rustc_session::getopts;
-use rustc_session::{early_error, early_warn};
+use rustc_session::{getopts, EarlyErrorHandler};
 
 use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
 
@@ -155,6 +154,8 @@ pub fn main() {
         }
     }
 
+    let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     rustc_driver::install_ice_hook(
         "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md",
@@ -170,11 +171,12 @@ pub fn main() {
     // NOTE: The reason this doesn't show double logging when `download-rustc = false` and
     // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
     // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
-    init_logging();
-    rustc_driver::init_env_logger("RUSTDOC_LOG");
 
-    let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() {
-        Some(args) => main_args(&args),
+    init_logging(&handler);
+    rustc_driver::init_env_logger(&handler, "RUSTDOC_LOG");
+
+    let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&handler) {
+        Some(args) => main_args(&mut handler, &args),
         _ =>
         {
             #[allow(deprecated)]
@@ -184,22 +186,19 @@ pub fn main() {
     process::exit(exit_code);
 }
 
-fn init_logging() {
+fn init_logging(handler: &EarlyErrorHandler) {
     let color_logs = match std::env::var("RUSTDOC_LOG_COLOR").as_deref() {
         Ok("always") => true,
         Ok("never") => false,
         Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
-        Ok(value) => early_error(
-            ErrorOutputType::default(),
-            format!("invalid log color value '{}': expected one of always, never, or auto", value),
-        ),
-        Err(VarError::NotUnicode(value)) => early_error(
-            ErrorOutputType::default(),
-            format!(
-                "invalid log color value '{}': expected one of always, never, or auto",
-                value.to_string_lossy()
-            ),
-        ),
+        Ok(value) => handler.early_error(format!(
+            "invalid log color value '{}': expected one of always, never, or auto",
+            value
+        )),
+        Err(VarError::NotUnicode(value)) => handler.early_error(format!(
+            "invalid log color value '{}': expected one of always, never, or auto",
+            value.to_string_lossy()
+        )),
     };
     let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG");
     let layer = tracing_tree::HierarchicalLayer::default()
@@ -219,16 +218,13 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).unwrap();
 }
 
-fn get_args() -> Option<Vec<String>> {
+fn get_args(handler: &EarlyErrorHandler) -> Option<Vec<String>> {
     env::args_os()
         .enumerate()
         .map(|(i, arg)| {
             arg.into_string()
                 .map_err(|arg| {
-                    early_warn(
-                        ErrorOutputType::default(),
-                        format!("Argument {} is not valid Unicode: {:?}", i, arg),
-                    );
+                    handler.early_warn(format!("Argument {} is not valid Unicode: {:?}", i, arg));
                 })
                 .ok()
         })
@@ -710,7 +706,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     }
 }
 
-fn main_args(at_args: &[String]) -> MainResult {
+fn main_args(handler: &mut EarlyErrorHandler, at_args: &[String]) -> MainResult {
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
     // passing empty argument array to execve under some platforms,
@@ -721,7 +717,7 @@ fn main_args(at_args: &[String]) -> MainResult {
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = rustc_driver::args::arg_expand_all(at_args);
+    let args = rustc_driver::args::arg_expand_all(handler, at_args);
 
     let mut options = getopts::Options::new();
     for option in opts() {
@@ -730,13 +726,13 @@ fn main_args(at_args: &[String]) -> MainResult {
     let matches = match options.parse(&args) {
         Ok(m) => m,
         Err(err) => {
-            early_error(ErrorOutputType::default(), err.to_string());
+            handler.early_error(err.to_string());
         }
     };
 
     // Note that we discard any distinction between different non-zero exit
     // codes from `from_matches` here.
-    let (options, render_options) = match config::Options::from_matches(&matches, args) {
+    let (options, render_options) = match config::Options::from_matches(handler, &matches, args) {
         Ok(opts) => opts,
         Err(code) => {
             return if code == 0 {
@@ -764,7 +760,7 @@ fn main_args(at_args: &[String]) -> MainResult {
         (false, true) => {
             let input = options.input.clone();
             let edition = options.edition;
-            let config = core::create_config(options, &render_options);
+            let config = core::create_config(handler, options, &render_options);
 
             // `markdown::render` can invoke `doctest::make_test`, which
             // requires session globals and a thread pool, so we use
@@ -797,7 +793,7 @@ fn main_args(at_args: &[String]) -> MainResult {
     let scrape_examples_options = options.scrape_examples_options.clone();
     let bin_crate = options.bin_crate;
 
-    let config = core::create_config(options, &render_options);
+    let config = core::create_config(handler, options, &render_options);
 
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index ee6aef71980..1ecaa1a123c 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -27,7 +27,7 @@ use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
     self, Binder, BoundVariableKind, ClauseKind, EarlyBinder, FnSig, GenericArgKind, List, ParamEnv, ParamTy,
-    PredicateKind, ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
+    ProjectionPredicate, Ty, TyCtxt, TypeVisitableExt, TypeckResults,
 };
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span, Symbol};
@@ -1133,7 +1133,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
     let projection_predicates = predicates
         .iter()
         .filter_map(|predicate| {
-            if let PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) = predicate.kind().skip_binder() {
+            if let ClauseKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
                 Some(projection_predicate)
             } else {
                 None
@@ -1147,7 +1147,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
     if predicates
         .iter()
         .filter_map(|predicate| {
-            if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder()
+            if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
                 && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
             {
                 Some(trait_predicate.trait_ref.def_id)
@@ -1209,7 +1209,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
         }
 
         predicates.iter().all(|predicate| {
-            if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) = predicate.kind().skip_binder()
+            if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
                 && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
                 && let ty::Param(param_ty) = trait_predicate.self_ty().kind()
                 && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack()
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 8d84e756ff8..10a2f0cb1e7 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, Binder, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind,
-    TraitPredicate, Ty, TyCtxt,
+    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
+    ToPredicate, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
@@ -503,7 +503,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
 
     let ty_predicates = tcx.predicates_of(did).predicates;
     for (p, _) in ty_predicates {
-        if let PredicateKind::Clause(ClauseKind::Trait(p)) = p.kind().skip_binder()
+        if let ClauseKind::Trait(p) = p.kind().skip_binder()
             && p.trait_ref.def_id == eq_trait_id
             && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
             && p.constness == BoundConstness::NotConst
@@ -514,13 +514,13 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
     }
 
     ParamEnv::new(
-        tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
+        tcx.mk_clauses_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain(
             params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| {
-                tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
+                ClauseKind::Trait(TraitPredicate {
                     trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
-                }))))
+                }).to_predicate(tcx)
             }),
         )),
         Reveal::UserFacing,
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 5f1fdf00be8..10b5e1edf92 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -206,6 +206,12 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
                 NeverLoopResult::AlwaysBreak,
             )
         }),
+        ExprKind::Become(e) => {
+            combine_seq(
+                never_loop_expr(e, ignore_ids, main_loop_id),
+                NeverLoopResult::AlwaysBreak,
+            )
+        }
         ExprKind::InlineAsm(asm) => asm
             .operands
             .iter()
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 7945275393c..93ef07d36ae 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -329,6 +329,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
             ExprKind::Field(..) |
             ExprKind::Index(..) |
             ExprKind::Ret(..) |
+            ExprKind::Become(..) |
             ExprKind::Repeat(..) |
             ExprKind::Yield(..) => walk_expr(self, ex),
             ExprKind::AddrOf(_, _, _) |
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index cf85d3174db..0699997d0d2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -16,7 +16,7 @@ use rustc_hir::{
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty};
+use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol};
 
@@ -175,7 +175,7 @@ fn check_collect_into_intoiterator<'tcx>(
                 .caller_bounds()
                 .into_iter()
                 .filter_map(|p| {
-                    if let PredicateKind::Clause(ClauseKind::Trait(t)) = p.kind().skip_binder()
+                    if let ClauseKind::Trait(t) = p.kind().skip_binder()
                             && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) {
                                 Some(t.self_ty())
                             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 06fa95cd657..80eb00a1b42 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -14,7 +14,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
+use rustc_middle::ty::{self, ClauseKind, EarlyBinder, ParamTy, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_span::{sym, Symbol};
 use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
 
@@ -345,12 +345,12 @@ fn get_input_traits_and_projections<'tcx>(
     let mut projection_predicates = Vec::new();
     for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() {
         match predicate.kind().skip_binder() {
-            PredicateKind::Clause(ClauseKind::Trait(trait_predicate)) => {
+            ClauseKind::Trait(trait_predicate) => {
                 if trait_predicate.trait_ref.self_ty() == input {
                     trait_predicates.push(trait_predicate);
                 }
             },
-            PredicateKind::Clause(ClauseKind::Projection(projection_predicate)) => {
+            ClauseKind::Projection(projection_predicate) => {
                 if projection_predicate.projection_ty.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
@@ -407,7 +407,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
 
                         let mut trait_predicates = cx.tcx.param_env(callee_def_id)
                             .caller_bounds().iter().filter(|predicate| {
-                            if let PredicateKind::Clause(ClauseKind::Trait(trait_predicate))
+                            if let ClauseKind::Trait(trait_predicate)
                                     = predicate.kind().skip_binder()
                                 && trait_predicate.trait_ref.self_ty() == *param_ty
                             {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 3773975e955..c0970048cdf 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
             .filter_map(|pred| {
                 // Note that we do not want to deal with qualified predicates here.
                 match pred.kind().no_bound_vars() {
-                    Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) if pred.def_id() != sized_trait => {
+                    Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => {
                         Some(pred)
                     },
                     _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index a375e5d5b4c..99a1d197678 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -4,7 +4,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{Closure, Expr, ExprKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_middle::ty::{ClauseKind, GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
+use rustc_middle::ty::{ClauseKind, GenericPredicates, ProjectionPredicate, TraitPredicate};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, BytePos, Span};
 
@@ -45,7 +45,7 @@ fn get_trait_predicates_for_trait_id<'tcx>(
     let mut preds = Vec::new();
     for (pred, _) in generics.predicates {
         if_chain! {
-            if let PredicateKind::Clause(ClauseKind::Trait(poly_trait_pred)) = pred.kind().skip_binder();
+            if let ClauseKind::Trait(poly_trait_pred) = pred.kind().skip_binder();
             let trait_pred = cx.tcx.erase_late_bound_regions(pred.kind().rebind(poly_trait_pred));
             if let Some(trait_def_id) = trait_id;
             if trait_def_id == trait_pred.trait_ref.def_id;
@@ -63,7 +63,7 @@ fn get_projection_pred<'tcx>(
     trait_pred: TraitPredicate<'tcx>,
 ) -> Option<ProjectionPredicate<'tcx>> {
     generics.predicates.iter().find_map(|(proj_pred, _)| {
-        if let ty::PredicateKind::Clause(ClauseKind::Projection(pred)) = proj_pred.kind().skip_binder() {
+        if let ClauseKind::Projection(pred) = proj_pred.kind().skip_binder() {
             let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred.kind().rebind(pred));
             if projection_pred.projection_ty.substs == trait_pred.trait_ref.substs {
                 return Some(projection_pred);
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 3c2bf5abab2..6b51974d739 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -559,6 +559,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Ret({value})");
                 value.if_some(|e| self.expr(e));
             },
+            ExprKind::Become(value) => {
+                bind!(self, value);
+                kind!("Become({value})");
+                self.expr(value);
+            },
             ExprKind::InlineAsm(_) => {
                 kind!("InlineAsm(_)");
                 out!("// unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment");
diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
index 941df3318ae..659c693f87a 100644
--- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
+++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs
@@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, PredicateKind};
+use rustc_middle::ty;
 use rustc_span::{sym, Symbol};
 use std::cmp;
 use std::ops;
@@ -73,7 +73,7 @@ fn fn_eagerness(cx: &LateContext<'_>, fn_id: DefId, name: Symbol, have_one_arg:
             .flat_map(|v| v.fields.iter())
             .any(|x| matches!(cx.tcx.type_of(x.did).subst_identity().peel_refs().kind(), ty::Param(_)))
             && all_predicates_of(cx.tcx, fn_id).all(|(pred, _)| match pred.kind().skip_binder() {
-                PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
+                ty::ClauseKind::Trait(pred) => cx.tcx.trait_def(pred.trait_ref.def_id).is_marker,
                 _ => true,
             })
             && subs.types().all(|x| matches!(x.peel_refs().kind(), ty::Param(_)))
@@ -191,6 +191,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS
                 ExprKind::Break(..)
                 | ExprKind::Continue(_)
                 | ExprKind::Ret(_)
+                | ExprKind::Become(_)
                 | ExprKind::InlineAsm(_)
                 | ExprKind::Yield(..)
                 | ExprKind::Err(_) => {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index a49246a7832..3e1d7356414 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -845,6 +845,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_expr(e);
                 }
             },
+            ExprKind::Become(f) => {
+                self.hash_expr(f);
+            },
             ExprKind::Path(ref qpath) => {
                 self.hash_qpath(qpath);
             },
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 a10eb8646af..b7e83ce6caa 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
@@ -21,35 +21,6 @@ type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
 pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
     let def_id = body.source.def_id();
-    let mut current = def_id;
-    loop {
-        let predicates = tcx.predicates_of(current);
-        for (predicate, _) in predicates.predicates {
-            match predicate.kind().skip_binder() {
-                ty::PredicateKind::Clause(
-                    ty::ClauseKind::RegionOutlives(_)
-                    | ty::ClauseKind::TypeOutlives(_)
-                    | ty::ClauseKind::Projection(_)
-                    | ty::ClauseKind::Trait(..)
-                    | ty::ClauseKind::ConstArgHasType(..),
-                )
-                | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_))
-                | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..))
-                | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
-                ty::PredicateKind::AliasRelate(..) => panic!("alias relate predicate on function: {predicate:#?}"),
-                ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
-                ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
-                ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
-                ty::PredicateKind::Coerce(_) => panic!("coerce predicate on function: {predicate:#?}"),
-                ty::PredicateKind::Ambiguous => panic!("ambiguous predicate on function: {predicate:#?}"),
-            }
-        }
-        match predicates.parent {
-            Some(parent) => current = parent,
-            None => break,
-        }
-    }
 
     for local in &body.local_decls {
         check_ty(tcx, local.ty, local.source_info.span)?;
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index a87d58110b0..b38b9553558 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -147,6 +147,7 @@ impl<'a> Sugg<'a> {
             | hir::ExprKind::Path(..)
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Become(..)
             | hir::ExprKind::Struct(..)
             | hir::ExprKind::Tup(..)
             | hir::ExprKind::Err(_) => Sugg::NonParen(get_snippet(expr.span)),
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 2b185943c59..8d3aecd4785 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -17,7 +17,7 @@ use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
     self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv,
-    Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_middle::ty::{GenericArg, GenericArgKind};
@@ -563,7 +563,7 @@ fn is_uninit_value_valid_for_ty_fallback<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
 }
 
 /// Gets an iterator over all predicates which apply to the given item.
-pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(Predicate<'_>, Span)> {
+pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(ty::Clause<'_>, Span)> {
     let mut next_id = Some(id);
     iter::from_fn(move || {
         next_id.take().map(|id| {
@@ -665,7 +665,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
         ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => sig_from_bounds(
             cx,
             ty,
-            cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs).map(|c| c.as_predicate()),
+            cx.tcx.item_bounds(def_id).subst_iter(cx.tcx, substs),
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
@@ -698,7 +698,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
 fn sig_from_bounds<'tcx>(
     cx: &LateContext<'tcx>,
     ty: Ty<'tcx>,
-    predicates: impl IntoIterator<Item = Predicate<'tcx>>,
+    predicates: impl IntoIterator<Item = ty::Clause<'tcx>>,
     predicates_id: Option<DefId>,
 ) -> Option<ExprFnSig<'tcx>> {
     let mut inputs = None;
@@ -707,7 +707,7 @@ fn sig_from_bounds<'tcx>(
 
     for pred in predicates {
         match pred.kind().skip_binder() {
-            PredicateKind::Clause(ty::ClauseKind::Trait(p))
+            ty::ClauseKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id()))
@@ -720,7 +720,7 @@ fn sig_from_bounds<'tcx>(
                 }
                 inputs = Some(i);
             },
-            PredicateKind::Clause(ty::ClauseKind::Projection(p))
+            ty::ClauseKind::Projection(p)
                 if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
             {
                 if output.is_some() {
@@ -937,7 +937,7 @@ pub fn adt_and_variant_of_res<'tcx>(cx: &LateContext<'tcx>, res: Res) -> Option<
 }
 
 /// Checks if the type is a type parameter implementing `FnOnce`, but not `FnMut`.
-pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [Predicate<'_>]) -> bool {
+pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tcx [ty::Clause<'_>]) -> bool {
     let ty::Param(ty) = *ty.kind() else {
         return false;
     };
@@ -950,7 +950,7 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
     predicates
         .iter()
         .try_fold(false, |found, p| {
-            if let PredicateKind::Clause(ty::ClauseKind::Trait(p)) = p.kind().skip_binder()
+            if let ty::ClauseKind::Trait(p) = p.kind().skip_binder()
             && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
             && ty.index == self_ty.index
         {
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 5dcd71cef12..8dafa723afa 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -651,6 +651,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>(
             // Either drops temporaries, jumps out of the current expression, or has no sub expression.
             ExprKind::DropTemps(_)
             | ExprKind::Ret(_)
+            | ExprKind::Become(_)
             | ExprKind::Break(..)
             | ExprKind::Yield(..)
             | ExprKind::Block(..)
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 3c5b6e12b96..f3cc94aeff0 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -16,6 +16,8 @@ extern crate rustc_session;
 extern crate rustc_span;
 
 use rustc_interface::interface;
+use rustc_session::EarlyErrorHandler;
+use rustc_session::config::ErrorOutputType;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Symbol;
 
@@ -187,7 +189,9 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne
 
 #[allow(clippy::too_many_lines)]
 pub fn main() {
-    rustc_driver::init_rustc_env_logger();
+    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
+    rustc_driver::init_rustc_env_logger(&handler);
 
     rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
         // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
index 4506d1550bd..db34e6bfa7b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6250.stderr
@@ -12,11 +12,6 @@ LL |     for reference in vec![1, 2, 3] {
 ...
 LL |         Some(reference) = cache.data.get(key) {
    |              ^^^^^^^^^ expected integer, found `&i32`
-   |
-help: consider dereferencing the borrow
-   |
-LL |         Some(*reference) = cache.data.get(key) {
-   |              +
 
 error[E0308]: mismatched types
   --> $DIR/ice-6250.rs:12:9
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 1b46c42fa4c..85a8fbcffbe 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -453,7 +453,7 @@ impl TargetCfgs {
         let mut all_families = HashSet::new();
         let mut all_pointer_widths = HashSet::new();
 
-        for (target, cfg) in targets.into_iter() {
+        for (target, cfg) in targets.iter() {
             all_archs.insert(cfg.arch.clone());
             all_oses.insert(cfg.os.clone());
             all_oses_and_envs.insert(cfg.os_and_env());
@@ -464,11 +464,11 @@ impl TargetCfgs {
             }
             all_pointer_widths.insert(format!("{}bit", cfg.pointer_width));
 
-            all_targets.insert(target.into());
+            all_targets.insert(target.clone());
         }
 
         Self {
-            current: Self::get_current_target_config(config),
+            current: Self::get_current_target_config(config, &targets),
             all_targets,
             all_archs,
             all_oses,
@@ -480,16 +480,20 @@ impl TargetCfgs {
         }
     }
 
-    fn get_current_target_config(config: &Config) -> TargetCfg {
-        let mut arch = None;
-        let mut os = None;
-        let mut env = None;
-        let mut abi = None;
-        let mut families = Vec::new();
-        let mut pointer_width = None;
-        let mut endian = None;
-        let mut panic = None;
-
+    fn get_current_target_config(
+        config: &Config,
+        targets: &HashMap<String, TargetCfg>,
+    ) -> TargetCfg {
+        let mut cfg = targets[&config.target].clone();
+
+        // To get the target information for the current target, we take the target spec obtained
+        // from `--print=all-target-specs-json`, and then we enrich it with the information
+        // gathered from `--print=cfg --target=$target`.
+        //
+        // This is done because some parts of the target spec can be overridden with `-C` flags,
+        // which are respected for `--print=cfg` but not for `--print=all-target-specs-json`. The
+        // code below extracts them from `--print=cfg`: make sure to only override fields that can
+        // actually be changed with `-C` flags.
         for config in
             rustc_output(config, &["--print=cfg", "--target", &config.target]).trim().lines()
         {
@@ -507,60 +511,16 @@ impl TargetCfgs {
                 })
                 .unwrap_or_else(|| (config, None));
 
-            match name {
-                "target_arch" => {
-                    arch = Some(value.expect("target_arch should be a key-value pair").to_string());
-                }
-                "target_os" => {
-                    os = Some(value.expect("target_os sould be a key-value pair").to_string());
-                }
-                "target_env" => {
-                    env = Some(value.expect("target_env should be a key-value pair").to_string());
-                }
-                "target_abi" => {
-                    abi = Some(value.expect("target_abi should be a key-value pair").to_string());
-                }
-                "target_family" => {
-                    families
-                        .push(value.expect("target_family should be a key-value pair").to_string());
-                }
-                "target_pointer_width" => {
-                    pointer_width = Some(
-                        value
-                            .expect("target_pointer_width should be a key-value pair")
-                            .parse::<u32>()
-                            .expect("target_pointer_width should be a valid u32"),
-                    );
-                }
-                "target_endian" => {
-                    endian = Some(match value.expect("target_endian should be a key-value pair") {
-                        "big" => Endian::Big,
-                        "little" => Endian::Little,
-                        _ => panic!("target_endian should be either 'big' or 'little'"),
-                    });
-                }
-                "panic" => {
-                    panic = Some(match value.expect("panic should be a key-value pair") {
-                        "abort" => PanicStrategy::Abort,
-                        "unwind" => PanicStrategy::Unwind,
-                        _ => panic!("panic should be either 'abort' or 'unwind'"),
-                    });
-                }
-                _ => (),
+            match (name, value) {
+                // Can be overridden with `-C panic=$strategy`.
+                ("panic", Some("abort")) => cfg.panic = PanicStrategy::Abort,
+                ("panic", Some("unwind")) => cfg.panic = PanicStrategy::Unwind,
+                ("panic", other) => panic!("unexpected value for panic cfg: {other:?}"),
+                _ => {}
             }
         }
 
-        TargetCfg {
-            arch: arch.expect("target configuration should specify target_arch"),
-            os: os.expect("target configuration should specify target_os"),
-            env: env.expect("target configuration should specify target_env"),
-            abi: abi.expect("target configuration should specify target_abi"),
-            families,
-            pointer_width: pointer_width
-                .expect("target configuration should specify target_pointer_width"),
-            endian: endian.expect("target configuration should specify target_endian"),
-            panic: panic.expect("target configuration should specify panic"),
-        }
+        cfg
     }
 }
 
@@ -582,6 +542,8 @@ pub struct TargetCfg {
     endian: Endian,
     #[serde(rename = "panic-strategy", default)]
     pub(crate) panic: PanicStrategy,
+    #[serde(default)]
+    pub(crate) dynamic_linking: bool,
 }
 
 impl TargetCfg {
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 18b3b913a68..0e306696a90 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -130,6 +130,11 @@ pub(super) fn handle_needs(
             condition: config.git_hash,
             ignore_reason: "ignored when git hashes have been omitted for building",
         },
+        Need {
+            name: "needs-dynamic-linking",
+            condition: config.target_cfg().dynamic_linking,
+            ignore_reason: "ignored on targets without dynamic linking",
+        },
     ];
 
     let (name, comment) = match ln.split_once([':', ' ']) {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 25b16e38e53..5c8ee7895d3 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1810,8 +1810,8 @@ impl<'test> TestCx<'test> {
             || self.config.target.contains("wasm32")
             || self.config.target.contains("nvptx")
             || self.is_vxworks_pure_static()
-            || self.config.target.contains("sgx")
             || self.config.target.contains("bpf")
+            || !self.config.target_cfg().dynamic_linking
         {
             // We primarily compile all auxiliary libraries as dynamic libraries
             // to avoid code size bloat and large binaries as much as possible
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index f984275b164..62a58576da5 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -1,6 +1,7 @@
 #![feature(rustc_private)]
 
 extern crate rustc_driver;
+extern crate rustc_session;
 
 use std::env;
 use std::error::Error;
@@ -170,7 +171,9 @@ fn parse_args() -> (OutputFormat, PathBuf) {
 }
 
 fn main() {
-    rustc_driver::init_env_logger("RUST_LOG");
+    let handler =
+        rustc_session::EarlyErrorHandler::new(rustc_session::config::ErrorOutputType::default());
+    rustc_driver::init_env_logger(&handler, "RUST_LOG");
     let (format, dst) = parse_args();
     let result = main_with_result(format, &dst);
     if let Err(e) = result {
diff --git a/src/tools/generate-windows-sys/src/arm_shim.rs b/src/tools/generate-windows-sys/src/arm_shim.rs
deleted file mode 100644
index 17c2ccb223c..00000000000
--- a/src/tools/generate-windows-sys/src/arm_shim.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Begin of ARM32 shim
-// The raw content of this file should be processed by `generate-windows-sys`
-// to be merged with the generated binding. It is not supposed to be used as
-// a normal Rust module.
-cfg_if::cfg_if! {
-if #[cfg(target_arch = "arm")] {
-#[repr(C)]
-pub struct WSADATA {
-    pub wVersion: u16,
-    pub wHighVersion: u16,
-    pub szDescription: [u8; 257],
-    pub szSystemStatus: [u8; 129],
-    pub iMaxSockets: u16,
-    pub iMaxUdpDg: u16,
-    pub lpVendorInfo: PSTR,
-}
-pub enum CONTEXT {}
-}
-}
-// End of ARM32 shim
diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs
index 65e480715ee..91d981462e8 100644
--- a/src/tools/generate-windows-sys/src/main.rs
+++ b/src/tools/generate-windows-sys/src/main.rs
@@ -11,9 +11,6 @@ const PRELUDE: &str = r#"// This file is autogenerated.
 // ignore-tidy-filelength
 "#;
 
-/// This is a shim for the ARM (32-bit) architecture, which is no longer supported by windows-rs.
-const ARM_SHIM: &str = include_str!("arm_shim.rs");
-
 fn main() -> io::Result<()> {
     let mut path: PathBuf =
         std::env::args_os().nth(1).expect("a path to the rust repository is required").into();
@@ -35,7 +32,6 @@ fn main() -> io::Result<()> {
     let mut f = std::fs::File::create(&path)?;
     f.write_all(PRELUDE.as_bytes())?;
     f.write_all(bindings.as_bytes())?;
-    f.write_all(ARM_SHIM.as_bytes())?;
 
     Ok(())
 }
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 0ac1e277eb7..3e024086a6b 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-0928a1f7574f5ca019b5443b3a90008588d18c8c
+08fd6f719ee764cf62659ddf481e22dbfe4b8894
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 083dd4800d9..cc14cfecea4 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -31,9 +31,9 @@ use rustc_middle::{
     query::{ExternProviders, LocalCrate},
     ty::TyCtxt,
 };
-use rustc_session::config::OptLevel;
-
-use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace};
+use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
+use rustc_session::search_paths::PathKind;
+use rustc_session::{CtfeBacktrace, EarlyErrorHandler};
 
 use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields};
 
@@ -59,6 +59,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
 
     fn after_analysis<'tcx>(
         &mut self,
+        handler: &EarlyErrorHandler,
         _: &rustc_interface::interface::Compiler,
         queries: &'tcx rustc_interface::Queries<'tcx>,
     ) -> Compilation {
@@ -66,8 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             if tcx.sess.compile_status().is_err() {
                 tcx.sess.fatal("miri cannot be run on programs that fail compilation");
             }
-
-            init_late_loggers(tcx);
+;
+            init_late_loggers(handler, tcx);
             if !tcx.sess.crate_types().contains(&CrateType::Executable) {
                 tcx.sess.fatal("miri only makes sense on bin crates");
             }
@@ -181,7 +182,7 @@ macro_rules! show_error {
     ($($tt:tt)*) => { show_error(&format_args!($($tt)*)) };
 }
 
-fn init_early_loggers() {
+fn init_early_loggers(handler: &EarlyErrorHandler) {
     // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
     // initialize them both, and we always initialize `miri`'s first.
     let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
@@ -195,11 +196,11 @@ fn init_early_loggers() {
     // later with our custom settings, and *not* log anything for what happens before
     // `miri` gets started.
     if env::var_os("RUSTC_LOG").is_some() {
-        rustc_driver::init_rustc_env_logger();
+        rustc_driver::init_rustc_env_logger(handler);
     }
 }
 
-fn init_late_loggers(tcx: TyCtxt<'_>) {
+fn init_late_loggers(handler: &EarlyErrorHandler, tcx: TyCtxt<'_>) {
     // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
     // env var if it is not set, control it based on `MIRI_LOG`.
     // (FIXME: use `var_os`, but then we need to manually concatenate instead of `format!`.)
@@ -218,7 +219,7 @@ fn init_late_loggers(tcx: TyCtxt<'_>) {
             } else {
                 env::set_var("RUSTC_LOG", &var);
             }
-            rustc_driver::init_rustc_env_logger();
+            rustc_driver::init_rustc_env_logger(handler);
         }
     }
 
@@ -284,6 +285,8 @@ fn parse_comma_list<T: FromStr>(input: &str) -> Result<Vec<T>, T::Err> {
 }
 
 fn main() {
+    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+
     // Snapshot a copy of the environment before `rustc` starts messing with it.
     // (`install_ice_hook` might change `RUST_BACKTRACE`.)
     let env_snapshot = env::vars_os().collect::<Vec<_>>();
@@ -292,7 +295,7 @@ fn main() {
     if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
         // Earliest rustc setup.
         rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
-        rustc_driver::init_rustc_env_logger();
+        rustc_driver::init_rustc_env_logger(&handler);
 
         let target_crate = if crate_kind == "target" {
             true
@@ -314,7 +317,7 @@ fn main() {
     rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
 
     // Init loggers the Miri way.
-    init_early_loggers();
+    init_early_loggers(&handler);
 
     // Parse our arguments and split them across `rustc` and `miri`.
     let mut miri_config = miri::MiriConfig::default();
diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml
index 85e979f07bf..471f2b5ac73 100644
--- a/src/tools/rust-installer/Cargo.toml
+++ b/src/tools/rust-installer/Cargo.toml
@@ -2,7 +2,7 @@
 authors = ["The Rust Project Developers"]
 name = "installer"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [[bin]]
 doc = false
@@ -20,4 +20,4 @@ num_cpus = "1"
 
 [dependencies.clap]
 features = ["derive"]
-version = "3.1"
+version = "4.2"
diff --git a/src/tools/rust-installer/src/combiner.rs b/src/tools/rust-installer/src/combiner.rs
index abcf59cfe36..19466f63fed 100644
--- a/src/tools/rust-installer/src/combiner.rs
+++ b/src/tools/rust-installer/src/combiner.rs
@@ -13,47 +13,47 @@ actor! {
     #[derive(Debug)]
     pub struct Combiner {
         /// The name of the product, for display.
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         product_name: String = "Product",
 
         /// The name of the package  tarball.
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         package_name: String = "package",
 
         /// The directory under lib/ where the manifest lives.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         rel_manifest_dir: String = "packagelib",
 
         /// The string to print after successful installation.
-        #[clap(value_name = "MESSAGE")]
+        #[arg(value_name = "MESSAGE")]
         success_message: String = "Installed.",
 
         /// Places to look for legacy manifests to uninstall.
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         legacy_manifest_dirs: String = "",
 
         /// Installers to combine.
-        #[clap(value_name = "FILE,FILE")]
+        #[arg(value_name = "FILE,FILE")]
         input_tarballs: String = "",
 
         /// Directory containing files that should not be installed.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         non_installed_overlay: String = "",
 
         /// The directory to do temporary work.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         work_dir: String = "./workdir",
 
         /// The location to put the final image and tarball.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         output_dir: String = "./dist",
 
         /// The profile used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_profile: CompressionProfile,
 
         /// The formats used to compress the tarball
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
     }
 }
@@ -94,7 +94,7 @@ impl Combiner {
             let pkg_name =
                 input_tarball.trim_end_matches(&format!(".tar.{}", compression.extension()));
             let pkg_name = Path::new(pkg_name).file_name().unwrap();
-            let pkg_dir = Path::new(&self.work_dir).join(&pkg_name);
+            let pkg_dir = Path::new(&self.work_dir).join(pkg_name);
 
             // Verify the version number.
             let mut version = String::new();
@@ -114,9 +114,9 @@ impl Combiner {
                 // All we need to do is copy the component directory. We could
                 // move it, but rustbuild wants to reuse the unpacked package
                 // dir for OS-specific installers on macOS and Windows.
-                let component_dir = package_dir.join(&component);
+                let component_dir = package_dir.join(component);
                 create_dir(&component_dir)?;
-                copy_recursive(&pkg_dir.join(&component), &component_dir)?;
+                copy_recursive(&pkg_dir.join(component), &component_dir)?;
 
                 // Merge the component name.
                 writeln!(&components, "{}", component).context("failed to write new components")?;
@@ -158,7 +158,7 @@ impl Combiner {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats.clone());
+            .compression_formats(self.compression_formats);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs
index 7c9c946e0b5..902b2ec6907 100644
--- a/src/tools/rust-installer/src/compression.rs
+++ b/src/tools/rust-installer/src/compression.rs
@@ -166,7 +166,7 @@ impl Default for CompressionFormats {
 
 impl CompressionFormats {
     pub(crate) fn iter(&self) -> impl Iterator<Item = CompressionFormat> + '_ {
-        self.0.iter().map(|i| *i)
+        self.0.iter().copied()
     }
 }
 
diff --git a/src/tools/rust-installer/src/generator.rs b/src/tools/rust-installer/src/generator.rs
index ddd1052599d..45f8c49d03e 100644
--- a/src/tools/rust-installer/src/generator.rs
+++ b/src/tools/rust-installer/src/generator.rs
@@ -11,55 +11,55 @@ actor! {
     #[derive(Debug)]
     pub struct Generator {
         /// The name of the product, for display
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         product_name: String = "Product",
 
         /// The name of the component, distinct from other installed components
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         component_name: String = "component",
 
         /// The name of the package, tarball
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         package_name: String = "package",
 
         /// The directory under lib/ where the manifest lives
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         rel_manifest_dir: String = "packagelib",
 
         /// The string to print after successful installation
-        #[clap(value_name = "MESSAGE")]
+        #[arg(value_name = "MESSAGE")]
         success_message: String = "Installed.",
 
         /// Places to look for legacy manifests to uninstall
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         legacy_manifest_dirs: String = "",
 
         /// Directory containing files that should not be installed
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         non_installed_overlay: String = "",
 
         /// Path prefixes of directories that should be installed/uninstalled in bulk
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         bulk_dirs: String = "",
 
         /// The directory containing the installation medium
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         image_dir: String = "./install_image",
 
         /// The directory to do temporary work
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         work_dir: String = "./workdir",
 
         /// The location to put the final image and tarball
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         output_dir: String = "./dist",
 
         /// The profile used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_profile: CompressionProfile,
 
         /// The formats used to compress the tarball
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
     }
 }
@@ -118,7 +118,7 @@ impl Generator {
             .input(self.package_name)
             .output(path_to_str(&output)?.into())
             .compression_profile(self.compression_profile)
-            .compression_formats(self.compression_formats.clone());
+            .compression_formats(self.compression_formats);
         tarballer.run()?;
 
         Ok(())
diff --git a/src/tools/rust-installer/src/scripter.rs b/src/tools/rust-installer/src/scripter.rs
index 06affc029fd..8180f925cb0 100644
--- a/src/tools/rust-installer/src/scripter.rs
+++ b/src/tools/rust-installer/src/scripter.rs
@@ -2,29 +2,29 @@ use crate::util::*;
 use anyhow::{Context, Result};
 use std::io::Write;
 
-const TEMPLATE: &'static str = include_str!("../install-template.sh");
+const TEMPLATE: &str = include_str!("../install-template.sh");
 
 actor! {
     #[derive(Debug)]
     pub struct Scripter {
         /// The name of the product, for display
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         product_name: String = "Product",
 
         /// The directory under lib/ where the manifest lives
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         rel_manifest_dir: String = "manifestlib",
 
         /// The string to print after successful installation
-        #[clap(value_name = "MESSAGE")]
+        #[arg(value_name = "MESSAGE")]
         success_message: String = "Installed.",
 
         /// Places to look for legacy manifests to uninstall
-        #[clap(value_name = "DIRS")]
+        #[arg(value_name = "DIRS")]
         legacy_manifest_dirs: String = "",
 
         /// The name of the output script
-        #[clap(value_name = "FILE")]
+        #[arg(value_name = "FILE")]
         output_script: String = "install.sh",
     }
 }
diff --git a/src/tools/rust-installer/src/tarballer.rs b/src/tools/rust-installer/src/tarballer.rs
index 7353a49fe03..c60d5f648ff 100644
--- a/src/tools/rust-installer/src/tarballer.rs
+++ b/src/tools/rust-installer/src/tarballer.rs
@@ -14,23 +14,23 @@ actor! {
     #[derive(Debug)]
     pub struct Tarballer {
         /// The input folder to be compressed.
-        #[clap(value_name = "NAME")]
+        #[arg(value_name = "NAME")]
         input: String = "package",
 
         /// The prefix of the tarballs.
-        #[clap(value_name = "PATH")]
+        #[arg(value_name = "PATH")]
         output: String = "./dist",
 
         /// The folder in which the input is to be found.
-        #[clap(value_name = "DIR")]
+        #[arg(value_name = "DIR")]
         work_dir: String = "./workdir",
 
         /// The profile used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_profile: CompressionProfile,
 
         /// The formats used to compress the tarball.
-        #[clap(value_name = "FORMAT", default_value_t)]
+        #[arg(value_name = "FORMAT", default_value_t)]
         compression_formats: CompressionFormats,
     }
 }
@@ -98,7 +98,7 @@ fn append_path<W: Write>(builder: &mut Builder<W>, src: &Path, path: &String) ->
         if cfg!(windows) {
             // Windows doesn't really have a mode, so `tar` never marks files executable.
             // Use an extension whitelist to update files that usually should be so.
-            const EXECUTABLES: [&'static str; 4] = ["exe", "dll", "py", "sh"];
+            const EXECUTABLES: [&str; 4] = ["exe", "dll", "py", "sh"];
             if let Some(ext) = src.extension().and_then(|s| s.to_str()) {
                 if EXECUTABLES.contains(&ext) {
                     let mode = header.mode()?;
@@ -134,7 +134,7 @@ where
     for entry in WalkDir::new(root.join(name)) {
         let entry = entry?;
         let path = entry.path().strip_prefix(root)?;
-        let path = path_to_str(&path)?;
+        let path = path_to_str(path)?;
 
         if entry.file_type().is_dir() {
             dirs.push(path.to_owned());
diff --git a/src/tools/rust-installer/src/util.rs b/src/tools/rust-installer/src/util.rs
index 6cac314b68d..4eb2e75fd7e 100644
--- a/src/tools/rust-installer/src/util.rs
+++ b/src/tools/rust-installer/src/util.rs
@@ -117,7 +117,7 @@ where
         } else {
             copy(entry.path(), dst)?;
         }
-        callback(&path, file_type)?;
+        callback(path, file_type)?;
     }
     Ok(())
 }
@@ -135,7 +135,7 @@ macro_rules! actor {
         $( #[ $attr ] )+
         #[derive(clap::Args)]
         pub struct $name {
-            $( $( #[ $field_attr ] )+ #[clap(long, $(default_value = $default)*)] $field : $type, )*
+            $( $( #[ $field_attr ] )+ #[arg(long, $(default_value = $default)*)] $field : $type, )*
         }
 
         impl Default for $name {
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 2fd4c797b43..7ad8f5c5c05 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -160,10 +160,10 @@ pub fn check(
     for &(name, _) in gate_untested.iter() {
         println!("Expected a gate test for the feature '{name}'.");
         println!(
-            "Hint: create a failing test file named 'feature-gate-{}.rs'\
-                \n      in the 'ui' test suite, with its failures due to\
-                \n      missing usage of `#![feature({})]`.",
-            name, name
+            "Hint: create a failing test file named 'tests/ui/feature-gates/feature-gate-{}.rs',\
+                \n      with its failures due to missing usage of `#![feature({})]`.",
+            name.replace("_", "-"),
+            name
         );
         println!(
             "Hint: If you already have such a test and don't want to rename it,\
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 55bf38110a6..3ed587caadc 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 const ISSUES_ENTRY_LIMIT: usize = 1896;
-const ROOT_ENTRY_LIMIT: usize = 870;
+const ROOT_ENTRY_LIMIT: usize = 871;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/codegen/issues/issue-111603.rs b/tests/codegen/issues/issue-111603.rs
index 90b3c314d2f..06429ed3fa9 100644
--- a/tests/codegen/issues/issue-111603.rs
+++ b/tests/codegen/issues/issue-111603.rs
@@ -5,6 +5,18 @@
 
 use std::sync::Arc;
 
+// CHECK-LABEL: @new_from_array
+#[no_mangle]
+pub fn new_from_array(x: u64) -> Arc<[u64]> {
+    // Ensure that we only generate one alloca for the array.
+
+    // CHECK: alloca
+    // CHECK-SAME: [1000 x i64]
+    // CHECK-NOT: alloca
+    let array = [x; 1000];
+    Arc::new(array)
+}
+
 // CHECK-LABEL: @new_uninit
 #[no_mangle]
 pub fn new_uninit(x: u64) -> Arc<[u64; 1000]> {
diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
index 2f6c92d9e85..4b05610f731 100644
--- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
+++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
@@ -36,7 +36,7 @@ fn main() -> () {
         StorageLive(_5);
         StorageLive(_6);
         _6 = _3;
-        _5 = foo(move _6) -> bb1;
+        _5 = foo(move _6) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -45,7 +45,7 @@ fn main() -> () {
         _7 = _2;
         _8 = Len(_1);
         _9 = Lt(_7, _8);
-        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2;
+        assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb2, unwind continue];
     }
 
     bb2: {
diff --git a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
index 41732211628..9c7b3c5197b 100644
--- a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
+++ b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
@@ -58,7 +58,7 @@
   
       bb4: {
           StorageDead(_5);
--         drop(_4) -> bb5;
+-         drop(_4) -> [return: bb5, unwind continue];
 +         goto -> bb5;
       }
   
diff --git a/tests/mir-opt/box_expr.main.ElaborateDrops.before.panic-unwind.mir b/tests/mir-opt/box_expr.main.ElaborateDrops.before.panic-unwind.mir
index cf63c4f19da..a72d22a9c9f 100644
--- a/tests/mir-opt/box_expr.main.ElaborateDrops.before.panic-unwind.mir
+++ b/tests/mir-opt/box_expr.main.ElaborateDrops.before.panic-unwind.mir
@@ -19,7 +19,7 @@ fn main() -> () {
         StorageLive(_1);
         _2 = SizeOf(S);
         _3 = AlignOf(S);
-        _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1;
+        _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -30,7 +30,7 @@ fn main() -> () {
 
     bb2: {
         _1 = move _5;
-        drop(_5) -> bb3;
+        drop(_5) -> [return: bb3, unwind continue];
     }
 
     bb3: {
@@ -45,7 +45,7 @@ fn main() -> () {
         StorageDead(_7);
         StorageDead(_6);
         _0 = const ();
-        drop(_1) -> bb5;
+        drop(_1) -> [return: bb5, unwind continue];
     }
 
     bb5: {
diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir
index 7e8206b02fc..074ebddf78b 100644
--- a/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/building/async_await.a-{closure#0}.generator_resume.0.mir
@@ -30,7 +30,7 @@ fn a::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:11:14: 11:16]>
     }
 
     bb2: {
-        assert(const false, "`async fn` resumed after completion") -> bb2;
+        assert(const false, "`async fn` resumed after completion") -> [success: bb2, unwind continue];
     }
 
     bb3: {
diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
index ed138871851..f774f32eb23 100644
--- a/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
+++ b/tests/mir-opt/building/async_await.b-{closure#0}.generator_resume.0.mir
@@ -310,7 +310,7 @@ fn b::{closure#0}(_1: Pin<&mut [async fn body@$DIR/async_await.rs:14:18: 17:2]>,
     }
 
     bb28: {
-        assert(const false, "`async fn` resumed after completion") -> bb28;
+        assert(const false, "`async fn` resumed after completion") -> [success: bb28, unwind continue];
     }
 
     bb29: {
diff --git a/tests/mir-opt/building/custom/terminators.direct_call.built.after.mir b/tests/mir-opt/building/custom/terminators.direct_call.built.after.mir
index 534d7615180..07044ceaef4 100644
--- a/tests/mir-opt/building/custom/terminators.direct_call.built.after.mir
+++ b/tests/mir-opt/building/custom/terminators.direct_call.built.after.mir
@@ -4,7 +4,7 @@ fn direct_call(_1: i32) -> i32 {
     let mut _0: i32;
 
     bb0: {
-        _0 = ident::<i32>(_1) -> bb1;
+        _0 = ident::<i32>(_1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir b/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir
index aba724a4b0d..6524f754d9c 100644
--- a/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir
+++ b/tests/mir-opt/building/custom/terminators.drop_first.built.after.mir
@@ -4,7 +4,7 @@ fn drop_first(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
     let mut _0: ();
 
     bb0: {
-        drop(_1) -> bb1;
+        drop(_1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/building/custom/terminators.drop_second.built.after.mir b/tests/mir-opt/building/custom/terminators.drop_second.built.after.mir
index 32d770bb0c1..ed3728121bd 100644
--- a/tests/mir-opt/building/custom/terminators.drop_second.built.after.mir
+++ b/tests/mir-opt/building/custom/terminators.drop_second.built.after.mir
@@ -4,7 +4,7 @@ fn drop_second(_1: WriteOnDrop<'_>, _2: WriteOnDrop<'_>) -> () {
     let mut _0: ();
 
     bb0: {
-        drop(_2) -> bb1;
+        drop(_2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/building/custom/terminators.indirect_call.built.after.mir b/tests/mir-opt/building/custom/terminators.indirect_call.built.after.mir
index 56371c78666..3b849354dcd 100644
--- a/tests/mir-opt/building/custom/terminators.indirect_call.built.after.mir
+++ b/tests/mir-opt/building/custom/terminators.indirect_call.built.after.mir
@@ -4,7 +4,7 @@ fn indirect_call(_1: i32, _2: fn(i32) -> i32) -> i32 {
     let mut _0: i32;
 
     bb0: {
-        _0 = _2(_1) -> bb1;
+        _0 = _2(_1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/combine_array_len.norm2.InstSimplify.panic-unwind.diff b/tests/mir-opt/combine_array_len.norm2.InstSimplify.panic-unwind.diff
index ab7a34f840d..4833c1089e3 100644
--- a/tests/mir-opt/combine_array_len.norm2.InstSimplify.panic-unwind.diff
+++ b/tests/mir-opt/combine_array_len.norm2.InstSimplify.panic-unwind.diff
@@ -32,7 +32,7 @@
 -         _4 = Len(_1);
 +         _4 = const 2_usize;
           _5 = Lt(_3, _4);
-          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
+          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -44,7 +44,7 @@
 -         _8 = Len(_1);
 +         _8 = const 2_usize;
           _9 = Lt(_7, _8);
-          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2;
+          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstSimplify.panic-unwind.diff b/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstSimplify.panic-unwind.diff
index ee0f9fbf828..1a4372afe69 100644
--- a/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstSimplify.panic-unwind.diff
+++ b/tests/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstSimplify.panic-unwind.diff
@@ -21,7 +21,7 @@
           _4 = &((*_1).0: T);
 -         _3 = &(*_4);
 +         _3 = _4;
-          _2 = <T as Clone>::clone(move _3) -> bb1;
+          _2 = <T as Clone>::clone(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff
index 73b5baafb33..e4650046bdf 100644
--- a/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/aggregate.main.ConstProp.panic-unwind.diff
@@ -27,7 +27,7 @@
           StorageLive(_5);
 -         _5 = _1;
 +         _5 = const 1_u8;
-          _4 = foo(move _5) -> bb1;
+          _4 = foo(move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.panic-unwind.mir
index 93d461a38c4..9590c7f90aa 100644
--- a/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/const_prop/aggregate.main.PreCodegen.after.panic-unwind.mir
@@ -23,7 +23,7 @@ fn main() -> () {
         StorageLive(_4);
         StorageLive(_5);
         _5 = const 1_u8;
-        _4 = foo(move _5) -> bb1;
+        _4 = foo(move _5) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff
index 9ac2fac6c00..ec11395c376 100644
--- a/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.ConstProp.32bit.panic-unwind.diff
@@ -20,10 +20,10 @@
           _3 = const 2_usize;
 -         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
 +         _4 = const 4_usize;
 +         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff
index 9ac2fac6c00..ec11395c376 100644
--- a/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/array_index.main.ConstProp.64bit.panic-unwind.diff
@@ -20,10 +20,10 @@
           _3 = const 2_usize;
 -         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
 +         _4 = const 4_usize;
 +         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff
index 2aff357cc3e..a5b51681ec9 100644
--- a/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.panic-unwind.diff
@@ -24,21 +24,21 @@
           StorageLive(_3);
 -         _3 = _1;
 -         _4 = Eq(_3, const 0_i32);
--         assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1;
+-         assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> [success: bb1, unwind continue];
 +         _3 = const 0_i32;
 +         _4 = const true;
-+         assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1;
++         assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _5 = Eq(_3, const -1_i32);
 -         _6 = Eq(const 1_i32, const i32::MIN);
 -         _7 = BitAnd(move _5, move _6);
--         assert(!move _7, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2;
+-         assert(!move _7, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind continue];
 +         _5 = const false;
 +         _6 = const false;
 +         _7 = const false;
-+         assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2;
++         assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff
index db93de9630b..4afddf3c92d 100644
--- a/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.panic-unwind.diff
@@ -24,21 +24,21 @@
           StorageLive(_3);
 -         _3 = _1;
 -         _4 = Eq(_3, const 0_i32);
--         assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1;
+-         assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> [success: bb1, unwind continue];
 +         _3 = const 0_i32;
 +         _4 = const true;
-+         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1;
++         assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
 -         _5 = Eq(_3, const -1_i32);
 -         _6 = Eq(const 1_i32, const i32::MIN);
 -         _7 = BitAnd(move _5, move _6);
--         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2;
+-         assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind continue];
 +         _5 = const false;
 +         _6 = const false;
 +         _7 = const false;
-+         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2;
++         assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff
index f39468d9684..2c0e4844ecc 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.panic-unwind.diff
@@ -36,9 +36,9 @@
           _6 = const 3_usize;
           _7 = const 3_usize;
 -         _8 = Lt(_6, _7);
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
 +         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
++         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff
index f39468d9684..2c0e4844ecc 100644
--- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.panic-unwind.diff
@@ -36,9 +36,9 @@
           _6 = const 3_usize;
           _7 = const 3_usize;
 -         _8 = Lt(_6, _7);
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
 +         _8 = const false;
-+         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
++         assert(const false, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff
index 8e3c2f6c844..6214766c7ee 100644
--- a/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/boxes.main.ConstProp.panic-unwind.diff
@@ -26,7 +26,7 @@
 -         _5 = AlignOf(i32);
 +         _4 = const 4_usize;
 +         _5 = const 4_usize;
-          _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1;
+          _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff
index 175e2b51a37..125407bf285 100644
--- a/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.ConstProp.panic-unwind.diff
@@ -12,9 +12,9 @@
       bb0: {
           StorageLive(_1);
 -         _2 = CheckedAdd(const 1_u32, const 1_u32);
--         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1;
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind continue];
 +         _2 = const (2_u32, false);
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1;
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.panic-unwind.diff
index 01ec24916c8..850b743feb1 100644
--- a/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.panic-unwind.diff
@@ -24,7 +24,7 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = _1;
-          _4 = read(move _5) -> bb1;
+          _4 = read(move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff
index 4593ffaac2b..7496d254309 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.panic-unwind.diff
@@ -14,7 +14,7 @@
       }
   
       bb1: {
-          _2 = begin_panic::<&str>(const "explicit panic");
+          _2 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
       }
   
       bb2: {
diff --git a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff
index affef00bb73..ccfa35f001b 100644
--- a/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/indirect.main.ConstProp.panic-unwind.diff
@@ -15,10 +15,10 @@
           StorageLive(_2);
 -         _2 = const 2_u32 as u8 (IntToInt);
 -         _3 = CheckedAdd(_2, const 1_u8);
--         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1;
+-         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind continue];
 +         _2 = const 2_u8;
 +         _3 = const (3_u8, false);
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1;
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff
index 9dae4b404aa..4f8e0f0f599 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.ConstProp.panic-unwind.diff
@@ -21,9 +21,9 @@
           StorageLive(_3);
           _3 = const 1_u8;
 -         _4 = CheckedAdd(_2, _3);
--         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> bb1;
+-         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
 +         _4 = const (0_u8, true);
-+         assert(!const true, "attempt to compute `{} + {}`, which would overflow", _2, _3) -> bb1;
++         assert(!const true, "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff
index e83c18735b6..5e3443228cd 100644
--- a/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/issue_66971.main.ConstProp.panic-unwind.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = (const (), const 0_u8, const 0_u8);
-          _1 = encode(move _2) -> bb1;
+          _1 = encode(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff
index cbbc2582973..95776030162 100644
--- a/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/issue_67019.main.ConstProp.panic-unwind.diff
@@ -14,7 +14,7 @@
 +         _3 = const (1_u8, 2_u8);
           _2 = (move _3,);
           StorageDead(_3);
-          _1 = test(move _2) -> bb1;
+          _1 = test(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff
index be245b424c1..658607116c8 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.panic-unwind.diff
@@ -20,10 +20,10 @@
           _3 = const 2_usize;
 -         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
 +         _4 = const 5000_usize;
 +         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff
index be245b424c1..658607116c8 100644
--- a/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.panic-unwind.diff
@@ -20,10 +20,10 @@
           _3 = const 2_usize;
 -         _4 = Len(_2);
 -         _5 = Lt(_3, _4);
--         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
+-         assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
 +         _4 = const 5000_usize;
 +         _5 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff
index 50006f5f5b5..7ba2b483dc3 100644
--- a/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.panic-unwind.diff
@@ -14,7 +14,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = foo() -> bb1;
+          _1 = foo() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff
index 69a0c3e2429..15ef0fa4dff 100644
--- a/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.panic-unwind.diff
@@ -23,7 +23,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = foo() -> bb1;
+          _1 = foo() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff
index 29cad611b54..bbb807d8fcd 100644
--- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.panic-unwind.diff
@@ -29,7 +29,7 @@
           StorageLive(_2);
 -         _2 = OffsetOf(Alpha, [0]);
 +         _2 = const 4_usize;
-          _1 = must_use::<usize>(move _2) -> bb1;
+          _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -38,7 +38,7 @@
           StorageLive(_4);
 -         _4 = OffsetOf(Alpha, [1]);
 +         _4 = const 0_usize;
-          _3 = must_use::<usize>(move _4) -> bb2;
+          _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -47,7 +47,7 @@
           StorageLive(_6);
 -         _6 = OffsetOf(Alpha, [2, 0]);
 +         _6 = const 2_usize;
-          _5 = must_use::<usize>(move _6) -> bb3;
+          _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -56,7 +56,7 @@
           StorageLive(_8);
 -         _8 = OffsetOf(Alpha, [2, 1]);
 +         _8 = const 3_usize;
-          _7 = must_use::<usize>(move _8) -> bb4;
+          _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
       }
   
       bb4: {
diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff
index 2a58a1a5ceb..fd5206e460c 100644
--- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.panic-unwind.diff
@@ -28,7 +28,7 @@
           StorageLive(_1);
           StorageLive(_2);
           _2 = OffsetOf(Gamma<T>, [0]);
-          _1 = must_use::<usize>(move _2) -> bb1;
+          _1 = must_use::<usize>(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -36,7 +36,7 @@
           StorageLive(_3);
           StorageLive(_4);
           _4 = OffsetOf(Gamma<T>, [1]);
-          _3 = must_use::<usize>(move _4) -> bb2;
+          _3 = must_use::<usize>(move _4) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -44,7 +44,7 @@
           StorageLive(_5);
           StorageLive(_6);
           _6 = OffsetOf(Delta<T>, [1]);
-          _5 = must_use::<usize>(move _6) -> bb3;
+          _5 = must_use::<usize>(move _6) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -52,7 +52,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = OffsetOf(Delta<T>, [2]);
-          _7 = must_use::<usize>(move _8) -> bb4;
+          _7 = must_use::<usize>(move _8) -> [return: bb4, unwind continue];
       }
   
       bb4: {
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff
index f94708605ee..571f279a8c1 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.ConstProp.32bit.panic-unwind.diff
@@ -22,10 +22,10 @@
           _4 = const 2_usize;
 -         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
--         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1;
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
 +         _5 = const 8_usize;
 +         _6 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff
index f94708605ee..571f279a8c1 100644
--- a/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/repeat.main.ConstProp.64bit.panic-unwind.diff
@@ -22,10 +22,10 @@
           _4 = const 2_usize;
 -         _5 = Len(_3);
 -         _6 = Lt(_4, _5);
--         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1;
+-         assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
 +         _5 = const 8_usize;
 +         _6 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff
index f89e9dd5b63..79f85fcef11 100644
--- a/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/return_place.add.ConstProp.panic-unwind.diff
@@ -7,9 +7,9 @@
   
       bb0: {
 -         _1 = CheckedAdd(const 2_u32, const 2_u32);
--         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1;
+-         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind continue];
 +         _1 = const (4_u32, false);
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1;
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir
index 148f16c7ee2..9a064697463 100644
--- a/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir
+++ b/tests/mir-opt/const_prop/return_place.add.PreCodegen.before.panic-unwind.mir
@@ -6,7 +6,7 @@ fn add() -> u32 {
 
     bb0: {
         _1 = const (4_u32, false);
-        assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1;
+        assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff
index d7d6e8e435e..a7d7a7224ce 100644
--- a/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.panic-unwind.diff
@@ -17,7 +17,7 @@
           StorageLive(_3);
 -         _3 = _1;
 +         _3 = const 1_u32;
-          _2 = consume(move _3) -> bb1;
+          _2 = consume(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff
index b07ec0ad502..c0f290a9ab4 100644
--- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.32bit.panic-unwind.diff
@@ -27,10 +27,10 @@
           _6 = const 1_usize;
 -         _7 = Len((*_2));
 -         _8 = Lt(_6, _7);
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
 +         _7 = const 3_usize;
 +         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff
index b07ec0ad502..c0f290a9ab4 100644
--- a/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.ConstProp.64bit.panic-unwind.diff
@@ -27,10 +27,10 @@
           _6 = const 1_usize;
 -         _7 = Len((*_2));
 -         _8 = Lt(_6, _7);
--         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
+-         assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
 +         _7 = const 3_usize;
 +         _8 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff
index 02dca4d3dea..1ce28e979a5 100644
--- a/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.ConstProp.panic-unwind.diff
@@ -13,11 +13,11 @@
       }
   
       bb1: {
-          _0 = foo(const -1_i32) -> bb3;
+          _0 = foo(const -1_i32) -> [return: bb3, unwind continue];
       }
   
       bb2: {
-          _0 = foo(const 0_i32) -> bb3;
+          _0 = foo(const 0_i32) -> [return: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
index 72ce94e1429..e598a0d3df0 100644
--- a/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
@@ -13,11 +13,11 @@
       }
   
       bb1: {
-          _0 = foo(const -1_i32) -> bb3;
+          _0 = foo(const -1_i32) -> [return: bb3, unwind continue];
       }
   
       bb2: {
-          _0 = foo(const 0_i32) -> bb3;
+          _0 = foo(const 0_i32) -> [return: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff
index d44c69ca440..6255f9ec596 100644
--- a/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.panic-unwind.diff
@@ -18,7 +18,7 @@
           StorageLive(_3);
 -         _3 = _1;
 +         _3 = const (1_u32, 2_u32);
-          _2 = consume(move _3) -> bb1;
+          _2 = consume(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff
index 074f8270241..b702e3b7d1e 100644
--- a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff
@@ -13,11 +13,11 @@
           _2 = &_1;
           _3 = _1;
           _4 = &_3;
-          _0 = cmp_ref(_2, _4) -> bb1;
+          _0 = cmp_ref(_2, _4) -> [return: bb1, unwind continue];
       }
   
       bb1: {
-          _0 = opaque::<u8>(_3) -> bb2;
+          _0 = opaque::<u8>(_3) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/copy-prop/branch.foo.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/branch.foo.CopyProp.panic-unwind.diff
index 0dcc5cef734..2f92d8818cf 100644
--- a/tests/mir-opt/copy-prop/branch.foo.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/branch.foo.CopyProp.panic-unwind.diff
@@ -16,13 +16,13 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = val() -> bb1;
+          _1 = val() -> [return: bb1, unwind continue];
       }
   
       bb1: {
           StorageLive(_2);
           StorageLive(_3);
-          _3 = cond() -> bb2;
+          _3 = cond() -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -36,7 +36,7 @@
   
       bb4: {
           StorageLive(_4);
-          _4 = val() -> bb5;
+          _4 = val() -> [return: bb5, unwind continue];
       }
   
       bb5: {
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.panic-unwind.diff
index 95c1c12ee69..ef9c343a264 100644
--- a/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/copy_propagation_arg.bar.CopyProp.panic-unwind.diff
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = _1;
-          _2 = dummy(move _3) -> bb1;
+          _2 = dummy(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.panic-unwind.diff
index e16d6220ef2..769089e16f3 100644
--- a/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/copy_propagation_arg.foo.CopyProp.panic-unwind.diff
@@ -11,7 +11,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = _1;
-          _2 = dummy(move _3) -> bb1;
+          _2 = dummy(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff
index 2d7e34f2d6e..eb40183c1c9 100644
--- a/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/custom_move_arg.f.CopyProp.panic-unwind.diff
@@ -8,14 +8,14 @@
   
       bb0: {
 -         _2 = _1;
--         _0 = opaque::<NotCopy>(move _1) -> bb1;
-+         _0 = opaque::<NotCopy>(_1) -> bb1;
+-         _0 = opaque::<NotCopy>(move _1) -> [return: bb1, unwind continue];
++         _0 = opaque::<NotCopy>(_1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
 -         _3 = move _2;
--         _0 = opaque::<NotCopy>(_3) -> bb2;
-+         _0 = opaque::<NotCopy>(_1) -> bb2;
+-         _0 = opaque::<NotCopy>(_3) -> [return: bb2, unwind continue];
++         _0 = opaque::<NotCopy>(_1) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/copy-prop/cycle.main.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/cycle.main.CopyProp.panic-unwind.diff
index bf9e941c7b6..e343b78924a 100644
--- a/tests/mir-opt/copy-prop/cycle.main.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/cycle.main.CopyProp.panic-unwind.diff
@@ -22,7 +22,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = val() -> bb1;
+          _1 = val() -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -38,7 +38,7 @@
           StorageLive(_5);
           StorageLive(_6);
           _6 = _1;
-          _5 = std::mem::drop::<i32>(move _6) -> bb2;
+          _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.panic-unwind.mir b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.panic-unwind.mir
index 617e57d884b..f8c285ff384 100644
--- a/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.panic-unwind.mir
+++ b/tests/mir-opt/copy-prop/dead_stores_79191.f.CopyProp.after.panic-unwind.mir
@@ -16,7 +16,7 @@ fn f(_1: usize) -> usize {
         _1 = _2;
         StorageLive(_4);
         _4 = _1;
-        _0 = id::<usize>(move _4) -> bb1;
+        _0 = id::<usize>(move _4) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.panic-unwind.mir b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.panic-unwind.mir
index 617e57d884b..f8c285ff384 100644
--- a/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.panic-unwind.mir
+++ b/tests/mir-opt/copy-prop/dead_stores_better.f.CopyProp.after.panic-unwind.mir
@@ -16,7 +16,7 @@ fn f(_1: usize) -> usize {
         _1 = _2;
         StorageLive(_4);
         _4 = _1;
-        _0 = id::<usize>(move _4) -> bb1;
+        _0 = id::<usize>(move _4) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
index 69f399bf1fa..c2d892be35d 100644
--- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff
@@ -49,14 +49,14 @@
           _7 = &_2;
           _6 = move _7 as &[i32] (Pointer(Unsize));
           StorageDead(_7);
-          _5 = core::slice::<impl [i32]>::len(move _6) -> bb1;
+          _5 = core::slice::<impl [i32]>::len(move _6) -> [return: bb1, unwind continue];
       }
   
       bb1: {
           StorageDead(_6);
           _4 = std::ops::Range::<usize> { start: const 0_usize, end: move _5 };
           StorageDead(_5);
-          _3 = <std::ops::Range<usize> as IntoIterator>::into_iter(move _4) -> bb2;
+          _3 = <std::ops::Range<usize> as IntoIterator>::into_iter(move _4) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -73,7 +73,7 @@
           StorageLive(_13);
           _13 = &mut _8;
           _12 = &mut (*_13);
-          _11 = <std::ops::Range<usize> as Iterator>::next(move _12) -> bb4;
+          _11 = <std::ops::Range<usize> as Iterator>::next(move _12) -> [return: bb4, unwind continue];
       }
   
       bb4: {
@@ -90,9 +90,9 @@
 -         _18 = _16;
           _19 = Len(_2);
 -         _20 = Lt(_18, _19);
--         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _18) -> bb8;
+-         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _18) -> [success: bb8, unwind continue];
 +         _20 = Lt(_16, _19);
-+         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _16) -> bb8;
++         assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, _16) -> [success: bb8, unwind continue];
       }
   
       bb6: {
diff --git a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.panic-unwind.diff
index cbbf6686b04..0c6a3c6d5c9 100644
--- a/tests/mir-opt/copy-prop/move_arg.f.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/move_arg.f.CopyProp.panic-unwind.diff
@@ -21,8 +21,8 @@
 -         _4 = _1;
 -         StorageLive(_5);
 -         _5 = _2;
--         _3 = g::<T>(move _4, move _5) -> bb1;
-+         _3 = g::<T>(_1, _1) -> bb1;
+-         _3 = g::<T>(move _4, move _5) -> [return: bb1, unwind continue];
++         _3 = g::<T>(_1, _1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff
index 3ebee0ed80d..ad3889639e0 100644
--- a/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/move_projection.f.CopyProp.panic-unwind.diff
@@ -9,13 +9,13 @@
       bb0: {
 -         _2 = _1;
 -         _3 = move (_2.0: u8);
--         _0 = opaque::<Foo>(move _1) -> bb1;
+-         _0 = opaque::<Foo>(move _1) -> [return: bb1, unwind continue];
 +         _3 = (_1.0: u8);
-+         _0 = opaque::<Foo>(_1) -> bb1;
++         _0 = opaque::<Foo>(_1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
-          _0 = opaque::<u8>(move _3) -> bb2;
+          _0 = opaque::<u8>(move _3) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
index 0f14b53e9ad..66a0f49cfb9 100644
--- a/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.demiraw.CopyProp.panic-unwind.diff
@@ -36,8 +36,8 @@
           StorageLive(_6);
 -         StorageLive(_7);
 -         _7 = _5;
--         _6 = opaque::<*mut u8>(move _7) -> bb1;
-+         _6 = opaque::<*mut u8>(_2) -> bb1;
+-         _6 = opaque::<*mut u8>(move _7) -> [return: bb1, unwind continue];
++         _6 = opaque::<*mut u8>(_2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
index ba6e09fa95c..f5a512b8995 100644
--- a/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.miraw.CopyProp.panic-unwind.diff
@@ -32,8 +32,8 @@
           StorageLive(_5);
 -         StorageLive(_6);
 -         _6 = _4;
--         _5 = opaque::<*mut u8>(move _6) -> bb1;
-+         _5 = opaque::<*mut u8>(_2) -> bb1;
+-         _5 = opaque::<*mut u8>(move _6) -> [return: bb1, unwind continue];
++         _5 = opaque::<*mut u8>(_2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.panic-unwind.diff
index 4379aa06385..67763fdce66 100644
--- a/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.remut.CopyProp.panic-unwind.diff
@@ -30,8 +30,8 @@
           StorageLive(_5);
 -         StorageLive(_6);
 -         _6 = move _4;
--         _5 = opaque::<&mut u8>(move _6) -> bb1;
-+         _5 = opaque::<&mut u8>(move _2) -> bb1;
+-         _5 = opaque::<&mut u8>(move _6) -> [return: bb1, unwind continue];
++         _5 = opaque::<&mut u8>(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.panic-unwind.diff
index 53332f8161e..becc4256321 100644
--- a/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/reborrow.reraw.CopyProp.panic-unwind.diff
@@ -30,8 +30,8 @@
           StorageLive(_5);
 -         StorageLive(_6);
 -         _6 = move _4;
--         _5 = opaque::<&mut u8>(move _6) -> bb1;
-+         _5 = opaque::<&mut u8>(move _2) -> bb1;
+-         _5 = opaque::<&mut u8>(move _6) -> [return: bb1, unwind continue];
++         _5 = opaque::<&mut u8>(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
index 784841eacbf..0d8a9aca3d8 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
@@ -41,10 +41,10 @@
           StorageLive(_5);
 -         _5 = _2;
 -         _6 = CheckedAdd(_4, _5);
--         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> bb1;
+-         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind continue];
 +         _5 = const 2_i32;
 +         _6 = CheckedAdd(const 1_i32, const 2_i32);
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> bb1;
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -58,10 +58,10 @@
           StorageLive(_9);
 -         _9 = _7;
 -         _10 = CheckedAdd(_9, const 1_i32);
--         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> bb2;
+-         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind continue];
 +         _9 = const i32::MAX;
 +         _10 = CheckedAdd(const i32::MAX, const 1_i32);
-+         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> bb2;
++         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const i32::MAX, const 1_i32) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
index d79a2da1ddb..c1d281ab788 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
@@ -21,9 +21,9 @@
           StorageLive(_3);
           _3 = const 1_u8;
 -         _4 = CheckedAdd(_2, _3);
--         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> bb1;
+-         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
 +         _4 = CheckedAdd(const u8::MAX, const 1_u8);
-+         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1;
++         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.panic-unwind.diff
index 83d2f78323e..4e1d26acfa3 100644
--- a/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/ref_without_sb.main.DataflowConstProp.panic-unwind.diff
@@ -24,7 +24,7 @@
           StorageLive(_4);
           _4 = &_1;
           _3 = &(*_4);
-          _2 = escape::<i32>(move _3) -> bb1;
+          _2 = escape::<i32>(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -33,7 +33,7 @@
           StorageDead(_2);
           _1 = const 1_i32;
           StorageLive(_5);
-          _5 = some_function() -> bb2;
+          _5 = some_function() -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
index 927ca0124bb..ebeb8619d73 100644
--- a/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/sibling_ptr.main.DataflowConstProp.panic-unwind.diff
@@ -30,7 +30,7 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = _3;
-          _4 = ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> bb1;
+          _4 = ptr::mut_ptr::<impl *mut u8>::add(move _5, const 1_usize) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.panic-unwind.diff
index f9723a04983..395620fec52 100644
--- a/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/terminator.main.DataflowConstProp.panic-unwind.diff
@@ -22,8 +22,8 @@
 +         _4 = const 1_i32;
 +         _3 = const 2_i32;
           StorageDead(_4);
--         _2 = foo(move _3) -> bb1;
-+         _2 = foo(const 2_i32) -> bb1;
+-         _2 = foo(move _3) -> [return: bb1, unwind continue];
++         _2 = foo(const 2_i32) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff
index 80a4dd37183..4b922e05e10 100644
--- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff
+++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.panic-unwind.diff
@@ -28,9 +28,9 @@
   
       bb1: {
 -         StorageLive(_5);
--         _5 = cond() -> bb2;
+-         _5 = cond() -> [return: bb2, unwind continue];
 +         StorageLive(_4);
-+         _4 = cond() -> bb2;
++         _4 = cond() -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
index 66396d28e70..3d9aa829052 100644
--- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
+++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff
@@ -17,7 +17,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = &(*_1);
-          _2 = core::str::<impl str>::as_bytes(move _3) -> bb1;
+          _2 = core::str::<impl str>::as_bytes(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff b/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff
index 62085341d37..da4cc188cfa 100644
--- a/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff
+++ b/tests/mir-opt/derefer_complex_case.main.Derefer.panic-unwind.diff
@@ -30,7 +30,7 @@
           StorageLive(_2);
           _14 = const _;
           _2 = &(*_14);
-          _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1;
+          _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -47,7 +47,7 @@
           StorageLive(_9);
           _9 = &mut _4;
           _8 = &mut (*_9);
-          _7 = <std::slice::Iter<'_, i32> as Iterator>::next(move _8) -> bb3;
+          _7 = <std::slice::Iter<'_, i32> as Iterator>::next(move _8) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -63,7 +63,7 @@
 +         _12 = (*_15);
           StorageLive(_13);
           _13 = _12;
-          _6 = std::mem::drop::<i32>(move _13) -> bb7;
+          _6 = std::mem::drop::<i32>(move _13) -> [return: bb7, unwind continue];
       }
   
       bb5: {
diff --git a/tests/mir-opt/derefer_inline_test.main.Derefer.panic-unwind.diff b/tests/mir-opt/derefer_inline_test.main.Derefer.panic-unwind.diff
index 50683837097..2ada087b4bd 100644
--- a/tests/mir-opt/derefer_inline_test.main.Derefer.panic-unwind.diff
+++ b/tests/mir-opt/derefer_inline_test.main.Derefer.panic-unwind.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = f() -> bb1;
+          _2 = f() -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -18,7 +18,7 @@
   
       bb2: {
           StorageDead(_2);
-          drop(_1) -> bb3;
+          drop(_1) -> [return: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff b/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff
index 59168eda2f3..19b26c901cb 100644
--- a/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff
+++ b/tests/mir-opt/derefer_terminator_test.main.Derefer.panic-unwind.diff
@@ -30,12 +30,12 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = foo() -> bb1;
+          _1 = foo() -> [return: bb1, unwind continue];
       }
   
       bb1: {
           StorageLive(_2);
-          _2 = foo() -> bb2;
+          _2 = foo() -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.panic-unwind.diff
index e0734f47de2..759c1cabf45 100644
--- a/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/branch.foo.DestinationPropagation.panic-unwind.diff
@@ -18,16 +18,16 @@
   
       bb0: {
 -         StorageLive(_1);
--         _1 = val() -> bb1;
+-         _1 = val() -> [return: bb1, unwind continue];
 +         nop;
-+         _0 = val() -> bb1;
++         _0 = val() -> [return: bb1, unwind continue];
       }
   
       bb1: {
 -         StorageLive(_2);
 +         nop;
           StorageLive(_3);
-          _3 = cond() -> bb2;
+          _3 = cond() -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -42,7 +42,7 @@
   
       bb4: {
           StorageLive(_4);
-          _4 = val() -> bb5;
+          _4 = val() -> [return: bb5, unwind continue];
       }
   
       bb5: {
diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.panic-unwind.diff
index b181066df04..8b2835c8ced 100644
--- a/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.panic-unwind.diff
@@ -11,10 +11,10 @@
           StorageLive(_2);
 -         StorageLive(_3);
 -         _3 = _1;
--         _2 = dummy(move _3) -> bb1;
+-         _2 = dummy(move _3) -> [return: bb1, unwind continue];
 +         nop;
 +         nop;
-+         _2 = dummy(move _1) -> bb1;
++         _2 = dummy(move _1) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff
index f1972866936..b4c8a89278b 100644
--- a/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.panic-unwind.diff
@@ -12,8 +12,8 @@
 +         nop;
           StorageLive(_3);
           _3 = _1;
--         _2 = dummy(move _3) -> bb1;
-+         _1 = dummy(move _3) -> bb1;
+-         _2 = dummy(move _3) -> [return: bb1, unwind continue];
++         _1 = dummy(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff
index 0dc7de31cc4..6f6e01d37b1 100644
--- a/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/cycle.main.DestinationPropagation.panic-unwind.diff
@@ -24,9 +24,9 @@
   
       bb0: {
 -         StorageLive(_1);
--         _1 = val() -> bb1;
+-         _1 = val() -> [return: bb1, unwind continue];
 +         nop;
-+         _6 = val() -> bb1;
++         _6 = val() -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -51,7 +51,7 @@
 -         _6 = _1;
 +         nop;
 +         nop;
-          _5 = std::mem::drop::<i32>(move _6) -> bb2;
+          _5 = std::mem::drop::<i32>(move _6) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir
index bf515d328ae..9147de2ec47 100644
--- a/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_79191.f.DestinationPropagation.after.panic-unwind.mir
@@ -20,7 +20,7 @@ fn f(_1: usize) -> usize {
         nop;
         nop;
         nop;
-        _0 = id::<usize>(move _1) -> bb1;
+        _0 = id::<usize>(move _1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
index 038bd4b6da9..185feb4b418 100644
--- a/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
+++ b/tests/mir-opt/dest-prop/dead_stores_better.f.DestinationPropagation.after.panic-unwind.mir
@@ -19,7 +19,7 @@ fn f(_1: usize) -> usize {
         nop;
         nop;
         nop;
-        _0 = id::<usize>(move _1) -> bb1;
+        _0 = id::<usize>(move _1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.panic-unwind.diff
index 4e32823c1ee..9c3cbef38d6 100644
--- a/tests/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.panic-unwind.diff
@@ -25,8 +25,8 @@
           StorageLive(_6);
           _6 = &mut _2;
           _5 = &mut (*_6);
--         _3 = move _4(move _5) -> bb1;
-+         _3 = move _1(move _5) -> bb1;
+-         _3 = move _4(move _5) -> [return: bb1, unwind continue];
++         _3 = move _1(move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
index 8d1297d0299..d2eef90582d 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
@@ -18,7 +18,7 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
-          _2 = val() -> bb1;
+          _2 = val() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff
index e46a318f51a..7f730a77b06 100644
--- a/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/unreachable.f.DestinationPropagation.panic-unwind.diff
@@ -34,7 +34,7 @@
 -         _5 = _1;
 -         StorageLive(_6);
 -         _6 = _2;
--         _4 = g::<T>(move _5, move _6) -> bb2;
+-         _4 = g::<T>(move _5, move _6) -> [return: bb2, unwind continue];
 -     }
 - 
 -     bb2: {
@@ -53,9 +53,9 @@
 +         nop;
           StorageLive(_9);
 -         _9 = _2;
--         _7 = g::<T>(move _8, move _9) -> bb4;
+-         _7 = g::<T>(move _8, move _9) -> [return: bb4, unwind continue];
 +         _9 = _1;
-+         _7 = g::<T>(move _1, move _9) -> bb2;
++         _7 = g::<T>(move _1, move _9) -> [return: bb2, unwind continue];
       }
   
 -     bb4: {
diff --git a/tests/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir b/tests/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
index 4fe11435fab..5fddfd494ea 100644
--- a/tests/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
+++ b/tests/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
@@ -1,10 +1,10 @@
 // MIR for `std::ops::Fn::call` before AddMovesForPackedDrops
 
-fn std::ops::Fn::call(_1: *const fn(), _2: ()) -> <fn() as FnOnce<()>>::Output {
+fn std::ops::Fn::call(_1: &fn(), _2: ()) -> <fn() as FnOnce<()>>::Output {
     let mut _0: <fn() as std::ops::FnOnce<()>>::Output;
 
     bb0: {
-        _0 = move (*_1)() -> bb1;
+        _0 = move (*_1)() -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff
index 513ff03c426..8a3dcfab44b 100644
--- a/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/funky_arms.float_to_exponential_common.ConstProp.panic-unwind.diff
@@ -38,7 +38,7 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = &(*_1);
-          _4 = Formatter::<'_>::sign_plus(move _5) -> bb1;
+          _4 = Formatter::<'_>::sign_plus(move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -63,7 +63,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = &(*_1);
-          _7 = Formatter::<'_>::precision(move _8) -> bb5;
+          _7 = Formatter::<'_>::precision(move _8) -> [return: bb5, unwind continue];
       }
   
       bb5: {
@@ -81,7 +81,7 @@
           _15 = _10 as u32 (IntToInt);
           _14 = Add(move _15, const 1_u32);
           StorageDead(_15);
-          _0 = float_to_exponential_common_exact::<T>(_1, _2, move _13, move _14, _3) -> bb7;
+          _0 = float_to_exponential_common_exact::<T>(_1, _2, move _13, move _14, _3) -> [return: bb7, unwind continue];
       }
   
       bb7: {
@@ -93,7 +93,7 @@
       bb8: {
           StorageLive(_20);
           _20 = _6;
-          _0 = float_to_exponential_common_shortest::<T>(_1, _2, move _20, _3) -> bb9;
+          _0 = float_to_exponential_common_shortest::<T>(_1, _2, move _20, _3) -> [return: bb9, unwind continue];
       }
   
       bb9: {
diff --git a/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
index af67723d937..684211b53b3 100644
--- a/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/asm_unwind.main.Inline.panic-unwind.diff
@@ -15,7 +15,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = foo() -> bb1;
+-         _1 = foo() -> [return: bb1, unwind continue];
 +         StorageLive(_2);
 +         asm!("", options(MAY_UNWIND)) -> [return: bb2, unwind: bb3];
       }
@@ -28,7 +28,7 @@
 +     }
 + 
 +     bb2: {
-+         drop(_2) -> bb1;
++         drop(_2) -> [return: bb1, unwind continue];
 +     }
 + 
 +     bb3 (cleanup): {
diff --git a/tests/mir-opt/inline/caller_with_trivial_bound.foo.Inline.panic-unwind.diff b/tests/mir-opt/inline/caller_with_trivial_bound.foo.Inline.panic-unwind.diff
index 67f16833435..d4427b2a807 100644
--- a/tests/mir-opt/inline/caller_with_trivial_bound.foo.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/caller_with_trivial_bound.foo.Inline.panic-unwind.diff
@@ -10,7 +10,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = bar::<T>() -> bb1;
+          _1 = bar::<T>() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
index 2bdb942379c..3ce8d9acf36 100644
--- a/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/cycle.g.Inline.panic-unwind.diff
@@ -16,7 +16,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = f::<fn() {main}>(main) -> bb1;
+-         _1 = f::<fn() {main}>(main) -> [return: bb1, unwind continue];
 +         StorageLive(_2);
 +         _2 = main;
 +         StorageLive(_4);
@@ -46,7 +46,7 @@
 +     bb4: {
 +         StorageDead(_5);
 +         StorageDead(_3);
-+         drop(_2) -> bb1;
++         drop(_2) -> [return: bb1, unwind continue];
       }
   }
   
diff --git a/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff
index c4f97d75308..198a2322618 100644
--- a/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/cycle.main.Inline.panic-unwind.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = f::<fn() {g}>(g) -> bb1;
+-         _1 = f::<fn() {g}>(g) -> [return: bb1, unwind continue];
 +         StorageLive(_2);
 +         _2 = g;
 +         StorageLive(_4);
@@ -56,7 +56,7 @@
 +         StorageDead(_6);
 +         StorageDead(_5);
 +         StorageDead(_3);
-+         drop(_2) -> bb1;
++         drop(_2) -> [return: bb1, unwind continue];
       }
   }
   
diff --git a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff
index ca772cf4383..941ba24605c 100644
--- a/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/dyn_trait.get_query.Inline.panic-unwind.diff
@@ -22,17 +22,17 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = &(*_1);
-          _2 = <Q as Query>::cache::<T>(move _3) -> bb1;
+          _2 = <Q as Query>::cache::<T>(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
           StorageDead(_3);
           StorageLive(_4);
           _4 = &(*_2);
--         _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2;
+-         _0 = try_execute_query::<<Q as Query>::C>(move _4) -> [return: bb2, unwind continue];
 +         StorageLive(_5);
 +         _5 = _4 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize));
-+         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(_5) -> bb2;
++         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(_5) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.panic-unwind.diff b/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.panic-unwind.diff
index 12b539fc250..7b1cf895a87 100644
--- a/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/dyn_trait.mk_cycle.Inline.panic-unwind.diff
@@ -9,7 +9,7 @@
       bb0: {
           StorageLive(_2);
           _2 = &(*_1);
-          _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1;
+          _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff
index 9bcd73e1c8b..5e30da400d2 100644
--- a/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/dyn_trait.try_execute_query.Inline.panic-unwind.diff
@@ -16,8 +16,8 @@
           _3 = &(*_1);
           _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize));
           StorageDead(_3);
--         _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1;
-+         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(_2) -> bb1;
+-         _0 = mk_cycle::<<C as Cache>::V>(move _2) -> [return: bb1, unwind continue];
++         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(_2) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/exponential_runtime.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/exponential_runtime.main.Inline.panic-unwind.diff
index b87e164e471..0a4ce40c529 100644
--- a/tests/mir-opt/inline/exponential_runtime.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/exponential_runtime.main.Inline.panic-unwind.diff
@@ -37,7 +37,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = <() as G>::call() -> bb1;
+-         _1 = <() as G>::call() -> [return: bb1, unwind continue];
 +         StorageLive(_2);
 +         StorageLive(_3);
 +         StorageLive(_4);
@@ -56,7 +56,7 @@
 +         StorageLive(_17);
 +         StorageLive(_18);
 +         StorageLive(_19);
-+         _17 = <() as A>::call() -> bb12;
++         _17 = <() as A>::call() -> [return: bb12, unwind continue];
       }
   
       bb1: {
@@ -72,63 +72,63 @@
 +         StorageDead(_7);
 +         StorageDead(_6);
 +         StorageDead(_5);
-+         _3 = <() as F>::call() -> bb3;
++         _3 = <() as F>::call() -> [return: bb3, unwind continue];
 +     }
 + 
 +     bb3: {
-+         _4 = <() as F>::call() -> bb1;
++         _4 = <() as F>::call() -> [return: bb1, unwind continue];
 +     }
 + 
 +     bb4: {
 +         StorageDead(_10);
 +         StorageDead(_9);
 +         StorageDead(_8);
-+         _6 = <() as E>::call() -> bb5;
++         _6 = <() as E>::call() -> [return: bb5, unwind continue];
 +     }
 + 
 +     bb5: {
-+         _7 = <() as E>::call() -> bb2;
++         _7 = <() as E>::call() -> [return: bb2, unwind continue];
 +     }
 + 
 +     bb6: {
 +         StorageDead(_13);
 +         StorageDead(_12);
 +         StorageDead(_11);
-+         _9 = <() as D>::call() -> bb7;
++         _9 = <() as D>::call() -> [return: bb7, unwind continue];
 +     }
 + 
 +     bb7: {
-+         _10 = <() as D>::call() -> bb4;
++         _10 = <() as D>::call() -> [return: bb4, unwind continue];
 +     }
 + 
 +     bb8: {
 +         StorageDead(_16);
 +         StorageDead(_15);
 +         StorageDead(_14);
-+         _12 = <() as C>::call() -> bb9;
++         _12 = <() as C>::call() -> [return: bb9, unwind continue];
 +     }
 + 
 +     bb9: {
-+         _13 = <() as C>::call() -> bb6;
++         _13 = <() as C>::call() -> [return: bb6, unwind continue];
 +     }
 + 
 +     bb10: {
 +         StorageDead(_19);
 +         StorageDead(_18);
 +         StorageDead(_17);
-+         _15 = <() as B>::call() -> bb11;
++         _15 = <() as B>::call() -> [return: bb11, unwind continue];
 +     }
 + 
 +     bb11: {
-+         _16 = <() as B>::call() -> bb8;
++         _16 = <() as B>::call() -> [return: bb8, unwind continue];
 +     }
 + 
 +     bb12: {
-+         _18 = <() as A>::call() -> bb13;
++         _18 = <() as A>::call() -> [return: bb13, unwind continue];
 +     }
 + 
 +     bb13: {
-+         _19 = <() as A>::call() -> bb10;
++         _19 = <() as A>::call() -> [return: bb10, unwind continue];
       }
   }
   
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff
index 10e0f0efcbc..eba5ad9cf26 100644
--- a/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.panic-unwind.diff
@@ -9,7 +9,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = no_sanitize() -> bb1;
+-         _1 = no_sanitize() -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff
index b854e93d9b7..24457819b2c 100644
--- a/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.panic-unwind.diff
@@ -9,7 +9,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = target_feature() -> bb1;
+-         _1 = target_feature() -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff
index d9e7177e627..364acab6d93 100644
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.panic-unwind.diff
@@ -10,7 +10,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1;
+          _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff
index 7d9b1d847b0..965b7ddca32 100644
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.panic-unwind.diff
@@ -7,7 +7,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = no_sanitize() -> bb1;
+          _1 = no_sanitize() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff
index 5bee5865283..bcdbd6e3314 100644
--- a/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.panic-unwind.diff
@@ -7,7 +7,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = target_feature() -> bb1;
+          _1 = target_feature() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_cycle.one.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_cycle.one.Inline.panic-unwind.diff
index 66d25162cb1..75ac40bea61 100644
--- a/tests/mir-opt/inline/inline_cycle.one.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_cycle.one.Inline.panic-unwind.diff
@@ -13,7 +13,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = <C as Call>::call() -> bb1;
+          _1 = <C as Call>::call() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff
index d3bd412d953..a08662959dd 100644
--- a/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_cycle.two.Inline.panic-unwind.diff
@@ -23,14 +23,14 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = call::<fn() {f}>(f) -> bb1;
+-         _1 = call::<fn() {f}>(f) -> [return: bb1, unwind continue];
 +         StorageLive(_2);
 +         _2 = f;
 +         StorageLive(_3);
 +         StorageLive(_4);
 +         _4 = const ();
 +         StorageLive(_5);
-+         _5 = f() -> bb1;
++         _5 = f() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff
index 2a4002f0499..8314526ee04 100644
--- a/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_cycle_generic.main.Inline.panic-unwind.diff
@@ -13,8 +13,8 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = <C as Call>::call() -> bb1;
-+         _1 = <B<C> as Call>::call() -> bb1;
+-         _1 = <C as Call>::call() -> [return: bb1, unwind continue];
++         _1 = <B<C> as Call>::call() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/inline/inline_diverging.f.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.f.Inline.panic-unwind.diff
index 76bb3356f50..b7991899253 100644
--- a/tests/mir-opt/inline/inline_diverging.f.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_diverging.f.Inline.panic-unwind.diff
@@ -10,7 +10,7 @@
   
       bb0: {
           StorageLive(_2);
--         _2 = sleep();
+-         _2 = sleep() -> unwind continue;
 +         goto -> bb1;
 +     }
 + 
diff --git a/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff
index d65efa43a7b..5663b462400 100644
--- a/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_diverging.g.Inline.panic-unwind.diff
@@ -33,9 +33,9 @@
   
       bb2: {
           StorageLive(_6);
--         _6 = panic();
+-         _6 = panic() -> unwind continue;
 +         StorageLive(_7);
-+         _7 = begin_panic::<&str>(const "explicit panic");
++         _7 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
       }
   }
   
diff --git a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
index f7e0e1c55f8..dfc12db12a8 100644
--- a/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_diverging.h.Inline.panic-unwind.diff
@@ -27,7 +27,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = call_twice::<!, fn() -> ! {sleep}>(sleep);
+-         _1 = call_twice::<!, fn() -> ! {sleep}>(sleep) -> unwind continue;
 +         StorageLive(_2);
 +         _2 = sleep;
 +         StorageLive(_6);
diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff
index 588f04048d6..fedcf04231d 100644
--- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff
@@ -35,7 +35,7 @@
           StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
--         _4 = g() -> bb1;
+-         _4 = g() -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff
index 4615a3f9826..0b643b3c7a9 100644
--- a/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_into_box_place.main.Inline.panic-unwind.diff
@@ -117,7 +117,7 @@
       bb0: {
           StorageLive(_1);
           StorageLive(_2);
--         _2 = Vec::<u32>::new() -> bb1;
+-         _2 = Vec::<u32>::new() -> [return: bb1, unwind continue];
 +         StorageLive(_3);
 +         _3 = const _;
 +         _2 = Vec::<u32> { buf: move _3, len: const 0_usize };
diff --git a/tests/mir-opt/inline/inline_options.main.Inline.after.panic-unwind.mir b/tests/mir-opt/inline/inline_options.main.Inline.after.panic-unwind.mir
index d006c73f954..df0cab513ec 100644
--- a/tests/mir-opt/inline/inline_options.main.Inline.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/inline_options.main.Inline.after.panic-unwind.mir
@@ -12,7 +12,7 @@ fn main() -> () {
 
     bb0: {
         StorageLive(_1);
-        _1 = not_inlined() -> bb1;
+        _1 = not_inlined() -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -21,7 +21,7 @@ fn main() -> () {
         StorageLive(_3);
         StorageLive(_4);
         StorageLive(_5);
-        _3 = g() -> bb3;
+        _3 = g() -> [return: bb3, unwind continue];
     }
 
     bb2: {
@@ -34,10 +34,10 @@ fn main() -> () {
     }
 
     bb3: {
-        _4 = g() -> bb4;
+        _4 = g() -> [return: bb4, unwind continue];
     }
 
     bb4: {
-        _5 = g() -> bb2;
+        _5 = g() -> [return: bb2, unwind continue];
     }
 }
diff --git a/tests/mir-opt/inline/inline_shims.clone.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.clone.Inline.panic-unwind.diff
index 9897ed78edf..00e92a0f5e5 100644
--- a/tests/mir-opt/inline/inline_shims.clone.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_shims.clone.Inline.panic-unwind.diff
@@ -11,7 +11,7 @@
       bb0: {
           StorageLive(_2);
           _2 = &_1;
--         _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1;
+-         _0 = <fn(A, B) as Clone>::clone(move _2) -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
index 1d24756e1d2..4270ae00b66 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
@@ -21,7 +21,7 @@
           StorageLive(_3);
           StorageLive(_4);
           _4 = _1;
-          _3 = std::ptr::drop_in_place::<Vec<A>>(move _4) -> bb1;
+          _3 = std::ptr::drop_in_place::<Vec<A>>(move _4) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -29,7 +29,7 @@
           StorageDead(_3);
           StorageLive(_5);
           _5 = _2;
--         _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> bb2;
+-         _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> [return: bb2, unwind continue];
 +         StorageLive(_6);
 +         StorageLive(_7);
 +         _6 = discriminant((*_5));
@@ -44,7 +44,7 @@
 +     }
 + 
 +     bb3: {
-+         drop((((*_5) as Some).0: B)) -> bb2;
++         drop((((*_5) as Some).0: B)) -> [return: bb2, unwind continue];
       }
   }
   
diff --git a/tests/mir-opt/inline/inline_specialization.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_specialization.main.Inline.panic-unwind.diff
index 0f7b1909f8d..bc841101df7 100644
--- a/tests/mir-opt/inline/inline_specialization.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_specialization.main.Inline.panic-unwind.diff
@@ -12,7 +12,7 @@
   
       bb0: {
           StorageLive(_1);
--         _1 = <Vec<()> as Foo>::bar() -> bb1;
+-         _1 = <Vec<()> as Foo>::bar() -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-unwind.mir b/tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-unwind.mir
index 9550fdea192..da18a5adc37 100644
--- a/tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/inline_trait_method.test.Inline.after.panic-unwind.mir
@@ -8,7 +8,7 @@ fn test(_1: &dyn X) -> u32 {
     bb0: {
         StorageLive(_2);
         _2 = &(*_1);
-        _0 = <dyn X as X>::y(move _2) -> bb1;
+        _0 = <dyn X as X>::y(move _2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir
index ffc16bfe670..5d4979680a4 100644
--- a/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir
+++ b/tests/mir-opt/inline/inline_trait_method_2.test2.Inline.after.panic-unwind.mir
@@ -15,7 +15,7 @@ fn test2(_1: &dyn X) -> bool {
         _3 = &(*_1);
         _2 = move _3 as &dyn X (Pointer(Unsize));
         StorageDead(_3);
-        _0 = <dyn X as X>::y(_2) -> bb1;
+        _0 = <dyn X as X>::y(_2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff
index 1e407f07d09..16a19f4a356 100644
--- a/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff
@@ -16,16 +16,16 @@
 +     }
   
       bb0: {
--         _0 = inner() -> bb1;
+-         _0 = inner() -> [return: bb1, unwind continue];
 +         StorageLive(_1);
 +         _1 = const _;
-+         _0 = index() -> bb1;
++         _0 = index() -> [return: bb1, unwind continue];
       }
   
       bb1: {
 +         StorageLive(_3);
 +         _2 = Lt(_0, const 1_usize);
-+         assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> bb2;
++         assert(move _2, "index out of bounds: the length is {} but the index is {}", const 1_usize, _0) -> [success: bb2, unwind continue];
 +     }
 + 
 +     bb2: {
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff
index 577fc8bee66..d71b5c4a626 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_bigger.Inline.panic-unwind.diff
@@ -20,7 +20,7 @@
           _3 = _1;
           StorageLive(_4);
           _4 = _2;
--         _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> bb1;
+-         _0 = core::num::<impl u64>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
index ba159c063b3..cae25759cd8 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff
@@ -22,7 +22,7 @@
           _3 = _1;
           StorageLive(_4);
           _4 = _2;
--         _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> bb1;
+-         _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
index d7ff104b92e..6aafb61dc55 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff
@@ -20,7 +20,7 @@
           _3 = _1;
           StorageLive(_4);
           _4 = _2;
--         _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> bb1;
+-         _0 = core::num::<impl i64>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff
index 3d398e00fc8..fe533121486 100644
--- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.panic-unwind.diff
@@ -22,7 +22,7 @@
           _3 = _1;
           StorageLive(_4);
           _4 = _2;
--         _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> bb1;
+-         _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff
index fbfb8f1fd4e..a6bd29e1c9d 100644
--- a/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/issue_101973.inner.ConstProp.panic-unwind.diff
@@ -45,10 +45,10 @@
           StorageLive(_8);
 -         _10 = const 8_i32 as u32 (IntToInt);
 -         _11 = Lt(move _10, const 32_u32);
--         assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1;
+-         assert(move _11, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> [success: bb1, unwind continue];
 +         _10 = const 8_u32;
 +         _11 = const true;
-+         assert(const true, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1;
++         assert(const true, "attempt to shift right by `{}`, which would overflow", const 8_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -57,10 +57,10 @@
           StorageDead(_8);
 -         _12 = const 1_i32 as u32 (IntToInt);
 -         _13 = Lt(move _12, const 32_u32);
--         assert(move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2;
+-         assert(move _13, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> [success: bb2, unwind continue];
 +         _12 = const 1_u32;
 +         _13 = const true;
-+         assert(const true, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2;
++         assert(const true, "attempt to shift left by `{}`, which would overflow", const 1_i32) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
index 8ffd46311dc..1851747f0a6 100644
--- a/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
+++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.panic-unwind.mir
@@ -11,6 +11,6 @@ fn main() -> () {
         StorageLive(_1);
         StorageLive(_2);
         _2 = ();
-        _1 = const_eval_select::<(), fn() -> ! {ow_ct}, fn() -> ! {ow_ct}, !>(move _2, ow_ct, ow_ct);
+        _1 = const_eval_select::<(), fn() -> ! {ow_ct}, fn() -> ! {ow_ct}, !>(move _2, ow_ct, ow_ct) -> unwind continue;
     }
 }
diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff
index b33d8fc52b4..254658c810d 100644
--- a/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff
+++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.panic-unwind.diff
@@ -58,7 +58,7 @@
   
       bb5: {
           StorageDead(_2);
--         drop(_1) -> bb6;
+-         drop(_1) -> [return: bb6, unwind continue];
 +         goto -> bb6;
       }
   
diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff
index 04071c72555..4ef3650cdea 100644
--- a/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff
+++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.panic-unwind.diff
@@ -85,7 +85,7 @@
   
       bb9: {
           StorageDead(_2);
--         drop(_1) -> bb10;
+-         drop(_1) -> [return: bb10, unwind continue];
 +         goto -> bb19;
       }
   
diff --git a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
index 4bbfe47299c..7ecdc428e59 100644
--- a/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
+++ b/tests/mir-opt/issue_62289.test.ElaborateDrops.before.panic-unwind.mir
@@ -31,7 +31,7 @@ fn test() -> Option<Box<u32>> {
         StorageLive(_1);
         _2 = SizeOf(u32);
         _3 = AlignOf(u32);
-        _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1;
+        _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -73,13 +73,13 @@ fn test() -> Option<Box<u32>> {
     bb6: {
         StorageDead(_11);
         StorageDead(_9);
-        drop(_5) -> bb9;
+        drop(_5) -> [return: bb9, unwind continue];
     }
 
     bb7: {
         StorageDead(_5);
         _0 = Option::<Box<u32>>::Some(move _1);
-        drop(_1) -> bb8;
+        drop(_1) -> [return: bb8, unwind continue];
     }
 
     bb8: {
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
index 761673ca546..25df839c2db 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
@@ -42,7 +42,7 @@
       }
   
       bb1: {
-          _15 = core::panicking::panic(const "internal error: entered unreachable code");
+          _15 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue;
       }
   
       bb2: {
diff --git a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir
index e7c1be7e6e6..43a1a1eed20 100644
--- a/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.panic-unwind.mir
@@ -26,7 +26,7 @@ fn num_to_digit(_1: char) -> u32 {
     bb0: {
         StorageLive(_3);
         StorageLive(_2);
-        _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb1;
+        _2 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -39,7 +39,7 @@ fn num_to_digit(_1: char) -> u32 {
 
     bb2: {
         StorageLive(_5);
-        _5 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> bb3;
+        _5 = char::methods::<impl char>::to_digit(_1, const 8_u32) -> [return: bb3, unwind continue];
     }
 
     bb3: {
@@ -48,7 +48,7 @@ fn num_to_digit(_1: char) -> u32 {
     }
 
     bb4: {
-        _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value");
+        _7 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value") -> unwind continue;
     }
 
     bb5: {
diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff
index 35a1e51a3ac..1cba0f27afa 100644
--- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.panic-unwind.diff
@@ -42,7 +42,7 @@
           _8 = _1;
           _9 = Len((*_2));
           _10 = Lt(_8, _9);
-          assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3;
+          assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff
index 3c6f3734624..6c450067cc4 100644
--- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff
+++ b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.panic-unwind.diff
@@ -45,7 +45,7 @@
           _8 = _1;
           _9 = Len((*_2));
           _10 = Lt(_8, _9);
-          assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb3;
+          assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> [success: bb3, unwind continue];
       }
   
       bb3: {
@@ -59,7 +59,7 @@
           _11 = const 0_usize;
           _12 = Len((*_2));
           _13 = Lt(_11, _12);
-          assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb5;
+          assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> [success: bb5, unwind continue];
       }
   
       bb5: {
diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff
index d90f3dddf58..310b3b26ac5 100644
--- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff
+++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff
@@ -20,7 +20,7 @@
           StorageLive(_5);
           StorageLive(_6);
           _6 = &(*_2);
--         _5 = core::slice::<impl [u8]>::len(move _6) -> bb1;
+-         _5 = core::slice::<impl [u8]>::len(move _6) -> [return: bb1, unwind continue];
 +         _5 = Len((*_6));
 +         goto -> bb1;
       }
@@ -38,7 +38,7 @@
           _7 = _1;
           _8 = Len((*_2));
           _9 = Lt(_7, _8);
-          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb3;
+          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> [success: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.panic-unwind.mir b/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.panic-unwind.mir
index 568ad441cbc..6fb107929e6 100644
--- a/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.panic-unwind.mir
+++ b/tests/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.panic-unwind.mir
@@ -14,7 +14,7 @@ fn main() -> () {
         StorageLive(_4);
         _4 = const "";
         _3 = &(*_4);
-        _2 = <str as ToString>::to_string(move _3) -> bb1;
+        _2 = <str as ToString>::to_string(move _3) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff b/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff
index b17675ec1ed..3df8e567f1f 100644
--- a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff
+++ b/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff
@@ -26,7 +26,7 @@
 -         _6 = &mut _2;
 +         _6 = &mut _0;
           _5 = &mut (*_6);
-          _3 = move _4(move _5) -> bb1;
+          _3 = move _4(move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir
index 46c078cea0d..98c267e8e71 100644
--- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.mir
@@ -31,7 +31,7 @@ fn step_forward(_1: u32, _2: usize) -> u32 {
         StorageLive(_7);
         StorageLive(_4);
         StorageLive(_3);
-        _3 = <u32 as Step>::forward_checked(_1, _2) -> bb1;
+        _3 = <u32 as Step>::forward_checked(_1, _2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -47,7 +47,7 @@ fn step_forward(_1: u32, _2: usize) -> u32 {
     }
 
     bb2: {
-        assert(!const true, "attempt to compute `{} + {}`, which would overflow", const _, const 1_u32) -> bb3;
+        assert(!const true, "attempt to compute `{} + {}`, which would overflow", const _, const 1_u32) -> [success: bb3, unwind continue];
     }
 
     bb3: {
diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
index b8b2d91adb6..3b49cb711b7 100644
--- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
@@ -30,7 +30,7 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
     bb0: {
         StorageLive(_4);
         StorageLive(_3);
-        _3 = <impl Iterator<Item = T> as Iterator>::filter_map::<U, impl Fn(T) -> Option<U>>(move _1, move _2) -> bb1;
+        _3 = <impl Iterator<Item = T> as Iterator>::filter_map::<U, impl Fn(T) -> Option<U>>(move _1, move _2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -60,7 +60,7 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
 
     bb4: {
         StorageDead(_9);
-        drop(_5) -> bb5;
+        drop(_5) -> [return: bb5, unwind continue];
     }
 
     bb5: {
diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
index 609555c8c43..40bb3a37c58 100644
--- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
@@ -79,7 +79,7 @@ fn int_range(_1: usize, _2: usize) -> () {
     bb3: {
         _12 = ((*_5).0: usize);
         StorageLive(_13);
-        _13 = <usize as Step>::forward_unchecked(_12, const 1_usize) -> bb4;
+        _13 = <usize as Step>::forward_unchecked(_12, const 1_usize) -> [return: bb4, unwind continue];
     }
 
     bb4: {
@@ -104,7 +104,7 @@ fn int_range(_1: usize, _2: usize) -> () {
 
     bb7: {
         _15 = ((_11 as Some).0: usize);
-        _16 = opaque::<usize>(_15) -> bb8;
+        _16 = opaque::<usize>(_15) -> [return: bb8, unwind continue];
     }
 
     bb8: {
diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
index f756f34b7d6..e4e1d052e73 100644
--- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
@@ -25,7 +25,7 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
     bb0: {
         StorageLive(_4);
         StorageLive(_3);
-        _3 = <impl Iterator<Item = T> as Iterator>::map::<U, impl Fn(T) -> U>(move _1, move _2) -> bb1;
+        _3 = <impl Iterator<Item = T> as Iterator>::map::<U, impl Fn(T) -> U>(move _1, move _2) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -49,7 +49,7 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
 
     bb4: {
         StorageDead(_7);
-        drop(_5) -> bb5;
+        drop(_5) -> [return: bb5, unwind continue];
     }
 
     bb5: {
diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
index 604cb773da5..1b5f2a0884b 100644
--- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
@@ -19,7 +19,7 @@ fn vec_move(_1: Vec<impl Sized>) -> () {
 
     bb0: {
         StorageLive(_2);
-        _2 = <Vec<impl Sized> as IntoIterator>::into_iter(move _1) -> bb1;
+        _2 = <Vec<impl Sized> as IntoIterator>::into_iter(move _1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -41,7 +41,7 @@ fn vec_move(_1: Vec<impl Sized>) -> () {
 
     bb4: {
         StorageDead(_5);
-        drop(_3) -> bb5;
+        drop(_3) -> [return: bb5, unwind continue];
     }
 
     bb5: {
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff
index a57ce86bc25..b6929f3f93c 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.32bit.panic-unwind.diff
@@ -25,9 +25,9 @@
       bb0: {
           StorageLive(_1);
 -         _2 = CheckedAdd(const 2_i32, const 2_i32);
--         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1;
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
 +         _2 = const (4_i32, false);
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1;
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -40,9 +40,9 @@
           _5 = const 3_usize;
           _6 = const 6_usize;
 -         _7 = Lt(_5, _6);
--         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2;
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> [success: bb2, unwind continue];
 +         _7 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff
index a57ce86bc25..b6929f3f93c 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ConstProp.64bit.panic-unwind.diff
@@ -25,9 +25,9 @@
       bb0: {
           StorageLive(_1);
 -         _2 = CheckedAdd(const 2_i32, const 2_i32);
--         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1;
+-         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
 +         _2 = const (4_i32, false);
-+         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1;
++         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -40,9 +40,9 @@
           _5 = const 3_usize;
           _6 = const 6_usize;
 -         _7 = Lt(_5, _6);
--         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2;
+-         assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> [success: bb2, unwind continue];
 +         _7 = const true;
-+         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2;
++         assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
index 1a5617c7639..e987969d313 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
@@ -27,7 +27,7 @@
       bb0: {
           StorageLive(_1);
           _2 = CheckedAdd(const 2_i32, const 2_i32);
-          assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1;
+          assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -39,7 +39,7 @@
           _5 = const 3_usize;
           _6 = Len(_4);
           _7 = Lt(_5, _6);
-          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2;
+          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
index 1a5617c7639..e987969d313 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
@@ -27,7 +27,7 @@
       bb0: {
           StorageLive(_1);
           _2 = CheckedAdd(const 2_i32, const 2_i32);
-          assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1;
+          assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
       bb1: {
@@ -39,7 +39,7 @@
           _5 = const 3_usize;
           _6 = Len(_4);
           _7 = Lt(_5, _6);
-          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2;
+          assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> [success: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index cf98f2022c5..fbe16dc3cd4 100644
--- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -102,7 +102,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     bb6: {
         StorageDead(_12);
         StorageDead(_5);
-        drop(_3) -> bb7;
+        drop(_3) -> [return: bb7, unwind continue];
     }
 
     bb7: {
diff --git a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir
index a7525b8b9a8..04d6da1d9bd 100644
--- a/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.inclusive_loop.PreCodegen.after.panic-unwind.mir
@@ -52,7 +52,7 @@ fn inclusive_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () {
     bb3: {
         StorageDead(_7);
         StorageDead(_5);
-        drop(_3) -> bb4;
+        drop(_3) -> [return: bb4, unwind continue];
     }
 
     bb4: {
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_inclusive_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_inclusive_iter_next.PreCodegen.after.panic-unwind.mir
index af775b454a7..fd565fe75ec 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_inclusive_iter_next.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_inclusive_iter_next.PreCodegen.after.panic-unwind.mir
@@ -8,7 +8,7 @@ fn range_inclusive_iter_next(_1: &mut RangeInclusive<u32>) -> Option<u32> {
     }
 
     bb0: {
-        _0 = <RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next(_1) -> bb1;
+        _0 = <RangeInclusive<u32> as iter::range::RangeInclusiveIteratorImpl>::spec_next(_1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
index 33752e970d1..65870f693c0 100644
--- a/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/range_iter.range_iter_next.PreCodegen.after.panic-unwind.mir
@@ -53,7 +53,7 @@ fn range_iter_next(_1: &mut std::ops::Range<u32>) -> Option<u32> {
     bb2: {
         _7 = ((*_1).0: u32);
         StorageLive(_8);
-        _8 = <u32 as Step>::forward_unchecked(_7, const 1_usize) -> bb3;
+        _8 = <u32 as Step>::forward_unchecked(_7, const 1_usize) -> [return: bb3, unwind continue];
     }
 
     bb3: {
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir
index 9f7fca639f7..a6b931d2c24 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir
@@ -12,7 +12,7 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] {
 
     bb0: {
         StorageLive(_3);
-        _3 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, _1) -> bb1;
+        _3 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, _1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir
index 13bd84f9596..d576520a8d5 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir
@@ -10,7 +10,7 @@ fn slice_index_usize(_1: &[u32], _2: usize) -> u32 {
     bb0: {
         _3 = Len((*_1));
         _4 = Lt(_2, _3);
-        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> bb1;
+        assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
index 71162df4bd0..8294a5cb6dc 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir
@@ -164,7 +164,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     bb6: {
         StorageDead(_17);
         StorageDead(_15);
-        drop(_2) -> bb7;
+        drop(_2) -> [return: bb7, unwind continue];
     }
 
     bb7: {
diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
index 08d829d52cc..ff40e450968 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir
@@ -152,7 +152,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     bb6: {
         StorageDead(_16);
         StorageDead(_14);
-        drop(_2) -> bb7;
+        drop(_2) -> [return: bb7, unwind continue];
     }
 
     bb7: {
diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
index 5ce8143d98b..3423c5d865d 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir
@@ -111,7 +111,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {
     bb6: {
         StorageDead(_12);
         StorageDead(_5);
-        drop(_2) -> bb7;
+        drop(_2) -> [return: bb7, unwind continue];
     }
 
     bb7: {
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 14ca6004dfe..b40d9209d25 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
@@ -169,7 +169,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     bb6: {
         StorageDead(_18);
         StorageDead(_15);
-        drop(_2) -> bb7;
+        drop(_2) -> [return: bb7, unwind continue];
     }
 
     bb7: {
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 f9253a321f9..386f3a9edcd 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
@@ -5,7 +5,7 @@ fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut
     let mut _0: std::option::Option<&mut T>;
 
     bb0: {
-        _0 = <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back(_1) -> bb1;
+        _0 = <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back(_1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir
index 207fc8c752f..e76ec00391c 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir
@@ -5,7 +5,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> {
     let mut _0: std::option::Option<&T>;
 
     bb0: {
-        _0 = <std::slice::Iter<'_, T> as Iterator>::next(_1) -> bb1;
+        _0 = <std::slice::Iter<'_, T> as Iterator>::next(_1) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
index 52e85809735..1e20b1be56b 100644
--- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
@@ -7,7 +7,7 @@ fn outer(_1: u8) -> u8 {
 
     bb0: {
         _2 = &_1;                        // scope 0 at $DIR/spans.rs:11:11: 11:13
-        _0 = inner(_2) -> bb1;           // scope 0 at $DIR/spans.rs:11:5: 11:14
+        _0 = inner(_2) -> [return: bb1, unwind continue]; // scope 0 at $DIR/spans.rs:11:5: 11:14
                                          // mir::Constant
                                          // + span: $DIR/spans.rs:11:5: 11:10
                                          // + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(<ZST>) }
diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
index 6732f8b4bb3..132f66a1ad3 100644
--- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff
@@ -104,7 +104,7 @@
           _13 = &(*_26);
           StorageLive(_15);
           _15 = RangeFull;
-          _12 = <[i32; 10] as Index<RangeFull>>::index(move _13, move _15) -> bb5;
+          _12 = <[i32; 10] as Index<RangeFull>>::index(move _13, move _15) -> [return: bb5, unwind continue];
       }
   
       bb5: {
diff --git a/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff b/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff
index 3baa565f03e..012efa9693e 100644
--- a/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff
@@ -22,7 +22,7 @@
   
       bb2: {
           _5 = (*_2);
-          _0 = opaque::<i32>(_5) -> bb3;
+          _0 = opaque::<i32>(_5) -> [return: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff b/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff
index 9ceb5a7634d..c6bd6c21210 100644
--- a/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff
@@ -27,17 +27,17 @@
       bb1: {
           StorageDead(_2);
           StorageDead(_3);
-          _0 = opaque::<i32>(_6) -> bb2;
+          _0 = opaque::<i32>(_6) -> [return: bb2, unwind continue];
       }
   
       bb2: {
           _7 = (*_4);
-          _0 = opaque::<i32>(_7) -> bb3;
+          _0 = opaque::<i32>(_7) -> [return: bb3, unwind continue];
       }
   
       bb3: {
           _8 = (*_5);
-          _0 = opaque::<i32>(_8) -> bb4;
+          _0 = opaque::<i32>(_8) -> [return: bb4, unwind continue];
       }
   
       bb4: {
diff --git a/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff b/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff
index 03add126545..0fd74155aa3 100644
--- a/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff
@@ -14,7 +14,7 @@
           StorageDead(_1);
           StorageLive(_1);
           _3 = (*_2);
-          _0 = opaque::<i32>(_3) -> bb1;
+          _0 = opaque::<i32>(_3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff
index 43292dd7249..f1f77cffd20 100644
--- a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff
@@ -201,7 +201,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = ();
-          _7 = opaque::<()>(move _8) -> bb1;
+          _7 = opaque::<()>(move _8) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -232,7 +232,7 @@
           StorageLive(_16);
           StorageLive(_17);
           _17 = ();
-          _16 = opaque::<()>(move _17) -> bb2;
+          _16 = opaque::<()>(move _17) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -256,7 +256,7 @@
           StorageLive(_23);
           StorageLive(_24);
           _24 = _21;
-          _23 = opaque::<&&usize>(move _24) -> bb3;
+          _23 = opaque::<&&usize>(move _24) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -280,7 +280,7 @@
           StorageLive(_30);
           StorageLive(_31);
           _31 = _28;
-          _30 = opaque::<*mut &usize>(move _31) -> bb4;
+          _30 = opaque::<*mut &usize>(move _31) -> [return: bb4, unwind continue];
       }
   
       bb4: {
@@ -303,7 +303,7 @@
           StorageLive(_36);
           StorageLive(_37);
           _37 = _34;
-          _36 = opaque::<&usize>(move _37) -> bb5;
+          _36 = opaque::<&usize>(move _37) -> [return: bb5, unwind continue];
       }
   
       bb5: {
@@ -332,7 +332,7 @@
           StorageLive(_45);
           StorageLive(_46);
           _46 = _44;
-          _45 = opaque::<&usize>(move _46) -> bb6;
+          _45 = opaque::<&usize>(move _46) -> [return: bb6, unwind continue];
       }
   
       bb6: {
@@ -355,7 +355,7 @@
           StorageLive(_50);
           StorageLive(_51);
           _51 = ();
-          _50 = opaque::<()>(move _51) -> bb7;
+          _50 = opaque::<()>(move _51) -> [return: bb7, unwind continue];
       }
   
       bb7: {
@@ -381,7 +381,7 @@
           StorageLive(_57);
           StorageLive(_58);
           _58 = ();
-          _57 = opaque::<()>(move _58) -> bb8;
+          _57 = opaque::<()>(move _58) -> [return: bb8, unwind continue];
       }
   
       bb8: {
@@ -404,7 +404,7 @@
           StorageLive(_64);
           StorageLive(_65);
           _65 = ();
-          _64 = opaque::<()>(move _65) -> bb9;
+          _64 = opaque::<()>(move _65) -> [return: bb9, unwind continue];
       }
   
       bb9: {
@@ -428,7 +428,7 @@
           StorageLive(_70);
           StorageLive(_71);
           _71 = ();
-          _70 = opaque::<()>(move _71) -> bb10;
+          _70 = opaque::<()>(move _71) -> [return: bb10, unwind continue];
       }
   
       bb10: {
diff --git a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
index 3a317853bdb..05eab7989df 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
@@ -242,7 +242,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = ();
-          _7 = opaque::<()>(move _8) -> bb1;
+          _7 = opaque::<()>(move _8) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -269,7 +269,7 @@
           StorageLive(_15);
           StorageLive(_16);
           _16 = ();
-          _15 = opaque::<()>(move _16) -> bb2;
+          _15 = opaque::<()>(move _16) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -293,7 +293,7 @@
           StorageLive(_22);
           StorageLive(_23);
           _23 = _20;
-          _22 = opaque::<&*const usize>(move _23) -> bb3;
+          _22 = opaque::<&*const usize>(move _23) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -317,7 +317,7 @@
           StorageLive(_29);
           StorageLive(_30);
           _30 = _27;
-          _29 = opaque::<*mut *const usize>(move _30) -> bb4;
+          _29 = opaque::<*mut *const usize>(move _30) -> [return: bb4, unwind continue];
       }
   
       bb4: {
@@ -340,7 +340,7 @@
           StorageLive(_35);
           StorageLive(_36);
           _36 = _33;
-          _35 = opaque::<*const usize>(move _36) -> bb5;
+          _35 = opaque::<*const usize>(move _36) -> [return: bb5, unwind continue];
       }
   
       bb5: {
@@ -369,7 +369,7 @@
           StorageLive(_44);
           StorageLive(_45);
           _45 = _43;
-          _44 = opaque::<*const usize>(move _45) -> bb6;
+          _44 = opaque::<*const usize>(move _45) -> [return: bb6, unwind continue];
       }
   
       bb6: {
@@ -392,7 +392,7 @@
           StorageLive(_49);
           StorageLive(_50);
           _50 = ();
-          _49 = opaque::<()>(move _50) -> bb7;
+          _49 = opaque::<()>(move _50) -> [return: bb7, unwind continue];
       }
   
       bb7: {
@@ -414,7 +414,7 @@
           StorageLive(_55);
           StorageLive(_56);
           _56 = ();
-          _55 = opaque::<()>(move _56) -> bb8;
+          _55 = opaque::<()>(move _56) -> [return: bb8, unwind continue];
       }
   
       bb8: {
@@ -437,7 +437,7 @@
           StorageLive(_62);
           StorageLive(_63);
           _63 = ();
-          _62 = opaque::<()>(move _63) -> bb9;
+          _62 = opaque::<()>(move _63) -> [return: bb9, unwind continue];
       }
   
       bb9: {
@@ -462,7 +462,7 @@
           StorageLive(_69);
           StorageLive(_70);
           _70 = ();
-          _69 = opaque::<()>(move _70) -> bb10;
+          _69 = opaque::<()>(move _70) -> [return: bb10, unwind continue];
       }
   
       bb10: {
@@ -486,7 +486,7 @@
           StorageLive(_75);
           StorageLive(_76);
           _76 = ();
-          _75 = opaque::<()>(move _76) -> bb11;
+          _75 = opaque::<()>(move _76) -> [return: bb11, unwind continue];
       }
   
       bb11: {
diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff
index 91c6b2b6322..ee680fdb3f2 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff
@@ -201,7 +201,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = ();
-          _7 = opaque::<()>(move _8) -> bb1;
+          _7 = opaque::<()>(move _8) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -232,7 +232,7 @@
           StorageLive(_16);
           StorageLive(_17);
           _17 = ();
-          _16 = opaque::<()>(move _17) -> bb2;
+          _16 = opaque::<()>(move _17) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -256,7 +256,7 @@
           StorageLive(_23);
           StorageLive(_24);
           _24 = _21;
-          _23 = opaque::<&&mut usize>(move _24) -> bb3;
+          _23 = opaque::<&&mut usize>(move _24) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -280,7 +280,7 @@
           StorageLive(_30);
           StorageLive(_31);
           _31 = _28;
-          _30 = opaque::<*mut &mut usize>(move _31) -> bb4;
+          _30 = opaque::<*mut &mut usize>(move _31) -> [return: bb4, unwind continue];
       }
   
       bb4: {
@@ -302,7 +302,7 @@
           StorageLive(_36);
           StorageLive(_37);
           _37 = move _34;
-          _36 = opaque::<&mut usize>(move _37) -> bb5;
+          _36 = opaque::<&mut usize>(move _37) -> [return: bb5, unwind continue];
       }
   
       bb5: {
@@ -329,7 +329,7 @@
           StorageLive(_45);
           StorageLive(_46);
           _46 = move _44;
-          _45 = opaque::<&mut usize>(move _46) -> bb6;
+          _45 = opaque::<&mut usize>(move _46) -> [return: bb6, unwind continue];
       }
   
       bb6: {
@@ -352,7 +352,7 @@
           StorageLive(_50);
           StorageLive(_51);
           _51 = ();
-          _50 = opaque::<()>(move _51) -> bb7;
+          _50 = opaque::<()>(move _51) -> [return: bb7, unwind continue];
       }
   
       bb7: {
@@ -378,7 +378,7 @@
           StorageLive(_57);
           StorageLive(_58);
           _58 = ();
-          _57 = opaque::<()>(move _58) -> bb8;
+          _57 = opaque::<()>(move _58) -> [return: bb8, unwind continue];
       }
   
       bb8: {
@@ -401,7 +401,7 @@
           StorageLive(_64);
           StorageLive(_65);
           _65 = ();
-          _64 = opaque::<()>(move _65) -> bb9;
+          _64 = opaque::<()>(move _65) -> [return: bb9, unwind continue];
       }
   
       bb9: {
@@ -425,7 +425,7 @@
           StorageLive(_70);
           StorageLive(_71);
           _71 = ();
-          _70 = opaque::<()>(move _71) -> bb10;
+          _70 = opaque::<()>(move _71) -> [return: bb10, unwind continue];
       }
   
       bb10: {
diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
index 8c669644c48..fb0ef3184f0 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff
@@ -219,7 +219,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = ();
-          _7 = opaque::<()>(move _8) -> bb1;
+          _7 = opaque::<()>(move _8) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -246,7 +246,7 @@
           StorageLive(_15);
           StorageLive(_16);
           _16 = ();
-          _15 = opaque::<()>(move _16) -> bb2;
+          _15 = opaque::<()>(move _16) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -270,7 +270,7 @@
           StorageLive(_22);
           StorageLive(_23);
           _23 = _20;
-          _22 = opaque::<&*mut usize>(move _23) -> bb3;
+          _22 = opaque::<&*mut usize>(move _23) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -294,7 +294,7 @@
           StorageLive(_29);
           StorageLive(_30);
           _30 = _27;
-          _29 = opaque::<*mut *mut usize>(move _30) -> bb4;
+          _29 = opaque::<*mut *mut usize>(move _30) -> [return: bb4, unwind continue];
       }
   
       bb4: {
@@ -316,7 +316,7 @@
           StorageLive(_35);
           StorageLive(_36);
           _36 = _33;
-          _35 = opaque::<*mut usize>(move _36) -> bb5;
+          _35 = opaque::<*mut usize>(move _36) -> [return: bb5, unwind continue];
       }
   
       bb5: {
@@ -343,7 +343,7 @@
           StorageLive(_44);
           StorageLive(_45);
           _45 = _43;
-          _44 = opaque::<*mut usize>(move _45) -> bb6;
+          _44 = opaque::<*mut usize>(move _45) -> [return: bb6, unwind continue];
       }
   
       bb6: {
@@ -366,7 +366,7 @@
           StorageLive(_49);
           StorageLive(_50);
           _50 = ();
-          _49 = opaque::<()>(move _50) -> bb7;
+          _49 = opaque::<()>(move _50) -> [return: bb7, unwind continue];
       }
   
       bb7: {
@@ -388,7 +388,7 @@
           StorageLive(_55);
           StorageLive(_56);
           _56 = ();
-          _55 = opaque::<()>(move _56) -> bb8;
+          _55 = opaque::<()>(move _56) -> [return: bb8, unwind continue];
       }
   
       bb8: {
@@ -411,7 +411,7 @@
           StorageLive(_62);
           StorageLive(_63);
           _63 = ();
-          _62 = opaque::<()>(move _63) -> bb9;
+          _62 = opaque::<()>(move _63) -> [return: bb9, unwind continue];
       }
   
       bb9: {
@@ -435,7 +435,7 @@
           StorageLive(_68);
           StorageLive(_69);
           _69 = ();
-          _68 = opaque::<()>(move _69) -> bb10;
+          _68 = opaque::<()>(move _69) -> [return: bb10, unwind continue];
       }
   
       bb10: {
diff --git a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
index b4c34c07022..b4912a918ba 100644
--- a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff
@@ -34,7 +34,7 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = (*_3);
-          _4 = opaque::<i32>(move _5) -> bb1;
+          _4 = opaque::<i32>(move _5) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -47,7 +47,7 @@
           StorageLive(_7);
 -         _7 = (*_1);
 +         _7 = (*_3);
-          _6 = opaque::<i32>(move _7) -> bb2;
+          _6 = opaque::<i32>(move _7) -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.panic-unwind.diff b/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.panic-unwind.diff
index d7f867e31dd..faaebc300ef 100644
--- a/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.panic-unwind.diff
+++ b/tests/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.panic-unwind.diff
@@ -32,7 +32,7 @@
 -         StorageLive(_2);
 -         StorageLive(_3);
           _3 = std::ops::Range::<i32> { start: const 0_i32, end: const 10_i32 };
-          _2 = <std::ops::Range<i32> as IntoIterator>::into_iter(move _3) -> bb1;
+          _2 = <std::ops::Range<i32> as IntoIterator>::into_iter(move _3) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -49,7 +49,7 @@
 -         StorageLive(_9);
           _9 = &mut _4;
           _8 = &mut (*_9);
-          _7 = <std::ops::Range<i32> as Iterator>::next(move _8) -> bb3;
+          _7 = <std::ops::Range<i32> as Iterator>::next(move _8) -> [return: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff
index 8cb773e4807..a335e8853f3 100644
--- a/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff
+++ b/tests/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.panic-unwind.diff
@@ -14,7 +14,7 @@
 -         nop;
           StorageLive(_3);
           _3 = _1;
--         drop(_3) -> bb1;
+-         drop(_3) -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff
index d189e587982..1f7a6f9ad59 100644
--- a/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff
+++ b/tests/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.panic-unwind.diff
@@ -14,7 +14,7 @@
 -         nop;
           StorageLive(_3);
           _3 = _1;
--         drop(_3) -> bb1;
+-         drop(_3) -> [return: bb1, unwind continue];
 -     }
 - 
 -     bb1: {
diff --git a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
index 18eb21d6542..93f14af29b4 100644
--- a/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
@@ -76,7 +76,7 @@ fn array_casts() -> () {
         StorageLive(_6);
         StorageLive(_7);
         _7 = _2;
-        _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> bb1;
+        _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> [return: bb1, unwind continue];
     }
 
     bb1: {
@@ -102,7 +102,7 @@ fn array_casts() -> () {
         StorageLive(_16);
         StorageLive(_17);
         _17 = _9;
-        _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> bb2;
+        _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> [return: bb2, unwind continue];
     }
 
     bb2: {
@@ -154,7 +154,7 @@ fn array_casts() -> () {
         StorageLive(_34);
         _34 = Option::<Arguments<'_>>::None;
         Retag(_34);
-        _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34);
+        _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34) -> unwind continue;
     }
 
     bb4: {
diff --git a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir
index 96d2abf98b4..70c53bafa37 100644
--- a/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.panic-unwind.mir
@@ -10,7 +10,7 @@ fn std::ptr::drop_in_place(_1: *mut Test) -> () {
         _2 = &mut (*_1);
         Retag([fn entry] _2);
         _3 = &mut (*_2);
-        _4 = <Test as Drop>::drop(move _3) -> bb1;
+        _4 = <Test as Drop>::drop(move _3) -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
index 483485f2942..45034946328 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir
@@ -114,7 +114,7 @@ fn main() -> () {
         StorageLive(_18);
         _18 = &_1;
         _17 = &(*_18);
-        _15 = move _16(move _17) -> bb3;
+        _15 = move _16(move _17) -> [return: bb3, unwind continue];
     }
 
     bb3: {
@@ -153,7 +153,7 @@ fn main() -> () {
         _25 = _26;
         StorageDead(_26);
         StorageLive(_27);
-        _27 = array_casts() -> bb6;
+        _27 = array_casts() -> [return: bb6, unwind continue];
     }
 
     bb6: {
diff --git a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
index 2a841f72ba3..81903c64dbd 100644
--- a/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
+++ b/tests/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.panic-unwind.diff
@@ -14,7 +14,7 @@
       }
   
       bb1: {
-          _2 = noop() -> bb2;
+          _2 = noop() -> [return: bb2, unwind continue];
       }
   
       bb2: {
diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff
index ef3a923fd69..ba5262b0ee1 100644
--- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff
+++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff
@@ -39,7 +39,7 @@
       }
   
       bb3: {
-          drop(_1) -> bb4;
+          drop(_1) -> [return: bb4, unwind continue];
       }
   
       bb4: {
diff --git a/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.panic-unwind.diff b/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.panic-unwind.diff
index dca51602021..a5d9bbc49af 100644
--- a/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.panic-unwind.diff
+++ b/tests/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals-before-const-prop.panic-unwind.diff
@@ -36,7 +36,7 @@
 +         _2 = (move _3, move _4);
 +         StorageDead(_4);
           StorageDead(_3);
-+         _1 = use_zst(move _2) -> bb1;
++         _1 = use_zst(move _2) -> [return: bb1, unwind continue];
 +     }
 + 
 +     bb1: {
@@ -55,8 +55,8 @@
 +         _6 = Add(move _7, const 2_u8);
           StorageDead(_7);
 -         StorageDead(_6);
--         _4 = use_zst(move _5) -> bb1;
-+         _5 = use_u8(move _6) -> bb2;
+-         _4 = use_zst(move _5) -> [return: bb1, unwind continue];
++         _5 = use_u8(move _6) -> [return: bb2, unwind continue];
       }
   
 -     bb1: {
@@ -70,7 +70,7 @@
 -         _10 = (_11.0: u8);
 -         _9 = Add(move _10, const 2_u8);
 -         StorageDead(_10);
--         _8 = use_u8(move _9) -> bb2;
+-         _8 = use_u8(move _9) -> [return: bb2, unwind continue];
 -     }
 - 
       bb2: {
diff --git a/tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff b/tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff
index dc2f75ec9b2..c881dec28c7 100644
--- a/tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff
+++ b/tests/mir-opt/simplify_match.main.ConstProp.panic-unwind.diff
@@ -20,7 +20,7 @@
       }
   
       bb2: {
-          _0 = noop() -> bb3;
+          _0 = noop() -> [return: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff b/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff
index 19ea846bf2c..906dce9819f 100644
--- a/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff
+++ b/tests/mir-opt/unreachable.main.UnreachablePropagation.panic-unwind.diff
@@ -19,7 +19,7 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = empty() -> bb1;
+          _1 = empty() -> [return: bb1, unwind continue];
       }
   
       bb1: {
diff --git a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff
index 9d54a2f234b..a0479fb9130 100644
--- a/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff
+++ b/tests/mir-opt/unreachable_diverging.main.UnreachablePropagation.panic-unwind.diff
@@ -21,7 +21,7 @@
           StorageLive(_1);
           _1 = const true;
           StorageLive(_2);
-          _2 = empty() -> bb1;
+          _2 = empty() -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -39,7 +39,7 @@
       }
   
       bb3: {
-          _5 = loop_forever() -> bb5;
+          _5 = loop_forever() -> [return: bb5, unwind continue];
       }
   
       bb4: {
diff --git a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir
index ec4782e5f3c..7dc4f7ab1a8 100644
--- a/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/while_storage.while_loop.PreCodegen.after.panic-unwind.mir
@@ -12,7 +12,7 @@ fn while_loop(_1: bool) -> () {
 
     bb1: {
         StorageLive(_2);
-        _2 = get_bool(_1) -> bb2;
+        _2 = get_bool(_1) -> [return: bb2, unwind continue];
     }
 
     bb2: {
@@ -21,7 +21,7 @@ fn while_loop(_1: bool) -> () {
 
     bb3: {
         StorageLive(_3);
-        _3 = get_bool(_1) -> bb4;
+        _3 = get_bool(_1) -> [return: bb4, unwind continue];
     }
 
     bb4: {
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index b59a65a713f..04c551cf4bb 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -27,7 +27,7 @@ use rustc_interface::{Config, Queries};
 use rustc_middle::query::queries::mir_borrowck::ProvidedValue;
 use rustc_middle::query::{ExternProviders, Providers};
 use rustc_middle::ty::TyCtxt;
-use rustc_session::Session;
+use rustc_session::{Session, EarlyErrorHandler};
 use std::cell::RefCell;
 use std::collections::HashMap;
 use std::thread_local;
@@ -58,6 +58,7 @@ impl rustc_driver::Callbacks for CompilerCalls {
     // the result.
     fn after_analysis<'tcx>(
         &mut self,
+        _handler: &EarlyErrorHandler,
         compiler: &Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/tests/run-make/const_fn_mir/dump.mir b/tests/run-make/const_fn_mir/dump.mir
index 25ac0c7e852..ced170bbeee 100644
--- a/tests/run-make/const_fn_mir/dump.mir
+++ b/tests/run-make/const_fn_mir/dump.mir
@@ -6,7 +6,7 @@ fn foo() -> i32 {
 
     bb0: {
         _1 = CheckedAdd(const 5_i32, const 6_i32);
-        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> bb1;
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> [success: bb1, unwind continue];
     }
 
     bb1: {
@@ -22,7 +22,7 @@ fn foo() -> i32 {
 
     bb0: {
         _1 = CheckedAdd(const 5_i32, const 6_i32);
-        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> bb1;
+        assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> [success: bb1, unwind continue];
     }
 
     bb1: {
@@ -36,7 +36,7 @@ fn main() -> () {
     let _1: i32;
 
     bb0: {
-        _1 = foo() -> bb1;
+        _1 = foo() -> [return: bb1, unwind continue];
     }
 
     bb1: {
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index 4c36394a30c..a50449e1701 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -37,15 +37,15 @@ define-function: (
 )
 call-function: ("check-colors", {
     "theme": "ayu",
-    "color": "rgb(92, 103, 115)",
+    "color": "#5c6773",
 })
 call-function: ("check-colors", {
     "theme": "dark",
-    "color": "rgb(59, 145, 226)",
+    "color": "#3b91e2",
 })
 call-function: ("check-colors", {
     "theme": "light",
-    "color": "rgb(198, 126, 45)",
+    "color": "#c67e2d",
 })
 
 // The first code block has two lines so let's check its `<pre>` elements lists both of them.
diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml
index afb3a44be30..6593c1a9c45 100644
--- a/tests/rustdoc-gui/search-result-display.goml
+++ b/tests/rustdoc-gui/search-result-display.goml
@@ -14,7 +14,8 @@ set-window-size: (600, 100)
 assert-size: (".search-results div.desc", {"width": 566})
 
 // The result set is all on one line.
-assert-css: (".search-results .result-name > span", {"display": "inline"})
+assert-css: (".search-results .result-name > span:not(.typename)", {"display": "inline"})
+assert-css: (".search-results .result-name > span.typename", {"display": "inline-block"})
 
 // Check that the crate filter `<select>` is correctly handled when it goes to next line.
 // To do so we need to update the length of one of its `<option>`.
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index c37d969324c..e40c637dcf7 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -56,19 +56,19 @@ move-cursor-to: "#settings-menu > a"
 assert-css: (
     "#theme-dark",
     {
-        "border-color": "rgb(153, 153, 153)",
-        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+        "border-color": "#999",
+        "box-shadow": "#353535 0px 0px 0px 3px inset",
         "border-width": "2px",
     },
 )
-assert-css: ("#theme-light", {"border-color": "rgb(153, 153, 153)", "box-shadow": "none"})
+assert-css: ("#theme-light", {"border-color": "#999", "box-shadow": "none"})
 // Let's start with the hover for radio buttons.
 move-cursor-to: "#theme-dark"
 assert-css: (
     "#theme-dark",
     {
-        "border-color": "rgb(33, 150, 243)",
-        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset",
+        "border-color": "#2196f3",
+        "box-shadow": "#353535 0px 0px 0px 3px inset",
         "border-width": "2px",
     },
 )
@@ -76,7 +76,7 @@ move-cursor-to: "#theme-light"
 assert-css: (
     "#theme-light",
     {
-        "border-color": "rgb(33, 150, 243)",
+        "border-color": "#2196f3",
         "box-shadow": "none",
         "border-width": "2px",
     }
@@ -87,8 +87,8 @@ focus: "#theme-dark"
 assert-css: (
     "#theme-dark",
     {
-        "border-color": "rgb(153, 153, 153)",
-        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+        "border-color": "#999",
+        "box-shadow": "#353535 0px 0px 0px 3px inset, #2196f3 0px 0px 2px 2px",
         "border-width": "2px",
     },
 )
@@ -96,8 +96,8 @@ focus: "#theme-light"
 assert-css: (
     "#theme-light",
     {
-        "border-color": "rgb(153, 153, 153)",
-        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+        "border-color": "#999",
+        "box-shadow": "#2196f3 0px 0px 1px 1px",
         "border-width": "2px",
     },
 )
@@ -107,8 +107,8 @@ focus: "#theme-dark"
 assert-css: (
     "#theme-dark",
     {
-        "border-color": "rgb(33, 150, 243)",
-        "box-shadow": "rgb(53, 53, 53) 0px 0px 0px 3px inset, rgb(33, 150, 243) 0px 0px 2px 2px",
+        "border-color": "#2196f3",
+        "box-shadow": "#353535 0px 0px 0px 3px inset, #2196f3 0px 0px 2px 2px",
         "border-width": "2px",
     },
 )
@@ -117,8 +117,8 @@ focus: "#theme-light"
 assert-css: (
     "#theme-light",
     {
-        "border-color": "rgb(33, 150, 243)",
-        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+        "border-color": "#2196f3",
+        "box-shadow": "#2196f3 0px 0px 1px 1px",
         "border-width": "2px",
     },
 )
@@ -154,8 +154,8 @@ compare-elements-position-near: (
 assert-css: (
     "#auto-hide-large-items",
     {
-        "background-color": "rgb(33, 150, 243)",
-        "border-color": "rgb(153, 153, 153)",
+        "background-color": "#2196f3",
+        "border-color": "#999",
         // 1px border when checked
         "border-width": "1px",
     },
@@ -164,7 +164,7 @@ assert-css: (
     "#auto-hide-method-docs",
     {
         "background-color": "rgba(0, 0, 0, 0)",
-        "border-color": "rgb(153, 153, 153)",
+        "border-color": "#999",
         // 2px border when unchecked
         "border-width": "2px",
     },
@@ -174,8 +174,8 @@ move-cursor-to: "#auto-hide-large-items"
 assert-css: (
     "#auto-hide-large-items",
     {
-        "background-color": "rgb(33, 150, 243)",
-        "border-color": "rgb(33, 150, 243)",
+        "background-color": "#2196f3",
+        "border-color": "#2196f3",
         // 1px border when checked
         "border-width": "1px",
     },
@@ -185,7 +185,7 @@ assert-css: (
     "#auto-hide-method-docs",
     {
         "background-color": "rgba(0, 0, 0, 0)",
-        "border-color": "rgb(33, 150, 243)",
+        "border-color": "#2196f3",
         // 2px border when unchecked
         "border-width": "2px",
     },
@@ -196,9 +196,9 @@ focus: "#auto-hide-large-items"
 assert-css: (
     "#auto-hide-large-items",
     {
-        "background-color": "rgb(33, 150, 243)",
-        "border-color": "rgb(153, 153, 153)",
-        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+        "background-color": "#2196f3",
+        "border-color": "#999",
+        "box-shadow": "#2196f3 0px 0px 1px 1px",
         // 1px border when checked
         "border-width": "1px",
     },
@@ -208,8 +208,8 @@ assert-css: (
     "#auto-hide-method-docs",
     {
         "background-color": "rgba(0, 0, 0, 0)",
-        "border-color": "rgb(153, 153, 153)",
-        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+        "border-color": "#999",
+        "box-shadow": "#2196f3 0px 0px 1px 1px",
         // 2px border when unchecked
         "border-width": "2px",
     },
@@ -220,9 +220,9 @@ focus: "#auto-hide-large-items"
 assert-css: (
     "#auto-hide-large-items",
     {
-        "background-color": "rgb(33, 150, 243)",
-        "border-color": "rgb(33, 150, 243)",
-        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+        "background-color": "#2196f3",
+        "border-color": "#2196f3",
+        "box-shadow": "#2196f3 0px 0px 1px 1px",
         // 1px border when checked
         "border-width": "1px",
     },
@@ -233,8 +233,8 @@ assert-css: (
     "#auto-hide-method-docs",
     {
         "background-color": "rgba(0, 0, 0, 0)",
-        "border-color": "rgb(33, 150, 243)",
-        "box-shadow": "rgb(33, 150, 243) 0px 0px 1px 1px",
+        "border-color": "#2196f3",
+        "box-shadow": "#2196f3 0px 0px 1px 1px",
         // 2px border when unchecked
         "border-width": "2px",
     },
diff --git a/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html b/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html
new file mode 100644
index 00000000000..29c08c5bd5d
--- /dev/null
+++ b/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html
@@ -0,0 +1,2 @@
+<pre class="rust item-decl"><code>pub fn create(
+) -&gt; <a class="struct" href="struct.Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000.html" title="struct decl_line_wrapping_empty_arg_list::Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000">Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000</a></code></pre>
\ No newline at end of file
diff --git a/tests/rustdoc/decl-line-wrapping-empty-arg-list.rs b/tests/rustdoc/decl-line-wrapping-empty-arg-list.rs
new file mode 100644
index 00000000000..4cfb87496b4
--- /dev/null
+++ b/tests/rustdoc/decl-line-wrapping-empty-arg-list.rs
@@ -0,0 +1,12 @@
+// Ensure that we don't add an extra line containing nothing but whitespace in between the two
+// parentheses of an empty argument list when line-wrapping a function declaration.
+
+// ignore-tidy-linelength
+
+pub struct Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+
+// @has 'decl_line_wrapping_empty_arg_list/fn.create.html'
+// @snapshot decl - '//pre[@class="rust item-decl"]'
+pub fn create() -> Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000 {
+    loop {}
+}
diff --git a/tests/rustdoc/inline_cross/assoc-const-equality.rs b/tests/rustdoc/inline_cross/assoc-const-equality.rs
new file mode 100644
index 00000000000..1d3ce9e3172
--- /dev/null
+++ b/tests/rustdoc/inline_cross/assoc-const-equality.rs
@@ -0,0 +1,8 @@
+// aux-crate:assoc_const_equality=assoc-const-equality.rs
+// edition:2021
+
+#![crate_name = "user"]
+
+// @has user/fn.accept.html
+// @has - '//pre[@class="rust item-decl"]' 'fn accept(_: impl Trait<K = 0>)'
+pub use assoc_const_equality::accept;
diff --git a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs b/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs
index db2491b87b4..74ceb697af6 100644
--- a/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs
+++ b/tests/rustdoc/inline_cross/assoc_item_trait_bounds.rs
@@ -42,3 +42,15 @@ pub use aux::Main;
 // @has main/trait.Aid.html
 // @has - '//*[@id="associatedtype.Result"]' "type Result<'inter: 'src>"
 pub use aux::Aid;
+
+// Below, ensure that we correctly display generic parameters and where-clauses on
+// associated types inside trait *impls*. More particularly, check that we don't render
+// any bounds (here `Self::Alias<T>: ...`) as item bounds unlike all the trait test cases above.
+
+// @has main/struct.Implementor.html
+// @has - '//*[@id="associatedtype.Alias"]' \
+// "type Alias<T: Eq> = T \
+// where \
+//     String: From<T>, \
+//     <Implementor as Implementee>::Alias<T>: From<<Implementor as Implementee>::Alias<T>>"
+pub use aux::Implementor;
diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs b/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs
new file mode 100644
index 00000000000..6a25dcea62e
--- /dev/null
+++ b/tests/rustdoc/inline_cross/auxiliary/assoc-const-equality.rs
@@ -0,0 +1,7 @@
+#![feature(associated_const_equality)]
+
+pub fn accept(_: impl Trait<K = 0>) {}
+
+pub trait Trait {
+    const K: i32;
+}
diff --git a/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs b/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
index 6644c8e4147..551e97a2fa9 100644
--- a/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
+++ b/tests/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs
@@ -44,3 +44,20 @@ pub trait Helper {
 pub trait Aid<'src> {
     type Result<'inter: 'src>;
 }
+
+pub trait Implementee {
+    type Alias<T: Eq>
+    where
+        String: From<T>;
+}
+
+pub struct Implementor;
+
+impl Implementee for Implementor {
+    type Alias<T: Eq> = T
+    where
+        String: From<T>,
+        // We will check that this bound doesn't get turned into an item bound since
+        // associated types in impls are not allowed to have any.
+        Self::Alias<T>: From<Self::Alias<T>>;
+}
diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs
index 1e4216d3c0c..e9d243d8abf 100644
--- a/tests/rustdoc/reexport-doc-hidden-inside-private.rs
+++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs
@@ -1,4 +1,4 @@
-// This test ensures that a re-export of  `#[doc(hidden)]` item inside a private
+// This test ensures that a re-export of `#[doc(hidden)]` item inside a private
 // module will still be displayed (the re-export, not the item).
 
 #![crate_name = "foo"]
diff --git a/tests/ui-fulldeps/session-diagnostic/example.ftl b/tests/ui-fulldeps/session-diagnostic/example.ftl
index cb2d476d815..1d1ba8e1bd5 100644
--- a/tests/ui-fulldeps/session-diagnostic/example.ftl
+++ b/tests/ui-fulldeps/session-diagnostic/example.ftl
@@ -3,3 +3,5 @@ no_crate_example = this is an example message used in testing
     .help = with a help
     .suggestion = with a suggestion
     .label = with a label
+
+no_crate_bad_reference = {$r} does not exist
diff --git a/tests/ui-fulldeps/session-diagnostic/invalid-variable.rs b/tests/ui-fulldeps/session-diagnostic/invalid-variable.rs
new file mode 100644
index 00000000000..57798dda3eb
--- /dev/null
+++ b/tests/ui-fulldeps/session-diagnostic/invalid-variable.rs
@@ -0,0 +1,21 @@
+// run-fail
+// compile-flags: --test
+// test that messages referencing non-existent fields cause test failures
+
+#![feature(rustc_private)]
+#![crate_type = "lib"]
+
+extern crate rustc_driver;
+extern crate rustc_fluent_macro;
+extern crate rustc_macros;
+extern crate rustc_errors;
+use rustc_fluent_macro::fluent_messages;
+use rustc_macros::Diagnostic;
+use rustc_errors::{SubdiagnosticMessage, DiagnosticMessage};
+extern crate rustc_session;
+
+fluent_messages! { "./example.ftl" }
+
+#[derive(Diagnostic)]
+#[diag(no_crate_bad_reference)]
+struct BadRef;
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index a3db2e9ef24..9ef208a14b2 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -12,12 +12,14 @@ extern crate rustc_driver;
 extern crate rustc_hir;
 extern crate rustc_interface;
 extern crate rustc_middle;
+extern crate rustc_session;
 extern crate rustc_smir;
 
 use rustc_driver::{Callbacks, Compilation, RunCompiler};
 use rustc_hir::def::DefKind;
 use rustc_interface::{interface, Queries};
 use rustc_middle::ty::TyCtxt;
+use rustc_session::EarlyErrorHandler;
 use rustc_smir::{rustc_internal, stable_mir};
 use std::io::Write;
 
@@ -121,6 +123,7 @@ impl Callbacks for SMirCalls {
     /// continue the compilation afterwards (defaults to `Compilation::Continue`)
     fn after_analysis<'tcx>(
         &mut self,
+        _handler: &EarlyErrorHandler,
         _compiler: &interface::Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
diff --git a/tests/ui/associated-consts/issue-110933.rs b/tests/ui/associated-consts/issue-110933.rs
new file mode 100644
index 00000000000..aa4882ae535
--- /dev/null
+++ b/tests/ui/associated-consts/issue-110933.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(associated_const_equality)]
+
+pub trait Trait {
+    const ASSOC: usize;
+}
+
+pub fn foo<
+    T: Trait<
+        ASSOC = {
+                    let a = 10_usize;
+                    let b: &'_ usize = &a;
+                    *b
+                },
+    >,
+>() {
+}
+
+fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr
new file mode 100644
index 00000000000..8b6a8206569
--- /dev/null
+++ b/tests/ui/associated-inherent-types/issue-109071.no_gate.stderr
@@ -0,0 +1,35 @@
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/issue-109071.rs:8:17
+   |
+LL |     type Item = &[T];
+   |                 ^ explicit lifetime name needed here
+
+error[E0107]: missing generics for struct `Windows`
+  --> $DIR/issue-109071.rs:7:9
+   |
+LL | impl<T> Windows {
+   |         ^^^^^^^ expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-109071.rs:5:8
+   |
+LL | struct Windows<T> {}
+   |        ^^^^^^^ -
+help: add missing generic argument
+   |
+LL | impl<T> Windows<T> {
+   |                +++
+
+error[E0658]: inherent associated types are unstable
+  --> $DIR/issue-109071.rs:8:5
+   |
+LL |     type Item = &[T];
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information
+   = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0107, E0637, E0658.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/associated-inherent-types/issue-109071.rs b/tests/ui/associated-inherent-types/issue-109071.rs
new file mode 100644
index 00000000000..73b969d5940
--- /dev/null
+++ b/tests/ui/associated-inherent-types/issue-109071.rs
@@ -0,0 +1,18 @@
+// revisions: with_gate no_gate
+#![cfg_attr(with_gate, feature(inherent_associated_types))]
+#![cfg_attr(with_gate, allow(incomplete_features))]
+
+struct Windows<T> {}
+
+impl<T> Windows { //~ ERROR: missing generics for struct `Windows`
+    type Item = &[T]; //~ ERROR: `&` without an explicit lifetime name cannot be used here
+    //[no_gate]~^ ERROR: inherent associated types are unstable
+
+    fn next() -> Option<Self::Item> {}
+}
+
+impl<T> Windows<T> {
+    fn T() -> Option<Self::Item> {}
+}
+
+fn main() {}
diff --git a/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr
new file mode 100644
index 00000000000..a91bb7a5162
--- /dev/null
+++ b/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr
@@ -0,0 +1,26 @@
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+  --> $DIR/issue-109071.rs:8:17
+   |
+LL |     type Item = &[T];
+   |                 ^ explicit lifetime name needed here
+
+error[E0107]: missing generics for struct `Windows`
+  --> $DIR/issue-109071.rs:7:9
+   |
+LL | impl<T> Windows {
+   |         ^^^^^^^ expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/issue-109071.rs:5:8
+   |
+LL | struct Windows<T> {}
+   |        ^^^^^^^ -
+help: add missing generic argument
+   |
+LL | impl<T> Windows<T> {
+   |                +++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0107, E0637.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs
index 1d43d6ba02f..b9548e91183 100644
--- a/tests/ui/cfg/diagnostics-reexport.rs
+++ b/tests/ui/cfg/diagnostics-reexport.rs
@@ -9,6 +9,30 @@ pub mod inner {
     //~^ NOTE found an item that was configured out
 }
 
+pub use a::x;
+//~^ ERROR unresolved import `a::x`
+//~| NOTE no `x` in `a`
+
+mod a {
+    #[cfg(no)]
+    pub fn x() {}
+    //~^ NOTE found an item that was configured out
+}
+
+pub use b::{x, y};
+//~^ ERROR unresolved imports `b::x`, `b::y`
+//~| NOTE no `x` in `b`
+//~| NOTE no `y` in `b`
+
+mod b {
+    #[cfg(no)]
+    pub fn x() {}
+    //~^ NOTE found an item that was configured out
+    #[cfg(no)]
+    pub fn y() {}
+    //~^ NOTE found an item that was configured out
+}
+
 fn main() {
     // There is no uwu at this path - no diagnostic.
     inner::uwu(); //~ ERROR cannot find function
diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr
index 6c977cbfa41..e25b7cf86e2 100644
--- a/tests/ui/cfg/diagnostics-reexport.stderr
+++ b/tests/ui/cfg/diagnostics-reexport.stderr
@@ -1,5 +1,36 @@
+error[E0432]: unresolved import `a::x`
+  --> $DIR/diagnostics-reexport.rs:12:9
+   |
+LL | pub use a::x;
+   |         ^^^^ no `x` in `a`
+   |
+note: found an item that was configured out
+  --> $DIR/diagnostics-reexport.rs:18:12
+   |
+LL |     pub fn x() {}
+   |            ^
+
+error[E0432]: unresolved imports `b::x`, `b::y`
+  --> $DIR/diagnostics-reexport.rs:22:13
+   |
+LL | pub use b::{x, y};
+   |             ^  ^ no `y` in `b`
+   |             |
+   |             no `x` in `b`
+   |
+note: found an item that was configured out
+  --> $DIR/diagnostics-reexport.rs:29:12
+   |
+LL |     pub fn x() {}
+   |            ^
+note: found an item that was configured out
+  --> $DIR/diagnostics-reexport.rs:32:12
+   |
+LL |     pub fn y() {}
+   |            ^
+
 error[E0425]: cannot find function `uwu` in module `inner`
-  --> $DIR/diagnostics-reexport.rs:14:12
+  --> $DIR/diagnostics-reexport.rs:38:12
    |
 LL |     inner::uwu();
    |            ^^^ not found in `inner`
@@ -10,6 +41,7 @@ note: found an item that was configured out
 LL |     pub use super::uwu;
    |                    ^^^
 
-error: aborting due to previous error
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0425`.
+Some errors have detailed explanations: E0425, E0432.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/codegen/subtyping-impacts-selection-1.rs b/tests/ui/codegen/subtyping-impacts-selection-1.rs
new file mode 100644
index 00000000000..09e06f6d684
--- /dev/null
+++ b/tests/ui/codegen/subtyping-impacts-selection-1.rs
@@ -0,0 +1,44 @@
+// run-pass
+// revisions: mir codegen
+//[mir] compile-flags: -Zmir-opt-level=3
+//[codegen] compile-flags: -Zmir-opt-level=0
+
+// A regression test for #107205
+#![allow(coherence_leak_check)]
+struct Foo<T: 'static>(T);
+
+fn useful<'a>(_: &'a u8) {}
+
+trait GetInner {
+    type Assoc;
+    fn muahaha(&mut self) -> Self::Assoc;
+}
+
+impl GetInner for Foo<fn(&'static u8)> {
+    type Assoc = String;
+    fn muahaha(&mut self) -> String {
+        String::from("I am a string")
+    }
+}
+
+impl GetInner for Foo<for<'a> fn(&'a u8)> {
+    type Assoc = [usize; 3];
+    fn muahaha(&mut self) -> [usize; 3] {
+        [100; 3]
+    }
+}
+
+fn break_me(hr_fnptr: Box<Foo::<for<'a> fn(&'a u8)>>) -> Box<dyn GetInner<Assoc = String>> {
+    let lr_fnptr = hr_fnptr as Box<Foo<fn(&'static u8)>>;
+    lr_fnptr as Box<dyn GetInner<Assoc = String>>
+}
+
+fn main() {
+    drop(Box::new(Foo(useful as fn(&'static u8))) as Box<dyn GetInner<Assoc = String>>);
+    drop(Box::new(Foo(useful as fn(&u8))) as Box<dyn GetInner<Assoc = [usize; 3]>>);
+
+    let mut any = break_me(Box::new(Foo(useful)));
+
+    let evil_string = any.muahaha();
+    assert_eq!(evil_string, "I am a string");
+}
diff --git a/tests/ui/codegen/subtyping-impacts-selection-2.rs b/tests/ui/codegen/subtyping-impacts-selection-2.rs
new file mode 100644
index 00000000000..921136775b7
--- /dev/null
+++ b/tests/ui/codegen/subtyping-impacts-selection-2.rs
@@ -0,0 +1,12 @@
+// run-pass
+// revisions: mir codegen
+//[mir] compile-flags: -Zmir-opt-level=3
+//[codegen] compile-flags: -Zmir-opt-level=0
+
+// A regression test for #107205
+
+const X: for<'b> fn(&'b ()) = |&()| ();
+fn main() {
+    let dyn_debug = Box::new(X) as Box<fn(&'static ())> as Box<dyn Send>;
+    drop(dyn_debug)
+}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-109141.rs b/tests/ui/const-generics/generic_const_exprs/issue-109141.rs
new file mode 100644
index 00000000000..148c3bda8d2
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/issue-109141.rs
@@ -0,0 +1,13 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+impl EntriesBuffer {
+    fn a(&self) -> impl Iterator {
+        self.0.iter_mut() //~ ERROR: cannot borrow `*self.0` as mutable, as it is behind a `&` reference
+    }
+}
+
+struct EntriesBuffer(Box<[[u8; HashesEntryLEN]; 5]>);
+//~^ ERROR: cannot find value `HashesEntryLEN` in this scope
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr
new file mode 100644
index 00000000000..f61edd60e3b
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/issue-109141.stderr
@@ -0,0 +1,26 @@
+error[E0425]: cannot find value `HashesEntryLEN` in this scope
+  --> $DIR/issue-109141.rs:10:32
+   |
+LL | struct EntriesBuffer(Box<[[u8; HashesEntryLEN]; 5]>);
+   |                                ^^^^^^^^^^^^^^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL | struct EntriesBuffer<const HashesEntryLEN: /* Type */>(Box<[[u8; HashesEntryLEN]; 5]>);
+   |                     ++++++++++++++++++++++++++++++++++
+
+error[E0596]: cannot borrow `*self.0` as mutable, as it is behind a `&` reference
+  --> $DIR/issue-109141.rs:6:9
+   |
+LL |         self.0.iter_mut()
+   |         ^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
+   |
+help: consider changing this to be a mutable reference
+   |
+LL |     fn a(&mut self) -> impl Iterator {
+   |          ~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0425, E0596.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-96699.rs b/tests/ui/const-generics/generic_const_exprs/issue-96699.rs
new file mode 100644
index 00000000000..83f329d2a2d
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/issue-96699.rs
@@ -0,0 +1,87 @@
+// check-pass
+
+#![allow(dead_code, incomplete_features)]
+#![feature(generic_const_exprs)]
+
+const fn min(a: usize, b: usize) -> usize {
+    if a < b {
+        a
+    } else {
+        b
+    }
+}
+
+trait Trait1<Inner1>
+where
+    Self: Sized,
+{
+    fn crash_here()
+    where
+        Inner1: Default,
+    {
+        Inner1::default();
+    }
+}
+
+struct Struct1<T>(T);
+impl<T> Trait1<T> for Struct1<T> {}
+
+trait Trait2<Inner2>
+where
+    Self: Sized,
+{
+    type Assoc: Trait1<Inner2>;
+
+    fn call_crash()
+    where
+        Inner2: Default,
+    {
+        // if Inner2 implements Default, we can call crash_here.
+        Self::Assoc::crash_here();
+    }
+}
+
+struct Struct2<const SIZE1: usize, const SIZE2: usize> {}
+/*
+where
+    [(); min(SIZE1, SIZE2)]:,
+{
+    elem: [i32; min(SIZE1, SIZE2)],
+}
+*/
+
+impl<const SIZE1: usize, const SIZE2: usize> Trait2<[i32; min(SIZE1, SIZE2)]>
+    for Struct2<SIZE1, SIZE2>
+{
+    type Assoc = Struct1<[i32; min(SIZE1, SIZE2)]>;
+    // dose Struct1<[i32; min(SIZE1, SIZE2)]> implement Default?
+}
+
+fn main() {
+    pattern2();
+
+    print_fully_name(<Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here);
+    // <compiler_bug2::Struct1<[i32; 1]> as compiler_bug2::Trait1<[i32; 1]>>::crash_here
+}
+
+fn pattern1() {
+    // no crash
+    <Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here();
+    <Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::call_crash();
+}
+
+fn pattern2() {
+    // crash
+    <Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::call_crash();
+
+    // undefined reference to `compiler_bug2::Trait1::crash_here'
+}
+
+fn pattern3() {
+    // no crash
+    <Struct2<1, 2> as Trait2<[i32; min(1, 2)]>>::Assoc::crash_here();
+}
+
+fn print_fully_name<T>(_: T) {
+    let _ = std::any::type_name::<T>();
+}
diff --git a/tests/ui/explicit-tail-calls/become-outside.array.stderr b/tests/ui/explicit-tail-calls/become-outside.array.stderr
new file mode 100644
index 00000000000..839c20509fe
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/become-outside.array.stderr
@@ -0,0 +1,9 @@
+error[E0572]: become statement outside of function body
+  --> $DIR/become-outside.rs:11:17
+   |
+LL | struct Bad([(); become f()]);
+   |                 ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0572`.
diff --git a/tests/ui/explicit-tail-calls/become-outside.constant.stderr b/tests/ui/explicit-tail-calls/become-outside.constant.stderr
new file mode 100644
index 00000000000..9b67f08af3a
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/become-outside.constant.stderr
@@ -0,0 +1,9 @@
+error[E0572]: become statement outside of function body
+  --> $DIR/become-outside.rs:7:5
+   |
+LL |     become f();
+   |     ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0572`.
diff --git a/tests/ui/explicit-tail-calls/become-outside.rs b/tests/ui/explicit-tail-calls/become-outside.rs
new file mode 100644
index 00000000000..51b4389c88f
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/become-outside.rs
@@ -0,0 +1,15 @@
+// revisions: constant array
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+#[cfg(constant)]
+const _: () = {
+    become f(); //[constant]~ error: become statement outside of function body
+};
+
+#[cfg(array)]
+struct Bad([(); become f()]); //[array]~ error: become statement outside of function body
+
+fn f() {}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/return-lifetime-sub.rs b/tests/ui/explicit-tail-calls/return-lifetime-sub.rs
new file mode 100644
index 00000000000..8a3f43d4b92
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/return-lifetime-sub.rs
@@ -0,0 +1,13 @@
+// check-pass
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+fn _f<'a>() -> &'a [u8] {
+    become _g();
+}
+
+fn _g() -> &'static [u8] {
+    &[0, 1, 2, 3]
+}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/return-mismatches.rs b/tests/ui/explicit-tail-calls/return-mismatches.rs
new file mode 100644
index 00000000000..935a1a1d28b
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/return-mismatches.rs
@@ -0,0 +1,28 @@
+#![allow(incomplete_features)]
+#![feature(explicit_tail_calls)]
+
+fn _f0<'a>() -> &'static [u8] {
+    become _g0(); //~ error: mismatched types
+}
+
+fn _g0() -> &'static [u8; 1] {
+    &[0]
+}
+
+fn _f1() {
+    become _g1(); //~ error: mismatched types
+}
+
+fn _g1() -> ! {
+    become _g1();
+}
+
+fn _f2() -> u32 {
+    become _g2(); //~ error: mismatched types
+}
+
+fn _g2() -> u16 {
+    0
+}
+
+fn main() {}
diff --git a/tests/ui/explicit-tail-calls/return-mismatches.stderr b/tests/ui/explicit-tail-calls/return-mismatches.stderr
new file mode 100644
index 00000000000..1dcc35797c1
--- /dev/null
+++ b/tests/ui/explicit-tail-calls/return-mismatches.stderr
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/return-mismatches.rs:5:5
+   |
+LL |     become _g0();
+   |     ^^^^^^^^^^^^ expected `&[u8]`, found `&[u8; 1]`
+   |
+   = note: expected reference `&'static [u8]`
+              found reference `&'static [u8; 1]`
+
+error[E0308]: mismatched types
+  --> $DIR/return-mismatches.rs:13:5
+   |
+LL |     become _g1();
+   |     ^^^^^^^^^^^^ expected `()`, found `!`
+   |
+   = note: expected unit type `()`
+                   found type `!`
+
+error[E0308]: mismatched types
+  --> $DIR/return-mismatches.rs:21:5
+   |
+LL |     become _g2();
+   |     ^^^^^^^^^^^^ expected `u32`, found `u16`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/higher-ranked/trait-bounds/future.classic.stderr b/tests/ui/higher-ranked/trait-bounds/future.classic.stderr
new file mode 100644
index 00000000000..33c0f7173a1
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/future.classic.stderr
@@ -0,0 +1,6 @@
+error: the compiler unexpectedly panicked. this is a bug.
+
+query stack during panic:
+#0 [evaluate_obligation] evaluating trait selection obligation `for<'a> [async fn body@$DIR/future.rs:32:35: 34:2]: core::future::future::Future`
+#1 [codegen_select_candidate] computing candidate for `<strlen as Trait>`
+end of query stack
diff --git a/tests/ui/higher-ranked/trait-bounds/future.rs b/tests/ui/higher-ranked/trait-bounds/future.rs
new file mode 100644
index 00000000000..da7ee034329
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/future.rs
@@ -0,0 +1,38 @@
+// ignore-tidy-linelength
+// edition:2021
+// revisions: classic next
+//[next] compile-flags: -Ztrait-solver=next
+//[next] check-pass
+//[classic] known-bug: #112347
+//[classic] build-fail
+//[classic] failure-status: 101
+//[classic] normalize-stderr-test "note: .*\n\n" -> ""
+//[classic] normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
+//[classic] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
+//[classic] rustc-env:RUST_BACKTRACE=0
+
+#![feature(unboxed_closures)]
+
+use std::future::Future;
+
+trait Trait {
+    fn func(&self, _: &str);
+}
+
+impl<T> Trait for T
+where
+    for<'a> T: Fn<(&'a str,)> + Send + Sync,
+    for<'a> <T as FnOnce<(&'a str,)>>::Output: Future<Output = usize> + Send,
+{
+    fn func(&self, _: &str) {
+        println!("hello!");
+    }
+}
+
+async fn strlen(x: &str) -> usize {
+    x.len()
+}
+
+fn main() {
+    strlen.func("hi");
+}
diff --git a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs
new file mode 100644
index 00000000000..98dbaf036be
--- /dev/null
+++ b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![allow(incomplete_features)]
+#![feature(adt_const_params, return_position_impl_trait_in_trait)]
+
+pub struct Element;
+
+pub trait Node {
+    fn elements<const T: &'static str>(&self) -> impl Iterator<Item = Element>;
+}
+
+fn main() {}
diff --git a/tests/ui/issues/issue-12133-3.rs b/tests/ui/issues/issue-12133-3.rs
index e6b16e2da1d..988b61e3baf 100644
--- a/tests/ui/issues/issue-12133-3.rs
+++ b/tests/ui/issues/issue-12133-3.rs
@@ -4,7 +4,7 @@
 // aux-build:issue-12133-dylib2.rs
 // ignore-emscripten no dylib support
 // ignore-musl
-// ignore-sgx no dylib support
+// needs-dynamic-linking
 
 // pretty-expanded FIXME #23616
 
diff --git a/tests/ui/issues/issue-51714.rs b/tests/ui/issues/issue-51714.rs
index 8716524d6f4..03b50b7963e 100644
--- a/tests/ui/issues/issue-51714.rs
+++ b/tests/ui/issues/issue-51714.rs
@@ -1,9 +1,9 @@
 fn main() {
-//~^ NOTE: not the enclosing function body
-//~| NOTE: not the enclosing function body
-//~| NOTE: not the enclosing function body
-//~| NOTE: not the enclosing function body
-    |_:  [_; return || {}] | {};
+    //~^ NOTE: not the enclosing function body
+    //~| NOTE: not the enclosing function body
+    //~| NOTE: not the enclosing function body
+    //~| NOTE: not the enclosing function body
+    |_: [_; return || {}]| {};
     //~^ ERROR: return statement outside of function body [E0572]
     //~| NOTE: the return is part of this body...
 
diff --git a/tests/ui/issues/issue-51714.stderr b/tests/ui/issues/issue-51714.stderr
index 514d69c1c7d..e53e10afcaf 100644
--- a/tests/ui/issues/issue-51714.stderr
+++ b/tests/ui/issues/issue-51714.stderr
@@ -1,13 +1,13 @@
 error[E0572]: return statement outside of function body
-  --> $DIR/issue-51714.rs:6:14
+  --> $DIR/issue-51714.rs:6:13
    |
 LL | / fn main() {
 LL | |
 LL | |
 LL | |
 LL | |
-LL | |     |_:  [_; return || {}] | {};
-   | |              ^^^^^^^^^^^^ the return is part of this body...
+LL | |     |_: [_; return || {}]| {};
+   | |             ^^^^^^^^^^^^ the return is part of this body...
 ...  |
 LL | |
 LL | | }
diff --git a/tests/ui/issues/issue-85461.rs b/tests/ui/issues/issue-85461.rs
index 9655108876f..092105df24e 100644
--- a/tests/ui/issues/issue-85461.rs
+++ b/tests/ui/issues/issue-85461.rs
@@ -1,6 +1,7 @@
 // compile-flags: -Cinstrument-coverage -Ccodegen-units=4 --crate-type dylib -Copt-level=0
 // build-pass
 // needs-profiler-support
+// needs-dynamic-linking
 
 // Regression test for #85461 where MSVC sometimes fails to link instrument-coverage binaries
 // with dead code and #[inline(always)].
diff --git a/tests/ui/parser/bad-interpolated-block.stderr b/tests/ui/parser/bad-interpolated-block.stderr
index 2a0999afdfa..651036c51c9 100644
--- a/tests/ui/parser/bad-interpolated-block.stderr
+++ b/tests/ui/parser/bad-interpolated-block.stderr
@@ -10,6 +10,10 @@ LL |     m!({});
    |     ------ in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: wrap this in another block
+   |
+LL |         'lab: { $b };
+   |               +    +
 
 error: cannot use a `block` macro fragment here
   --> $DIR/bad-interpolated-block.rs:6:16
@@ -23,6 +27,10 @@ LL |     m!({});
    |     ------ in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: wrap this in another block
+   |
+LL |         unsafe { $b };
+   |                +    +
 
 error: cannot use a `block` macro fragment here
   --> $DIR/bad-interpolated-block.rs:7:23
@@ -34,6 +42,10 @@ LL |     m!({});
    |     ------ in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: wrap this in another block
+   |
+LL |         |x: u8| -> () { $b };
+   |                       +    +
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/labeled-no-colon-expr.stderr b/tests/ui/parser/labeled-no-colon-expr.stderr
index 62288fe152d..4d61d9c1403 100644
--- a/tests/ui/parser/labeled-no-colon-expr.stderr
+++ b/tests/ui/parser/labeled-no-colon-expr.stderr
@@ -77,6 +77,10 @@ LL |     m!({});
    |     ------ in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: wrap this in another block
+   |
+LL |             'l5 { $b };
+   |                 +    +
 
 error: labeled expression must be followed by `:`
   --> $DIR/labeled-no-colon-expr.rs:14:8
diff --git a/tests/ui/pattern/byte-string-inference.rs b/tests/ui/pattern/byte-string-inference.rs
new file mode 100644
index 00000000000..b1517de6b67
--- /dev/null
+++ b/tests/ui/pattern/byte-string-inference.rs
@@ -0,0 +1,15 @@
+// check-pass
+
+fn load<L>() -> Option<L> {
+    todo!()
+}
+
+fn main() {
+    while let Some(tag) = load() {
+        match &tag {
+            b"NAME" => {}
+            b"DATA" => {}
+            _ => {}
+        }
+    }
+}
diff --git a/tests/ui/proc-macro/crt-static.rs b/tests/ui/proc-macro/crt-static.rs
index 020128fa214..78592f82709 100644
--- a/tests/ui/proc-macro/crt-static.rs
+++ b/tests/ui/proc-macro/crt-static.rs
@@ -7,6 +7,7 @@
 // build-pass
 // force-host
 // no-prefer-dynamic
+// needs-dynamic-linking
 
 #![crate_type = "proc-macro"]
 
diff --git a/tests/ui/return/issue-64620.rs b/tests/ui/return/issue-64620.rs
index a62e5bf8d3c..ab293165195 100644
--- a/tests/ui/return/issue-64620.rs
+++ b/tests/ui/return/issue-64620.rs
@@ -1,5 +1,5 @@
 enum Bug {
-    V1 = return [0][0] //~ERROR return statement outside of function body
+    V1 = return [0][0], //~ERROR return statement outside of function body
 }
 
 fn main() {}
diff --git a/tests/ui/return/issue-64620.stderr b/tests/ui/return/issue-64620.stderr
index f40ac4de32d..3210a67d418 100644
--- a/tests/ui/return/issue-64620.stderr
+++ b/tests/ui/return/issue-64620.stderr
@@ -1,7 +1,7 @@
 error[E0572]: return statement outside of function body
   --> $DIR/issue-64620.rs:2:10
    |
-LL |     V1 = return [0][0]
+LL |     V1 = return [0][0],
    |          ^^^^^^^^^^^^^
 
 error: aborting due to previous error
diff --git a/tests/ui/return/issue-86188-return-not-in-fn-body.rs b/tests/ui/return/issue-86188-return-not-in-fn-body.rs
index 4f076fa0693..3117cf3fd91 100644
--- a/tests/ui/return/issue-86188-return-not-in-fn-body.rs
+++ b/tests/ui/return/issue-86188-return-not-in-fn-body.rs
@@ -7,7 +7,7 @@
 
 const C: [(); 42] = {
     [(); return || {
-    //~^ ERROR: return statement outside of function body [E0572]
+        //~^ ERROR: return statement outside of function body [E0572]
         let tx;
     }]
 };
@@ -16,7 +16,7 @@ struct S {}
 trait Tr {
     fn foo();
     fn bar() {
-    //~^ NOTE: ...not the enclosing function body
+        //~^ NOTE: ...not the enclosing function body
         [(); return];
         //~^ ERROR: return statement outside of function body [E0572]
         //~| NOTE: the return is part of this body...
@@ -24,7 +24,7 @@ trait Tr {
 }
 impl Tr for S {
     fn foo() {
-    //~^ NOTE: ...not the enclosing function body
+        //~^ NOTE: ...not the enclosing function body
         [(); return];
         //~^ ERROR: return statement outside of function body [E0572]
         //~| NOTE: the return is part of this body...
@@ -32,10 +32,10 @@ impl Tr for S {
 }
 
 fn main() {
-//~^ NOTE: ...not the enclosing function body
+    //~^ NOTE: ...not the enclosing function body
     [(); return || {
-    //~^ ERROR: return statement outside of function body [E0572]
-    //~| NOTE: the return is part of this body...
+        //~^ ERROR: return statement outside of function body [E0572]
+        //~| NOTE: the return is part of this body...
         let tx;
     }];
 }
diff --git a/tests/ui/return/tail-expr-as-potential-return.rs b/tests/ui/return/tail-expr-as-potential-return.rs
index f46e088b85f..2046d6680dd 100644
--- a/tests/ui/return/tail-expr-as-potential-return.rs
+++ b/tests/ui/return/tail-expr-as-potential-return.rs
@@ -1,8 +1,8 @@
-// > Suggest `return`ing tail expressions that match return type
+// > Suggest returning tail expressions that match return type
 // >
 // > Some newcomers are confused by the behavior of tail expressions,
 // > interpreting that "leaving out the `;` makes it the return value".
-// > To help them go in the right direction, suggest using `return` instead
+// > To help them go in the right direction, suggest using return instead
 // > when applicable.
 // (original commit description for this test)
 //
diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
index a776e508907..a9d678c1e6a 100644
--- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
+++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
@@ -1,4 +1,4 @@
-// compile-flags -Wrust-2021-incompatible-closure-captures
+#![warn(rust_2021_incompatible_closure_captures)]
 
 fn main() {}
 
@@ -9,7 +9,7 @@ impl Numberer {
     //~^ ERROR `async fn` is not permitted in Rust 2015
         interval: Duration,
         //~^ ERROR cannot find type `Duration` in this scope
-    ) -> Numberer {
+    ) -> Numberer { //~WARN: changes to closure capture in Rust 2021
         Numberer {}
     }
 }
diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
index 60433e1c284..71e9e7602e8 100644
--- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
+++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
@@ -18,7 +18,32 @@ help: consider importing this struct
 LL + use std::time::Duration;
    |
 
-error: aborting due to 2 previous errors
+warning: changes to closure capture in Rust 2021 will affect drop order
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19
+   |
+LL |           interval: Duration,
+   |           -------- in Rust 2018, this causes the closure to capture `interval`, but in Rust 2021, it has no effect
+LL |
+LL |       ) -> Numberer {
+   |  _________________-_^
+   | |                 |
+   | |                 in Rust 2018, `interval` is dropped here along with the closure, but in Rust 2021 `interval` is not part of the closure
+LL | |         Numberer {}
+LL | |     }
+   | |_____^
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+note: the lint level is defined here
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:1:9
+   |
+LL | #![warn(rust_2021_incompatible_closure_captures)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: add a dummy let to cause `interval` to be fully captured
+   |
+LL |     ) -> Numberer { let _ = &interval;
+   |                     ++++++++++++++++++
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0412, E0670.
 For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/stability-attribute/auxiliary/default_body.rs b/tests/ui/stability-attribute/auxiliary/default_body.rs
index 3a177419d66..2f315eb1bc8 100644
--- a/tests/ui/stability-attribute/auxiliary/default_body.rs
+++ b/tests/ui/stability-attribute/auxiliary/default_body.rs
@@ -11,6 +11,10 @@ pub trait JustTrait {
     #[rustc_default_body_unstable(feature = "fun_default_body", issue = "none")]
     #[stable(feature = "stable_feature", since = "1.0.0")]
     fn fun() {}
+
+    #[rustc_default_body_unstable(feature = "fun_default_body", issue = "none", reason = "reason")]
+    #[stable(feature = "stable_feature", since = "1.0.0")]
+    fn fun2() {}
 }
 
 #[rustc_must_implement_one_of(eq, neq)]
diff --git a/tests/ui/stability-attribute/default-body-stability-err.rs b/tests/ui/stability-attribute/default-body-stability-err.rs
index ecb281bccf6..d1a3597687d 100644
--- a/tests/ui/stability-attribute/default-body-stability-err.rs
+++ b/tests/ui/stability-attribute/default-body-stability-err.rs
@@ -10,6 +10,7 @@ struct Type;
 impl JustTrait for Type {}
 //~^ ERROR not all trait items implemented, missing: `CONSTANT` [E0046]
 //~| ERROR not all trait items implemented, missing: `fun` [E0046]
+//~| ERROR not all trait items implemented, missing: `fun2` [E0046]
 
 impl Equal for Type {
     //~^ ERROR not all trait items implemented, missing: `eq` [E0046]
diff --git a/tests/ui/stability-attribute/default-body-stability-err.stderr b/tests/ui/stability-attribute/default-body-stability-err.stderr
index ef666f30fc2..12ec9ea3adb 100644
--- a/tests/ui/stability-attribute/default-body-stability-err.stderr
+++ b/tests/ui/stability-attribute/default-body-stability-err.stderr
@@ -18,8 +18,18 @@ LL | impl JustTrait for Type {}
    = note: use of unstable library feature 'fun_default_body'
    = help: add `#![feature(fun_default_body)]` to the crate attributes to enable
 
+error[E0046]: not all trait items implemented, missing: `fun2`
+  --> $DIR/default-body-stability-err.rs:10:1
+   |
+LL | impl JustTrait for Type {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: default implementation of `fun2` is unstable
+   = note: use of unstable library feature 'fun_default_body': reason
+   = help: add `#![feature(fun_default_body)]` to the crate attributes to enable
+
 error[E0046]: not all trait items implemented, missing: `eq`
-  --> $DIR/default-body-stability-err.rs:14:1
+  --> $DIR/default-body-stability-err.rs:15:1
    |
 LL | / impl Equal for Type {
 LL | |
@@ -33,6 +43,6 @@ LL | | }
    = note: use of unstable library feature 'eq_default_body'
    = help: add `#![feature(eq_default_body)]` to the crate attributes to enable
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/stability-attribute/default-body-stability-ok-impls.rs b/tests/ui/stability-attribute/default-body-stability-ok-impls.rs
index e1f5c017096..b29d45256bf 100644
--- a/tests/ui/stability-attribute/default-body-stability-ok-impls.rs
+++ b/tests/ui/stability-attribute/default-body-stability-ok-impls.rs
@@ -12,6 +12,8 @@ impl JustTrait for Type {
     const CONSTANT: usize = 1;
 
     fn fun() {}
+
+    fn fun2() {}
 }
 
 impl Equal for Type {
diff --git a/tests/ui/suggestions/issue-109991.rs b/tests/ui/suggestions/issue-109991.rs
new file mode 100644
index 00000000000..918451cb8ee
--- /dev/null
+++ b/tests/ui/suggestions/issue-109991.rs
@@ -0,0 +1,27 @@
+struct S {
+    a: usize,
+    b: usize,
+}
+
+fn main() {
+    let a: usize;
+    let b: usize;
+    let c: usize;
+
+    (c) = (&123); //~ ERROR mismatched types
+    (a, b) = (123, &mut 123); //~ ERROR mismatched types
+
+    let x: String;
+    (x,) = (1,); //~ ERROR mismatched types
+
+    let x: i32;
+    [x] = [&1]; //~ ERROR mismatched types
+
+    let x: &i32;
+    [x] = [1]; //~ ERROR mismatched types
+
+    let x = (1, &mut 2);
+    (a, b) = x; //~ ERROR mismatched types
+
+    S { a, b } = S { a: 1, b: &mut 2 }; //~ ERROR mismatched types
+}
diff --git a/tests/ui/suggestions/issue-109991.stderr b/tests/ui/suggestions/issue-109991.stderr
new file mode 100644
index 00000000000..bd21e4de648
--- /dev/null
+++ b/tests/ui/suggestions/issue-109991.stderr
@@ -0,0 +1,72 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:11:11
+   |
+LL |     let c: usize;
+   |            ----- expected due to this type
+LL |
+LL |     (c) = (&123);
+   |           ^^^^^^ expected `usize`, found `&{integer}`
+   |
+help: consider removing the borrow
+   |
+LL -     (c) = (&123);
+LL +     (c) = (123);
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:12:9
+   |
+LL |     let b: usize;
+   |            ----- expected due to this type
+...
+LL |     (a, b) = (123, &mut 123);
+   |         ^ expected `usize`, found `&mut {integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:15:6
+   |
+LL |     let x: String;
+   |            ------ expected due to this type
+LL |     (x,) = (1,);
+   |      ^ expected `String`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:18:6
+   |
+LL |     let x: i32;
+   |            --- expected due to this type
+LL |     [x] = [&1];
+   |      ^ expected `i32`, found `&{integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:21:6
+   |
+LL |     let x: &i32;
+   |            ---- expected due to this type
+LL |     [x] = [1];
+   |      ^ expected `&i32`, found integer
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:24:9
+   |
+LL |     let b: usize;
+   |            ----- expected due to this type
+...
+LL |     (a, b) = x;
+   |         ^ expected `usize`, found `&mut {integer}`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-109991.rs:26:31
+   |
+LL |     S { a, b } = S { a: 1, b: &mut 2 };
+   |                               ^^^^^^ expected `usize`, found `&mut {integer}`
+   |
+help: consider removing the borrow
+   |
+LL -     S { a, b } = S { a: 1, b: &mut 2 };
+LL +     S { a, b } = S { a: 1, b: 2 };
+   |
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.rs b/tests/ui/traits/ice-with-dyn-pointee-errors.rs
new file mode 100644
index 00000000000..46cef2c8bc0
--- /dev/null
+++ b/tests/ui/traits/ice-with-dyn-pointee-errors.rs
@@ -0,0 +1,15 @@
+#![feature(ptr_metadata)]
+// Address issue #112737 -- ICE with dyn Pointee
+extern crate core;
+use core::ptr::Pointee;
+
+fn unknown_sized_object_ptr_in(_: &(impl Pointee<Metadata = ()> + ?Sized)) {}
+
+fn raw_pointer_in(x: &dyn Pointee<Metadata = ()>) {
+    unknown_sized_object_ptr_in(x)
+    //~^ ERROR type mismatch resolving `<dyn Pointee<Metadata = ()> as Pointee>::Metadata == ()`
+}
+
+fn main() {
+    raw_pointer_in(&42)
+}
diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr
new file mode 100644
index 00000000000..8ad11c3344a
--- /dev/null
+++ b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr
@@ -0,0 +1,19 @@
+error[E0271]: type mismatch resolving `<dyn Pointee<Metadata = ()> as Pointee>::Metadata == ()`
+  --> $DIR/ice-with-dyn-pointee-errors.rs:9:33
+   |
+LL |     unknown_sized_object_ptr_in(x)
+   |     --------------------------- ^ expected `()`, found `DynMetadata<dyn Pointee<Metadata = ...>>`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected unit type `()`
+                 found struct `DynMetadata<dyn Pointee<Metadata = ()>>`
+note: required by a bound in `unknown_sized_object_ptr_in`
+  --> $DIR/ice-with-dyn-pointee-errors.rs:6:50
+   |
+LL | fn unknown_sized_object_ptr_in(_: &(impl Pointee<Metadata = ()> + ?Sized)) {}
+   |                                                  ^^^^^^^^^^^^^ required by this bound in `unknown_sized_object_ptr_in`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/ice-with-dyn-pointee.rs b/tests/ui/traits/ice-with-dyn-pointee.rs
new file mode 100644
index 00000000000..9b3b9c8cddf
--- /dev/null
+++ b/tests/ui/traits/ice-with-dyn-pointee.rs
@@ -0,0 +1,11 @@
+// run-pass
+#![feature(ptr_metadata)]
+// Address issue #112737 -- ICE with dyn Pointee
+extern crate core;
+use core::ptr::Pointee;
+
+fn raw_pointer_in(_: &dyn Pointee<Metadata = ()>) {}
+
+fn main() {
+    raw_pointer_in(&42)
+}
diff --git a/tests/ui/traits/new-solver/member-constraints-in-root-universe.rs b/tests/ui/traits/new-solver/member-constraints-in-root-universe.rs
new file mode 100644
index 00000000000..97c44305864
--- /dev/null
+++ b/tests/ui/traits/new-solver/member-constraints-in-root-universe.rs
@@ -0,0 +1,17 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait Trait {
+    type Ty;
+}
+
+impl Trait for for<'a> fn(&'a u8, &'a u8) {
+    type Ty = ();
+}
+
+// argument is necessary to create universes before registering the hidden type.
+fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized {
+    "hidden type is `&'?0 str` with '?0 member of ['static,]"
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/slice-match-byte-lit.rs b/tests/ui/traits/new-solver/slice-match-byte-lit.rs
index 4f848062595..5f9c0df6450 100644
--- a/tests/ui/traits/new-solver/slice-match-byte-lit.rs
+++ b/tests/ui/traits/new-solver/slice-match-byte-lit.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Ztrait-solver=next
-// check-pass
+// known-bug: rust-lang/trait-system-refactor-initiative#38
 
 fn test(s: &[u8]) {
     match &s[0..3] {
diff --git a/tests/ui/traits/new-solver/slice-match-byte-lit.stderr b/tests/ui/traits/new-solver/slice-match-byte-lit.stderr
new file mode 100644
index 00000000000..294e8bc94be
--- /dev/null
+++ b/tests/ui/traits/new-solver/slice-match-byte-lit.stderr
@@ -0,0 +1,11 @@
+error[E0271]: type mismatch resolving `[u8; 3] <: <Range<usize> as SliceIndex<[u8]>>::Output`
+  --> $DIR/slice-match-byte-lit.rs:6:9
+   |
+LL |     match &s[0..3] {
+   |           -------- this expression has type `&<std::ops::Range<usize> as SliceIndex<[u8]>>::Output`
+LL |         b"uwu" => {}
+   |         ^^^^^^ types differ
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr b/tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr
new file mode 100644
index 00000000000..dd2737c706d
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/normalize-hidden-types.current.stderr
@@ -0,0 +1,55 @@
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/normalize-hidden-types.rs:25:20
+   |
+LL |     fn define() -> Opaque {
+   |                    ^^^^^^ expected `*const (dyn FnOnce(()) + 'static)`, got `*const dyn for<'a> FnOnce(<u8 as Trait>::Gat<'a>)`
+   |
+note: previous use here
+  --> $DIR/normalize-hidden-types.rs:27:9
+   |
+LL |         dyn_hoops::<_>(0)
+   |         ^^^^^^^^^^^^^^^^^
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/normalize-hidden-types.rs:34:22
+   |
+LL |     fn define_1() -> Opaque { dyn_hoops::<_>(0) }
+   |                      ^^^^^^ expected `*const (dyn FnOnce(()) + 'static)`, got `*const dyn for<'a> FnOnce(<u8 as Trait>::Gat<'a>)`
+   |
+note: previous use here
+  --> $DIR/normalize-hidden-types.rs:34:31
+   |
+LL |     fn define_1() -> Opaque { dyn_hoops::<_>(0) }
+   |                               ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+  --> $DIR/normalize-hidden-types.rs:44:25
+   |
+LL |     type Opaque = impl Sized;
+   |                   ---------- the expected opaque type
+...
+LL |         let _: Opaque = dyn_hoops::<u8>(0);
+   |                ------   ^^^^^^^^^^^^^^^^^^ expected opaque type, found `*const dyn FnOnce(())`
+   |                |
+   |                expected due to this
+   |
+   = note: expected opaque type `typeck::Opaque`
+              found raw pointer `*const (dyn FnOnce(()) + 'static)`
+   = help: consider constraining the associated type `<u8 as Trait>::Gat<'_>` to `()` or calling a method that returns `<u8 as Trait>::Gat<'_>`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/normalize-hidden-types.rs:54:25
+   |
+LL |         let _: Opaque = dyn_hoops::<_>(0);
+   |                         ^^^^^^^^^^^^^^^^^ expected `*const (dyn FnOnce(()) + 'static)`, got `*const dyn for<'a> FnOnce(<u8 as Trait>::Gat<'a>)`
+   |
+note: previous use here
+  --> $DIR/normalize-hidden-types.rs:56:9
+   |
+LL |         None
+   |         ^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type-alias-impl-trait/normalize-hidden-types.rs b/tests/ui/type-alias-impl-trait/normalize-hidden-types.rs
new file mode 100644
index 00000000000..8d80546444a
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/normalize-hidden-types.rs
@@ -0,0 +1,60 @@
+// Regression test for #112691
+//
+// revisions: current next
+// [next] compile-flags: -Ztrait-solver=next
+// [next] check-pass
+// [current]: known-bug: #112691
+
+#![feature(type_alias_impl_trait)]
+
+trait Trait {
+    type Gat<'lt>;
+}
+
+impl Trait for u8 {
+    type Gat<'lt> = ();
+}
+
+fn dyn_hoops<T: Trait>(_: T) -> *const dyn FnOnce(T::Gat<'_>) {
+    loop {}
+}
+
+mod typeof_1 {
+    use super::*;
+    type Opaque = impl Sized;
+    fn define() -> Opaque {
+        //[current]~^ ERROR concrete type differs
+        dyn_hoops::<_>(0)
+    }
+}
+
+mod typeof_2 {
+    use super::*;
+    type Opaque = impl Sized;
+    fn define_1() -> Opaque { dyn_hoops::<_>(0) }
+    //[current]~^ ERROR concrete type differs
+    fn define_2() -> Opaque { dyn_hoops::<u8>(0) }
+}
+
+mod typeck {
+    use super::*;
+    type Opaque = impl Sized;
+    fn define() -> Option<Opaque> {
+        let _: Opaque = dyn_hoops::<_>(0);
+        let _: Opaque = dyn_hoops::<u8>(0);
+        //[current]~^ ERROR mismatched types
+        None
+    }
+}
+
+mod borrowck {
+    use super::*;
+    type Opaque = impl Sized;
+    fn define() -> Option<Opaque> {
+        let _: Opaque = dyn_hoops::<_>(0);
+        //[current]~^ ERROR concrete type differs
+        None
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-86721-return-expr-ice.rs b/tests/ui/typeck/issue-86721-return-expr-ice.rs
index cd7135f18b1..4f882f7a3f1 100644
--- a/tests/ui/typeck/issue-86721-return-expr-ice.rs
+++ b/tests/ui/typeck/issue-86721-return-expr-ice.rs
@@ -2,7 +2,7 @@
 
 // revisions: rev1 rev2
 #![cfg_attr(any(), rev1, rev2)]
-#![crate_type="lib"]
+#![crate_type = "lib"]
 
 #[cfg(any(rev1))]
 trait T {
diff --git a/tests/ui/uninhabited/projection.rs b/tests/ui/uninhabited/projection.rs
new file mode 100644
index 00000000000..be0d3ff7da7
--- /dev/null
+++ b/tests/ui/uninhabited/projection.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(never_type, exhaustive_patterns)]
+
+trait Tag {
+    type TagType;
+}
+
+enum Keep {}
+enum Erase {}
+
+impl Tag for Keep {
+    type TagType = ();
+}
+
+impl Tag for Erase {
+    type TagType = !;
+}
+
+enum TagInt<T: Tag> {
+    Untagged(i32),
+    Tagged(T::TagType, i32)
+}
+
+fn test(keep: TagInt<Keep>, erase: TagInt<Erase>) {
+    match erase {
+        TagInt::Untagged(_) => (),
+        TagInt::Tagged(_, _) => ()
+    };
+}
+
+fn main() {}
diff --git a/x.ps1 b/x.ps1
index a156017628d..55f99901645 100755
--- a/x.ps1
+++ b/x.ps1
@@ -5,7 +5,7 @@
 $ErrorActionPreference = "Stop"
 
 # syntax check
-Get-Command -syntax ${PSCommandPath}
+Get-Command -syntax ${PSCommandPath} >$null
 
 $xpy = Join-Path $PSScriptRoot x.py
 # Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?)
@@ -16,7 +16,13 @@ foreach ($arg in $args) {
 }
 
 function Get-Application($app) {
-    return Get-Command $app -ErrorAction SilentlyContinue -CommandType Application
+    $cmd = Get-Command $app -ErrorAction SilentlyContinue -CommandType Application | Select-Object -First 1
+    if ($cmd.source -match '.*AppData\\Local\\Microsoft\\WindowsApps\\.*exe') {
+        # Windows for some reason puts a `python3.exe` executable in PATH that just opens the windows store.
+        # Ignore it.
+        return $false
+    }
+    return $cmd
 }
 
 function Invoke-Application($application, $arguments) {
@@ -51,5 +57,7 @@ if (($null -ne $found) -and ($found.Length -ge 1)) {
     Invoke-Application $python $xpy_args
 }
 
-Write-Error "${PSCommandPath}: error: did not find python installed"
+$msg = "${PSCommandPath}: error: did not find python installed`n"
+$msg += "help: consider installing it from https://www.python.org/downloads/"
+Write-Error $msg -Category NotInstalled
 Exit 1
diff --git a/x.py b/x.py
index 7163df5cfe9..ba959a3047e 100755
--- a/x.py
+++ b/x.py
@@ -31,7 +31,7 @@ if __name__ == '__main__':
 
     # soft deprecation of old python versions
     skip_check = os.environ.get("RUST_IGNORE_OLD_PYTHON") == "1"
-    if major < 3 or (major == 3 and minor < 6):
+    if not skip_check and (major < 3 or (major == 3 and minor < 6)):
         msg = cleandoc("""
             Using python {}.{} but >= 3.6 is recommended. Your python version
             should continue to work for the near future, but this will