about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock19
-rw-r--r--Cargo.toml1
-rw-r--r--compiler/rustc_ast/src/ast.rs3
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs4
-rw-r--r--compiler/rustc_ast/src/visit.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs5
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs3
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs5
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs3
-rw-r--r--compiler/rustc_borrowck/src/lib.rs5
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs19
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/pattern_type.rs29
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs18
-rw-r--r--compiler/rustc_codegen_gcc/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs39
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs30
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs9
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs1
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs1
-rw-r--r--compiler/rustc_driver_impl/messages.ftl2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0699.md4
-rw-r--r--compiler/rustc_error_codes/src/lib.rs2
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/intravisit.rs9
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl3
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/errors/pattern_types.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs65
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs14
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl3
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs42
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs9
-rw-r--r--compiler/rustc_infer/src/infer/at.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs16
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs9
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs50
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs104
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs1
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/builtin.rs5
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs1
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs6
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs7
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs38
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/hooks/mod.rs27
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs14
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs52
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs6
-rw-r--r--compiler/rustc_middle/src/mir/traversal.rs96
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs11
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs8
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs32
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs3
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs12
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs18
-rw-r--r--compiler/rustc_middle/src/ty/context.rs34
-rw-r--r--compiler/rustc_middle/src/ty/error.rs1
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs6
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs14
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs6
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs5
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs1
-rw-r--r--compiler/rustc_middle/src/ty/list.rs6
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/pattern.rs48
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs3
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs38
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs40
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs12
-rw-r--r--compiler/rustc_middle/src/ty/util.rs15
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs197
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs1
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs172
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs552
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs20
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs4
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs3
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs4
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs4
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs1
-rw-r--r--compiler/rustc_privacy/src/lib.rs1
-rw-r--r--compiler/rustc_sanitizers/Cargo.toml15
-rw-r--r--compiler/rustc_sanitizers/README.md2
-rw-r--r--compiler/rustc_sanitizers/src/cfi/mod.rs6
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs (renamed from compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs)801
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs123
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs450
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/mod.rs54
-rw-r--r--compiler/rustc_sanitizers/src/kcfi/mod.rs7
-rw-r--r--compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs55
-rw-r--r--compiler/rustc_sanitizers/src/lib.rs7
-rw-r--r--compiler/rustc_session/src/cstore.rs18
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs54
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs11
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs17
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml3
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs100
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs23
-rw-r--r--compiler/rustc_target/src/abi/call/aarch64.rs8
-rw-r--r--compiler/rustc_target/src/abi/call/arm.rs6
-rw-r--r--compiler/rustc_target/src/abi/call/csky.rs4
-rw-r--r--compiler/rustc_target/src/abi/call/loongarch.rs10
-rw-r--r--compiler/rustc_target/src/abi/call/mips.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mips64.rs4
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs19
-rw-r--r--compiler/rustc_target/src/abi/call/nvptx64.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/powerpc64.rs24
-rw-r--r--compiler/rustc_target/src/abi/call/riscv.rs10
-rw-r--r--compiler/rustc_target/src/abi/call/sparc.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/sparc64.rs4
-rw-r--r--compiler/rustc_target/src/abi/call/wasm.rs4
-rw-r--r--compiler/rustc_target/src/spec/base/apple/mod.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs7
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs31
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs50
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs103
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs4
-rw-r--r--compiler/rustc_transmute/src/layout/dfa.rs2
-rw-r--r--compiler/rustc_transmute/src/layout/nfa.rs1
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs441
-rw-r--r--compiler/rustc_transmute/src/lib.rs4
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs19
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/query_context.rs10
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs33
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs1
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs39
-rw-r--r--compiler/rustc_type_ir/src/debug.rs4
-rw-r--r--compiler/rustc_type_ir/src/infcx.rs2
-rw-r--r--compiler/rustc_type_ir/src/interner.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs24
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs5
-rw-r--r--compiler/stable_mir/src/mir/body.rs38
-rw-r--r--compiler/stable_mir/src/ty.rs7
-rw-r--r--compiler/stable_mir/src/visitor.rs1
-rw-r--r--library/alloc/benches/lib.rs2
-rw-r--r--library/alloc/src/boxed/thin.rs96
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs10
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/alloc/src/sync.rs4
-rw-r--r--library/core/benches/lib.rs2
-rw-r--r--library/core/src/iter/adapters/step_by.rs80
-rw-r--r--library/core/src/iter/traits/iterator.rs2
-rw-r--r--library/core/src/lib.rs3
-rw-r--r--library/core/src/ops/try_trait.rs2
-rw-r--r--library/core/src/pat.rs14
-rw-r--r--library/core/src/str/traits.rs15
-rw-r--r--library/std/benches/lib.rs2
-rw-r--r--library/std/src/lib.rs3
-rw-r--r--library/std/src/pat.rs3
-rw-r--r--library/std/src/sys/pal/hermit/fd.rs5
-rw-r--r--library/std/src/sys/pal/hermit/fs.rs339
-rw-r--r--library/std/src/sys/pal/hermit/time.rs10
-rw-r--r--library/std/src/sys_common/thread_local_key.rs5
-rw-r--r--library/std/tests/process_spawning.rs1
-rw-r--r--library/std/tests/switch-stdout.rs1
-rw-r--r--library/std/tests/thread.rs3
-rw-r--r--src/bootstrap/mk/Makefile.in30
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs31
-rw-r--r--src/bootstrap/src/core/builder.rs21
-rw-r--r--src/bootstrap/src/lib.rs9
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile22
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version2
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/embedded-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/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs229
-rw-r--r--src/librustdoc/clean/mod.rs11
-rw-r--r--src/librustdoc/clean/types.rs30
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/librustdoc/html/format.rs4
-rw-r--r--src/librustdoc/html/render/search_index.rs2
-rw-r--r--src/librustdoc/json/conversions.rs4
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs5
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs8
-rw-r--r--src/rustdoc-json-types/lib.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/utils.rs37
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/tests/ui-internal/custom_ice_message.stderr2
-rw-r--r--src/tools/compiletest/src/runtest.rs40
-rw-r--r--src/tools/compiletest/src/runtest/tests.rs100
-rw-r--r--src/tools/coverage-dump/src/covfun.rs46
-rw-r--r--src/tools/jsondoclint/src/validator.rs1
-rw-r--r--src/tools/run-make-support/src/rustc.rs48
-rw-r--r--src/tools/rustfmt/src/types.rs5
-rw-r--r--src/tools/tidy/src/error_codes.rs45
-rw-r--r--src/tools/tidy/src/issues.txt51
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/codegen/enum/enum-early-otherwise-branch.rs26
-rw-r--r--tests/codegen/issues/issue-122805.rs1
-rw-r--r--tests/codegen/match-optimized.rs4
-rw-r--r--tests/codegen/pattern_type_symbols.rs23
-rw-r--r--tests/codegen/powerpc64le-struct-align-128.rs93
-rw-r--r--tests/codegen/slice-indexing.rs28
-rw-r--r--tests/codegen/step_by-overflow-checks.rs26
-rw-r--r--tests/codegen/vecdeque_pop_push.rs67
-rw-r--r--tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir60
-rw-r--r--tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir4
-rw-r--r--tests/mir-opt/building/issue_101867.main.built.after.mir4
-rw-r--r--tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir8
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff39
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff57
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff105
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff107
-rw-r--r--tests/mir-opt/early_otherwise_branch.rs63
-rw-r--r--tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff91
-rw-r--r--tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff141
-rw-r--r--tests/mir-opt/early_otherwise_branch_3_element_tuple.rs37
-rw-r--r--tests/mir-opt/early_otherwise_branch_68867.rs9
-rw-r--r--tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff6
-rw-r--r--tests/mir-opt/early_otherwise_branch_noopt.rs9
-rw-r--r--tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff8
-rw-r--r--tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff8
-rw-r--r--tests/mir-opt/early_otherwise_branch_soundness.rs16
-rw-r--r--tests/mir-opt/issue_72181_1.main.built.after.mir4
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.32bit.mir4
-rw-r--r--tests/mir-opt/issue_99325.main.built.after.64bit.mir4
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff47
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff26
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff32
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff31
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff42
-rw-r--r--tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff37
-rw-r--r--tests/mir-opt/matches_reduce_branches.rs233
-rw-r--r--tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff41
-rw-r--r--tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff41
-rw-r--r--tests/run-make/artifact-incr-cache/lib.rs6
-rw-r--r--tests/run-make/artifact-incr-cache/rmake.rs25
-rw-r--r--tests/rustdoc-gui/docblock-code-block-line-number.goml16
-rw-r--r--tests/rustdoc-gui/scrape-examples-toggle.goml3
-rw-r--r--tests/rustdoc-gui/search-result-color.goml15
-rw-r--r--tests/rustdoc-gui/settings.goml7
-rw-r--r--tests/rustdoc-gui/utils.goml13
-rw-r--r--tests/rustdoc/primitive/primitive.rs14
-rw-r--r--tests/rustdoc/synthetic_auto/supertrait-bounds.rs14
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs1
-rw-r--r--tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr52
-rw-r--r--tests/ui-fulldeps/stable-mir/check_binop.rs147
-rw-r--r--tests/ui/asm/inline-syntax.rs2
-rw-r--r--tests/ui/async-await/async-closures/mut-ref-reborrow.rs27
-rw-r--r--tests/ui/async-await/async-closures/overlapping-projs.rs27
-rw-r--r--tests/ui/async-await/async-closures/overlapping-projs.run.stdout1
-rw-r--r--tests/ui/async-await/async-closures/precise-captures.call.run.stdout29
-rw-r--r--tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout29
-rw-r--r--tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout29
-rw-r--r--tests/ui/async-await/async-closures/precise-captures.rs157
-rw-r--r--tests/ui/cfg/cfg-attr-cfg.rs2
-rw-r--r--tests/ui/cfg/cfg-attr-crate.rs2
-rw-r--r--tests/ui/cfg/cfg-macros-notfoo.rs6
-rw-r--r--tests/ui/cfg/cfg-match-arm.rs4
-rw-r--r--tests/ui/cfg/cfg-panic-abort.rs4
-rw-r--r--tests/ui/cfg/cfg-panic.rs4
-rw-r--r--tests/ui/cfg/cfg_stmt_expr.rs34
-rw-r--r--tests/ui/cfg/conditional-compile.rs44
-rw-r--r--tests/ui/cfg/diagnostics-reexport.rs6
-rw-r--r--tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed9
-rw-r--r--tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr14
-rw-r--r--tests/ui/compiletest-self-test/run-rustfix-revisions.rs9
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs4
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr10
-rw-r--r--tests/ui/conditional-compilation/cfg-in-crate-1.rs2
-rw-r--r--tests/ui/conditional-compilation/cfg-in-crate-1.stderr6
-rw-r--r--tests/ui/conditional-compilation/cfg-non-opt-expr.rs6
-rw-r--r--tests/ui/conditional-compilation/cfg-non-opt-expr.stderr6
-rw-r--r--tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs15
-rw-r--r--tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr19
-rw-r--r--tests/ui/editions/edition-raw-pointer-method-2018.rs2
-rw-r--r--tests/ui/editions/edition-raw-pointer-method-2018.stderr16
-rw-r--r--tests/ui/expr/if/attrs/cfg-false-if-attr.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-type_privacy_lints.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr14
-rw-r--r--tests/ui/filter-block-view-items.rs2
-rw-r--r--tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs19
-rw-r--r--tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr14
-rw-r--r--tests/ui/impl-trait/different_where_bounds.rs27
-rw-r--r--tests/ui/impl-trait/equality-in-canonical-query.clone.stderr23
-rw-r--r--tests/ui/impl-trait/equality-in-canonical-query.rs11
-rw-r--r--tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs42
-rw-r--r--tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr16
-rw-r--r--tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs20
-rw-r--r--tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr15
-rw-r--r--tests/ui/impl-trait/nested-hkl-lifetime.rs32
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb.rs2
-rw-r--r--tests/ui/impl-trait/nested-rpit-hrtb.stderr7
-rw-r--r--tests/ui/imports/unused-import-issue-87973.rs2
-rw-r--r--tests/ui/inference/issue-80409.no-compat.stderr2
-rw-r--r--tests/ui/inner-attrs-on-impl.rs6
-rw-r--r--tests/ui/instrument-coverage/off-values.rs4
-rw-r--r--tests/ui/issues/issue-11004.rs4
-rw-r--r--tests/ui/issues/issue-11085.rs8
-rw-r--r--tests/ui/issues/issue-16819.rs2
-rw-r--r--tests/ui/issues/issue-21763.rs2
-rw-r--r--tests/ui/layout/base-layout-is-sized-ice-123078.rs17
-rw-r--r--tests/ui/layout/base-layout-is-sized-ice-123078.stderr31
-rw-r--r--tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs10
-rw-r--r--tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr27
-rw-r--r--tests/ui/linkage-attr/auxiliary/issue-12133-dylib.rs (renamed from tests/ui/issues/auxiliary/issue-12133-dylib.rs)0
-rw-r--r--tests/ui/linkage-attr/auxiliary/issue-12133-dylib2.rs (renamed from tests/ui/issues/auxiliary/issue-12133-dylib2.rs)0
-rw-r--r--tests/ui/linkage-attr/auxiliary/issue-12133-rlib.rs (renamed from tests/ui/issues/auxiliary/issue-12133-rlib.rs)0
-rw-r--r--tests/ui/linkage-attr/framework.omit.stderr2
-rw-r--r--tests/ui/linkage-attr/framework.rs4
-rw-r--r--tests/ui/linkage-attr/issue-12133-1.rs (renamed from tests/ui/issues/issue-12133-1.rs)0
-rw-r--r--tests/ui/linkage-attr/issue-12133-2.rs (renamed from tests/ui/issues/issue-12133-2.rs)0
-rw-r--r--tests/ui/linkage-attr/issue-12133-3.rs (renamed from tests/ui/issues/issue-12133-3.rs)0
-rw-r--r--tests/ui/lint/unused_braces_macro.rs2
-rw-r--r--tests/ui/macros/macro-attributes.rs2
-rw-r--r--tests/ui/macros/macro-error.rs2
-rw-r--r--tests/ui/macros/macro-error.stderr4
-rw-r--r--tests/ui/macros/macro-inner-attributes.rs4
-rw-r--r--tests/ui/macros/macro-outer-attributes.rs4
-rw-r--r--tests/ui/macros/macro-with-attrs2.rs4
-rw-r--r--tests/ui/methods/call_method_unknown_pointee.rs8
-rw-r--r--tests/ui/methods/call_method_unknown_pointee.stderr40
-rw-r--r--tests/ui/modules/auxiliary/issue-13872-1.rs (renamed from tests/ui/issues/auxiliary/issue-13872-1.rs)0
-rw-r--r--tests/ui/modules/auxiliary/issue-13872-2.rs (renamed from tests/ui/issues/auxiliary/issue-13872-2.rs)0
-rw-r--r--tests/ui/modules/auxiliary/issue-13872-3.rs (renamed from tests/ui/issues/auxiliary/issue-13872-3.rs)0
-rw-r--r--tests/ui/modules/auxiliary/issue-1920.rs (renamed from tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs)0
-rw-r--r--tests/ui/modules/issue-13872.rs (renamed from tests/ui/issues/issue-13872.rs)0
-rw-r--r--tests/ui/modules/issue-1920-1.rs (renamed from tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs)0
-rw-r--r--tests/ui/modules/issue-1920-1.stderr (renamed from tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr)0
-rw-r--r--tests/ui/modules/issue-1920-2.rs (renamed from tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs)0
-rw-r--r--tests/ui/modules/issue-1920-2.stderr (renamed from tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr)0
-rw-r--r--tests/ui/modules/issue-1920-3.rs (renamed from tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs)0
-rw-r--r--tests/ui/modules/issue-1920-3.stderr (renamed from tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr)0
-rw-r--r--tests/ui/nested-cfg-attrs.rs2
-rw-r--r--tests/ui/nll/issue-40510-1.rs (renamed from tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs)0
-rw-r--r--tests/ui/nll/issue-40510-1.stderr (renamed from tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr)0
-rw-r--r--tests/ui/nll/issue-40510-2.rs (renamed from tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs)0
-rw-r--r--tests/ui/nll/issue-40510-3.rs (renamed from tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs)0
-rw-r--r--tests/ui/nll/issue-40510-3.stderr (renamed from tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr)0
-rw-r--r--tests/ui/nll/issue-40510-4.rs (renamed from tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs)0
-rw-r--r--tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed2
-rw-r--r--tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr2
-rw-r--r--tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr6
-rw-r--r--tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs2
-rw-r--r--tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs4
-rw-r--r--tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr10
-rw-r--r--tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs2
-rw-r--r--tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr2
-rw-r--r--tests/ui/parser/issues/issue-103381.fixed15
-rw-r--r--tests/ui/parser/issues/issue-103381.rs15
-rw-r--r--tests/ui/privacy/unnameable_types.rs1
-rw-r--r--tests/ui/privacy/unnameable_types.stderr8
-rw-r--r--tests/ui/proc-macro/modify-ast.rs2
-rw-r--r--tests/ui/recursion/issue-23302-1.rs (renamed from tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs)0
-rw-r--r--tests/ui/recursion/issue-23302-1.stderr (renamed from tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr)0
-rw-r--r--tests/ui/recursion/issue-23302-2.rs (renamed from tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs)0
-rw-r--r--tests/ui/recursion/issue-23302-2.stderr (renamed from tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr)0
-rw-r--r--tests/ui/recursion/issue-23302-3.rs (renamed from tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs)0
-rw-r--r--tests/ui/recursion/issue-23302-3.stderr (renamed from tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr)0
-rw-r--r--tests/ui/sanitizer/cfg-kasan.rs4
-rw-r--r--tests/ui/sanitizer/cfi-fn-ptr.rs (renamed from tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs)8
-rw-r--r--tests/ui/sanitizer/kcfi-mangling.rs30
-rw-r--r--tests/ui/stmt_expr_attrs_no_feature.rs32
-rw-r--r--tests/ui/suggestions/option-to-bool.rs2
-rw-r--r--tests/ui/suggestions/option-to-bool.stderr2
-rw-r--r--tests/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--tests/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--tests/ui/traits/issue-2611-3.rs (renamed from tests/ui/issues/issue-2611-3.rs)0
-rw-r--r--tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs244
-rw-r--r--tests/ui/transmutability/arrays/huge-len.stderr4
-rw-r--r--tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr12
-rw-r--r--tests/ui/transmutability/enums/niche_optimization.rs156
-rw-r--r--tests/ui/transmutability/enums/repr/padding_differences.rs80
-rw-r--r--tests/ui/transmutability/enums/repr/should_handle_all.rs (renamed from tests/ui/transmutability/enums/repr/should_require_well_defined_layout.rs)21
-rw-r--r--tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr135
-rw-r--r--tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr2
-rw-r--r--tests/ui/transmutability/maybeuninit.rs43
-rw-r--r--tests/ui/transmutability/maybeuninit.stderr18
-rw-r--r--tests/ui/transmutability/references/unsafecell.rs47
-rw-r--r--tests/ui/transmutability/references/unsafecell.stderr33
-rw-r--r--tests/ui/transmutability/structs/repr/should_handle_all.rs (renamed from tests/ui/transmutability/structs/repr/should_require_well_defined_layout.rs)29
-rw-r--r--tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr267
-rw-r--r--tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs1
-rw-r--r--tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr19
-rw-r--r--tests/ui/transmutability/transmute-padding-ice.rs9
-rw-r--r--tests/ui/transmutability/transmute-padding-ice.stderr22
-rw-r--r--tests/ui/transmutability/uninhabited.rs71
-rw-r--r--tests/ui/transmutability/uninhabited.stderr86
-rw-r--r--tests/ui/transmutability/unions/repr/should_handle_align.rs4
-rw-r--r--tests/ui/transmutability/unions/repr/should_handle_all.rs (renamed from tests/ui/transmutability/unions/repr/should_require_well_defined_layout.rs)24
-rw-r--r--tests/ui/transmutability/unions/repr/should_handle_packed.rs1
-rw-r--r--tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr47
-rw-r--r--tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs11
-rw-r--r--tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr23
-rw-r--r--tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs12
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs (renamed from tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs)6
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr9
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs (renamed from tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs)2
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr9
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs10
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr9
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs16
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr39
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr10
-rw-r--r--tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr10
-rw-r--r--tests/ui/type/pattern_types/bad_pat.rs14
-rw-r--r--tests/ui/type/pattern_types/bad_pat.stderr25
-rw-r--r--tests/ui/type/pattern_types/derives.noimpl.stderr14
-rw-r--r--tests/ui/type/pattern_types/derives.rs20
-rw-r--r--tests/ui/type/pattern_types/derives.stderr14
-rw-r--r--tests/ui/type/pattern_types/feature-gate-pattern_types.rs14
-rw-r--r--tests/ui/type/pattern_types/feature-gate-pattern_types.stderr48
-rw-r--r--tests/ui/type/pattern_types/feature-gate-pattern_types2.rs12
-rw-r--r--tests/ui/type/pattern_types/macros.active.stderr10
-rw-r--r--tests/ui/type/pattern_types/macros.gated.stderr10
-rw-r--r--tests/ui/type/pattern_types/macros.rs15
-rw-r--r--tests/ui/type/pattern_types/range_patterns.rs23
-rw-r--r--tests/ui/type/pattern_types/range_patterns.stderr343
-rw-r--r--tests/ui/type/pattern_types/range_patterns_inherent_impls.rs30
-rw-r--r--tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr16
-rw-r--r--tests/ui/type/pattern_types/range_patterns_trait_impls.rs19
-rw-r--r--tests/ui/type/pattern_types/range_patterns_trait_impls2.rs16
-rw-r--r--tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr14
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable.rs15
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable.stderr12
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable_math.rs16
-rw-r--r--tests/ui/type/pattern_types/range_patterns_unusable_math.stderr11
-rw-r--r--tests/ui/type/pattern_types/range_patterns_usage.rs26
-rw-r--r--tests/ui/type/pattern_types/unimplemented_pat.rs15
-rw-r--r--tests/ui/type/pattern_types/unimplemented_pat.stderr23
-rw-r--r--tests/ui/unsized/issue-23649-1.rs (renamed from tests/ui/issues/issue-23649-1.rs)0
-rw-r--r--tests/ui/unsized/issue-23649-2.rs (renamed from tests/ui/issues/issue-23649-2.rs)0
-rw-r--r--tests/ui/unsized/issue-23649-3.rs (renamed from tests/ui/issues/issue-23649-3.rs)0
492 files changed, 8535 insertions, 3517 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 17856e1f52a..b1bdaef81ff 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3670,6 +3670,7 @@ dependencies = [
  "rustc_metadata",
  "rustc_middle",
  "rustc_query_system",
+ "rustc_sanitizers",
  "rustc_session",
  "rustc_span",
  "rustc_symbol_mangling",
@@ -4559,6 +4560,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_sanitizers"
+version = "0.0.0"
+dependencies = [
+ "bitflags 2.5.0",
+ "rustc_data_structures",
+ "rustc_hir",
+ "rustc_middle",
+ "rustc_span",
+ "rustc_target",
+ "rustc_trait_selection",
+ "tracing",
+ "twox-hash",
+]
+
+[[package]]
 name = "rustc_serialize"
 version = "0.0.0"
 dependencies = [
@@ -4633,7 +4649,6 @@ dependencies = [
 name = "rustc_symbol_mangling"
 version = "0.0.0"
 dependencies = [
- "bitflags 2.5.0",
  "punycode",
  "rustc-demangle",
  "rustc_data_structures",
@@ -4643,9 +4658,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
- "rustc_trait_selection",
  "tracing",
- "twox-hash",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index e12c968e205..bbf4ecfe61d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -96,6 +96,7 @@ adler.debug = 0
 gimli.debug = 0
 miniz_oxide.debug = 0
 object.debug = 0
+rustc-demangle.debug = 0
 
 # These are very thin wrappers around executing lld with the right binary name.
 # Basically nothing within them can go wrong without having been explicitly logged anyway.
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e29ef591bcb..63ce6685e43 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2152,6 +2152,9 @@ pub enum TyKind {
     MacCall(P<MacCall>),
     /// Placeholder for a `va_list`.
     CVarArgs,
+    /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZeroU32`,
+    /// just as part of the type system.
+    Pat(P<Ty>, P<Pat>),
     /// Sometimes we need a dummy value when no error has occurred.
     Dummy,
     /// Placeholder for a kind that has failed to be defined.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 7337b969242..da57def263d 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -502,6 +502,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
         }
         TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)),
         TyKind::Paren(ty) => vis.visit_ty(ty),
+        TyKind::Pat(ty, pat) => {
+            vis.visit_ty(ty);
+            vis.visit_pat(pat);
+        }
         TyKind::Path(qself, path) => {
             vis.visit_qself(qself);
             vis.visit_path(path);
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 18986fb7504..9e9ae52962d 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -446,6 +446,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
             }
             try_visit!(visitor.visit_path(path, typ.id));
         }
+        TyKind::Pat(ty, pat) => {
+            try_visit!(visitor.visit_ty(ty));
+            try_visit!(visitor.visit_pat(pat));
+        }
         TyKind::Array(ty, length) => {
             try_visit!(visitor.visit_ty(ty));
             try_visit!(visitor.visit_anon_const(length));
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 1c34fd0afbb..4c552289a81 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -381,4 +381,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
             ArrayLen::Body(..) => intravisit::walk_array_len(self, len),
         }
     }
+
+    fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
+        self.visit_pat(p)
+    }
 }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 8cf347bfa96..5005c22d4cc 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1463,7 +1463,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                 }
             }
-            TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
+            TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)),
+            TyKind::MacCall(_) => {
+                span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
+            }
             TyKind::CVarArgs => {
                 let guar = self.dcx().span_delayed_bug(
                     t.span,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 5912dd3f931..d7cd3efe408 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -332,6 +332,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ast::TyKind::Never => {
                 gate!(&self, never_type, ty.span, "the `!` type is experimental");
             }
+            ast::TyKind::Pat(..) => {
+                gate!(&self, pattern_types, ty.span, "pattern types are unstable");
+            }
             _ => {}
         }
         visit::walk_ty(self, ty)
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 3ea182c5867..51ccfe89fbd 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1188,6 +1188,11 @@ impl<'a> State<'a> {
             ast::TyKind::CVarArgs => {
                 self.word("...");
             }
+            ast::TyKind::Pat(ty, pat) => {
+                self.print_type(ty);
+                self.word(" is ");
+                self.print_pat(pat);
+            }
         }
         self.end();
     }
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index 31307ef1410..64726eacca7 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -4,7 +4,6 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::{Body, Promoted};
-use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::TyCtxt;
 use std::rc::Rc;
 
@@ -106,7 +105,7 @@ pub fn get_body_with_borrowck_facts(
     options: ConsumerOptions,
 ) -> BodyWithBorrowckFacts<'_> {
     let (input_body, promoted) = tcx.mir_promoted(def);
-    let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
+    let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build();
     let input_body: &Body<'_> = &input_body.borrow();
     let promoted: &IndexSlice<_, _> = &promoted.borrow();
     *super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap()
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 4a5ba441878..7fbf4c47ec8 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -32,7 +32,6 @@ use rustc_infer::infer::{
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
-use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
 use rustc_session::lint::builtin::UNUSED_MUT;
 use rustc_span::{Span, Symbol};
@@ -126,7 +125,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
         return tcx.arena.alloc(result);
     }
 
-    let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build();
+    let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build();
     let promoted: &IndexSlice<_, _> = &promoted.borrow();
     let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0;
     debug!("mir_borrowck done");
@@ -1606,6 +1605,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ty::Foreign(_)
                     | ty::Str
                     | ty::Array(_, _)
+                    | ty::Pat(_, _)
                     | ty::Slice(_)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(_)
@@ -1648,6 +1648,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     | ty::Foreign(_)
                     | ty::Str
                     | ty::Array(_, _)
+                    | ty::Pat(_, _)
                     | ty::Slice(_)
                     | ty::RawPtr(_, _)
                     | ty::Ref(_, _, _)
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 63b80445817..9f0e54febe4 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -7,7 +7,6 @@ use rustc_infer::infer::TyCtxtInferExt as _;
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_macros::extension;
-use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
@@ -133,6 +132,18 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             let ty =
                 infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type);
+
+            // Sometimes, when the hidden type is an inference variable, it can happen that
+            // the hidden type becomes the opaque type itself. In this case, this was an opaque
+            // usage of the opaque type and we can ignore it. This check is mirrored in typeck's
+            // writeback.
+            // FIXME(-Znext-solver): This should be unnecessary with the new solver.
+            if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
+                && alias_ty.def_id == opaque_type_key.def_id.to_def_id()
+                && alias_ty.args == opaque_type_key.args
+            {
+                continue;
+            }
             // Sometimes two opaque types are the same only after we remap the generic parameters
             // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
             // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
@@ -321,13 +332,13 @@ fn check_opaque_type_well_formed<'tcx>(
         parent_def_id = tcx.local_parent(parent_def_id);
     }
 
-    // FIXME(-Znext-solver): We probably should use `DefiningAnchor::Bind(&[])`
+    // FIXME(-Znext-solver): We probably should use `&[]` instead of
     // and prepopulate this `InferCtxt` with known opaque values, rather than
-    // using the `Bind` anchor here. For now it's fine.
+    // allowing opaque types to be defined and checking them after the fact.
     let infcx = tcx
         .infer_ctxt()
         .with_next_trait_solver(next_trait_solver)
-        .with_opaque_type_inference(DefiningAnchor::bind(tcx, parent_def_id))
+        .with_opaque_type_inference(parent_def_id)
         .build();
     let ocx = ObligationCtxt::new(&infcx);
     let identity_args = GenericArgs::identity_for_item(tcx, def_id);
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index f28b786e4f7..a950f10787b 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -39,6 +39,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 
         let TypeOpOutput { output, constraints, error_info } =
             op.fully_perform(self.infcx, locations.span(self.body))?;
+        if cfg!(debug_assertions) {
+            let data = self.infcx.take_and_reset_region_constraints();
+            if !data.is_empty() {
+                panic!("leftover region constraints: {data:#?}");
+            }
+        }
 
         debug!(?output, ?constraints);
 
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 554dac0852f..1b4c6041294 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -46,6 +46,7 @@ mod format;
 mod format_foreign;
 mod global_allocator;
 mod log_syntax;
+mod pattern_type;
 mod source_util;
 mod test;
 mod trace_macros;
@@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
         option_env: env::expand_option_env,
+        pattern_type: pattern_type::expand,
         std_panic: edition_panic::expand_panic,
         stringify: source_util::expand_stringify,
         trace_macros: trace_macros::expand_trace_macros,
diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
new file mode 100644
index 00000000000..54039c2c538
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -0,0 +1,29 @@
+use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty};
+use rustc_errors::PResult;
+use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
+use rustc_span::{sym, Span};
+
+pub fn expand<'cx>(
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> MacroExpanderResult<'cx> {
+    let (ty, pat) = match parse_pat_ty(cx, tts) {
+        Ok(parsed) => parsed,
+        Err(err) => {
+            return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
+        }
+    };
+
+    ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat))))
+}
+
+fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<Pat>)> {
+    let mut parser = cx.new_parser_from_tts(stream);
+
+    let ty = parser.parse_ty()?;
+    parser.eat_keyword(sym::is);
+    let pat = parser.parse_pat_no_top_alt(None, None)?;
+
+    Ok((ty, pat))
+}
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 1307a62a60d..771e5b21958 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -267,7 +267,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
         .generic_activity("codegen prelude")
         .run(|| crate::abi::codegen_fn_prelude(fx, start_block));
 
-    for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() {
+    for (bb, bb_data) in traversal::mono_reachable(fx.mir, fx.tcx, fx.instance) {
         let block = fx.get_block(bb);
         fx.bcx.switch_to_block(block);
 
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 75268341a4f..e8c96486041 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -341,6 +341,8 @@ fn emit_cgu(
             object: Some(global_asm_object_file),
             dwarf_object: None,
             bytecode: None,
+            assembly: None,
+            llvm_ir: None,
         }),
         existing_work_product: None,
     })
@@ -378,7 +380,15 @@ fn emit_module(
 
     prof.artifact_size("object_file", &*name, file.metadata().unwrap().len());
 
-    Ok(CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None })
+    Ok(CompiledModule {
+        name,
+        kind,
+        object: Some(tmp_file),
+        dwarf_object: None,
+        bytecode: None,
+        assembly: None,
+        llvm_ir: None,
+    })
 }
 
 fn reuse_workproduct_for_cgu(
@@ -426,6 +436,8 @@ fn reuse_workproduct_for_cgu(
             object: Some(obj_out_regular),
             dwarf_object: None,
             bytecode: None,
+            assembly: None,
+            llvm_ir: None,
         },
         module_global_asm: has_global_asm.then(|| CompiledModule {
             name: cgu.name().to_string(),
@@ -433,6 +445,8 @@ fn reuse_workproduct_for_cgu(
             object: Some(obj_out_global_asm),
             dwarf_object: None,
             bytecode: None,
+            assembly: None,
+            llvm_ir: None,
         }),
         existing_work_product: Some((cgu.work_product_id(), work_product)),
     })
@@ -678,6 +692,8 @@ pub(crate) fn run_aot(
             object: Some(tmp_file),
             dwarf_object: None,
             bytecode: None,
+            assembly: None,
+            llvm_ir: None,
         })
     } else {
         None
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
index 76a619a1af7..3ea5be1ee56 100644
--- a/compiler/rustc_codegen_gcc/src/back/write.rs
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -158,6 +158,8 @@ pub(crate) unsafe fn codegen(
         config.emit_obj != EmitObj::None,
         cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
         config.emit_bc,
+        config.emit_asm,
+        config.emit_ir,
         &cgcx.output_filenames,
     ))
 }
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index 3fda59e8b52..bb5045ec872 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -28,6 +28,7 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_metadata = { path = "../rustc_metadata" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_query_system = { path = "../rustc_query_system" }
+rustc_sanitizers = { path = "../rustc_sanitizers" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index d2828669d43..f918facc86d 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -150,7 +150,10 @@ impl LlvmType for CastTarget {
         // Simplify to a single unit or an array if there's no prefix.
         // This produces the same layout, but using a simpler type.
         if self.prefix.iter().all(|x| x.is_none()) {
-            if rest_count == 1 {
+            // We can't do this if is_consecutive is set and the unit would get
+            // split on the target. Currently, this is only relevant for i128
+            // registers.
+            if rest_count == 1 && (!self.rest.is_consecutive || self.rest.unit != Reg::i128()) {
                 return rest_ll_unit;
             }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 68ba8cbf7b7..49f9d7ddab6 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -880,6 +880,8 @@ pub(crate) unsafe fn codegen(
         config.emit_obj != EmitObj::None,
         dwarf_object_emitted,
         config.emit_bc,
+        config.emit_asm,
+        config.emit_ir,
         &cgcx.output_filenames,
     ))
 }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 1a32958d362..b7235972204 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -20,12 +20,9 @@ use rustc_middle::ty::layout::{
     FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_sanitizers::{cfi, kcfi};
 use rustc_session::config::OptLevel;
 use rustc_span::Span;
-use rustc_symbol_mangling::typeid::{
-    kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
-    TypeIdOptions,
-};
 use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
 use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
 use smallvec::SmallVec;
@@ -1632,18 +1629,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
                 return;
             }
 
-            let mut options = TypeIdOptions::empty();
+            let mut options = cfi::TypeIdOptions::empty();
             if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
-                options.insert(TypeIdOptions::GENERALIZE_POINTERS);
+                options.insert(cfi::TypeIdOptions::GENERALIZE_POINTERS);
             }
             if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
-                options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
+                options.insert(cfi::TypeIdOptions::NORMALIZE_INTEGERS);
             }
 
             let typeid = if let Some(instance) = instance {
-                typeid_for_instance(self.tcx, instance, options)
+                cfi::typeid_for_instance(self.tcx, instance, options)
             } else {
-                typeid_for_fnabi(self.tcx, fn_abi, options)
+                cfi::typeid_for_fnabi(self.tcx, fn_abi, options)
             };
             let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
 
@@ -1680,18 +1677,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
                 return None;
             }
 
-            let mut options = TypeIdOptions::empty();
+            let mut options = kcfi::TypeIdOptions::empty();
             if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
-                options.insert(TypeIdOptions::GENERALIZE_POINTERS);
+                options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS);
             }
             if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
-                options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
+                options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS);
             }
 
             let kcfi_typeid = if let Some(instance) = instance {
-                kcfi_typeid_for_instance(self.tcx, instance, options)
+                kcfi::typeid_for_instance(self.tcx, instance, options)
             } else {
-                kcfi_typeid_for_fnabi(self.tcx, fn_abi, options)
+                kcfi::typeid_for_fnabi(self.tcx, fn_abi, options)
             };
 
             Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index f86cdcaa6f7..7117c4a0ed9 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -22,10 +22,7 @@ use itertools::Itertools;
 use rustc_codegen_ssa::traits::TypeMembershipMethods;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::ty::{Instance, Ty};
-use rustc_symbol_mangling::typeid::{
-    kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
-    TypeIdOptions,
-};
+use rustc_sanitizers::{cfi, kcfi};
 use smallvec::SmallVec;
 
 /// Declare a function.
@@ -145,27 +142,29 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
             if let Some(instance) = instance {
                 let mut typeids = FxIndexSet::default();
                 for options in [
-                    TypeIdOptions::GENERALIZE_POINTERS,
-                    TypeIdOptions::NORMALIZE_INTEGERS,
-                    TypeIdOptions::USE_CONCRETE_SELF,
+                    cfi::TypeIdOptions::GENERALIZE_POINTERS,
+                    cfi::TypeIdOptions::NORMALIZE_INTEGERS,
+                    cfi::TypeIdOptions::USE_CONCRETE_SELF,
                 ]
                 .into_iter()
                 .powerset()
-                .map(TypeIdOptions::from_iter)
+                .map(cfi::TypeIdOptions::from_iter)
                 {
-                    let typeid = typeid_for_instance(self.tcx, instance, options);
+                    let typeid = cfi::typeid_for_instance(self.tcx, instance, options);
                     if typeids.insert(typeid.clone()) {
                         self.add_type_metadata(llfn, typeid);
                     }
                 }
             } else {
-                for options in
-                    [TypeIdOptions::GENERALIZE_POINTERS, TypeIdOptions::NORMALIZE_INTEGERS]
-                        .into_iter()
-                        .powerset()
-                        .map(TypeIdOptions::from_iter)
+                for options in [
+                    cfi::TypeIdOptions::GENERALIZE_POINTERS,
+                    cfi::TypeIdOptions::NORMALIZE_INTEGERS,
+                ]
+                .into_iter()
+                .powerset()
+                .map(cfi::TypeIdOptions::from_iter)
                 {
-                    let typeid = typeid_for_fnabi(self.tcx, fn_abi, options);
+                    let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options);
                     self.add_type_metadata(llfn, typeid);
                 }
             }
@@ -173,19 +172,19 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
 
         if self.tcx.sess.is_sanitizer_kcfi_enabled() {
             // LLVM KCFI does not support multiple !kcfi_type attachments
-            let mut options = TypeIdOptions::empty();
+            let mut options = kcfi::TypeIdOptions::empty();
             if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
-                options.insert(TypeIdOptions::GENERALIZE_POINTERS);
+                options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS);
             }
             if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
-                options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
+                options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS);
             }
 
             if let Some(instance) = instance {
-                let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, instance, options);
+                let kcfi_typeid = kcfi::typeid_for_instance(self.tcx, instance, options);
                 self.set_kcfi_type_metadata(llfn, kcfi_typeid);
             } else {
-                let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
+                let kcfi_typeid = kcfi::typeid_for_fnabi(self.tcx, fn_abi, options);
                 self.set_kcfi_type_metadata(llfn, kcfi_typeid);
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index b7bcaac3b18..e7f692144ff 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -528,12 +528,20 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
     for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
         let mut files = Vec::new();
         if let Some(object_file_path) = &module.object {
-            files.push(("o", object_file_path.as_path()));
+            files.push((OutputType::Object.extension(), object_file_path.as_path()));
         }
         if let Some(dwarf_object_file_path) = &module.dwarf_object {
             files.push(("dwo", dwarf_object_file_path.as_path()));
         }
-
+        if let Some(path) = &module.assembly {
+            files.push((OutputType::Assembly.extension(), path.as_path()));
+        }
+        if let Some(path) = &module.llvm_ir {
+            files.push((OutputType::LlvmAssembly.extension(), path.as_path()));
+        }
+        if let Some(path) = &module.bytecode {
+            files.push((OutputType::Bitcode.extension(), path.as_path()));
+        }
         if let Some((id, product)) =
             copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice())
         {
@@ -937,12 +945,28 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
             load_from_incr_comp_dir(dwarf_obj_out, saved_dwarf_object_file)
         });
 
+    let load_from_incr_cache = |perform, output_type: OutputType| {
+        if perform {
+            let saved_file = module.source.saved_files.get(output_type.extension())?;
+            let output_path = cgcx.output_filenames.temp_path(output_type, Some(&module.name));
+            load_from_incr_comp_dir(output_path, &saved_file)
+        } else {
+            None
+        }
+    };
+
+    let assembly = load_from_incr_cache(module_config.emit_asm, OutputType::Assembly);
+    let llvm_ir = load_from_incr_cache(module_config.emit_ir, OutputType::LlvmAssembly);
+    let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode);
+
     WorkItemResult::Finished(CompiledModule {
         name: module.name,
         kind: ModuleKind::Regular,
         object,
         dwarf_object,
-        bytecode: None,
+        bytecode,
+        assembly,
+        llvm_ir,
     })
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 410b5d27c57..c4c16ee7311 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -656,6 +656,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                 object: Some(file_name),
                 dwarf_object: None,
                 bytecode: None,
+                assembly: None,
+                llvm_ir: None,
             }
         })
     });
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 64448441acb..5f0dcf9510f 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -202,6 +202,16 @@ fn push_debuginfo_type_name<'tcx>(
                 }
             }
         }
+        ty::Pat(inner_type, pat) => {
+            if cpp_like_debuginfo {
+                output.push_str("pat$<");
+                push_debuginfo_type_name(tcx, inner_type, true, output, visited);
+                // FIXME(wg-debugging): implement CPP like printing for patterns.
+                write!(output, ",{:?}>", pat).unwrap();
+            } else {
+                write!(output, "{:?}", t).unwrap();
+            }
+        }
         ty::Slice(inner_type) => {
             if cpp_like_debuginfo {
                 output.push_str("slice2$<");
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 9be8dcf166d..80fe7e0bb78 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -79,13 +79,26 @@ impl<M> ModuleCodegen<M> {
         emit_obj: bool,
         emit_dwarf_obj: bool,
         emit_bc: bool,
+        emit_asm: bool,
+        emit_ir: bool,
         outputs: &OutputFilenames,
     ) -> CompiledModule {
         let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name)));
         let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name)));
         let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name)));
+        let assembly = emit_asm.then(|| outputs.temp_path(OutputType::Assembly, Some(&self.name)));
+        let llvm_ir =
+            emit_ir.then(|| outputs.temp_path(OutputType::LlvmAssembly, Some(&self.name)));
 
-        CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode }
+        CompiledModule {
+            name: self.name.clone(),
+            kind: self.kind,
+            object,
+            dwarf_object,
+            bytecode,
+            assembly,
+            llvm_ir,
+        }
     }
 }
 
@@ -96,6 +109,8 @@ pub struct CompiledModule {
     pub object: Option<PathBuf>,
     pub dwarf_object: Option<PathBuf>,
     pub bytecode: Option<PathBuf>,
+    pub assembly: Option<PathBuf>, // --emit=asm
+    pub llvm_ir: Option<PathBuf>,  // --emit=llvm-ir, llvm-bc is in bytecode
 }
 
 pub struct CachedModuleCodegen {
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 387a5366b20..1f4473d2ec4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -257,20 +257,19 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     // Apply debuginfo to the newly allocated locals.
     fx.debug_introduce_locals(&mut start_bx);
 
-    let reachable_blocks = mir.reachable_blocks_in_mono(cx.tcx(), instance);
-
     // The builders will be created separately for each basic block at `codegen_block`.
     // So drop the builder of `start_llbb` to avoid having two at the same time.
     drop(start_bx);
 
+    let reachable_blocks = traversal::mono_reachable_as_bitset(mir, cx.tcx(), instance);
+
     // Codegen the body of each block using reverse postorder
     for (bb, _) in traversal::reverse_postorder(mir) {
         if reachable_blocks.contains(bb) {
             fx.codegen_block(bb);
         } else {
-            // This may have references to things we didn't monomorphize, so we
-            // don't actually codegen the body. We still create the block so
-            // terminators in other blocks can reference it without worry.
+            // We want to skip this block, because it's not reachable. But we still create
+            // the block so terminators in other blocks can reference it.
             fx.codegen_block_as_unreachable(bb);
         }
     }
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index d91ad3fcab1..dcfce4e35e0 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,3 +1,4 @@
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
@@ -98,6 +99,16 @@ fn const_to_valtree_inner<'tcx>(
             Ok(ty::ValTree::Leaf(val.assert_int()))
         }
 
+        ty::Pat(base, ..) => {
+            let mut place = place.clone();
+            // The valtree of the base type is the same as the valtree of the pattern type.
+            // Since the returned valtree does not contain the type or layout, we can just
+            // switch to the base type.
+            place.layout = ecx.layout_of(*base).unwrap();
+            ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes))
+        },
+
+
         ty::RawPtr(_, _) => {
             // Not all raw pointers are allowed, as we cannot properly test them for
             // equality at compile-time (see `ptr_guaranteed_cmp`).
@@ -273,7 +284,7 @@ pub fn valtree_to_const_value<'tcx>(
 
     let (param_env, ty) = param_env_ty.into_parts();
 
-    match ty.kind() {
+    match *ty.kind() {
         ty::FnDef(..) => {
             assert!(valtree.unwrap_branch().is_empty());
             mir::ConstValue::ZeroSized
@@ -286,10 +297,11 @@ pub fn valtree_to_const_value<'tcx>(
                 ),
             }
         }
+        ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree),
         ty::Ref(_, inner_ty, _) => {
             let mut ecx =
                 mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No);
-            let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty);
+            let imm = valtree_to_ref(&mut ecx, valtree, inner_ty);
             let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap());
             op_to_const(&ecx, &imm.into(), /* for diagnostics */ false)
         }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 3283bcc4c45..62d169db628 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1060,6 +1060,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
                 ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)),
 
+                ty::Pat(ty, ..) => is_very_trivially_sized(*ty),
+
                 // We don't want to do any queries, so there is not much we can do with ADTs.
                 ty::Adt(..) => false,
 
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index a8478f721c7..63c709d8aed 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -69,6 +69,10 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => {
                 throw_inval!(TooGeneric)
             }
+            ty::Pat(_, pat) => match **pat {
+                ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx),
+                // Future pattern kinds may have more variants
+            },
             ty::Bound(_, _) => bug!("bound ty during ctfe"),
             ty::Bool
             | ty::Char
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index d18600ce7d7..9911c59d4b8 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -640,6 +640,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             | ty::Str
             | ty::Dynamic(..)
             | ty::Closure(..)
+            | ty::Pat(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(..) => Ok(false),
             // Some types only occur during typechecking, they have no layout.
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index f3db7d4cd42..e474b952938 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -31,6 +31,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
             | ty::Uint(_)
             | ty::Float(_)
             | ty::Str
+            | ty::Pat(_, _)
             | ty::Array(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index 1b69a6e2fbe..62391daecd0 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -2,7 +2,7 @@ driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
 driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
 driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly
 driver_impl_ice_bug_report_outdated =
-    it seems that this compiler `{$version}` is outdated, a newer nightly should have been released in the mean time
+    it seems that this compiler `{$version}` is outdated, a newer nightly should have been released in the meantime
     .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists
     .url = if the problem still persists, we would appreciate a bug report: {$bug_report_url}
 driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
diff --git a/compiler/rustc_error_codes/src/error_codes/E0699.md b/compiler/rustc_error_codes/src/error_codes/E0699.md
index 454d2507e5e..1094ebf4b8f 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0699.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0699.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A method was called on a raw pointer whose inner type wasn't completely known.
 
 Erroneous code example:
 
-```compile_fail,edition2018,E0699
+```compile_fail,edition2018
 # #![deny(warnings)]
 # fn main() {
 let foo = &1;
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index da688e385aa..f4a33a05c1b 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -441,7 +441,7 @@ E0695: 0695,
 E0696: 0696,
 E0697: 0697,
 E0698: 0698,
-E0699: 0699,
+E0699: 0699, // REMOVED: merged into generic inference var error
 E0700: 0700,
 E0701: 0701,
 E0703: 0703,
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index a83f9f56beb..1eee11604ce 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -355,6 +355,8 @@ declare_features! (
     (accepted, type_alias_enum_variants, "1.37.0", Some(49683)),
     /// Allows macros to appear in the type position.
     (accepted, type_macros, "1.13.0", Some(27245)),
+    /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`).
+    (accepted, type_privacy_lints, "CURRENT_RUSTC_VERSION", Some(48054)),
     /// Allows `const _: TYPE = VALUE`.
     (accepted, underscore_const_names, "1.37.0", Some(54912)),
     /// Allows `use path as _;` and `extern crate c as _;`.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 6fe51c62936..e6b19817de3 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -215,6 +215,8 @@ declare_features! (
     (internal, omit_gdb_pretty_printer_section, "1.5.0", None),
     /// Set the maximum pattern complexity allowed (not limited by default).
     (internal, pattern_complexity, "1.78.0", None),
+    /// Allows using pattern types.
+    (internal, pattern_types, "CURRENT_RUSTC_VERSION", Some(123646)),
     /// Allows using `#[prelude_import]` on glob `use` items.
     (internal, prelude_import, "1.2.0", None),
     /// Used to identify crates that contain the profiler runtime.
@@ -615,8 +617,6 @@ declare_features! (
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
     (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
-    /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`).
-    (unstable, type_privacy_lints, "1.72.0", Some(48054)),
     /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
     (unstable, unix_sigpipe, "1.65.0", Some(97889)),
     /// Allows unnamed fields of struct and union type
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index f21cd653f96..c6e3ad31f01 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2624,6 +2624,8 @@ pub enum TyKind<'hir> {
     Infer,
     /// Placeholder for a type that has failed to be defined.
     Err(rustc_span::ErrorGuaranteed),
+    /// Pattern types (`pattern_type!(u32 is 1..)`)
+    Pat(&'hir Ty<'hir>, &'hir Pat<'hir>),
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 8c44f21a57b..5da9d4444da 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -356,6 +356,11 @@ pub trait Visitor<'v>: Sized {
     fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result {
         walk_ty(self, t)
     }
+    fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) {
+        // Do nothing. Only a few visitors need to know the details of the pattern type,
+        // and they opt into it. All other visitors will just choke on our fake patterns
+        // because they aren't in a body.
+    }
     fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result {
         walk_generic_param(self, p)
     }
@@ -882,6 +887,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
         TyKind::AnonAdt(item_id) => {
             try_visit!(visitor.visit_nested_item(item_id));
         }
+        TyKind::Pat(ty, pat) => {
+            try_visit!(visitor.visit_ty(ty));
+            try_visit!(visitor.visit_pattern_type_pattern(pat));
+        }
     }
     V::Result::output()
 }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index d8a90d62dac..e66a834ab9e 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -349,6 +349,9 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
     .suggestion = cast the value to `{$cast_ty}`
     .help = cast the value to `{$cast_ty}`
 
+hir_analysis_pattern_type_non_const_range = "range patterns must have constant range start and end"
+hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pattern types"
+    .label = "this type is the same as the inner type without a pattern"
 hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
     .label = not allowed in type signatures
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 739a7086992..8d4ae10d4bf 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -13,7 +13,7 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::{Obligation, TraitEngineExt as _};
 use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::middle::stability::EvalResult;
-use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode};
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
@@ -345,10 +345,7 @@ fn check_opaque_meets_bounds<'tcx>(
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
-    let infcx = tcx
-        .infer_ctxt()
-        .with_opaque_type_inference(DefiningAnchor::bind(tcx, defining_use_anchor))
-        .build();
+    let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build();
     let ocx = ObligationCtxt::new(&infcx);
 
     let args = match *origin {
@@ -1567,7 +1564,7 @@ pub(super) fn check_coroutine_obligations(
         .ignoring_regions()
         // Bind opaque types to type checking root, as they should have been checked by borrowck,
         // but may show up in some cases, like when (root) obligations are stalled in the new solver.
-        .with_opaque_type_inference(DefiningAnchor::bind(tcx, typeck.hir_owner.def_id))
+        .with_opaque_type_inference(typeck.hir_owner.def_id)
         .build();
 
     let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx);
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 067878091a7..4a85e9983f4 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -144,7 +144,12 @@ impl<'tcx> InherentCollect<'tcx> {
         let id = id.owner_id.def_id;
         let item_span = self.tcx.def_span(id);
         let self_ty = self.tcx.type_of(id).instantiate_identity();
-        let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
+        let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty);
+        // We allow impls on pattern types exactly when we allow impls on the base type.
+        // FIXME(pattern_types): Figure out the exact coherence rules we want here.
+        while let ty::Pat(base, _) = *self_ty.kind() {
+            self_ty = base;
+        }
         match *self_ty.kind() {
             ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()),
             ty::Foreign(did) => self.check_def_id(id, self_ty, did),
@@ -154,6 +159,7 @@ impl<'tcx> InherentCollect<'tcx> {
             ty::Dynamic(..) => {
                 Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span }))
             }
+            ty::Pat(_, _) => unreachable!(),
             ty::Bool
             | ty::Char
             | ty::Int(_)
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 1770f7b4e91..5585d2e069c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -206,6 +206,11 @@ pub(crate) fn orphan_check_impl(
                 (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther)
             }
 
+            ty::Pat(..) => (
+                LocalImpl::Disallow { problematic_kind: "pattern type" },
+                NonlocalImpl::DisallowOther,
+            ),
+
             ty::Bool
             | ty::Char
             | ty::Int(..)
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 2d4742fa1dc..d129614e0e1 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -7,6 +7,8 @@ use rustc_errors::{
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
+mod pattern_types;
+pub use pattern_types::*;
 
 #[derive(Diagnostic)]
 #[diag(hir_analysis_ambiguous_assoc_item)]
@@ -1629,3 +1631,10 @@ pub struct OpaqueCapturesHigherRankedLifetime {
     pub decl_span: Span,
     pub bad_place: &'static str,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_pattern_type_non_const_range)]
+pub struct NonConstRange {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
new file mode 100644
index 00000000000..008d2698989
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs
@@ -0,0 +1,9 @@
+use rustc_macros::Diagnostic;
+use rustc_span::Span;
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_pattern_type_wild_pat)]
+pub struct WildPatTy {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index f726f2a7b89..59f0fac5aa7 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -21,7 +21,7 @@ mod object_safety;
 
 use crate::bounds::Bounds;
 use crate::collect::HirPlaceholderCollector;
-use crate::errors::AmbiguousLifetimeBound;
+use crate::errors::{AmbiguousLifetimeBound, WildPatTy};
 use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend};
 use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args};
 use crate::middle::resolve_bound_vars as rbv;
@@ -39,6 +39,7 @@ use rustc_hir::{GenericArg, GenericArgs};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::middle::stability::AllowUnstable;
+use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::ty::{
     self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
     TypeVisitableExt,
@@ -2195,6 +2196,68 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // handled specially and will not descend into this routine.
                 self.ty_infer(None, hir_ty.span)
             }
+            hir::TyKind::Pat(ty, pat) => {
+                let ty = self.lower_ty(ty);
+                let pat_ty = match pat.kind {
+                    hir::PatKind::Wild => {
+                        let err = tcx.dcx().emit_err(WildPatTy { span: pat.span });
+                        Ty::new_error(tcx, err)
+                    }
+                    hir::PatKind::Range(start, end, include_end) => {
+                        let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> {
+                            let (expr, neg) = match expr.kind {
+                                hir::ExprKind::Unary(hir::UnOp::Neg, negated) => {
+                                    (negated, Some((expr.hir_id, expr.span)))
+                                }
+                                _ => (expr, None),
+                            };
+                            let c = match &expr.kind {
+                                hir::ExprKind::Lit(lit) => {
+                                    let lit_input =
+                                        LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() };
+                                    match tcx.lit_to_const(lit_input) {
+                                        Ok(c) => c,
+                                        Err(LitToConstError::Reported(err)) => {
+                                            ty::Const::new_error(tcx, err, ty)
+                                        }
+                                        Err(LitToConstError::TypeError) => todo!(),
+                                    }
+                                }
+                                _ => {
+                                    let err = tcx
+                                        .dcx()
+                                        .emit_err(crate::errors::NonConstRange { span: expr.span });
+                                    ty::Const::new_error(tcx, err, ty)
+                                }
+                            };
+                            self.record_ty(expr.hir_id, c.ty(), expr.span);
+                            if let Some((id, span)) = neg {
+                                self.record_ty(id, c.ty(), span);
+                            }
+                            c
+                        };
+
+                        let start = start.map(expr_to_const);
+                        let end = end.map(expr_to_const);
+
+                        let include_end = match include_end {
+                            hir::RangeEnd::Included => true,
+                            hir::RangeEnd::Excluded => false,
+                        };
+
+                        let pat = tcx.mk_pat(ty::PatternKind::Range { start, end, include_end });
+                        Ty::new_pat(tcx, ty, pat)
+                    }
+                    hir::PatKind::Err(e) => Ty::new_error(tcx, e),
+                    _ => Ty::new_error_with_message(
+                        tcx,
+                        pat.span,
+                        format!("unsupported pattern for pattern type: {pat:#?}"),
+                    ),
+                };
+                self.record_ty(pat.hir_id, ty, pat.span);
+                pat_ty
+            }
             hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar),
         };
 
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 28c86d8019e..20e4110e137 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -249,6 +249,20 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_ty(current, typ, variance);
             }
 
+            ty::Pat(typ, pat) => {
+                match *pat {
+                    ty::PatternKind::Range { start, end, include_end: _ } => {
+                        if let Some(start) = start {
+                            self.add_constraints_from_const(current, start, variance);
+                        }
+                        if let Some(end) = end {
+                            self.add_constraints_from_const(current, end, variance);
+                        }
+                    }
+                }
+                self.add_constraints_from_ty(current, typ, variance);
+            }
+
             ty::Slice(typ) => {
                 self.add_constraints_from_ty(current, typ, variance);
             }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index bd528432e70..a590c648d20 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -330,6 +330,11 @@ impl<'a> State<'a> {
                 self.word("_");
             }
             hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
+            hir::TyKind::Pat(ty, pat) => {
+                self.print_type(ty);
+                self.word(" is ");
+                self.print_pat(pat);
+            }
         }
         self.end()
     }
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 1d51101c940..18d9d739dd6 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -93,9 +93,6 @@ hir_typeck_lossy_provenance_ptr2int =
     .suggestion = use `.addr()` to obtain the address of a pointer
     .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead
 
-hir_typeck_method_call_on_unknown_raw_pointee =
-    cannot call a method on a raw pointer with an unknown pointee type
-
 hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
 
 hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index c948b6343b7..92f74281ab9 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -40,17 +40,19 @@ use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
 use rustc_session::lint;
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_span::DUMMY_SP;
 use rustc_trait_selection::infer::InferCtxtExt;
 
 /// Reifies a cast check to be checked once we have full type information for
 /// a function context.
 #[derive(Debug)]
-pub struct CastCheck<'tcx> {
+pub(crate) struct CastCheck<'tcx> {
     /// The expression whose value is being casted
     expr: &'tcx hir::Expr<'tcx>,
     /// The source type for the cast expression
@@ -60,8 +62,6 @@ pub struct CastCheck<'tcx> {
     cast_ty: Ty<'tcx>,
     cast_span: Span,
     span: Span,
-    /// whether the cast is made in a const context or not.
-    pub constness: hir::Constness,
 }
 
 /// The kind of pointer and associated metadata (thin, length or vtable) - we
@@ -130,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | ty::CoroutineWitness(..)
             | ty::RawPtr(_, _)
             | ty::Ref(..)
+            | ty::Pat(..)
             | ty::FnDef(..)
             | ty::FnPtr(..)
             | ty::Closure(..)
@@ -194,18 +195,45 @@ fn make_invalid_casting_error<'a, 'tcx>(
     )
 }
 
+/// If a cast from `from_ty` to `to_ty` is valid, returns a `Some` containing the kind
+/// of the cast.
+///
+/// This is a helper used from clippy.
+pub fn check_cast<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    e: &'tcx hir::Expr<'tcx>,
+    from_ty: Ty<'tcx>,
+    to_ty: Ty<'tcx>,
+) -> Option<CastKind> {
+    let hir_id = e.hir_id;
+    let local_def_id = hir_id.owner.def_id;
+
+    let root_ctxt = crate::TypeckRootCtxt::new(tcx, local_def_id);
+    let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, local_def_id);
+
+    if let Ok(check) = CastCheck::new(
+        &fn_ctxt, e, from_ty, to_ty,
+        // We won't show any errors to the user, so the span is irrelevant here.
+        DUMMY_SP, DUMMY_SP,
+    ) {
+        check.do_check(&fn_ctxt).ok()
+    } else {
+        None
+    }
+}
+
 impl<'a, 'tcx> CastCheck<'tcx> {
-    pub fn new(
+    pub(crate) fn new(
         fcx: &FnCtxt<'a, 'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
         expr_ty: Ty<'tcx>,
         cast_ty: Ty<'tcx>,
         cast_span: Span,
         span: Span,
-        constness: hir::Constness,
     ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
         let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
-        let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness };
+        let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };
 
         // For better error messages, check for some obviously unsized
         // cases now. We do a more thorough check at the end, once
@@ -644,7 +672,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
     /// Checks a cast, and report an error if one exists. In some cases, this
     /// can return Ok and create type errors in the fcx rather than returning
     /// directly. coercion-cast is handled in check instead of here.
-    pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
+    fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
         use rustc_middle::ty::cast::CastTy::*;
         use rustc_middle::ty::cast::IntTy::*;
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 44b19318d5d..51d01afc4eb 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1318,6 +1318,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 }
 
+/// Check whether `ty` can be coerced to `output_ty`.
+/// Used from clippy.
+pub fn can_coerce<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: LocalDefId,
+    ty: Ty<'tcx>,
+    output_ty: Ty<'tcx>,
+) -> bool {
+    let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id);
+    let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id);
+    fn_ctxt.can_coerce(ty, output_ty)
+}
+
 /// CoerceMany encapsulates the pattern you should use when you have
 /// many expressions that are all getting coerced to a common
 /// type. This arises, for example, when you have a match (the result
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index f9b2ec69730..d399730bf3d 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -77,13 +77,6 @@ pub struct StructExprNonExhaustive {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = E0699)]
-pub struct MethodCallOnUnknownRawPointee {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_typeck_functional_record_update_on_non_struct, code = E0436)]
 pub struct FunctionalRecordUpdateOnNonStruct {
     #[primary_span]
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 4da45303d12..d3df3dd3885 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1390,15 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else {
             // Defer other checks until we're done type checking.
             let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
-            match cast::CastCheck::new(
-                self,
-                e,
-                t_expr,
-                t_cast,
-                t.span,
-                expr.span,
-                hir::Constness::NotConst,
-            ) {
+            match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                 Ok(cast_check) => {
                     debug!(
                         "check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 85d04f7d1c4..f1e82543a99 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -730,8 +730,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for ty in ret_ty.walk() {
                 if let ty::GenericArgKind::Type(ty) = ty.unpack()
                     && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind()
-                    && let Some(def_id) = def_id.as_local()
-                    && self.opaque_type_origin(def_id).is_some()
+                    && self.can_define_opaque_ty(def_id)
                 {
                     return None;
                 }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 05e7c5b2b41..0b69c7a2431 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -38,7 +38,7 @@ use std::ops::Deref;
 ///
 /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt
 /// [`InferCtxt`]: infer::InferCtxt
-pub struct FnCtxt<'a, 'tcx> {
+pub(crate) struct FnCtxt<'a, 'tcx> {
     pub(super) body_id: LocalDefId,
 
     /// The parameter environment used for proving trait obligations
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 80fd4be53e1..700dde184f2 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -42,8 +42,9 @@ mod typeck_root_ctxt;
 mod upvar;
 mod writeback;
 
-pub use fn_ctxt::FnCtxt;
-pub use typeck_root_ctxt::TypeckRootCtxt;
+pub use coercion::can_coerce;
+use fn_ctxt::FnCtxt;
+use typeck_root_ctxt::TypeckRootCtxt;
 
 use crate::check::check_fn;
 use crate::coercion::DynamicCoerceMany;
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 4e63600dbdf..28e17e1de36 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,7 +3,6 @@ use super::CandidateSource;
 use super::MethodError;
 use super::NoMatchData;
 
-use crate::errors::MethodCallOnUnknownRawPointee;
 use crate::FnCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -430,21 +429,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if is_suggestion.0 {
                 // Ambiguity was encountered during a suggestion. Just keep going.
                 debug!("ProbeContext: encountered ambiguity in suggestion");
-            } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
+            } else if bad_ty.reached_raw_pointer
+                && !self.tcx.features().arbitrary_self_types
+                && !self.tcx.sess.at_least_rust_2018()
+            {
                 // this case used to be allowed by the compiler,
                 // so we do a future-compat lint here for the 2015 edition
                 // (see https://github.com/rust-lang/rust/issues/46906)
-                if self.tcx.sess.at_least_rust_2018() {
-                    self.dcx().emit_err(MethodCallOnUnknownRawPointee { span });
-                } else {
-                    self.tcx.node_span_lint(
-                        lint::builtin::TYVAR_BEHIND_RAW_POINTER,
-                        scope_expr_id,
-                        span,
-                        "type annotations needed",
-                        |_| {},
-                    );
-                }
+                self.tcx.node_span_lint(
+                    lint::builtin::TYVAR_BEHIND_RAW_POINTER,
+                    scope_expr_id,
+                    span,
+                    "type annotations needed",
+                    |_| {},
+                );
             } else {
                 // Ended up encountering a type variable when doing autoderef,
                 // but it may not be a type variable after processing obligations
@@ -455,10 +453,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
                 let ty = self.resolve_vars_if_possible(ty.value);
                 let guar = match *ty.kind() {
-                    ty::Infer(ty::TyVar(_)) => self
-                        .err_ctxt()
-                        .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true)
-                        .emit(),
+                    ty::Infer(ty::TyVar(_)) => {
+                        let raw_ptr_call =
+                            bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types;
+                        let mut err = self.err_ctxt().emit_inference_failure_err(
+                            self.body_id,
+                            span,
+                            ty.into(),
+                            E0282,
+                            !raw_ptr_call,
+                        );
+                        if raw_ptr_call {
+                            err.span_label(span, "cannot call a method on a raw pointer with an unknown pointee type");
+                        }
+                        err.emit()
+                    }
                     ty::Error(guar) => guar,
                     _ => bug!("unexpected bad final type in method autoderef"),
                 };
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index e493e6a0a7e..694ddd0e3e8 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -5,7 +5,6 @@ use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::HirIdMap;
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
-use rustc_middle::traits::DefiningAnchor;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefIdMap;
@@ -27,7 +26,7 @@ use std::ops::Deref;
 /// `bar()` will each have their own `FnCtxt`, but they will
 /// share the inference context, will process obligations together,
 /// can access each other's local types (scoping permitted), etc.
-pub struct TypeckRootCtxt<'tcx> {
+pub(crate) struct TypeckRootCtxt<'tcx> {
     pub(super) infcx: InferCtxt<'tcx>,
 
     pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>,
@@ -78,11 +77,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
 
-        let infcx = tcx
-            .infer_ctxt()
-            .ignoring_regions()
-            .with_opaque_type_inference(DefiningAnchor::bind(tcx, def_id))
-            .build();
+        let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build();
         let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
 
         TypeckRootCtxt {
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 94088216c02..f2222eec76a 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -75,7 +75,7 @@ impl<'tcx> InferCtxt<'tcx> {
     pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
         Self {
             tcx: self.tcx,
-            defining_use_anchor: self.defining_use_anchor,
+            defining_opaque_types: self.defining_opaque_types,
             considering_regions: self.considering_regions,
             skip_leak_check: self.skip_leak_check,
             inner: self.inner.clone(),
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9f70fee993d..825c3bf82fc 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -42,7 +42,7 @@ impl<'tcx> InferCtxt<'tcx> {
         V: TypeFoldable<TyCtxt<'tcx>>,
     {
         let (param_env, value) = value.into_parts();
-        let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
+        let mut param_env = self.tcx.canonical_param_env_cache.get_or_insert(
             self.tcx,
             param_env,
             query_state,
@@ -59,6 +59,8 @@ impl<'tcx> InferCtxt<'tcx> {
             },
         );
 
+        param_env.defining_opaque_types = self.defining_opaque_types;
+
         Canonicalizer::canonicalize_with_base(
             param_env,
             value,
@@ -440,6 +442,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
             | ty::Tuple(..)
             | ty::Alias(..)
             | ty::Foreign(..)
+            | ty::Pat(..)
             | ty::Param(..) => {
                 if t.flags().intersects(self.needs_canonical_flags) {
                     t.super_fold_with(self)
@@ -540,6 +543,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             max_universe: ty::UniverseIndex::ROOT,
             variables: List::empty(),
             value: (),
+            defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(),
         };
         Canonicalizer::canonicalize_with_base(
             base,
@@ -609,7 +613,15 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             .max()
             .unwrap_or(ty::UniverseIndex::ROOT);
 
-        Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) }
+        assert!(
+            !infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types)
+        );
+        Canonical {
+            max_universe,
+            variables: canonical_variables,
+            value: (base.value, out_value),
+            defining_opaque_types: base.defining_opaque_types,
+        }
     }
 
     /// Creates a canonical variable replacing `kind` from the input,
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 9d2e065afa3..b948067e750 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -505,12 +505,9 @@ impl<'tcx> InferCtxt<'tcx> {
             let b = instantiate_value(self.tcx, &result_args, b);
             debug!(?a, ?b, "constrain opaque type");
             // We use equate here instead of, for example, just registering the
-            // opaque type's hidden value directly, because we may be instantiating
-            // a query response that was canonicalized in an InferCtxt that had
-            // a different defining anchor. In that case, we may have inferred
-            // `NonLocalOpaque := LocalOpaque` but can only instantiate it in
-            // the other direction as `LocalOpaque := NonLocalOpaque`. Using eq
-            // here allows us to try both directions (in `InferCtxt::handle_opaque_type`).
+            // opaque type's hidden value directly, because the hidden type may have been an inference
+            // variable that got constrained to the opaque type itself. In that case we want to equate
+            // the generic args of the opaque with the generic params of its hidden type version.
             obligations.extend(
                 self.at(cause, param_env)
                     .eq(
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 6e5ed0a31cb..0b8061104ab 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -34,7 +34,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin
 use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
 use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::traits::{select, DefiningAnchor};
+use rustc_middle::traits::select;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BoundVarReplacerDelegate;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@@ -243,18 +243,8 @@ impl<'tcx> InferCtxtInner<'tcx> {
 pub struct InferCtxt<'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
-    /// The `DefId` of the item in whose context we are performing inference or typeck.
-    /// It is used to check whether an opaque type use is a defining use.
-    ///
-    /// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
-    /// the obligation. This frequently happens for
-    /// short lived InferCtxt within queries. The opaque type obligations are forwarded
-    /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
-    ///
-    /// Its default value is `DefiningAnchor::Bind(&[])`, which means no opaque types may be defined.
-    /// This way it is easier to catch errors that
-    /// might come up during inference or typeck.
-    pub defining_use_anchor: DefiningAnchor<'tcx>,
+    /// The `DefIds` of the opaque types that may have their hidden types constrained.
+    defining_opaque_types: &'tcx ty::List<LocalDefId>,
 
     /// Whether this inference context should care about region obligations in
     /// the root universe. Most notably, this is used during hir typeck as region
@@ -401,6 +391,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
     fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
         self.probe_const_var(vid).ok()
     }
+
+    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
+        self.defining_opaque_types
+    }
 }
 
 /// See the `error_reporting` module for more details.
@@ -615,7 +609,7 @@ impl fmt::Display for FixupError {
 /// Used to configure inference contexts before their creation.
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    defining_use_anchor: DefiningAnchor<'tcx>,
+    defining_opaque_types: &'tcx ty::List<LocalDefId>,
     considering_regions: bool,
     skip_leak_check: bool,
     /// Whether we are in coherence mode.
@@ -630,7 +624,7 @@ impl<'tcx> TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
         InferCtxtBuilder {
             tcx: self,
-            defining_use_anchor: DefiningAnchor::Bind(ty::List::empty()),
+            defining_opaque_types: ty::List::empty(),
             considering_regions: true,
             skip_leak_check: false,
             intercrate: false,
@@ -646,8 +640,16 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     /// It is only meant to be called in two places, for typeck
     /// (via `Inherited::build`) and for the inference context used
     /// in mir borrowck.
-    pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor<'tcx>) -> Self {
-        self.defining_use_anchor = defining_use_anchor;
+    pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
+        self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
+        self
+    }
+
+    pub fn with_defining_opaque_types(
+        mut self,
+        defining_opaque_types: &'tcx ty::List<LocalDefId>,
+    ) -> Self {
+        self.defining_opaque_types = defining_opaque_types;
         self
     }
 
@@ -679,14 +681,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     /// the bound values in `C` to their instantiated values in `V`
     /// (in other words, `S(C) = V`).
     pub fn build_with_canonical<T>(
-        &mut self,
+        self,
         span: Span,
         canonical: &Canonical<'tcx, T>,
     ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>)
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        let infcx = self.build();
+        let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build();
         let (value, args) = infcx.instantiate_canonical(span, canonical);
         (infcx, value, args)
     }
@@ -694,7 +696,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     pub fn build(&mut self) -> InferCtxt<'tcx> {
         let InferCtxtBuilder {
             tcx,
-            defining_use_anchor,
+            defining_opaque_types,
             considering_regions,
             skip_leak_check,
             intercrate,
@@ -702,7 +704,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         } = *self;
         InferCtxt {
             tcx,
-            defining_use_anchor,
+            defining_opaque_types,
             considering_regions,
             skip_leak_check,
             inner: RefCell::new(InferCtxtInner::new()),
@@ -1230,6 +1232,12 @@ impl<'tcx> InferCtxt<'tcx> {
         self.inner.borrow().opaque_type_storage.opaque_types.clone()
     }
 
+    #[inline(always)]
+    pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
+        let Some(id) = id.into().as_local() else { return false };
+        self.defining_opaque_types.contains(&id)
+    }
+
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
         self.resolve_vars_if_possible(t).to_string()
     }
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 01430e830e5..d32515425c4 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -4,11 +4,10 @@ use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::{self, PredicateObligation};
 use hir::def_id::{DefId, LocalDefId};
-use hir::OpaqueTyOrigin;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
-use rustc_middle::traits::{DefiningAnchor, ObligationCause};
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::GenericArgKind;
@@ -54,16 +53,13 @@ impl<'tcx> InferCtxt<'tcx> {
         }
 
         let mut obligations = vec![];
-        let replace_opaque_type = |def_id: DefId| {
-            def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some())
-        };
         let value = value.fold_with(&mut BottomUpFolder {
             tcx: self.tcx,
             lt_op: |lt| lt,
             ct_op: |ct| ct,
             ty_op: |ty| match *ty.kind() {
                 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. })
-                    if replace_opaque_type(def_id) && !ty.has_escaping_bound_vars() =>
+                    if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() =>
                 {
                     let def_span = self.tcx.def_span(def_id);
                     let span = if span.contains(def_span) { def_span } else { span };
@@ -106,56 +102,52 @@ impl<'tcx> InferCtxt<'tcx> {
                         b,
                     ));
                 }
-                match self.defining_use_anchor {
-                    DefiningAnchor::Bind(_) => {
-                        // Check that this is `impl Trait` type is
-                        // declared by `parent_def_id` -- i.e., one whose
-                        // value we are inferring. At present, this is
-                        // always true during the first phase of
-                        // type-check, but not always true later on during
-                        // NLL. Once we support named opaque types more fully,
-                        // this same scenario will be able to arise during all phases.
-                        //
-                        // Here is an example using type alias `impl Trait`
-                        // that indicates the distinction we are checking for:
-                        //
-                        // ```rust
-                        // mod a {
-                        //   pub type Foo = impl Iterator;
-                        //   pub fn make_foo() -> Foo { .. }
-                        // }
-                        //
-                        // mod b {
-                        //   fn foo() -> a::Foo { a::make_foo() }
-                        // }
-                        // ```
-                        //
-                        // Here, the return type of `foo` references an
-                        // `Opaque` indeed, but not one whose value is
-                        // presently being inferred. You can get into a
-                        // similar situation with closure return types
-                        // today:
-                        //
-                        // ```rust
-                        // fn foo() -> impl Iterator { .. }
-                        // fn bar() {
-                        //     let x = || foo(); // returns the Opaque assoc with `foo`
-                        // }
-                        // ```
-                        if self.opaque_type_origin(def_id).is_none() {
-                            return None;
-                        }
-                    }
-                    DefiningAnchor::Bubble => {}
+                // Check that this is `impl Trait` type is
+                // declared by `parent_def_id` -- i.e., one whose
+                // value we are inferring. At present, this is
+                // always true during the first phase of
+                // type-check, but not always true later on during
+                // NLL. Once we support named opaque types more fully,
+                // this same scenario will be able to arise during all phases.
+                //
+                // Here is an example using type alias `impl Trait`
+                // that indicates the distinction we are checking for:
+                //
+                // ```rust
+                // mod a {
+                //   pub type Foo = impl Iterator;
+                //   pub fn make_foo() -> Foo { .. }
+                // }
+                //
+                // mod b {
+                //   fn foo() -> a::Foo { a::make_foo() }
+                // }
+                // ```
+                //
+                // Here, the return type of `foo` references an
+                // `Opaque` indeed, but not one whose value is
+                // presently being inferred. You can get into a
+                // similar situation with closure return types
+                // today:
+                //
+                // ```rust
+                // fn foo() -> impl Iterator { .. }
+                // fn bar() {
+                //     let x = || foo(); // returns the Opaque assoc with `foo`
+                // }
+                // ```
+                if !self.can_define_opaque_ty(def_id) {
+                    return None;
                 }
+
                 if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
                     // We could accept this, but there are various ways to handle this situation, and we don't
                     // want to make a decision on it right now. Likely this case is so super rare anyway, that
                     // no one encounters it in practice.
                     // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
                     // where it is of no concern, so we only check for TAITs.
-                    if let Some(OpaqueTyOrigin::TyAlias { .. }) =
-                        b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
+                    if self.can_define_opaque_ty(b_def_id)
+                        && self.tcx.is_type_alias_impl_trait(b_def_id)
                     {
                         self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag {
                             span: cause.span,
@@ -367,20 +359,6 @@ impl<'tcx> InferCtxt<'tcx> {
             op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions),
         });
     }
-
-    /// Returns the origin of the opaque type `def_id` if we're currently
-    /// in its defining scope.
-    #[instrument(skip(self), level = "trace", ret)]
-    pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> {
-        let defined_opaque_types = match self.defining_use_anchor {
-            DefiningAnchor::Bubble => return None,
-            DefiningAnchor::Bind(bind) => bind,
-        };
-
-        let origin = self.tcx.opaque_type_origin(def_id);
-
-        defined_opaque_types.contains(&def_id).then_some(origin)
-    }
 }
 
 /// Visitor that requires that (almost) all regions in the type visited outlive
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index 7dd1ec32542..6bab3ad6ba3 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -93,6 +93,7 @@ fn compute_components<'tcx>(
                 }
             }
 
+            ty::Pat(element, _) |
             ty::Array(element, _) => {
                 // Don't look into the len const as it doesn't affect regions
                 compute_components(tcx, element, out, visited);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 797c0df4d73..82b90e1660a 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -299,6 +299,9 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
 
 lint_improper_ctypes_opaque = opaque types have no C equivalent
 
+lint_improper_ctypes_pat_help = consider using the base type instead
+
+lint_improper_ctypes_pat_reason = pattern types have no C equivalent
 lint_improper_ctypes_slice_help = consider using a raw pointer instead
 
 lint_improper_ctypes_slice_reason = slices have no C equivalent
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 70c7aff3f20..8b974a461d4 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1337,8 +1337,9 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
 }
 
 declare_lint! {
-    /// The `unreachable_pub` lint triggers for `pub` items not reachable from
-    /// the crate root.
+    /// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that
+    /// means neither directly accessible, nor reexported, nor leaked through things like return
+    /// types.
     ///
     /// ### Example
     ///
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 1e9c60a540d..870e198d70a 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -157,6 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                     | TyKind::Never
                     | TyKind::Tup(_)
                     | TyKind::Path(_)
+                    | TyKind::Pat(..)
                     | TyKind::AnonAdt(_)
                     | TyKind::OpaqueDef(_, _, _)
                     | TyKind::Typeof(_)
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index cf825be7a55..ec7954536be 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -20,7 +20,7 @@ declare_lint! {
     /// This functionality was removed in #97346, but then rolled back in #99860
     /// because it caused regressions.
     ///
-    /// We plan on reintroducing this as a hard error, but in the mean time,
+    /// We plan on reintroducing this as a hard error, but in the meantime,
     /// this lint serves to warn and suggest fixes for any use-cases which rely
     /// on this behavior.
     ///
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 534eb60eeb0..e982842f536 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1379,6 +1379,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 help: Some(fluent::lint_improper_ctypes_char_help),
             },
 
+            ty::Pat(..) => FfiUnsafe {
+                ty,
+                reason: fluent::lint_improper_ctypes_pat_reason,
+                help: Some(fluent::lint_improper_ctypes_pat_help),
+            },
+
             ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
                 FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None }
             }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 30522628f46..53b5273803c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -4311,7 +4311,6 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,compile_fail
-    /// # #![feature(type_privacy_lints)]
     /// # #![allow(unused)]
     /// #![deny(unnameable_types)]
     /// mod m {
@@ -4328,10 +4327,14 @@ declare_lint! {
     ///
     /// It is often expected that if you can obtain an object of type `T`, then
     /// you can name the type `T` as well, this lint attempts to enforce this rule.
+    /// The recommended action is to either reexport the type properly to make it nameable,
+    /// or document that users are not supposed to be able to name it for one reason or another.
+    ///
+    /// Besides types, this lint applies to traits because traits can also leak through signatures,
+    /// and you may obtain objects of their `dyn Trait` or `impl Trait` types.
     pub UNNAMEABLE_TYPES,
     Allow,
     "effective visibility of a type is larger than the area in which it can be named",
-    @feature_gate = sym::type_privacy_lints;
 }
 
 declare_lint! {
diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
index 40723ff9f5e..64e6c18092f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
@@ -147,7 +147,7 @@ LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) {
   Expected<StringRef> NameOrErr = Child->getName();
   if (!NameOrErr) {
     // rustc_codegen_llvm currently doesn't use this error string, but it might be
-    // useful in the future, and in the mean time this tells LLVM that the
+    // useful in the future, and in the meantime this tells LLVM that the
     // error was not ignored and that it shouldn't abort the process.
     LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str());
     return nullptr;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 8ec1f5a99e7..a6894a7e089 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1524,8 +1524,8 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVM
 }
 
 extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) {
-  return wrap(llvm::Intrinsic::getDeclaration(unwrap(M),
-              (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment));
+  return wrap(llvm::Intrinsic::getDeclaration(
+      unwrap(M), llvm::Intrinsic::instrprof_increment));
 }
 
 extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index b69a295f010..2935d5b8f63 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::{self, TyCtxt};
 use rustc_middle::util::Providers;
 use rustc_session::cstore::{CrateStore, ExternCrate};
 use rustc_session::{Session, StableCrateId};
-use rustc_span::hygiene::{ExpnHash, ExpnId};
+use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
@@ -378,6 +378,7 @@ provide! { tcx, def_id, other, cdata,
 }
 
 pub(in crate::rmeta) fn provide(providers: &mut Providers) {
+    provide_cstore_hooks(providers);
     // FIXME(#44234) - almost all of these queries have no sub-queries and
     // therefore no actual inputs, they're just reading tables calculated in
     // resolve! Does this work? Unsure! That's what the issue is about
@@ -649,26 +650,27 @@ impl CrateStore for CStore {
     fn def_path_hash(&self, def: DefId) -> DefPathHash {
         self.get_crate_data(def.krate).def_path_hash(def.index)
     }
+}
 
-    fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId {
-        let def_index = self.get_crate_data(cnum).def_path_hash_to_def_index(hash);
+fn provide_cstore_hooks(providers: &mut Providers) {
+    providers.hooks.def_path_hash_to_def_id_extern = |tcx, hash, stable_crate_id| {
+        // If this is a DefPathHash from an upstream crate, let the CrateStore map
+        // it to a DefId.
+        let cstore = CStore::from_tcx(tcx.tcx);
+        let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
+        let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash);
         DefId { krate: cnum, index: def_index }
-    }
-
-    fn expn_hash_to_expn_id(
-        &self,
-        sess: &Session,
-        cnum: CrateNum,
-        index_guess: u32,
-        hash: ExpnHash,
-    ) -> ExpnId {
-        self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash)
-    }
+    };
 
-    fn import_source_files(&self, sess: &Session, cnum: CrateNum) {
-        let cdata = self.get_crate_data(cnum);
+    providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| {
+        let cstore = CStore::from_tcx(tcx.tcx);
+        cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx.sess, index_guess, hash)
+    };
+    providers.hooks.import_source_files = |tcx, cnum| {
+        let cstore = CStore::from_tcx(tcx.tcx);
+        let cdata = cstore.get_crate_data(cnum);
         for file_index in 0..cdata.root.source_map.size() {
-            cdata.imported_source_file(file_index as u32, sess);
+            cdata.imported_source_file(file_index as u32, tcx.sess);
         }
-    }
+    };
 }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index bd11b3eb04c..13719268737 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -90,6 +90,7 @@ macro_rules! arena_types {
             [decode] attribute: rustc_ast::Attribute,
             [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>,
             [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>,
+            [] pats: rustc_middle::ty::PatternKind<'tcx>,
 
             // Note that this deliberately duplicates items in the `rustc_hir::arena`,
             // since we need to allocate this type on both the `rustc_hir` arena
diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs
index aa2cddad093..f7ce15d0a8d 100644
--- a/compiler/rustc_middle/src/hooks/mod.rs
+++ b/compiler/rustc_middle/src/hooks/mod.rs
@@ -6,8 +6,10 @@
 use crate::mir;
 use crate::query::TyCtxtAt;
 use crate::ty::{Ty, TyCtxt};
-use rustc_span::def_id::LocalDefId;
-use rustc_span::DUMMY_SP;
+use rustc_hir::def_id::{DefId, DefPathHash};
+use rustc_session::StableCrateId;
+use rustc_span::def_id::{CrateNum, LocalDefId};
+use rustc_span::{ExpnHash, ExpnId, DUMMY_SP};
 
 macro_rules! declare_hooks {
     ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => {
@@ -16,7 +18,6 @@ macro_rules! declare_hooks {
             $(
             $(#[$attr])*
             #[inline(always)]
-            #[must_use]
             pub fn $name(self, $($arg: $K,)*) -> $V
             {
                 self.at(DUMMY_SP).$name($($arg,)*)
@@ -28,7 +29,6 @@ macro_rules! declare_hooks {
             $(
             $(#[$attr])*
             #[inline(always)]
-            #[must_use]
             #[instrument(level = "debug", skip(self), ret)]
             pub fn $name(self, $($arg: $K,)*) -> $V
             {
@@ -83,4 +83,23 @@ declare_hooks! {
     /// You do not want to call this yourself, instead use the cached version
     /// via `mir_built`
     hook build_mir(key: LocalDefId) -> mir::Body<'tcx>;
+
+
+    /// Imports all `SourceFile`s from the given crate into the current session.
+    /// This normally happens automatically when we decode a `Span` from
+    /// that crate's metadata - however, the incr comp cache needs
+    /// to trigger this manually when decoding a foreign `Span`
+    hook import_source_files(key: CrateNum) -> ();
+
+    hook expn_hash_to_expn_id(
+        cnum: CrateNum,
+        index_guess: u32,
+        hash: ExpnHash
+    ) -> ExpnId;
+
+    /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation
+    /// session, if it still exists. This is used during incremental compilation to
+    /// turn a deserialized `DefPathHash` into its current `DefId`.
+    /// Will fetch a DefId from a DefPathHash for a foreign crate.
+    hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId;
 }
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index acea89e4aab..62d7b7c28d1 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -153,11 +153,6 @@ pub struct QueryResponse<'tcx, R> {
     pub var_values: CanonicalVarValues<'tcx>,
     pub region_constraints: QueryRegionConstraints<'tcx>,
     pub certainty: Certainty,
-    /// List of opaque types which we tried to compare to another type.
-    /// Inside the query we don't know yet whether the opaque type actually
-    /// should get its hidden type inferred. So we bubble the opaque type
-    /// and the type it was compared against upwards and let the query caller
-    /// handle it.
     pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
     pub value: R,
 }
@@ -330,6 +325,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
                 max_universe: ty::UniverseIndex::ROOT,
                 variables: List::empty(),
                 value: key,
+                defining_opaque_types: ty::List::empty(),
             };
         }
 
@@ -340,6 +336,14 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> {
         match self.map.borrow().entry(key) {
             Entry::Occupied(e) => {
                 let (canonical, var_values) = e.get();
+                if cfg!(debug_assertions) {
+                    let mut state = state.clone();
+                    let rerun_canonical = canonicalize_op(tcx, key, &mut state);
+                    assert_eq!(rerun_canonical, *canonical);
+                    let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state;
+                    assert_eq!(universe_map.len(), 1);
+                    assert_eq!(**var_values, *rerun_var_values);
+                }
                 state.var_values.extend_from_slice(var_values);
                 *canonical
             }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 7ecac0c0e78..601bfc770f4 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -30,7 +30,6 @@ pub use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::graph::dominators::Dominators;
-use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_serialize::{Decodable, Encodable};
@@ -687,57 +686,6 @@ impl<'tcx> Body<'tcx> {
         self.injection_phase.is_some()
     }
 
-    /// Finds which basic blocks are actually reachable for a specific
-    /// monomorphization of this body.
-    ///
-    /// This is allowed to have false positives; just because this says a block
-    /// is reachable doesn't mean that's necessarily true. It's thus always
-    /// legal for this to return a filled set.
-    ///
-    /// Regardless, the [`BitSet::domain_size`] of the returned set will always
-    /// exactly match the number of blocks in the body so that `contains`
-    /// checks can be done without worrying about panicking.
-    ///
-    /// This is mostly useful because it lets us skip lowering the `false` side
-    /// of `if <T as Trait>::CONST`, as well as `intrinsics::debug_assertions`.
-    pub fn reachable_blocks_in_mono(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        instance: Instance<'tcx>,
-    ) -> BitSet<BasicBlock> {
-        let mut set = BitSet::new_empty(self.basic_blocks.len());
-        self.reachable_blocks_in_mono_from(tcx, instance, &mut set, START_BLOCK);
-        set
-    }
-
-    fn reachable_blocks_in_mono_from(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        instance: Instance<'tcx>,
-        set: &mut BitSet<BasicBlock>,
-        bb: BasicBlock,
-    ) {
-        if !set.insert(bb) {
-            return;
-        }
-
-        let data = &self.basic_blocks[bb];
-
-        if let Some((bits, targets)) = Self::try_const_mono_switchint(tcx, instance, data) {
-            let target = targets.target_for_value(bits);
-            ensure_sufficient_stack(|| {
-                self.reachable_blocks_in_mono_from(tcx, instance, set, target)
-            });
-            return;
-        }
-
-        for target in data.terminator().successors() {
-            ensure_sufficient_stack(|| {
-                self.reachable_blocks_in_mono_from(tcx, instance, set, target)
-            });
-        }
-    }
-
     /// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the
     /// dimscriminant in monomorphization, we return the discriminant bits and the
     /// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator.
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index f116347cc2b..58a27c1f9ef 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -85,6 +85,12 @@ impl SwitchTargets {
         self.values.push(value);
         self.targets.insert(self.targets.len() - 1, bb);
     }
+
+    /// Returns true if all targets (including the fallback target) are distinct.
+    #[inline]
+    pub fn is_distinct(&self) -> bool {
+        self.targets.iter().collect::<FxHashSet<_>>().len() == self.targets.len()
+    }
 }
 
 pub struct SwitchTargetsIter<'a> {
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index 0a938bcd315..245e9096bad 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -245,7 +245,7 @@ pub fn reachable<'a, 'tcx>(
 /// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
 pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> {
     let mut iter = preorder(body);
-    iter.by_ref().for_each(drop);
+    while let Some(_) = iter.next() {}
     iter.visited
 }
 
@@ -279,3 +279,97 @@ pub fn reverse_postorder<'a, 'tcx>(
 {
     body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb]))
 }
+
+/// Traversal of a [`Body`] that tries to avoid unreachable blocks in a monomorphized [`Instance`].
+///
+/// This is allowed to have false positives; blocks may be visited even if they are not actually
+/// reachable.
+///
+/// Such a traversal is mostly useful because it lets us skip lowering the `false` side
+/// of `if <T as Trait>::CONST`, as well as [`NullOp::UbChecks`].
+///
+/// [`NullOp::UbChecks`]: rustc_middle::mir::NullOp::UbChecks
+pub fn mono_reachable<'a, 'tcx>(
+    body: &'a Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+) -> MonoReachable<'a, 'tcx> {
+    MonoReachable::new(body, tcx, instance)
+}
+
+/// [`MonoReachable`] internally accumulates a [`BitSet`] of visited blocks. This is just a
+/// convenience function to run that traversal then extract its set of reached blocks.
+pub fn mono_reachable_as_bitset<'a, 'tcx>(
+    body: &'a Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+) -> BitSet<BasicBlock> {
+    let mut iter = mono_reachable(body, tcx, instance);
+    while let Some(_) = iter.next() {}
+    iter.visited
+}
+
+pub struct MonoReachable<'a, 'tcx> {
+    body: &'a Body<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    visited: BitSet<BasicBlock>,
+    // Other traversers track their worklist in a Vec. But we don't care about order, so we can
+    // store ours in a BitSet and thus save allocations because BitSet has a small size
+    // optimization.
+    worklist: BitSet<BasicBlock>,
+}
+
+impl<'a, 'tcx> MonoReachable<'a, 'tcx> {
+    pub fn new(
+        body: &'a Body<'tcx>,
+        tcx: TyCtxt<'tcx>,
+        instance: Instance<'tcx>,
+    ) -> MonoReachable<'a, 'tcx> {
+        let mut worklist = BitSet::new_empty(body.basic_blocks.len());
+        worklist.insert(START_BLOCK);
+        MonoReachable {
+            body,
+            tcx,
+            instance,
+            visited: BitSet::new_empty(body.basic_blocks.len()),
+            worklist,
+        }
+    }
+
+    fn add_work(&mut self, blocks: impl IntoIterator<Item = BasicBlock>) {
+        for block in blocks.into_iter() {
+            if !self.visited.contains(block) {
+                self.worklist.insert(block);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> Iterator for MonoReachable<'a, 'tcx> {
+    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
+
+    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
+        while let Some(idx) = self.worklist.iter().next() {
+            self.worklist.remove(idx);
+            if !self.visited.insert(idx) {
+                continue;
+            }
+
+            let data = &self.body[idx];
+
+            if let Some((bits, targets)) =
+                Body::try_const_mono_switchint(self.tcx, self.instance, data)
+            {
+                let target = targets.target_for_value(bits);
+                self.add_work([target]);
+            } else {
+                self.add_work(data.terminator().successors());
+            }
+
+            return Some((idx, data));
+        }
+
+        None
+    }
+}
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 8f02b3121ac..db1b5a74f0a 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -492,9 +492,7 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
                 // expansion, so we use `import_source_files` to ensure that the foreign
                 // source files are actually imported before we call `source_file_by_stable_id`.
                 if source_file_cnum != LOCAL_CRATE {
-                    self.tcx
-                        .cstore_untracked()
-                        .import_source_files(self.tcx.sess, source_file_cnum);
+                    self.tcx.import_source_files(source_file_cnum);
                 }
 
                 source_map
@@ -634,12 +632,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> {
             expn_id
         } else {
             let index_guess = self.foreign_expn_data[&hash];
-            self.tcx.cstore_untracked().expn_hash_to_expn_id(
-                self.tcx.sess,
-                krate,
-                index_guess,
-                hash,
-            )
+            self.tcx.expn_hash_to_expn_id(krate, index_guess, hash)
         };
 
         debug_assert_eq!(expn_id.krate, krate);
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 8cb4ee7bd41..6555a687152 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -338,10 +338,11 @@ macro_rules! define_callbacks {
 
                 pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
 
-                // Ensure that keys grow no larger than 64 bytes
+                // Ensure that keys grow no larger than 72 bytes by accident.
+                // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
                 const _: () = {
-                    if mem::size_of::<Key<'static>>() > 64 {
+                    if mem::size_of::<Key<'static>>() > 72 {
                         panic!("{}", concat!(
                             "the query `",
                             stringify!($name),
@@ -352,7 +353,8 @@ macro_rules! define_callbacks {
                     }
                 };
 
-                // Ensure that values grow no larger than 64 bytes
+                // Ensure that values grow no larger than 64 bytes by accident.
+                // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))]
                 const _: () = {
                     if mem::size_of::<Value<'static>>() > 64 {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index ee816791919..d51e86c909c 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -12,8 +12,8 @@ pub mod util;
 use crate::infer::canonical::Canonical;
 use crate::mir::ConstraintCategory;
 use crate::ty::abstract_const::NotConstEvaluatable;
+use crate::ty::GenericArgsRef;
 use crate::ty::{self, AdtKind, Ty};
-use crate::ty::{GenericArgsRef, TyCtxt};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, Diag, EmissionGuarantee};
@@ -997,33 +997,3 @@ pub enum CodegenObligationError {
     Unimplemented,
     FulfillmentError,
 }
-
-/// Defines the treatment of opaque types in a given inference context.
-///
-/// This affects both what opaques are allowed to be defined, but also whether
-/// opaques are replaced with inference vars eagerly in the old solver (e.g.
-/// in projection, and in the signature during function type-checking).
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum DefiningAnchor<'tcx> {
-    /// Define opaques which are in-scope of the current item being analyzed.
-    /// Also, eagerly replace these opaque types in `replace_opaque_types_with_inference_vars`.
-    ///
-    /// If the list is empty, do not allow any opaques to be defined. This is used to catch type mismatch
-    /// errors when handling opaque types, and also should be used when we would
-    /// otherwise reveal opaques (such as [`Reveal::All`] reveal mode).
-    Bind(&'tcx ty::List<LocalDefId>),
-    /// In contexts where we don't currently know what opaques are allowed to be
-    /// defined, such as (old solver) canonical queries, we will simply allow
-    /// opaques to be defined, but "bubble" them up in the canonical response or
-    /// otherwise treat them to be handled later.
-    ///
-    /// We do not eagerly replace opaque types in `replace_opaque_types_with_inference_vars`,
-    /// which may affect what predicates pass and fail in the old trait solver.
-    Bubble,
-}
-
-impl<'tcx> DefiningAnchor<'tcx> {
-    pub fn bind(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self {
-        Self::Bind(tcx.opaque_types_defined_by(item))
-    }
-}
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 6dcea2aaff1..13504c6ae93 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -4,7 +4,7 @@ use rustc_span::def_id::DefId;
 
 use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
 use crate::traits::query::NoSolution;
-use crate::traits::{Canonical, DefiningAnchor};
+use crate::traits::Canonical;
 use crate::ty::{
     self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
     TypeVisitor,
@@ -114,7 +114,6 @@ impl MaybeCause {
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub struct QueryInput<'tcx, T> {
     pub goal: Goal<'tcx, T>,
-    pub anchor: DefiningAnchor<'tcx>,
     pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
 }
 
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 7db64504f85..95d1e08b58b 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -45,7 +45,7 @@ impl UpvarId {
 
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(Eq, PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable, Hash)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub enum UpvarCapture {
     /// Upvar is captured by value. This is always true when the
@@ -73,7 +73,7 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureLis
 pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
 
 /// A composite describing a `Place` that is captured by a closure.
-#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(Eq, PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable, Hash)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct CapturedPlace<'tcx> {
     /// Name and span where the binding happens.
@@ -192,7 +192,7 @@ impl<'tcx> CapturedPlace<'tcx> {
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct ClosureTypeInfo<'tcx> {
     user_provided_sig: ty::CanonicalPolyFnSig<'tcx>,
-    captures: &'tcx [&'tcx ty::CapturedPlace<'tcx>],
+    captures: &'tcx ty::List<&'tcx ty::CapturedPlace<'tcx>>,
     kind_origin: Option<&'tcx (Span, HirPlace<'tcx>)>,
 }
 
@@ -201,7 +201,7 @@ fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo
     let typeck_results = tcx.typeck(def);
     let user_provided_sig = typeck_results.user_provided_sigs[&def];
     let captures = typeck_results.closure_min_captures_flattened(def);
-    let captures = tcx.arena.alloc_from_iter(captures);
+    let captures = tcx.mk_captures_from_iter(captures);
     let hir_id = tcx.local_def_id_to_hir_id(def);
     let kind_origin = typeck_results.closure_kind_origins().get(hir_id);
     ClosureTypeInfo { user_provided_sig, captures, kind_origin }
@@ -253,7 +253,7 @@ pub fn is_ancestor_or_same_capture(
 /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
 /// for a particular capture as well as identifying the part of the source code
 /// that triggered this capture to occur.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(Eq, PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable, Hash)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct CaptureInfo {
     /// Expr Id pointing to use that resulted in selecting the current capture kind
@@ -332,7 +332,7 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc
     curr_string
 }
 
-#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
+#[derive(Eq, Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable, Hash)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 9068961d736..c0effe9804c 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -148,6 +148,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> {
     }
 }
 
+impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Pattern<'tcx> {
+    fn encode(&self, e: &mut E) {
+        self.0.0.encode(e);
+    }
+}
+
 impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> {
     fn encode(&self, e: &mut E) {
         self.inner().encode(e)
@@ -364,6 +370,12 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Pattern<'tcx> {
+    fn decode(decoder: &mut D) -> Self {
+        decoder.interner().mk_pat(Decodable::decode(decoder))
+    }
+}
+
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
     fn decode(decoder: &mut D) -> &'tcx Self {
         decoder
@@ -443,6 +455,12 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Lo
     }
 }
 
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for &'tcx ty::List<LocalDefId> {
+    fn decode(d: &mut D) -> Self {
+        RefDecodable::decode(d)
+    }
+}
+
 impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
     for ty::List<(VariantIdx, FieldIdx)>
 {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1db9bce73a6..0daf83162db 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -26,9 +26,10 @@ use crate::traits::solve::{
 };
 use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
-    GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy,
-    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region,
-    RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, Visibility,
+    GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern,
+    PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity,
+    Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable,
+    Visibility,
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_ast::{self as ast, attr};
@@ -84,6 +85,7 @@ use std::ops::{Bound, Deref};
 #[allow(rustc::usage_of_ty_tykind)]
 impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefId = DefId;
+    type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
     type AdtDef = ty::AdtDef<'tcx>;
     type GenericArgs = ty::GenericArgsRef<'tcx>;
     type GenericArg = ty::GenericArg<'tcx>;
@@ -95,6 +97,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type CanonicalVars = CanonicalVarInfos<'tcx>;
 
     type Ty = Ty<'tcx>;
+    type Pat = Pattern<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
     type AliasTy = ty::AliasTy<'tcx>;
     type ParamTy = ParamTy;
@@ -157,6 +160,7 @@ pub struct CtxtInterners<'tcx> {
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
     const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
+    pat: InternedSet<'tcx, PatternKind<'tcx>>,
     const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
     layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
@@ -165,6 +169,7 @@ pub struct CtxtInterners<'tcx> {
     predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
     fields: InternedSet<'tcx, List<FieldIdx>>,
     local_def_ids: InternedSet<'tcx, List<LocalDefId>>,
+    captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>,
     offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>,
 }
 
@@ -184,6 +189,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             projs: Default::default(),
             place_elems: Default::default(),
             const_: Default::default(),
+            pat: Default::default(),
             const_allocation: Default::default(),
             bound_variable_kinds: Default::default(),
             layout: Default::default(),
@@ -192,6 +198,7 @@ impl<'tcx> CtxtInterners<'tcx> {
             predefined_opaques_in_body: Default::default(),
             fields: Default::default(),
             local_def_ids: Default::default(),
+            captures: Default::default(),
             offset_of: Default::default(),
         }
     }
@@ -1158,11 +1165,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 .local_def_path_hash_to_def_id(hash, err_msg)
                 .to_def_id()
         } else {
-            // If this is a DefPathHash from an upstream crate, let the CrateStore map
-            // it to a DefId.
-            let cstore = &*self.cstore_untracked();
-            let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id);
-            cstore.def_path_hash_to_def_id(cnum, hash)
+            self.def_path_hash_to_def_id_extern(hash, stable_crate_id)
         }
     }
 
@@ -1578,6 +1581,7 @@ macro_rules! nop_list_lift {
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
 nop_lift! {const_; Const<'a> => Const<'tcx>}
+nop_lift! {pat; Pattern<'a> => Pattern<'tcx>}
 nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
 nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
 nop_lift! {predicate; Clause<'a> => Clause<'tcx>}
@@ -1715,6 +1719,7 @@ impl<'tcx> TyCtxt<'tcx> {
                     Param,
                     Infer,
                     Alias,
+                    Pat,
                     Foreign
                 )?;
 
@@ -1866,6 +1871,7 @@ macro_rules! direct_interners {
 // crate only, and have a corresponding `mk_` function.
 direct_interners! {
     region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
+    pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>,
     const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
     layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
     adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
@@ -1905,6 +1911,7 @@ slice_interners!(
     bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
     fields: pub mk_fields(FieldIdx),
     local_def_ids: intern_local_def_ids(LocalDefId),
+    captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>),
     offset_of: pub mk_offset_of((VariantIdx, FieldIdx)),
 );
 
@@ -2226,6 +2233,17 @@ impl<'tcx> TyCtxt<'tcx> {
         T::collect_and_apply(iter, |xs| self.mk_local_def_ids(xs))
     }
 
+    pub fn mk_captures_from_iter<I, T>(self, iter: I) -> T::Output
+    where
+        I: Iterator<Item = T>,
+        T: CollectAndApply<
+                &'tcx ty::CapturedPlace<'tcx>,
+                &'tcx List<&'tcx ty::CapturedPlace<'tcx>>,
+            >,
+    {
+        T::collect_and_apply(iter, |xs| self.intern_captures(xs))
+    }
+
     pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 09586a95f1c..ce85c28ece8 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -285,6 +285,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Adt(def, _) => def.descr().into(),
             ty::Foreign(_) => "extern type".into(),
             ty::Array(..) => "array".into(),
+            ty::Pat(..) => "pattern type".into(),
             ty::Slice(_) => "slice".into(),
             ty::RawPtr(_, _) => "raw pointer".into(),
             ty::Ref(.., mutbl) => match mutbl {
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 5b257cdfd86..7c925d5fbb6 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -120,6 +120,7 @@ pub fn simplify_type<'tcx>(
         ty::Str => Some(SimplifiedType::Str),
         ty::Array(..) => Some(SimplifiedType::Array),
         ty::Slice(..) => Some(SimplifiedType::Slice),
+        ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params),
         ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)),
         ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() {
             Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => {
@@ -231,6 +232,7 @@ impl DeepRejectCtxt {
             | ty::Slice(..)
             | ty::RawPtr(..)
             | ty::Dynamic(..)
+            | ty::Pat(..)
             | ty::Ref(..)
             | ty::Never
             | ty::Tuple(..)
@@ -269,6 +271,10 @@ impl DeepRejectCtxt {
                 }
                 _ => false,
             },
+            ty::Pat(obl_ty, _) => {
+                // FIXME(pattern_types): take pattern into account
+                matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty))
+            }
             ty::Slice(obl_ty) => {
                 matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty))
             }
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 5feb6ef76d5..0dc835671d5 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -218,6 +218,20 @@ impl FlagComputation {
                 self.add_const(len);
             }
 
+            &ty::Pat(ty, pat) => {
+                self.add_ty(ty);
+                match *pat {
+                    ty::PatternKind::Range { start, end, include_end: _ } => {
+                        if let Some(start) = start {
+                            self.add_const(start)
+                        }
+                        if let Some(end) = end {
+                            self.add_const(end)
+                        }
+                    }
+                }
+            }
+
             &ty::Slice(tt) => self.add_ty(tt),
 
             &ty::RawPtr(ty, _) => {
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 2630b96869b..e984f543701 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -316,11 +316,11 @@ impl<'tcx> Generics {
     /// of this item, excluding `Self`.
     ///
     /// **This should only be used for diagnostics purposes.**
-    pub fn own_args_no_defaults(
+    pub fn own_args_no_defaults<'a>(
         &'tcx self,
         tcx: TyCtxt<'tcx>,
-        args: &'tcx [ty::GenericArg<'tcx>],
-    ) -> &'tcx [ty::GenericArg<'tcx>] {
+        args: &'a [ty::GenericArg<'tcx>],
+    ) -> &'a [ty::GenericArg<'tcx>] {
         let mut own_params = self.parent_count..self.count();
         if self.has_self && self.parent.is_none() {
             own_params.start = 1;
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 4a7720b38f8..f8f59fbeab4 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -520,7 +520,10 @@ impl<'tcx> Instance<'tcx> {
                 // Reify `Trait::method` implementations if KCFI is enabled
                 // FIXME(maurer) only reify it if it is a vtable-safe function
                 _ if tcx.sess.is_sanitizer_kcfi_enabled()
-                    && tcx.associated_item(def_id).trait_item_def_id.is_some() =>
+                    && tcx
+                        .opt_associated_item(def_id)
+                        .and_then(|assoc| assoc.trait_item_def_id)
+                        .is_some() =>
                 {
                     // If this function could also go in a vtable, we need to `ReifyShim` it with
                     // KCFI because it can only attach one type per function.
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 66078663098..50e68bfdbe7 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -742,6 +742,7 @@ where
                 | ty::FnDef(..)
                 | ty::CoroutineWitness(..)
                 | ty::Foreign(..)
+                | ty::Pat(_, _)
                 | ty::Dynamic(_, _, ty::Dyn) => {
                     bug!("TyAndLayout::field({:?}): not applicable", this)
                 }
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 04e165c8a73..0db541899d2 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -55,6 +55,12 @@ struct ListSkeleton<H, T> {
     data: [T; 0],
 }
 
+impl<T> Default for &List<T> {
+    fn default() -> Self {
+        List::empty()
+    }
+}
+
 extern "C" {
     /// A dummy type used to force `List` to be unsized while not requiring
     /// references to it be wide pointers.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9bf5205edaa..ee4dc9744ac 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -91,6 +91,7 @@ pub use self::context::{
 pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams};
 pub use self::list::{List, ListWithCachedTypeInfo};
 pub use self::parameterized::ParameterizedOverTcx;
+pub use self::pattern::{Pattern, PatternKind};
 pub use self::predicate::{
     Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection,
     ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
@@ -130,6 +131,7 @@ pub mod fold;
 pub mod inhabitedness;
 pub mod layout;
 pub mod normalize_erasing_regions;
+pub mod pattern;
 pub mod print;
 pub mod relate;
 pub mod trait_def;
diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs
new file mode 100644
index 00000000000..8a41ba257ec
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/pattern.rs
@@ -0,0 +1,48 @@
+use std::fmt;
+
+use crate::ty;
+use rustc_data_structures::intern::Interned;
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
+#[rustc_pass_by_value]
+pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>);
+
+impl<'tcx> std::ops::Deref for Pattern<'tcx> {
+    type Target = PatternKind<'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        &*self.0
+    }
+}
+
+impl<'tcx> fmt::Debug for Pattern<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", **self)
+    }
+}
+
+impl<'tcx> fmt::Debug for PatternKind<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match *self {
+            PatternKind::Range { start, end, include_end } => {
+                if let Some(start) = start {
+                    write!(f, "{start}")?;
+                }
+                write!(f, "..")?;
+                if include_end {
+                    write!(f, "=")?;
+                }
+                if let Some(end) = end {
+                    write!(f, "{end}")?;
+                }
+                Ok(())
+            }
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
+pub enum PatternKind<'tcx> {
+    Range { start: Option<ty::Const<'tcx>>, end: Option<ty::Const<'tcx>>, include_end: bool },
+}
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index d9aa7f9e5c4..9d0e1123e43 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -259,7 +259,7 @@ fn characteristic_def_id_of_type_cached<'a>(
 
         ty::Dynamic(data, ..) => data.principal_def_id(),
 
-        ty::Array(subty, _) | ty::Slice(subty) => {
+        ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => {
             characteristic_def_id_of_type_cached(subty, visited)
         }
 
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 2a898430ce9..20ebd87c3d4 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -667,6 +667,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::Int(t) => p!(write("{}", t.name_str())),
             ty::Uint(t) => p!(write("{}", t.name_str())),
             ty::Float(t) => p!(write("{}", t.name_str())),
+            ty::Pat(ty, pat) => {
+                p!("(", print(ty), ") is ", write("{pat:?}"))
+            }
             ty::RawPtr(ty, mutbl) => {
                 p!(write(
                     "*{} ",
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index cf7caafcebb..3c1dea1d9f2 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -13,6 +13,8 @@ use rustc_hir::def_id::DefId;
 use rustc_target::spec::abi;
 use std::iter;
 
+use super::Pattern;
+
 pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>;
 
 pub trait TypeRelation<'tcx>: Sized {
@@ -351,6 +353,36 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> {
     }
 }
 
+impl<'tcx> Relate<'tcx> for Pattern<'tcx> {
+    #[inline]
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: Self,
+        b: Self,
+    ) -> RelateResult<'tcx, Self> {
+        match (&*a, &*b) {
+            (
+                &ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a },
+                &ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b },
+            ) => {
+                // FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`).
+                let mut relate_opt_const = |a, b| match (a, b) {
+                    (None, None) => Ok(None),
+                    (Some(a), Some(b)) => relation.relate(a, b).map(Some),
+                    // FIXME(pattern_types): report a better error
+                    _ => Err(TypeError::Mismatch),
+                };
+                let start = relate_opt_const(start_a, start_b)?;
+                let end = relate_opt_const(end_a, end_b)?;
+                if inc_a != inc_b {
+                    todo!()
+                }
+                Ok(relation.tcx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a }))
+            }
+        }
+    }
+}
+
 /// Relates `a` and `b` structurally, calling the relation for all nested values.
 /// Any semantic equality, e.g. of projections, and inference variables have to be
 /// handled by the caller.
@@ -533,6 +565,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(Ty::new_alias(tcx, a_kind, alias_ty))
         }
 
+        (&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => {
+            let ty = relation.relate(a_ty, b_ty)?;
+            let pat = relation.relate(a_pat, b_pat)?;
+            Ok(Ty::new_pat(tcx, ty, pat))
+        }
+
         _ => Err(TypeError::Sorts(expected_found(a, b))),
     }
 }
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 8231c0214cb..90c68e7ddfc 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -20,6 +20,8 @@ use std::fmt::{self, Debug};
 use super::print::PrettyPrinter;
 use super::{GenericArg, GenericArgKind, Region};
 
+use super::Pattern;
+
 impl fmt::Debug for ty::TraitDef {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         ty::tls::with(|tcx| {
@@ -210,6 +212,22 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
     }
 }
 
+impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
+    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut core::fmt::Formatter<'_>,
+    ) -> core::fmt::Result {
+        match &**this.data {
+            ty::PatternKind::Range { start, end, include_end } => f
+                .debug_struct("Pattern::Range")
+                .field("start", start)
+                .field("end", end)
+                .field("include_end", include_end)
+                .finish(),
+        }
+    }
+}
+
 impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         WithInfcx::with_no_infcx(self).fmt(f)
@@ -541,6 +559,22 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> {
     }
 }
 
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Pattern<'tcx> {
+    fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error> {
+        let pat = (*self).clone().try_fold_with(folder)?;
+        Ok(if pat == *self { self } else { folder.interner().mk_pat(pat) })
+    }
+}
+
+impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Pattern<'tcx> {
+    fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
+        (**self).visit_with(visitor)
+    }
+}
+
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
         self,
@@ -586,6 +620,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
                 ty::CoroutineClosure(did, args.try_fold_with(folder)?)
             }
             ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?),
+            ty::Pat(ty, pat) => ty::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?),
 
             ty::Bool
             | ty::Char
@@ -633,6 +668,11 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
             ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor),
             ty::Alias(_, ref data) => data.visit_with(visitor),
 
+            ty::Pat(ty, pat) => {
+                try_visit!(ty.visit_with(visitor));
+                pat.visit_with(visitor)
+            }
+
             ty::Bool
             | ty::Char
             | ty::Str
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 2ab63f01e7c..d9e99bf07af 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1523,6 +1523,11 @@ impl<'tcx> Ty<'tcx> {
     }
 
     #[inline]
+    pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<'tcx> {
+        Ty::new(tcx, Pat(base, pat))
+    }
+
+    #[inline]
     pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> {
         Ty::new_alias(tcx, ty::Opaque, AliasTy::new(tcx, def_id, args))
     }
@@ -2278,6 +2283,8 @@ impl<'tcx> Ty<'tcx> {
                 Ty::new_projection(tcx, assoc_items[0], tcx.mk_args(&[self.into()]))
             }
 
+            ty::Pat(ty, _) => ty.discriminant_ty(tcx),
+
             ty::Bool
             | ty::Char
             | ty::Int(_)
@@ -2359,6 +2366,7 @@ impl<'tcx> Ty<'tcx> {
             ty::Param(_) | ty::Alias(..) => Err(tail),
 
             ty::Infer(ty::TyVar(_))
+            | ty::Pat(..)
             | ty::Bound(..)
             | ty::Placeholder(..)
             | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(
@@ -2495,6 +2503,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Coroutine(..)
             | ty::CoroutineWitness(..)
             | ty::Array(..)
+            | ty::Pat(..)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Never
@@ -2549,6 +2558,8 @@ impl<'tcx> Ty<'tcx> {
                 field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy)
             }
 
+            ty::Pat(ty, _) => ty.is_trivially_pure_clone_copy(),
+
             // Sometimes traits aren't implemented for every ABI or arity,
             // because we can't be generic over everything yet.
             ty::FnPtr(..) => false,
@@ -2630,6 +2641,7 @@ impl<'tcx> Ty<'tcx> {
             | Foreign(_)
             | Str
             | Array(_, _)
+            | Pat(_, _)
             | Slice(_)
             | RawPtr(_, _)
             | Ref(_, _, _)
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index cef15b29a85..e422fb0d020 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -245,6 +245,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
                 ty::Tuple(_) => break,
 
+                ty::Pat(inner, _) => {
+                    f();
+                    ty = inner;
+                }
+
                 ty::Alias(..) => {
                     let normalized = normalize(ty);
                     if ty == normalized {
@@ -1242,7 +1247,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Error(_)
             | ty::FnPtr(_) => true,
             ty::Tuple(fields) => fields.iter().all(Self::is_trivially_freeze),
-            ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
+            ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_freeze(),
             ty::Adt(..)
             | ty::Bound(..)
             | ty::Closure(..)
@@ -1282,7 +1287,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Error(_)
             | ty::FnPtr(_) => true,
             ty::Tuple(fields) => fields.iter().all(Self::is_trivially_unpin),
-            ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(),
+            ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_unpin(),
             ty::Adt(..)
             | ty::Bound(..)
             | ty::Closure(..)
@@ -1398,7 +1403,7 @@ impl<'tcx> Ty<'tcx> {
             //
             // Because this function is "shallow", we return `true` for these composites regardless
             // of the type(s) contained within.
-            ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
+            ty::Pat(..) | ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true,
 
             // Raw pointers use bitwise comparison.
             ty::RawPtr(_, _) | ty::FnPtr(_) => true,
@@ -1528,7 +1533,7 @@ pub fn needs_drop_components<'tcx>(
 
         ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
 
-        ty::Slice(ty) => needs_drop_components(tcx, ty),
+        ty::Pat(ty, _) | ty::Slice(ty) => needs_drop_components(tcx, ty),
         ty::Array(elem_ty, size) => {
             match needs_drop_components(tcx, elem_ty) {
                 Ok(v) if v.is_empty() => Ok(v),
@@ -1597,7 +1602,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
         | ty::CoroutineWitness(..)
         | ty::Adt(..) => false,
 
-        ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
+        ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => is_trivially_const_drop(ty),
 
         ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)),
     }
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 9e7bf980237..7069bdcbcb9 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -151,6 +151,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
             | ty::Bound(..)
             | ty::Foreign(..) => {}
 
+            ty::Pat(ty, pat) => {
+                match *pat {
+                    ty::PatternKind::Range { start, end, include_end: _ } => {
+                        stack.extend(end.map(Into::into));
+                        stack.extend(start.map(Into::into));
+                    }
+                }
+                stack.push(ty.into());
+            }
             ty::Array(ty, len) => {
                 stack.push(len.into());
                 stack.push(ty.into());
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index ce39aff69cb..65c53be8ddd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -457,7 +457,7 @@ impl<'tcx> ConstToPat<'tcx> {
                     PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
                 }
             }
-            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
+            ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
                 // The raw pointers we see here have been "vetted" by valtree construction to be
                 // just integers, so we simply allow them.
                 PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index e73d945e0bb..d7477309400 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -153,6 +153,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                     | ty::Foreign(_)
                     | ty::Str
                     | ty::Array(_, _)
+                    | ty::Pat(_, _)
                     | ty::Slice(_)
                     | ty::FnDef(_, _)
                     | ty::FnPtr(_)
@@ -193,6 +194,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> {
                     | ty::Foreign(_)
                     | ty::Str
                     | ty::Array(_, _)
+                    | ty::Pat(_, _)
                     | ty::Slice(_)
                     | ty::RawPtr(_, _)
                     | ty::Ref(_, _, _)
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index de43f9faff9..320d8fd3977 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -58,16 +58,24 @@
 //! borrowing from the outer closure, and we simply peel off a `deref` projection
 //! from them. This second body is stored alongside the first body, and optimized
 //! with it in lockstep. When we need to resolve a body for `FnOnce` or `AsyncFnOnce`,
-//! we use this "by move" body instead.
-
-use itertools::Itertools;
+//! we use this "by-move" body instead.
+//!
+//! ## How does this work?
+//!
+//! This pass essentially remaps the body of the (child) closure of the coroutine-closure
+//! to take the set of upvars of the parent closure by value. This at least requires
+//! changing a by-ref upvar to be by-value in the case that the outer coroutine-closure
+//! captures something by value; however, it may also require renumbering field indices
+//! in case precise captures (edition 2021 closure capture rules) caused the inner coroutine
+//! to split one field capture into two.
 
-use rustc_data_structures::unord::UnordSet;
+use rustc_data_structures::unord::UnordMap;
 use rustc_hir as hir;
+use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir, MirPass};
 use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt};
-use rustc_target::abi::FieldIdx;
+use rustc_target::abi::{FieldIdx, VariantIdx};
 
 pub struct ByMoveBody;
 
@@ -116,32 +124,116 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
             .tuple_fields()
             .len();
 
-        let mut by_ref_fields = UnordSet::default();
-        for (idx, (coroutine_capture, parent_capture)) in tcx
+        let mut field_remapping = UnordMap::default();
+
+        // One parent capture may correspond to several child captures if we end up
+        // refining the set of captures via edition-2021 precise captures. We want to
+        // match up any number of child captures with one parent capture, so we keep
+        // peeking off this `Peekable` until the child doesn't match anymore.
+        let mut parent_captures =
+            tcx.closure_captures(parent_def_id).iter().copied().enumerate().peekable();
+        // Make sure we use every field at least once, b/c why are we capturing something
+        // if it's not used in the inner coroutine.
+        let mut field_used_at_least_once = false;
+
+        for (child_field_idx, child_capture) in tcx
             .closure_captures(coroutine_def_id)
             .iter()
+            .copied()
             // By construction we capture all the args first.
             .skip(num_args)
-            .zip_eq(tcx.closure_captures(parent_def_id))
             .enumerate()
         {
-            // This upvar is captured by-move from the parent closure, but by-ref
-            // from the inner async block. That means that it's being borrowed from
-            // the outer closure body -- we need to change the coroutine to take the
-            // upvar by value.
-            if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() {
-                assert_ne!(
-                    coroutine_kind,
-                    ty::ClosureKind::FnOnce,
-                    "`FnOnce` coroutine-closures return coroutines that capture from \
-                    their body; it will always result in a borrowck error!"
+            loop {
+                let Some(&(parent_field_idx, parent_capture)) = parent_captures.peek() else {
+                    bug!("we ran out of parent captures!")
+                };
+
+                let PlaceBase::Upvar(parent_base) = parent_capture.place.base else {
+                    bug!("expected capture to be an upvar");
+                };
+                let PlaceBase::Upvar(child_base) = child_capture.place.base else {
+                    bug!("expected capture to be an upvar");
+                };
+
+                assert!(
+                    child_capture.place.projections.len() >= parent_capture.place.projections.len()
                 );
-                by_ref_fields.insert(FieldIdx::from_usize(num_args + idx));
+                // A parent matches a child they share the same prefix of projections.
+                // The child may have more, if it is capturing sub-fields out of
+                // something that is captured by-move in the parent closure.
+                if parent_base.var_path.hir_id != child_base.var_path.hir_id
+                    || !std::iter::zip(
+                        &child_capture.place.projections,
+                        &parent_capture.place.projections,
+                    )
+                    .all(|(child, parent)| child.kind == parent.kind)
+                {
+                    // Make sure the field was used at least once.
+                    assert!(
+                        field_used_at_least_once,
+                        "we captured {parent_capture:#?} but it was not used in the child coroutine?"
+                    );
+                    field_used_at_least_once = false;
+                    // Skip this field.
+                    let _ = parent_captures.next().unwrap();
+                    continue;
+                }
+
+                // Store this set of additional projections (fields and derefs).
+                // We need to re-apply them later.
+                let child_precise_captures =
+                    &child_capture.place.projections[parent_capture.place.projections.len()..];
+
+                // If the parent captures by-move, and the child captures by-ref, then we
+                // need to peel an additional `deref` off of the body of the child.
+                let needs_deref = child_capture.is_by_ref() && !parent_capture.is_by_ref();
+                if needs_deref {
+                    assert_ne!(
+                        coroutine_kind,
+                        ty::ClosureKind::FnOnce,
+                        "`FnOnce` coroutine-closures return coroutines that capture from \
+                        their body; it will always result in a borrowck error!"
+                    );
+                }
+
+                // Finally, store the type of the parent's captured place. We need
+                // this when building the field projection in the MIR body later on.
+                let mut parent_capture_ty = parent_capture.place.ty();
+                parent_capture_ty = match parent_capture.info.capture_kind {
+                    ty::UpvarCapture::ByValue => parent_capture_ty,
+                    ty::UpvarCapture::ByRef(kind) => Ty::new_ref(
+                        tcx,
+                        tcx.lifetimes.re_erased,
+                        parent_capture_ty,
+                        kind.to_mutbl_lossy(),
+                    ),
+                };
+
+                field_remapping.insert(
+                    FieldIdx::from_usize(child_field_idx + num_args),
+                    (
+                        FieldIdx::from_usize(parent_field_idx + num_args),
+                        parent_capture_ty,
+                        needs_deref,
+                        child_precise_captures,
+                    ),
+                );
+
+                field_used_at_least_once = true;
+                break;
             }
+        }
+
+        // Pop the last parent capture
+        if field_used_at_least_once {
+            let _ = parent_captures.next().unwrap();
+        }
+        assert_eq!(parent_captures.next(), None, "leftover parent captures?");
 
-            // Make sure we're actually talking about the same capture.
-            // FIXME(async_closures): We could look at the `hir::Upvar` instead?
-            assert_eq!(coroutine_capture.place.ty(), parent_capture.place.ty());
+        if coroutine_kind == ty::ClosureKind::FnOnce {
+            assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());
+            return;
         }
 
         let by_move_coroutine_ty = tcx
@@ -157,7 +249,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
             );
 
         let mut by_move_body = body.clone();
-        MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body);
+        MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
         dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
         by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim {
             coroutine_def_id: coroutine_def_id.to_def_id(),
@@ -168,7 +260,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
 
 struct MakeByMoveBody<'tcx> {
     tcx: TyCtxt<'tcx>,
-    by_ref_fields: UnordSet<FieldIdx>,
+    field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>,
     by_move_coroutine_ty: Ty<'tcx>,
 }
 
@@ -183,24 +275,59 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
         context: mir::visit::PlaceContext,
         location: mir::Location,
     ) {
+        // Initializing an upvar local always starts with `CAPTURE_STRUCT_LOCAL` and a
+        // field projection. If this is in `field_remapping`, then it must not be an
+        // arg from calling the closure, but instead an upvar.
         if place.local == ty::CAPTURE_STRUCT_LOCAL
-            && let Some((&mir::ProjectionElem::Field(idx, ty), projection)) =
+            && let Some((&mir::ProjectionElem::Field(idx, _), projection)) =
                 place.projection.split_first()
-            && self.by_ref_fields.contains(&idx)
+            && let Some(&(remapped_idx, remapped_ty, needs_deref, additional_projections)) =
+                self.field_remapping.get(&idx)
         {
-            let (begin, end) = projection.split_first().unwrap();
-            // FIXME(async_closures): I'm actually a bit surprised to see that we always
-            // initially deref the by-ref upvars. If this is not actually true, then we
-            // will at least get an ICE that explains why this isn't true :^)
-            assert_eq!(*begin, mir::ProjectionElem::Deref);
-            // Peel one ref off of the ty.
-            let peeled_ty = ty.builtin_deref(true).unwrap().ty;
+            // As noted before, if the parent closure captures a field by value, and
+            // the child captures a field by ref, then for the by-move body we're
+            // generating, we also are taking that field by value. Peel off a deref,
+            // since a layer of reffing has now become redundant.
+            let final_deref = if needs_deref {
+                let Some((mir::ProjectionElem::Deref, projection)) = projection.split_first()
+                else {
+                    bug!(
+                        "There should be at least a single deref for an upvar local initialization, found {projection:#?}"
+                    );
+                };
+                // There may be more derefs, since we may also implicitly reborrow
+                // a captured mut pointer.
+                projection
+            } else {
+                projection
+            };
+
+            // The only thing that should be left is a deref, if the parent captured
+            // an upvar by-ref.
+            std::assert_matches::assert_matches!(final_deref, [] | [mir::ProjectionElem::Deref]);
+
+            // For all of the additional projections that come out of precise capturing,
+            // re-apply these projections.
+            let additional_projections =
+                additional_projections.iter().map(|elem| match elem.kind {
+                    ProjectionKind::Deref => mir::ProjectionElem::Deref,
+                    ProjectionKind::Field(idx, VariantIdx::ZERO) => {
+                        mir::ProjectionElem::Field(idx, elem.ty)
+                    }
+                    _ => unreachable!("precise captures only through fields and derefs"),
+                });
+
+            // We start out with an adjusted field index (and ty), representing the
+            // upvar that we get from our parent closure. We apply any of the additional
+            // projections to make sure that to the rest of the body of the closure, the
+            // place looks the same, and then apply that final deref if necessary.
             *place = mir::Place {
                 local: place.local,
                 projection: self.tcx.mk_place_elems_from_iter(
-                    [mir::ProjectionElem::Field(idx, peeled_ty)]
+                    [mir::ProjectionElem::Field(remapped_idx, remapped_ty)]
                         .into_iter()
-                        .chain(end.iter().copied()),
+                        .chain(additional_projections)
+                        .chain(final_deref.iter().copied()),
                 ),
             };
         }
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 3e9c1459f1c..d0f6ec8f21f 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -684,6 +684,7 @@ fn try_write_constant<'tcx>(
 
         // Unsupported for now.
         ty::Array(_, _)
+        | ty::Pat(_, _)
 
         // Do not attempt to support indirection in constants.
         | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_)
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 0d600f0f937..9edb8bcee6e 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -1,6 +1,6 @@
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt};
 use std::fmt::Debug;
 
 use super::simplify::simplify_cfg;
@@ -11,6 +11,7 @@ use super::simplify::simplify_cfg;
 /// let y: Option<()>;
 /// match (x,y) {
 ///     (Some(_), Some(_)) => {0},
+///     (None, None) => {2},
 ///     _ => {1}
 /// }
 /// ```
@@ -23,10 +24,10 @@ use super::simplify::simplify_cfg;
 /// if discriminant_x == discriminant_y {
 ///     match x {
 ///         Some(_) => 0,
-///         _ => 1, // <----
-///     } //               | Actually the same bb
-/// } else { //            |
-///     1 // <--------------
+///         None => 2,
+///     }
+/// } else {
+///     1
 /// }
 /// ```
 ///
@@ -47,18 +48,18 @@ use super::simplify::simplify_cfg;
 ///                         |    |    |
 ///     =================   |    |    |
 ///     |      BBU      | <-|    |    |    ============================
-///     |---------------|   |    \-------> |            BBD           |
-///     |---------------|   |         |    |--------------------------|
-///     |  unreachable  |   |         |    |   _dl = discriminant(P)  |
-///     =================   |         |    |--------------------------|
-///                         |         |    |       switchInt(_dl)     |
-///     =================   |         |    |            d             | ---> BBD.2
+///     |---------------|        \-------> |            BBD           |
+///     |---------------|             |    |--------------------------|
+///     |  unreachable  |             |    |   _dl = discriminant(P)  |
+///     =================             |    |--------------------------|
+///                                   |    |       switchInt(_dl)     |
+///     =================             |    |            d             | ---> BBD.2
 ///     |      BB9      | <--------------- |         otherwise        |
 ///     |---------------|                  ============================
 ///     |      ...      |
 ///     =================
 /// ```
-/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU` or to `BB9`. In the
+/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU`. In the
 /// code:
 ///  - `BB1` is `parent` and `BBC, BBD` are children
 ///  - `P` is `child_place`
@@ -78,7 +79,7 @@ use super::simplify::simplify_cfg;
 ///     |---------------------|         |        |       switchInt(Q)       |
 ///     |     switchInt(_t)   |         |        |            c             | ---> BBC.2
 ///     |        false        | --------/        |            d             | ---> BBD.2
-///     |       otherwise     | ---------------- |         otherwise        |
+///     |       otherwise     |       /--------- |         otherwise        |
 ///     =======================       |          ============================
 ///                                   |
 ///     =================             |
@@ -87,16 +88,11 @@ use super::simplify::simplify_cfg;
 ///     |      ...      |
 ///     =================
 /// ```
-///
-/// This is only correct for some `P`, since `P` is now computed outside the original `switchInt`.
-/// The filter on which `P` are allowed (together with discussion of its correctness) is found in
-/// `may_hoist`.
 pub struct EarlyOtherwiseBranch;
 
 impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        // unsound: https://github.com/rust-lang/rust/issues/95162
-        sess.mir_opt_level() >= 3 && sess.opts.unstable_opts.unsound_mir_opts
+        sess.mir_opt_level() >= 2
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -172,7 +168,8 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
                 };
                 (value, targets.target_for_value(value))
             });
-            let eq_targets = SwitchTargets::new(eq_new_targets, opt_data.destination);
+            // The otherwise either is the same target branch or an unreachable.
+            let eq_targets = SwitchTargets::new(eq_new_targets, parent_targets.otherwise());
 
             // Create `bbEq` in example above
             let eq_switch = BasicBlockData::new(Some(Terminator {
@@ -217,85 +214,6 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
     }
 }
 
-/// Returns true if computing the discriminant of `place` may be hoisted out of the branch
-fn may_hoist<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>) -> bool {
-    // FIXME(JakobDegen): This is unsound. Someone could write code like this:
-    // ```rust
-    // let Q = val;
-    // if discriminant(P) == otherwise {
-    //     let ptr = &mut Q as *mut _ as *mut u8;
-    //     unsafe { *ptr = 10; } // Any invalid value for the type
-    // }
-    //
-    // match P {
-    //    A => match Q {
-    //        A => {
-    //            // code
-    //        }
-    //        _ => {
-    //            // don't use Q
-    //        }
-    //    }
-    //    _ => {
-    //        // don't use Q
-    //    }
-    // };
-    // ```
-    //
-    // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an
-    // invalid value, which is UB.
-    //
-    // In order to fix this, we would either need to show that the discriminant computation of
-    // `place` is computed in all branches, including the `otherwise` branch, or we would need
-    // another analysis pass to determine that the place is fully initialized. It might even be best
-    // to have the hoisting be performed in a different pass and just do the CFG changing in this
-    // pass.
-    for (place, proj) in place.iter_projections() {
-        match proj {
-            // Dereferencing in the computation of `place` might cause issues from one of two
-            // categories. First, the referent might be invalid. We protect against this by
-            // dereferencing references only (not pointers). Second, the use of a reference may
-            // invalidate other references that are used later (for aliasing reasons). Consider
-            // where such an invalidated reference may appear:
-            //  - In `Q`: Not possible since `Q` is used as the operand of a `SwitchInt` and so
-            //    cannot contain referenced data.
-            //  - In `BBU`: Not possible since that block contains only the `unreachable` terminator
-            //  - In `BBC.2, BBD.2`: Not possible, since `discriminant(P)` was computed prior to
-            //    reaching that block in the input to our transformation, and so any data
-            //    invalidated by that computation could not have been used there.
-            //  - In `BB9`: Not possible since control flow might have reached `BB9` via the
-            //    `otherwise` branch in `BBC, BBD` in the input to our transformation, which would
-            //    have invalidated the data when computing `discriminant(P)`
-            // So dereferencing here is correct.
-            ProjectionElem::Deref => match place.ty(body.local_decls(), tcx).ty.kind() {
-                ty::Ref(..) => {}
-                _ => return false,
-            },
-            // Field projections are always valid
-            ProjectionElem::Field(..) => {}
-            // We cannot allow
-            // downcasts either, since the correctness of the downcast may depend on the parent
-            // branch being taken. An easy example of this is
-            // ```
-            // Q = discriminant(_3)
-            // P = (_3 as Variant)
-            // ```
-            // However, checking if the child and parent place are the same and only erroring then
-            // is not sufficient either, since the `discriminant(_3) == 1` (or whatever) check may
-            // be replaced by another optimization pass with any other condition that can be proven
-            // equivalent.
-            ProjectionElem::Downcast(..) => {
-                return false;
-            }
-            // We cannot allow indexing since the index may be out of bounds.
-            _ => {
-                return false;
-            }
-        }
-    }
-    true
-}
-
 #[derive(Debug)]
 struct OptimizationData<'tcx> {
     destination: BasicBlock,
@@ -315,18 +233,40 @@ fn evaluate_candidate<'tcx>(
         return None;
     };
     let parent_ty = parent_discr.ty(body.local_decls(), tcx);
-    let parent_dest = {
-        let poss = targets.otherwise();
-        // If the fallthrough on the parent is trivially unreachable, we can let the
-        // children choose the destination
-        if bbs[poss].statements.len() == 0
-            && bbs[poss].terminator().kind == TerminatorKind::Unreachable
-        {
-            None
-        } else {
-            Some(poss)
-        }
-    };
+    if !bbs[targets.otherwise()].is_empty_unreachable() {
+        // Someone could write code like this:
+        // ```rust
+        // let Q = val;
+        // if discriminant(P) == otherwise {
+        //     let ptr = &mut Q as *mut _ as *mut u8;
+        //     // It may be difficult for us to effectively determine whether values are valid.
+        //     // Invalid values can come from all sorts of corners.
+        //     unsafe { *ptr = 10; }
+        // }
+        //
+        // match P {
+        //    A => match Q {
+        //        A => {
+        //            // code
+        //        }
+        //        _ => {
+        //            // don't use Q
+        //        }
+        //    }
+        //    _ => {
+        //        // don't use Q
+        //    }
+        // };
+        // ```
+        //
+        // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an
+        // invalid value, which is UB.
+        // In order to fix this, **we would either need to show that the discriminant computation of
+        // `place` is computed in all branches**.
+        // FIXME(#95162) For the moment, we adopt a conservative approach and
+        // consider only the `otherwise` branch has no statements and an unreachable terminator.
+        return None;
+    }
     let (_, child) = targets.iter().next()?;
     let child_terminator = &bbs[child].terminator();
     let TerminatorKind::SwitchInt { targets: child_targets, discr: child_discr } =
@@ -344,13 +284,7 @@ fn evaluate_candidate<'tcx>(
     let (_, Rvalue::Discriminant(child_place)) = &**boxed else {
         return None;
     };
-    let destination = parent_dest.unwrap_or(child_targets.otherwise());
-
-    // Verify that the optimization is legal in general
-    // We can hoist evaluating the child discriminant out of the branch
-    if !may_hoist(tcx, body, *child_place) {
-        return None;
-    }
+    let destination = child_targets.otherwise();
 
     // Verify that the optimization is legal for each branch
     for (value, child) in targets.iter() {
@@ -411,5 +345,5 @@ fn verify_candidate_branch<'tcx>(
     if let Some(_) = iter.next() {
         return false;
     }
-    return true;
+    true
 }
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 6d4332793af..4d9a198eeb2 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -1,11 +1,125 @@
+use rustc_index::IndexSlice;
+use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
+use rustc_target::abi::Size;
 use std::iter;
 
 use super::simplify::simplify_cfg;
 
 pub struct MatchBranchSimplification;
 
+impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 1
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let def_id = body.source.def_id();
+        let param_env = tcx.param_env_reveal_all_normalized(def_id);
+
+        let mut should_cleanup = false;
+        for i in 0..body.basic_blocks.len() {
+            let bbs = &*body.basic_blocks;
+            let bb_idx = BasicBlock::from_usize(i);
+            if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {def_id:?} ")) {
+                continue;
+            }
+
+            match bbs[bb_idx].terminator().kind {
+                TerminatorKind::SwitchInt {
+                    discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)),
+                    ref targets,
+                    ..
+                    // We require that the possible target blocks don't contain this block.
+                } if !targets.all_targets().contains(&bb_idx) => {}
+                // Only optimize switch int statements
+                _ => continue,
+            };
+
+            if SimplifyToIf.simplify(tcx, body, bb_idx, param_env).is_some() {
+                should_cleanup = true;
+                continue;
+            }
+            if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() {
+                should_cleanup = true;
+                continue;
+            }
+        }
+
+        if should_cleanup {
+            simplify_cfg(body);
+        }
+    }
+}
+
+trait SimplifyMatch<'tcx> {
+    /// Simplifies a match statement, returning true if the simplification succeeds, false otherwise.
+    /// Generic code is written here, and we generally don't need a custom implementation.
+    fn simplify(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        body: &mut Body<'tcx>,
+        switch_bb_idx: BasicBlock,
+        param_env: ParamEnv<'tcx>,
+    ) -> Option<()> {
+        let bbs = &body.basic_blocks;
+        let (discr, targets) = match bbs[switch_bb_idx].terminator().kind {
+            TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets),
+            _ => unreachable!(),
+        };
+
+        let discr_ty = discr.ty(body.local_decls(), tcx);
+        self.can_simplify(tcx, targets, param_env, bbs, discr_ty)?;
+
+        let mut patch = MirPatch::new(body);
+
+        // Take ownership of items now that we know we can optimize.
+        let discr = discr.clone();
+
+        // Introduce a temporary for the discriminant value.
+        let source_info = bbs[switch_bb_idx].terminator().source_info;
+        let discr_local = patch.new_temp(discr_ty, source_info.span);
+
+        let (_, first) = targets.iter().next().unwrap();
+        let statement_index = bbs[switch_bb_idx].statements.len();
+        let parent_end = Location { block: switch_bb_idx, statement_index };
+        patch.add_statement(parent_end, StatementKind::StorageLive(discr_local));
+        patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr));
+        self.new_stmts(tcx, targets, param_env, &mut patch, parent_end, bbs, discr_local, discr_ty);
+        patch.add_statement(parent_end, StatementKind::StorageDead(discr_local));
+        patch.patch_terminator(switch_bb_idx, bbs[first].terminator().kind.clone());
+        patch.apply(body);
+        Some(())
+    }
+
+    /// Check that the BBs to be simplified satisfies all distinct and
+    /// that the terminator are the same.
+    /// There are also conditions for different ways of simplification.
+    fn can_simplify(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        targets: &SwitchTargets,
+        param_env: ParamEnv<'tcx>,
+        bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
+        discr_ty: Ty<'tcx>,
+    ) -> Option<()>;
+
+    fn new_stmts(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        targets: &SwitchTargets,
+        param_env: ParamEnv<'tcx>,
+        patch: &mut MirPatch<'tcx>,
+        parent_end: Location,
+        bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
+        discr_local: Local,
+        discr_ty: Ty<'tcx>,
+    );
+}
+
+struct SimplifyToIf;
+
 /// If a source block is found that switches between two blocks that are exactly
 /// the same modulo const bool assignments (e.g., one assigns true another false
 /// to the same place), merge a target block statements into the source block,
@@ -37,144 +151,350 @@ pub struct MatchBranchSimplification;
 ///    goto -> bb3;
 /// }
 /// ```
+impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf {
+    fn can_simplify(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        targets: &SwitchTargets,
+        param_env: ParamEnv<'tcx>,
+        bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
+        _discr_ty: Ty<'tcx>,
+    ) -> Option<()> {
+        if targets.iter().len() != 1 {
+            return None;
+        }
+        // We require that the possible target blocks all be distinct.
+        let (_, first) = targets.iter().next().unwrap();
+        let second = targets.otherwise();
+        if first == second {
+            return None;
+        }
+        // Check that destinations are identical, and if not, then don't optimize this block
+        if bbs[first].terminator().kind != bbs[second].terminator().kind {
+            return None;
+        }
 
-impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
-    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.mir_opt_level() >= 1
-    }
+        // Check that blocks are assignments of consts to the same place or same statement,
+        // and match up 1-1, if not don't optimize this block.
+        let first_stmts = &bbs[first].statements;
+        let second_stmts = &bbs[second].statements;
+        if first_stmts.len() != second_stmts.len() {
+            return None;
+        }
+        for (f, s) in iter::zip(first_stmts, second_stmts) {
+            match (&f.kind, &s.kind) {
+                // If two statements are exactly the same, we can optimize.
+                (f_s, s_s) if f_s == s_s => {}
 
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let def_id = body.source.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
+                // If two statements are const bool assignments to the same place, we can optimize.
+                (
+                    StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
+                    StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
+                ) if lhs_f == lhs_s
+                    && f_c.const_.ty().is_bool()
+                    && s_c.const_.ty().is_bool()
+                    && f_c.const_.try_eval_bool(tcx, param_env).is_some()
+                    && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {}
 
-        let bbs = body.basic_blocks.as_mut();
-        let mut should_cleanup = false;
-        'outer: for bb_idx in bbs.indices() {
-            if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {def_id:?} ")) {
-                continue;
+                // Otherwise we cannot optimize. Try another block.
+                _ => return None,
             }
+        }
+        Some(())
+    }
 
-            let (discr, val, first, second) = match bbs[bb_idx].terminator().kind {
-                TerminatorKind::SwitchInt {
-                    discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
-                    ref targets,
-                    ..
-                } if targets.iter().len() == 1 => {
-                    let (value, target) = targets.iter().next().unwrap();
-                    // We require that this block and the two possible target blocks all be
-                    // distinct.
-                    if target == targets.otherwise()
-                        || bb_idx == target
-                        || bb_idx == targets.otherwise()
-                    {
-                        continue;
+    fn new_stmts(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        targets: &SwitchTargets,
+        param_env: ParamEnv<'tcx>,
+        patch: &mut MirPatch<'tcx>,
+        parent_end: Location,
+        bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
+        discr_local: Local,
+        discr_ty: Ty<'tcx>,
+    ) {
+        let (val, first) = targets.iter().next().unwrap();
+        let second = targets.otherwise();
+        // We already checked that first and second are different blocks,
+        // and bb_idx has a different terminator from both of them.
+        let first = &bbs[first];
+        let second = &bbs[second];
+        for (f, s) in iter::zip(&first.statements, &second.statements) {
+            match (&f.kind, &s.kind) {
+                (f_s, s_s) if f_s == s_s => {
+                    patch.add_statement(parent_end, f.kind.clone());
+                }
+
+                (
+                    StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
+                    StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
+                ) => {
+                    // From earlier loop we know that we are dealing with bool constants only:
+                    let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap();
+                    let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap();
+                    if f_b == s_b {
+                        // Same value in both blocks. Use statement as is.
+                        patch.add_statement(parent_end, f.kind.clone());
+                    } else {
+                        // Different value between blocks. Make value conditional on switch condition.
+                        let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
+                        let const_cmp = Operand::const_from_scalar(
+                            tcx,
+                            discr_ty,
+                            rustc_const_eval::interpret::Scalar::from_uint(val, size),
+                            rustc_span::DUMMY_SP,
+                        );
+                        let op = if f_b { BinOp::Eq } else { BinOp::Ne };
+                        let rhs = Rvalue::BinaryOp(
+                            op,
+                            Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)),
+                        );
+                        patch.add_assign(parent_end, *lhs, rhs);
                     }
-                    (discr, value, target, targets.otherwise())
                 }
-                // Only optimize switch int statements
-                _ => continue,
-            };
 
-            // Check that destinations are identical, and if not, then don't optimize this block
-            if bbs[first].terminator().kind != bbs[second].terminator().kind {
-                continue;
+                _ => unreachable!(),
             }
+        }
+    }
+}
 
-            // Check that blocks are assignments of consts to the same place or same statement,
-            // and match up 1-1, if not don't optimize this block.
-            let first_stmts = &bbs[first].statements;
-            let scnd_stmts = &bbs[second].statements;
-            if first_stmts.len() != scnd_stmts.len() {
-                continue;
-            }
-            for (f, s) in iter::zip(first_stmts, scnd_stmts) {
-                match (&f.kind, &s.kind) {
-                    // If two statements are exactly the same, we can optimize.
-                    (f_s, s_s) if f_s == s_s => {}
+#[derive(Default)]
+struct SimplifyToExp {
+    transfrom_types: Vec<TransfromType>,
+}
 
-                    // If two statements are const bool assignments to the same place, we can optimize.
-                    (
-                        StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
-                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) if lhs_f == lhs_s
-                        && f_c.const_.ty().is_bool()
-                        && s_c.const_.ty().is_bool()
-                        && f_c.const_.try_eval_bool(tcx, param_env).is_some()
-                        && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {}
+#[derive(Clone, Copy)]
+enum CompareType<'tcx, 'a> {
+    /// Identical statements.
+    Same(&'a StatementKind<'tcx>),
+    /// Assignment statements have the same value.
+    Eq(&'a Place<'tcx>, Ty<'tcx>, ScalarInt),
+    /// Enum variant comparison type.
+    Discr { place: &'a Place<'tcx>, ty: Ty<'tcx>, is_signed: bool },
+}
 
-                    // Otherwise we cannot optimize. Try another block.
-                    _ => continue 'outer,
-                }
-            }
-            // Take ownership of items now that we know we can optimize.
-            let discr = discr.clone();
-            let discr_ty = discr.ty(&body.local_decls, tcx);
+enum TransfromType {
+    Same,
+    Eq,
+    Discr,
+}
+
+impl From<CompareType<'_, '_>> for TransfromType {
+    fn from(compare_type: CompareType<'_, '_>) -> Self {
+        match compare_type {
+            CompareType::Same(_) => TransfromType::Same,
+            CompareType::Eq(_, _, _) => TransfromType::Eq,
+            CompareType::Discr { .. } => TransfromType::Discr,
+        }
+    }
+}
+
+/// If we find that the value of match is the same as the assignment,
+/// merge a target block statements into the source block,
+/// using cast to transform different integer types.
+///
+/// For example:
+///
+/// ```ignore (MIR)
+/// bb0: {
+///     switchInt(_1) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
+/// }
+///
+/// bb1: {
+///     unreachable;
+/// }
+///
+/// bb2: {
+///     _0 = const 1_i16;
+///     goto -> bb5;
+/// }
+///
+/// bb3: {
+///     _0 = const 2_i16;
+///     goto -> bb5;
+/// }
+///
+/// bb4: {
+///     _0 = const 3_i16;
+///     goto -> bb5;
+/// }
+/// ```
+///
+/// into:
+///
+/// ```ignore (MIR)
+/// bb0: {
+///    _0 = _3 as i16 (IntToInt);
+///    goto -> bb5;
+/// }
+/// ```
+impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp {
+    fn can_simplify(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        targets: &SwitchTargets,
+        param_env: ParamEnv<'tcx>,
+        bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
+        discr_ty: Ty<'tcx>,
+    ) -> Option<()> {
+        if targets.iter().len() < 2 || targets.iter().len() > 64 {
+            return None;
+        }
+        // We require that the possible target blocks all be distinct.
+        if !targets.is_distinct() {
+            return None;
+        }
+        if !bbs[targets.otherwise()].is_empty_unreachable() {
+            return None;
+        }
+        let mut target_iter = targets.iter();
+        let (first_val, first_target) = target_iter.next().unwrap();
+        let first_terminator_kind = &bbs[first_target].terminator().kind;
+        // Check that destinations are identical, and if not, then don't optimize this block
+        if !targets
+            .iter()
+            .all(|(_, other_target)| first_terminator_kind == &bbs[other_target].terminator().kind)
+        {
+            return None;
+        }
 
-            // Introduce a temporary for the discriminant value.
-            let source_info = bbs[bb_idx].terminator().source_info;
-            let discr_local = body.local_decls.push(LocalDecl::new(discr_ty, source_info.span));
+        let discr_size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
+        let first_stmts = &bbs[first_target].statements;
+        let (second_val, second_target) = target_iter.next().unwrap();
+        let second_stmts = &bbs[second_target].statements;
+        if first_stmts.len() != second_stmts.len() {
+            return None;
+        }
 
-            // We already checked that first and second are different blocks,
-            // and bb_idx has a different terminator from both of them.
-            let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
+        fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool {
+            l.try_to_int(l.size()).unwrap()
+                == ScalarInt::try_from_uint(r, size).unwrap().try_to_int(size).unwrap()
+        }
 
-            let new_stmts = iter::zip(&first.statements, &second.statements).map(|(f, s)| {
-                match (&f.kind, &s.kind) {
-                    (f_s, s_s) if f_s == s_s => (*f).clone(),
+        // We first compare the two branches, and then the other branches need to fulfill the same conditions.
+        let mut compare_types = Vec::new();
+        for (f, s) in iter::zip(first_stmts, second_stmts) {
+            let compare_type = match (&f.kind, &s.kind) {
+                // If two statements are exactly the same, we can optimize.
+                (f_s, s_s) if f_s == s_s => CompareType::Same(f_s),
 
-                    (
-                        StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
-                        StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) => {
-                        // From earlier loop we know that we are dealing with bool constants only:
-                        let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap();
-                        let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap();
-                        if f_b == s_b {
-                            // Same value in both blocks. Use statement as is.
-                            (*f).clone()
-                        } else {
-                            // Different value between blocks. Make value conditional on switch condition.
-                            let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size;
-                            let const_cmp = Operand::const_from_scalar(
-                                tcx,
-                                discr_ty,
-                                rustc_const_eval::interpret::Scalar::from_uint(val, size),
-                                rustc_span::DUMMY_SP,
-                            );
-                            let op = if f_b { BinOp::Eq } else { BinOp::Ne };
-                            let rhs = Rvalue::BinaryOp(
-                                op,
-                                Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)),
-                            );
-                            Statement {
-                                source_info: f.source_info,
-                                kind: StatementKind::Assign(Box::new((*lhs, rhs))),
+                // If two statements are assignments with the match values to the same place, we can optimize.
+                (
+                    StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
+                    StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
+                ) if lhs_f == lhs_s
+                    && f_c.const_.ty() == s_c.const_.ty()
+                    && f_c.const_.ty().is_integral() =>
+                {
+                    match (
+                        f_c.const_.try_eval_scalar_int(tcx, param_env),
+                        s_c.const_.try_eval_scalar_int(tcx, param_env),
+                    ) {
+                        (Some(f), Some(s)) if f == s => CompareType::Eq(lhs_f, f_c.const_.ty(), f),
+                        // Enum variants can also be simplified to an assignment statement if their values are equal.
+                        // We need to consider both unsigned and signed scenarios here.
+                        (Some(f), Some(s))
+                            if ((f_c.const_.ty().is_signed() || discr_ty.is_signed())
+                                && int_equal(f, first_val, discr_size)
+                                && int_equal(s, second_val, discr_size))
+                                || (Some(f) == ScalarInt::try_from_uint(first_val, f.size())
+                                    && Some(s)
+                                        == ScalarInt::try_from_uint(second_val, s.size())) =>
+                        {
+                            CompareType::Discr {
+                                place: lhs_f,
+                                ty: f_c.const_.ty(),
+                                is_signed: f_c.const_.ty().is_signed() || discr_ty.is_signed(),
                             }
                         }
+                        _ => {
+                            return None;
+                        }
                     }
+                }
+
+                // Otherwise we cannot optimize. Try another block.
+                _ => return None,
+            };
+            compare_types.push(compare_type);
+        }
 
-                    _ => unreachable!(),
+        // All remaining BBs need to fulfill the same pattern as the two BBs from the previous step.
+        for (other_val, other_target) in target_iter {
+            let other_stmts = &bbs[other_target].statements;
+            if compare_types.len() != other_stmts.len() {
+                return None;
+            }
+            for (f, s) in iter::zip(&compare_types, other_stmts) {
+                match (*f, &s.kind) {
+                    (CompareType::Same(f_s), s_s) if f_s == s_s => {}
+                    (
+                        CompareType::Eq(lhs_f, f_ty, val),
+                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
+                    ) if lhs_f == lhs_s
+                        && s_c.const_.ty() == f_ty
+                        && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(val) => {}
+                    (
+                        CompareType::Discr { place: lhs_f, ty: f_ty, is_signed },
+                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
+                    ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty => {
+                        let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) else {
+                            return None;
+                        };
+                        if is_signed
+                            && s_c.const_.ty().is_signed()
+                            && int_equal(f, other_val, discr_size)
+                        {
+                            continue;
+                        }
+                        if Some(f) == ScalarInt::try_from_uint(other_val, f.size()) {
+                            continue;
+                        }
+                        return None;
+                    }
+                    _ => return None,
                 }
-            });
-
-            from.statements
-                .push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) });
-            from.statements.push(Statement {
-                source_info,
-                kind: StatementKind::Assign(Box::new((
-                    Place::from(discr_local),
-                    Rvalue::Use(discr),
-                ))),
-            });
-            from.statements.extend(new_stmts);
-            from.statements
-                .push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) });
-            from.terminator_mut().kind = first.terminator().kind.clone();
-            should_cleanup = true;
+            }
         }
+        self.transfrom_types = compare_types.into_iter().map(|c| c.into()).collect();
+        Some(())
+    }
 
-        if should_cleanup {
-            simplify_cfg(body);
+    fn new_stmts(
+        &self,
+        _tcx: TyCtxt<'tcx>,
+        targets: &SwitchTargets,
+        _param_env: ParamEnv<'tcx>,
+        patch: &mut MirPatch<'tcx>,
+        parent_end: Location,
+        bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
+        discr_local: Local,
+        discr_ty: Ty<'tcx>,
+    ) {
+        let (_, first) = targets.iter().next().unwrap();
+        let first = &bbs[first];
+
+        for (t, s) in iter::zip(&self.transfrom_types, &first.statements) {
+            match (t, &s.kind) {
+                (TransfromType::Same, _) | (TransfromType::Eq, _) => {
+                    patch.add_statement(parent_end, s.kind.clone());
+                }
+                (
+                    TransfromType::Discr,
+                    StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
+                ) => {
+                    let operand = Operand::Copy(Place::from(discr_local));
+                    let r_val = if f_c.const_.ty() == discr_ty {
+                        Rvalue::Use(operand)
+                    } else {
+                        Rvalue::Cast(CastKind::IntToInt, operand, f_c.const_.ty())
+                    };
+                    patch.add_assign(parent_end, *lhs, r_val);
+                }
+                _ => unreachable!(),
+            }
         }
     }
 }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 0c35f9838ed..ee6c154e6e8 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -214,6 +214,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
+use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Location, MentionedItem};
 use rustc_middle::query::TyCtxtAt;
@@ -1414,15 +1415,16 @@ fn collect_items_of_instance<'tcx>(
     };
 
     if mode == CollectionMode::UsedItems {
-        // Visit everything. Here we rely on the visitor also visiting `required_consts`, so that we
-        // evaluate them and abort compilation if any of them errors.
-        collector.visit_body(body);
-    } else {
-        // We only need to evaluate all constants, but can ignore the rest of the MIR.
-        for const_op in &body.required_consts {
-            if let Some(val) = collector.eval_constant(const_op) {
-                collect_const_value(tcx, val, mentioned_items);
-            }
+        for (bb, data) in traversal::mono_reachable(body, tcx, instance) {
+            collector.visit_basic_block_data(bb, data)
+        }
+    }
+
+    // Always visit all `required_consts`, so that we evaluate them and abort compilation if any of
+    // them errors.
+    for const_op in &body.required_consts {
+        if let Some(val) = collector.eval_constant(const_op) {
+            collect_const_value(tcx, val, mentioned_items);
         }
     }
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 1899517c0e2..6600b92fb31 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -69,7 +69,8 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
 
         let (max_universe, variables) = canonicalizer.finalize();
 
-        Canonical { max_universe, variables, value }
+        let defining_opaque_types = infcx.defining_opaque_types();
+        Canonical { defining_opaque_types, max_universe, variables, value }
     }
 
     fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) {
@@ -349,6 +350,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I>
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
+            | ty::Pat(_, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 69b48bf0aff..353c3f41ed8 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -34,8 +34,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char};
 rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12);
 
 #[derive(Clone, Debug)]
-pub struct UnmatchedDelim {
-    pub expected_delim: Delimiter,
+pub(crate) struct UnmatchedDelim {
     pub found_delim: Option<Delimiter>,
     pub found_span: Span,
     pub unclosed_span: Option<Span>,
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index a506f98bf3a..b5a5a2a90ee 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -77,7 +77,6 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
         for &(_, sp) in &self.diag_info.open_braces {
             err.span_label(sp, "unclosed delimiter");
             self.diag_info.unmatched_delims.push(UnmatchedDelim {
-                expected_delim: Delimiter::Brace,
                 found_delim: None,
                 found_span: self.token.span,
                 unclosed_span: Some(sp),
@@ -163,9 +162,8 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
                             candidate = Some(*brace_span);
                         }
                     }
-                    let (tok, _) = self.diag_info.open_braces.pop().unwrap();
+                    let (_, _) = self.diag_info.open_braces.pop().unwrap();
                     self.diag_info.unmatched_delims.push(UnmatchedDelim {
-                        expected_delim: tok,
                         found_delim: Some(close_delim),
                         found_span: self.token.span,
                         unclosed_span: unclosed_delimiter,
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index dd6c1166957..51a69809c7a 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -161,4 +161,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
         let mut inner_visitor = self.new_visitor(self.tcx);
         inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i));
     }
+
+    fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) {
+        self.visit_pat(p)
+    }
 }
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index e6e52648d6f..72c6a714e4d 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -352,6 +352,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 TraitObject,
                 Typeof,
                 Infer,
+                Pat,
                 Err
             ]
         );
@@ -611,6 +612,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 AnonStruct,
                 AnonUnion,
                 Path,
+                Pat,
                 TraitObject,
                 ImplTrait,
                 Paren,
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 467f09e4c29..548a7b43005 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -399,6 +399,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
             | ty::RawPtr(_, _)
             | ty::FnDef(_, _)
             | ty::FnPtr(_)
+            | ty::Pat(_, _)
             | ty::Dynamic(_, _, _)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 41d63407418..2039e994aaa 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -276,6 +276,7 @@ where
             | ty::Tuple(..)
             | ty::RawPtr(..)
             | ty::Ref(..)
+            | ty::Pat(..)
             | ty::FnPtr(..)
             | ty::Param(..)
             | ty::Bound(..)
diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml
new file mode 100644
index 00000000000..aea2f7dda7f
--- /dev/null
+++ b/compiler/rustc_sanitizers/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "rustc_sanitizers"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+bitflags = "2.5.0"
+tracing = "0.1"
+twox-hash = "1.6.3"
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_sanitizers/README.md b/compiler/rustc_sanitizers/README.md
new file mode 100644
index 00000000000..d2e8f5d3a97
--- /dev/null
+++ b/compiler/rustc_sanitizers/README.md
@@ -0,0 +1,2 @@
+The `rustc_sanitizers` crate contains the source code for providing support for
+the [sanitizers](https://github.com/google/sanitizers) to the Rust compiler.
diff --git a/compiler/rustc_sanitizers/src/cfi/mod.rs b/compiler/rustc_sanitizers/src/cfi/mod.rs
new file mode 100644
index 00000000000..90dab5e0333
--- /dev/null
+++ b/compiler/rustc_sanitizers/src/cfi/mod.rs
@@ -0,0 +1,6 @@
+//! LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI support for the Rust compiler.
+//!
+//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+//! see design document in the tracking issue #89653.
+pub mod typeid;
+pub use crate::cfi::typeid::{typeid_for_fnabi, typeid_for_instance, TypeIdOptions};
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index a3a18fb768f..ed7cd8c2da7 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -1,76 +1,46 @@
-/// Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow
-/// Integrity (CFI) and cross-language LLVM CFI support.
-///
-/// Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium
-/// C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that
-/// are not used across the FFI boundary.
-///
-/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
-/// see design document in the tracking issue #89653.
+//! Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium
+//! C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that
+//! are not used across the FFI boundary.
+//!
+//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+//! see design document in the tracking issue #89653.
 use rustc_data_structures::base_n;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::lang_items::LangItem;
-use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::bug;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
-    self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
-    TermKind, Ty, TyCtxt, UintTy,
+    self, Const, ExistentialPredicate, FloatTy, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+    IntTy, List, Region, RegionKind, TermKind, Ty, TyCtxt, TypeFoldable, UintTy,
 };
-use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef};
-use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
 use rustc_span::def_id::DefId;
 use rustc_span::sym;
-use rustc_target::abi::call::{Conv, FnAbi, PassMode};
 use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
 use std::fmt::Write as _;
-use std::iter;
+use tracing::instrument;
 
-use crate::typeid::TypeIdOptions;
+use crate::cfi::typeid::itanium_cxx_abi::transform::{TransformTy, TransformTyOptions};
+use crate::cfi::typeid::TypeIdOptions;
 
-/// Type and extended type qualifiers.
-#[derive(Eq, Hash, PartialEq)]
-enum TyQ {
-    None,
-    Const,
-    Mut,
-}
+/// Options for encode_ty.
+pub type EncodeTyOptions = TypeIdOptions;
 
 /// Substitution dictionary key.
 #[derive(Eq, Hash, PartialEq)]
-enum DictKey<'tcx> {
+pub enum DictKey<'tcx> {
     Ty(Ty<'tcx>, TyQ),
     Region(Region<'tcx>),
     Const(Const<'tcx>),
     Predicate(ExistentialPredicate<'tcx>),
 }
 
-/// Options for encode_ty.
-type EncodeTyOptions = TypeIdOptions;
-
-/// Options for transform_ty.
-type TransformTyOptions = TypeIdOptions;
-
-/// Converts a number to a disambiguator (see
-/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
-fn to_disambiguator(num: u64) -> String {
-    if let Some(num) = num.checked_sub(1) {
-        format!("s{}_", base_n::encode(num as u128, 62))
-    } else {
-        "s_".to_string()
-    }
-}
-
-/// Converts a number to a sequence number (see
-/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
-fn to_seq_id(num: usize) -> String {
-    if let Some(num) = num.checked_sub(1) {
-        base_n::encode(num as u128, 36).to_uppercase()
-    } else {
-        "".to_string()
-    }
+/// Type and extended type qualifiers.
+#[derive(Eq, Hash, PartialEq)]
+pub enum TyQ {
+    None,
+    Const,
+    Mut,
 }
 
 /// Substitutes a component if found in the substitution dictionary (see
@@ -91,6 +61,37 @@ fn compress<'tcx>(
     }
 }
 
+/// Encodes args using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust
+/// types that are not used at the FFI boundary.
+fn encode_args<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    args: GenericArgsRef<'tcx>,
+    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
+    options: EncodeTyOptions,
+) -> String {
+    // [I<subst1..substN>E] as part of vendor extended type
+    let mut s = String::new();
+    let args: Vec<GenericArg<'_>> = args.iter().collect();
+    if !args.is_empty() {
+        s.push('I');
+        for arg in args {
+            match arg.unpack() {
+                GenericArgKind::Lifetime(region) => {
+                    s.push_str(&encode_region(region, dict));
+                }
+                GenericArgKind::Type(ty) => {
+                    s.push_str(&encode_ty(tcx, ty, dict, options));
+                }
+                GenericArgKind::Const(c) => {
+                    s.push_str(&encode_const(tcx, c, dict, options));
+                }
+            }
+        }
+        s.push('E');
+    }
+    s
+}
+
 /// Encodes a const using the Itanium C++ ABI as a literal argument (see
 /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
 fn encode_const<'tcx>(
@@ -159,7 +160,6 @@ fn encode_const<'tcx>(
 
 /// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for
 /// Rust types that are not used at the FFI boundary.
-#[instrument(level = "trace", skip(tcx, dict))]
 fn encode_fnsig<'tcx>(
     tcx: TyCtxt<'tcx>,
     fn_sig: &FnSig<'tcx>,
@@ -299,137 +299,10 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>,
     s
 }
 
-/// Encodes args using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust
-/// types that are not used at the FFI boundary.
-fn encode_args<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    args: GenericArgsRef<'tcx>,
-    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
-    options: EncodeTyOptions,
-) -> String {
-    // [I<subst1..substN>E] as part of vendor extended type
-    let mut s = String::new();
-    let args: Vec<GenericArg<'_>> = args.iter().collect();
-    if !args.is_empty() {
-        s.push('I');
-        for arg in args {
-            match arg.unpack() {
-                GenericArgKind::Lifetime(region) => {
-                    s.push_str(&encode_region(region, dict));
-                }
-                GenericArgKind::Type(ty) => {
-                    s.push_str(&encode_ty(tcx, ty, dict, options));
-                }
-                GenericArgKind::Const(c) => {
-                    s.push_str(&encode_const(tcx, c, dict, options));
-                }
-            }
-        }
-        s.push('E');
-    }
-    s
-}
-
-/// Encodes a ty:Ty name, including its crate and path disambiguators and names.
-fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
-    // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where
-    // <element-type> is <subst>, using v0's <path> without v0's extended form of paths:
-    //
-    // N<namespace-tagN>..N<namespace-tag1>
-    // C<crate-disambiguator><crate-name>
-    // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN>
-    //
-    // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance:
-    //
-    //     pub type Type1 = impl Send;
-    //     let _: Type1 = <Struct1<i32>>::foo;
-    //     fn foo1(_: Type1) { }
-    //
-    //     pub type Type2 = impl Send;
-    //     let _: Type2 = <Trait1<i32>>::foo;
-    //     fn foo2(_: Type2) { }
-    //
-    //     pub type Type3 = impl Send;
-    //     let _: Type3 = <i32 as Trait1<i32>>::foo;
-    //     fn foo3(_: Type3) { }
-    //
-    //     pub type Type4 = impl Send;
-    //     let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo;
-    //     fn foo3(_: Type4) { }
-    //
-    // Are encoded as:
-    //
-    //     _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE
-    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE
-    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE
-    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE
-    //
-    // The reason for not using v0's extended form of paths is to use a consistent and simpler
-    // encoding, as the reasoning for using it isn't relevant for type metadata identifiers (i.e.,
-    // keep symbol names close to how methods are represented in error messages). See
-    // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods.
-    let mut s = String::new();
-
-    // Start and namespace tags
-    let mut def_path = tcx.def_path(def_id);
-    def_path.data.reverse();
-    for disambiguated_data in &def_path.data {
-        s.push('N');
-        s.push_str(match disambiguated_data.data {
-            hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace>
-            hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
-            hir::definitions::DefPathData::TypeNs(..) => "t",
-            hir::definitions::DefPathData::ValueNs(..) => "v",
-            hir::definitions::DefPathData::Closure => "C",
-            hir::definitions::DefPathData::Ctor => "c",
-            hir::definitions::DefPathData::AnonConst => "k",
-            hir::definitions::DefPathData::OpaqueTy => "i",
-            hir::definitions::DefPathData::CrateRoot
-            | hir::definitions::DefPathData::Use
-            | hir::definitions::DefPathData::GlobalAsm
-            | hir::definitions::DefPathData::MacroNs(..)
-            | hir::definitions::DefPathData::LifetimeNs(..)
-            | hir::definitions::DefPathData::AnonAdt => {
-                bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
-            }
-        });
-    }
-
-    // Crate disambiguator and name
-    s.push('C');
-    s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
-    let crate_name = tcx.crate_name(def_path.krate).to_string();
-    let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
-
-    // Disambiguators and names
-    def_path.data.reverse();
-    for disambiguated_data in &def_path.data {
-        let num = disambiguated_data.disambiguator as u64;
-        if num > 0 {
-            s.push_str(&to_disambiguator(num));
-        }
-
-        let name = disambiguated_data.data.to_string();
-        let _ = write!(s, "{}", name.len());
-
-        // Prepend a '_' if name starts with a digit or '_'
-        if let Some(first) = name.as_bytes().first() {
-            if first.is_ascii_digit() || *first == b'_' {
-                s.push('_');
-            }
-        } else {
-            bug!("encode_ty_name: invalid name `{:?}`", name);
-        }
-
-        s.push_str(&name);
-    }
-
-    s
-}
-
 /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for
 /// Rust types that are not used at the FFI boundary.
-fn encode_ty<'tcx>(
+#[instrument(level = "trace", skip(tcx, dict))]
+pub fn encode_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
     dict: &mut FxHashMap<DictKey<'tcx>, usize>,
@@ -533,6 +406,16 @@ fn encode_ty<'tcx>(
             typeid.push_str(&s);
         }
 
+        ty::Pat(ty0, pat) => {
+            // u3patI<element-type><pattern>E as vendor extended type
+            let mut s = String::from("u3patI");
+            s.push_str(&encode_ty(tcx, *ty0, dict, options));
+            write!(s, "{:?}", **pat).unwrap();
+            s.push('E');
+            compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+            typeid.push_str(&s);
+        }
+
         ty::Slice(ty0) => {
             // u5sliceI<element-type>E as vendor extended type
             let mut s = String::from("u5sliceI");
@@ -752,485 +635,119 @@ fn encode_ty<'tcx>(
     typeid
 }
 
-struct TransformTy<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    options: TransformTyOptions,
-    parents: Vec<Ty<'tcx>>,
-}
-
-impl<'tcx> TransformTy<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
-        TransformTy { tcx, options, parents: Vec::new() }
-    }
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
-    // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms
-    // all c_void types into unit types unconditionally, generalizes pointers if
-    // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
-    // TransformTyOptions::NORMALIZE_INTEGERS option is set.
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match t.kind() {
-            ty::Array(..)
-            | ty::Closure(..)
-            | ty::Coroutine(..)
-            | ty::CoroutineClosure(..)
-            | ty::CoroutineWitness(..)
-            | ty::Dynamic(..)
-            | ty::Float(..)
-            | ty::FnDef(..)
-            | ty::Foreign(..)
-            | ty::Never
-            | ty::Slice(..)
-            | ty::Str
-            | ty::Tuple(..) => t.super_fold_with(self),
-
-            ty::Bool => {
-                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                    // Note: on all platforms that Rust's currently supports, its size and alignment
-                    // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
-                    //
-                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
-                    //
-                    // Clang represents bool as an 8-bit unsigned integer.
-                    self.tcx.types.u8
-                } else {
-                    t
-                }
-            }
-
-            ty::Char => {
-                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                    // Since #118032, char is guaranteed to have the same size, alignment, and
-                    // function call ABI as u32 on all platforms.
-                    self.tcx.types.u32
-                } else {
-                    t
-                }
-            }
-
-            ty::Int(..) | ty::Uint(..) => {
-                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-                    // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
-                    // wide. All platforms we currently support have a C platform, and as a
-                    // consequence, isize/usize are at least 16-bit wide for all of them.
-                    //
-                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
-                    match t.kind() {
-                        ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
-                            16 => self.tcx.types.i16,
-                            32 => self.tcx.types.i32,
-                            64 => self.tcx.types.i64,
-                            128 => self.tcx.types.i128,
-                            _ => bug!(
-                                "fold_ty: unexpected pointer width `{}`",
-                                self.tcx.sess.target.pointer_width
-                            ),
-                        },
-                        ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width {
-                            16 => self.tcx.types.u16,
-                            32 => self.tcx.types.u32,
-                            64 => self.tcx.types.u64,
-                            128 => self.tcx.types.u128,
-                            _ => bug!(
-                                "fold_ty: unexpected pointer width `{}`",
-                                self.tcx.sess.target.pointer_width
-                            ),
-                        },
-                        _ => t,
-                    }
-                } else {
-                    t
-                }
-            }
-
-            ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
-
-            ty::Adt(adt_def, args) => {
-                if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t)
-                {
-                    // Don't transform repr(transparent) types with an user-defined CFI encoding to
-                    // preserve the user-defined CFI encoding.
-                    if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
-                        return t;
-                    }
-                    let variant = adt_def.non_enum_variant();
-                    let param_env = self.tcx.param_env(variant.def_id);
-                    let field = variant.fields.iter().find(|field| {
-                        let ty = self.tcx.type_of(field.did).instantiate_identity();
-                        let is_zst = self
-                            .tcx
-                            .layout_of(param_env.and(ty))
-                            .is_ok_and(|layout| layout.is_zst());
-                        !is_zst
-                    });
-                    if let Some(field) = field {
-                        let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args);
-                        // Generalize any repr(transparent) user-defined type that is either a
-                        // pointer or reference, and either references itself or any other type that
-                        // contains or references itself, to avoid a reference cycle.
-
-                        // If the self reference is not through a pointer, for example, due
-                        // to using `PhantomData`, need to skip normalizing it if we hit it again.
-                        self.parents.push(t);
-                        let ty = if ty0.is_any_ptr() && ty0.contains(t) {
-                            let options = self.options;
-                            self.options |= TransformTyOptions::GENERALIZE_POINTERS;
-                            let ty = ty0.fold_with(self);
-                            self.options = options;
-                            ty
-                        } else {
-                            ty0.fold_with(self)
-                        };
-                        self.parents.pop();
-                        ty
-                    } else {
-                        // Transform repr(transparent) types without non-ZST field into ()
-                        self.tcx.types.unit
-                    }
-                } else {
-                    t.super_fold_with(self)
-                }
-            }
-
-            ty::Ref(..) => {
-                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                    if t.is_mutable_ptr() {
-                        Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
-                    } else {
-                        Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
-                    }
-                } else {
-                    t.super_fold_with(self)
-                }
-            }
-
-            ty::RawPtr(..) => {
-                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                    if t.is_mutable_ptr() {
-                        Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
-                    } else {
-                        Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
-                    }
-                } else {
-                    t.super_fold_with(self)
-                }
-            }
-
-            ty::FnPtr(..) => {
-                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
-                    Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
-                } else {
-                    t.super_fold_with(self)
-                }
-            }
-
-            ty::Alias(..) => {
-                self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
-            }
+/// Encodes a ty:Ty name, including its crate and path disambiguators and names.
+fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
+    // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where
+    // <element-type> is <subst>, using v0's <path> without v0's extended form of paths:
+    //
+    // N<namespace-tagN>..N<namespace-tag1>
+    // C<crate-disambiguator><crate-name>
+    // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN>
+    //
+    // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance:
+    //
+    //     pub type Type1 = impl Send;
+    //     let _: Type1 = <Struct1<i32>>::foo;
+    //     fn foo1(_: Type1) { }
+    //
+    //     pub type Type2 = impl Send;
+    //     let _: Type2 = <Trait1<i32>>::foo;
+    //     fn foo2(_: Type2) { }
+    //
+    //     pub type Type3 = impl Send;
+    //     let _: Type3 = <i32 as Trait1<i32>>::foo;
+    //     fn foo3(_: Type3) { }
+    //
+    //     pub type Type4 = impl Send;
+    //     let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo;
+    //     fn foo3(_: Type4) { }
+    //
+    // Are encoded as:
+    //
+    //     _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE
+    //     _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE
+    //
+    // The reason for not using v0's extended form of paths is to use a consistent and simpler
+    // encoding, as the reasoning for using it isn't relevant for type metadata identifiers (i.e.,
+    // keep symbol names close to how methods are represented in error messages). See
+    // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods.
+    let mut s = String::new();
 
-            ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
-                bug!("fold_ty: unexpected `{:?}`", t.kind());
+    // Start and namespace tags
+    let mut def_path = tcx.def_path(def_id);
+    def_path.data.reverse();
+    for disambiguated_data in &def_path.data {
+        s.push('N');
+        s.push_str(match disambiguated_data.data {
+            hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace>
+            hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace>
+            hir::definitions::DefPathData::TypeNs(..) => "t",
+            hir::definitions::DefPathData::ValueNs(..) => "v",
+            hir::definitions::DefPathData::Closure => "C",
+            hir::definitions::DefPathData::Ctor => "c",
+            hir::definitions::DefPathData::AnonConst => "k",
+            hir::definitions::DefPathData::OpaqueTy => "i",
+            hir::definitions::DefPathData::CrateRoot
+            | hir::definitions::DefPathData::Use
+            | hir::definitions::DefPathData::GlobalAsm
+            | hir::definitions::DefPathData::MacroNs(..)
+            | hir::definitions::DefPathData::LifetimeNs(..)
+            | hir::definitions::DefPathData::AnonAdt => {
+                bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
             }
-        }
-    }
-
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.tcx
+        });
     }
-}
 
-/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
-/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
-#[instrument(level = "trace", skip(tcx))]
-pub fn typeid_for_fnabi<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
-    options: TypeIdOptions,
-) -> String {
-    // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
-    // its type.
-    let mut typeid = String::from("_Z");
-
-    // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
-    // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
-    // code (i.e., 'TS') prefixed to the type encoding for the function.
-    typeid.push_str("TS");
-
-    // Function types are delimited by an "F..E" pair
-    typeid.push('F');
-
-    // A dictionary of substitution candidates used for compression (see
-    // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
-    let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
+    // Crate disambiguator and name
+    s.push('C');
+    s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
+    let crate_name = tcx.crate_name(def_path.krate).to_string();
+    let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
 
-    let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
-        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
-    match fn_abi.conv {
-        Conv::C => {
-            encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
-        }
-        _ => {
-            encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
+    // Disambiguators and names
+    def_path.data.reverse();
+    for disambiguated_data in &def_path.data {
+        let num = disambiguated_data.disambiguator as u64;
+        if num > 0 {
+            s.push_str(&to_disambiguator(num));
         }
-    }
 
-    // Encode the return type
-    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
-        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
-    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
-    let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder);
-    typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
-
-    // Encode the parameter types
+        let name = disambiguated_data.data.to_string();
+        let _ = write!(s, "{}", name.len());
 
-    // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how
-    // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR
-    // interpretation today will allow skipped arguments to simply not be passed at a call-site.
-    if !fn_abi.c_variadic {
-        let mut pushed_arg = false;
-        for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
-            pushed_arg = true;
-            let ty = arg.layout.ty.fold_with(&mut type_folder);
-            typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
-        }
-        if !pushed_arg {
-            // Empty parameter lists, whether declared as () or conventionally as (void), are
-            // encoded with a void parameter specifier "v".
-            typeid.push('v');
-        }
-    } else {
-        for n in 0..fn_abi.fixed_count as usize {
-            if fn_abi.args[n].mode == PassMode::Ignore {
-                continue;
+        // Prepend a '_' if name starts with a digit or '_'
+        if let Some(first) = name.as_bytes().first() {
+            if first.is_ascii_digit() || *first == b'_' {
+                s.push('_');
             }
-            let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
-            typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+        } else {
+            bug!("encode_ty_name: invalid name `{:?}`", name);
         }
 
-        typeid.push('z');
-    }
-
-    // Close the "F..E" pair
-    typeid.push('E');
-
-    // Add encoding suffixes
-    if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
-        typeid.push_str(".normalized");
-    }
-
-    if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
-        typeid.push_str(".generalized");
+        s.push_str(&name);
     }
 
-    typeid
+    s
 }
 
-/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with
-/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
-pub fn typeid_for_instance<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    mut instance: Instance<'tcx>,
-    options: TypeIdOptions,
-) -> String {
-    if (matches!(instance.def, ty::InstanceDef::Virtual(..))
-        && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn())
-        || matches!(instance.def, ty::InstanceDef::DropGlue(..))
-    {
-        // Adjust the type ids of DropGlues
-        //
-        // DropGlues may have indirect calls to one or more given types drop function. Rust allows
-        // for types to be erased to any trait object and retains the drop function for the original
-        // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is
-        // called a second time, it only has information after type erasure and it could be a call
-        // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on
-        // declaration/definition, and during code generation at call sites so they have the same
-        // type id and match.
-        //
-        // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of
-        //   any other type.
-        //
-        let def_id = tcx
-            .lang_items()
-            .drop_trait()
-            .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
-        let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef {
-            def_id: def_id,
-            args: List::empty(),
-        });
-        let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
-        let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
-        instance.args = tcx.mk_args_trait(self_ty, List::empty());
-    } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def {
-        let upcast_ty = match tcx.trait_of_item(def_id) {
-            Some(trait_id) => trait_object_ty(
-                tcx,
-                ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
-            ),
-            // drop_in_place won't have a defining trait, skip the upcast
-            None => instance.args.type_at(0),
-        };
-        let stripped_ty = strip_receiver_auto(tcx, upcast_ty);
-        instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1));
-    } else if let ty::InstanceDef::VTableShim(def_id) = instance.def
-        && let Some(trait_id) = tcx.trait_of_item(def_id)
-    {
-        // VTableShims may have a trait method, but a concrete Self. This is not suitable for a vtable,
-        // as the caller will not know the concrete Self.
-        let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args);
-        let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
-        instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
-    }
-
-    if !options.contains(EncodeTyOptions::USE_CONCRETE_SELF) {
-        if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
-            && let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
-        {
-            let impl_method = tcx.associated_item(instance.def_id());
-            let method_id = impl_method
-                .trait_item_def_id
-                .expect("Part of a trait implementation, but not linked to the def_id?");
-            let trait_method = tcx.associated_item(method_id);
-            let trait_id = trait_ref.skip_binder().def_id;
-            if traits::is_vtable_safe_method(tcx, trait_id, trait_method)
-                && tcx.object_safety_violations(trait_id).is_empty()
-            {
-                // Trait methods will have a Self polymorphic parameter, where the concreteized
-                // implementatation will not. We need to walk back to the more general trait method
-                let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
-                    instance.args,
-                    ty::ParamEnv::reveal_all(),
-                    trait_ref,
-                );
-                let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
-
-                // At the call site, any call to this concrete function through a vtable will be
-                // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
-                // original method id, and we've recovered the trait arguments, we can make the callee
-                // instance we're computing the alias set for match the caller instance.
-                //
-                // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
-                // If we ever *do* start encoding the vtable index, we will need to generate an alias set
-                // based on which vtables we are putting this method into, as there will be more than one
-                // index value when supertraits are involved.
-                instance.def = ty::InstanceDef::Virtual(method_id, 0);
-                let abstract_trait_args =
-                    tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
-                instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
-            }
-        } else if tcx.is_closure_like(instance.def_id()) {
-            // We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
-            // instantiate it, and take the type of its only method as our own.
-            let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
-            let (trait_id, inputs) = match closure_ty.kind() {
-                ty::Closure(..) => {
-                    let closure_args = instance.args.as_closure();
-                    let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
-                    let tuple_args =
-                        tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
-                    (trait_id, Some(tuple_args))
-                }
-                ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
-                    hir::CoroutineKind::Coroutine(..) => (
-                        tcx.require_lang_item(LangItem::Coroutine, None),
-                        Some(instance.args.as_coroutine().resume_ty()),
-                    ),
-                    hir::CoroutineKind::Desugared(desugaring, _) => {
-                        let lang_item = match desugaring {
-                            hir::CoroutineDesugaring::Async => LangItem::Future,
-                            hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
-                            hir::CoroutineDesugaring::Gen => LangItem::Iterator,
-                        };
-                        (tcx.require_lang_item(lang_item, None), None)
-                    }
-                },
-                ty::CoroutineClosure(..) => (
-                    tcx.require_lang_item(LangItem::FnOnce, None),
-                    Some(
-                        tcx.instantiate_bound_regions_with_erased(
-                            instance.args.as_coroutine_closure().coroutine_closure_sig(),
-                        )
-                        .tupled_inputs_ty,
-                    ),
-                ),
-                x => bug!("Unexpected type kind for closure-like: {x:?}"),
-            };
-            let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
-            let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args);
-            let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
-            let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
-            // There should be exactly one method on this trait, and it should be the one we're
-            // defining.
-            let call = tcx
-                .associated_items(trait_id)
-                .in_definition_order()
-                .find(|it| it.kind == ty::AssocKind::Fn)
-                .expect("No call-family function on closure-like Fn trait?")
-                .def_id;
-
-            instance.def = ty::InstanceDef::Virtual(call, 0);
-            instance.args = abstract_args;
-        }
+/// Converts a number to a disambiguator (see
+/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>).
+fn to_disambiguator(num: u64) -> String {
+    if let Some(num) = num.checked_sub(1) {
+        format!("s{}_", base_n::encode(num as u128, 62))
+    } else {
+        "s_".to_string()
     }
-
-    let fn_abi = tcx
-        .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
-        .unwrap_or_else(|error| {
-            bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
-        });
-
-    typeid_for_fnabi(tcx, fn_abi, options)
 }
 
-fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
-    let ty::Dynamic(preds, lifetime, kind) = ty.kind() else {
-        bug!("Tried to strip auto traits from non-dynamic type {ty}");
-    };
-    if preds.principal().is_some() {
-        let filtered_preds =
-            tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
-                !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
-            }));
-        Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind)
+/// Converts a number to a sequence number (see
+/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>).
+fn to_seq_id(num: usize) -> String {
+    if let Some(num) = num.checked_sub(1) {
+        base_n::encode(num as u128, 36).to_uppercase()
     } else {
-        // If there's no principal type, re-encode it as a unit, since we don't know anything
-        // about it. This technically discards the knowledge that it was a type that was made
-        // into a trait object at some point, but that's not a lot.
-        tcx.types.unit
+        "".to_string()
     }
 }
-
-#[instrument(skip(tcx), ret)]
-fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> {
-    assert!(!poly_trait_ref.has_non_region_param());
-    let principal_pred = poly_trait_ref.map_bound(|trait_ref| {
-        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
-    });
-    let mut assoc_preds: Vec<_> = traits::supertraits(tcx, poly_trait_ref)
-        .flat_map(|super_poly_trait_ref| {
-            tcx.associated_items(super_poly_trait_ref.def_id())
-                .in_definition_order()
-                .filter(|item| item.kind == ty::AssocKind::Type)
-                .map(move |assoc_ty| {
-                    super_poly_trait_ref.map_bound(|super_trait_ref| {
-                        let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args);
-                        let resolved = tcx.normalize_erasing_regions(
-                            ty::ParamEnv::reveal_all(),
-                            alias_ty.to_ty(tcx),
-                        );
-                        debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
-                        ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                            def_id: assoc_ty.def_id,
-                            args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args,
-                            term: resolved.into(),
-                        })
-                    })
-                })
-        })
-        .collect();
-    assoc_preds.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
-    let preds = tcx.mk_poly_existential_predicates_from_iter(
-        iter::once(principal_pred).chain(assoc_preds.into_iter()),
-    );
-    Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn)
-}
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
new file mode 100644
index 00000000000..b6182dc4e63
--- /dev/null
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs
@@ -0,0 +1,123 @@
+//! Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow
+//! Integrity (CFI) and cross-language LLVM CFI support.
+//!
+//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+//! see design document in the tracking issue #89653.
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_target::abi::call::{Conv, FnAbi, PassMode};
+use tracing::instrument;
+
+mod encode;
+mod transform;
+use crate::cfi::typeid::itanium_cxx_abi::encode::{encode_ty, DictKey, EncodeTyOptions};
+use crate::cfi::typeid::itanium_cxx_abi::transform::{
+    transform_instance, TransformTy, TransformTyOptions,
+};
+use crate::cfi::typeid::TypeIdOptions;
+
+/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
+/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+#[instrument(level = "trace", skip(tcx))]
+pub fn typeid_for_fnabi<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+    options: TypeIdOptions,
+) -> String {
+    // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions
+    // its type.
+    let mut typeid = String::from("_Z");
+
+    // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type
+    // metadata identifiers for function pointers. The typeinfo name encoding is a two-character
+    // code (i.e., 'TS') prefixed to the type encoding for the function.
+    typeid.push_str("TS");
+
+    // Function types are delimited by an "F..E" pair
+    typeid.push('F');
+
+    // A dictionary of substitution candidates used for compression (see
+    // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
+    let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
+
+    let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
+    match fn_abi.conv {
+        Conv::C => {
+            encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+        _ => {
+            encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
+        }
+    }
+
+    // Encode the return type
+    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
+    let mut type_folder = TransformTy::new(tcx, transform_ty_options);
+    let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder);
+    typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+
+    // Encode the parameter types
+
+    // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how
+    // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR
+    // interpretation today will allow skipped arguments to simply not be passed at a call-site.
+    if !fn_abi.c_variadic {
+        let mut pushed_arg = false;
+        for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
+            pushed_arg = true;
+            let ty = arg.layout.ty.fold_with(&mut type_folder);
+            typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+        }
+        if !pushed_arg {
+            // Empty parameter lists, whether declared as () or conventionally as (void), are
+            // encoded with a void parameter specifier "v".
+            typeid.push('v');
+        }
+    } else {
+        for n in 0..fn_abi.fixed_count as usize {
+            if fn_abi.args[n].mode == PassMode::Ignore {
+                continue;
+            }
+            let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
+            typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
+        }
+
+        typeid.push('z');
+    }
+
+    // Close the "F..E" pair
+    typeid.push('E');
+
+    // Add encoding suffixes
+    if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+        typeid.push_str(".normalized");
+    }
+
+    if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
+        typeid.push_str(".generalized");
+    }
+
+    typeid
+}
+
+/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with
+/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+#[instrument(level = "trace", skip(tcx))]
+pub fn typeid_for_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    options: TypeIdOptions,
+) -> String {
+    let transform_ty_options = TransformTyOptions::from_bits(options.bits())
+        .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
+    let instance = transform_instance(tcx, instance, transform_ty_options);
+    let fn_abi = tcx
+        .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty())))
+        .unwrap_or_else(|error| {
+            bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
+        });
+    typeid_for_fnabi(tcx, fn_abi, options)
+}
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
new file mode 100644
index 00000000000..7141c6c9bb0
--- /dev/null
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -0,0 +1,450 @@
+//! Transforms instances and types for LLVM CFI and cross-language LLVM CFI support using Itanium
+//! C++ ABI mangling.
+//!
+//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+//! see design document in the tracking issue #89653.
+use rustc_hir as hir;
+use rustc_hir::LangItem;
+use rustc_middle::bug;
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{
+    self, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, UintTy,
+};
+use rustc_span::sym;
+use rustc_trait_selection::traits;
+use std::iter;
+use tracing::{debug, instrument};
+
+use crate::cfi::typeid::itanium_cxx_abi::encode::EncodeTyOptions;
+use crate::cfi::typeid::TypeIdOptions;
+
+/// Options for transform_ty.
+pub type TransformTyOptions = TypeIdOptions;
+
+pub struct TransformTy<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    options: TransformTyOptions,
+    parents: Vec<Ty<'tcx>>,
+}
+
+impl<'tcx> TransformTy<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self {
+        TransformTy { tcx, options, parents: Vec::new() }
+    }
+}
+
+/// Transforms a ty:Ty for being encoded and used in the substitution dictionary.
+///
+/// * Transforms all c_void types into unit types.
+/// * Generalizes pointers if TransformTyOptions::GENERALIZE_POINTERS option is set.
+/// * Normalizes integers if TransformTyOptions::NORMALIZE_INTEGERS option is set.
+/// * Generalizes any repr(transparent) user-defined type that is either a pointer or reference, and
+///   either references itself or any other type that contains or references itself, to avoid a
+///   reference cycle.
+/// * Transforms repr(transparent) types without non-ZST field into ().
+///
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> {
+    // Transforms a ty:Ty for being encoded and used in the substitution dictionary.
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match t.kind() {
+            ty::Array(..)
+            | ty::Closure(..)
+            | ty::Coroutine(..)
+            | ty::CoroutineClosure(..)
+            | ty::CoroutineWitness(..)
+            | ty::Dynamic(..)
+            | ty::Float(..)
+            | ty::FnDef(..)
+            | ty::Foreign(..)
+            | ty::Never
+            | ty::Pat(..)
+            | ty::Slice(..)
+            | ty::Str
+            | ty::Tuple(..) => t.super_fold_with(self),
+
+            ty::Bool => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: on all platforms that Rust's currently supports, its size and alignment
+                    // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
+                    //
+                    // Clang represents bool as an 8-bit unsigned integer.
+                    self.tcx.types.u8
+                } else {
+                    t
+                }
+            }
+
+            ty::Char => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Since #118032, char is guaranteed to have the same size, alignment, and
+                    // function call ABI as u32 on all platforms.
+                    self.tcx.types.u32
+                } else {
+                    t
+                }
+            }
+
+            ty::Int(..) | ty::Uint(..) => {
+                if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+                    // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit
+                    // wide. All platforms we currently support have a C platform, and as a
+                    // consequence, isize/usize are at least 16-bit wide for all of them.
+                    //
+                    // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
+                    match t.kind() {
+                        ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.i16,
+                            32 => self.tcx.types.i32,
+                            64 => self.tcx.types.i64,
+                            128 => self.tcx.types.i128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width {
+                            16 => self.tcx.types.u16,
+                            32 => self.tcx.types.u32,
+                            64 => self.tcx.types.u64,
+                            128 => self.tcx.types.u128,
+                            _ => bug!(
+                                "fold_ty: unexpected pointer width `{}`",
+                                self.tcx.sess.target.pointer_width
+                            ),
+                        },
+                        _ => t,
+                    }
+                } else {
+                    t
+                }
+            }
+
+            ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit,
+
+            ty::Adt(adt_def, args) => {
+                if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t)
+                {
+                    // Don't transform repr(transparent) types with an user-defined CFI encoding to
+                    // preserve the user-defined CFI encoding.
+                    if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
+                        return t;
+                    }
+                    let variant = adt_def.non_enum_variant();
+                    let param_env = self.tcx.param_env(variant.def_id);
+                    let field = variant.fields.iter().find(|field| {
+                        let ty = self.tcx.type_of(field.did).instantiate_identity();
+                        let is_zst = self
+                            .tcx
+                            .layout_of(param_env.and(ty))
+                            .is_ok_and(|layout| layout.is_zst());
+                        !is_zst
+                    });
+                    if let Some(field) = field {
+                        let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args);
+                        // Generalize any repr(transparent) user-defined type that is either a
+                        // pointer or reference, and either references itself or any other type that
+                        // contains or references itself, to avoid a reference cycle.
+
+                        // If the self reference is not through a pointer, for example, due
+                        // to using `PhantomData`, need to skip normalizing it if we hit it again.
+                        self.parents.push(t);
+                        let ty = if ty0.is_any_ptr() && ty0.contains(t) {
+                            let options = self.options;
+                            self.options |= TransformTyOptions::GENERALIZE_POINTERS;
+                            let ty = ty0.fold_with(self);
+                            self.options = options;
+                            ty
+                        } else {
+                            ty0.fold_with(self)
+                        };
+                        self.parents.pop();
+                        ty
+                    } else {
+                        // Transform repr(transparent) types without non-ZST field into ()
+                        self.tcx.types.unit
+                    }
+                } else {
+                    t.super_fold_with(self)
+                }
+            }
+
+            ty::Ref(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit)
+                    }
+                } else {
+                    t.super_fold_with(self)
+                }
+            }
+
+            ty::RawPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    if t.is_mutable_ptr() {
+                        Ty::new_mut_ptr(self.tcx, self.tcx.types.unit)
+                    } else {
+                        Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
+                    }
+                } else {
+                    t.super_fold_with(self)
+                }
+            }
+
+            ty::FnPtr(..) => {
+                if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) {
+                    Ty::new_imm_ptr(self.tcx, self.tcx.types.unit)
+                } else {
+                    t.super_fold_with(self)
+                }
+            }
+
+            ty::Alias(..) => {
+                self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t))
+            }
+
+            ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => {
+                bug!("fold_ty: unexpected `{:?}`", t.kind());
+            }
+        }
+    }
+
+    fn interner(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+#[instrument(skip(tcx), ret)]
+fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> {
+    assert!(!poly_trait_ref.has_non_region_param());
+    let principal_pred = poly_trait_ref.map_bound(|trait_ref| {
+        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
+    });
+    let mut assoc_preds: Vec<_> = traits::supertraits(tcx, poly_trait_ref)
+        .flat_map(|super_poly_trait_ref| {
+            tcx.associated_items(super_poly_trait_ref.def_id())
+                .in_definition_order()
+                .filter(|item| item.kind == ty::AssocKind::Type)
+                .map(move |assoc_ty| {
+                    super_poly_trait_ref.map_bound(|super_trait_ref| {
+                        let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args);
+                        let resolved = tcx.normalize_erasing_regions(
+                            ty::ParamEnv::reveal_all(),
+                            alias_ty.to_ty(tcx),
+                        );
+                        debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
+                        ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
+                            def_id: assoc_ty.def_id,
+                            args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args,
+                            term: resolved.into(),
+                        })
+                    })
+                })
+        })
+        .collect();
+    assoc_preds.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
+    let preds = tcx.mk_poly_existential_predicates_from_iter(
+        iter::once(principal_pred).chain(assoc_preds.into_iter()),
+    );
+    Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn)
+}
+
+/// Transforms an instance for LLVM CFI and cross-language LLVM CFI support using Itanium C++ ABI
+/// mangling.
+///
+/// typeid_for_instance is called at two locations, initially when declaring/defining functions and
+/// methods, and later during code generation at call sites, after type erasure might have ocurred.
+///
+/// In the first call (i.e., when declaring/defining functions and methods), it encodes type ids for
+/// an FnAbi or Instance, and these type ids are attached to functions and methods. (These type ids
+/// are used later by the LowerTypeTests LLVM pass to aggregate functions in groups derived from
+/// these type ids.)
+///
+/// In the second call (i.e., during code generation at call sites), it encodes a type id for an
+/// FnAbi or Instance, after type erasure might have occured, and this type id is used for testing
+/// if a function is member of the group derived from this type id. Therefore, in the first call to
+/// typeid_for_fnabi (when type ids are attached to functions and methods), it can only include at
+/// most as much information that would be available in the second call (i.e., during code
+/// generation at call sites); otherwise, the type ids would not not match.
+///
+/// For this, it:
+///
+/// * Adjust the type ids of DropGlues (see below).
+/// * Adjusts the type ids of VTableShims to the type id expected in the call sites for the
+///   entry in the vtable (i.e., by using the signature of the closure passed as an argument to the
+///   shim, or by just removing self).
+/// * Performs type erasure for calls on trait objects by transforming self into a trait object of
+///   the trait that defines the method.
+/// * Performs type erasure for closures call methods by transforming self into a trait object of
+///   the Fn trait that defines the method (for being attached as a secondary type id).
+///
+#[instrument(level = "trace", skip(tcx))]
+pub fn transform_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mut instance: Instance<'tcx>,
+    options: TransformTyOptions,
+) -> Instance<'tcx> {
+    if (matches!(instance.def, ty::InstanceDef::Virtual(..))
+        && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn())
+        || matches!(instance.def, ty::InstanceDef::DropGlue(..))
+    {
+        // Adjust the type ids of DropGlues
+        //
+        // DropGlues may have indirect calls to one or more given types drop function. Rust allows
+        // for types to be erased to any trait object and retains the drop function for the original
+        // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is
+        // called a second time, it only has information after type erasure and it could be a call
+        // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on
+        // declaration/definition, and during code generation at call sites so they have the same
+        // type id and match.
+        //
+        // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of
+        //   any other type.
+        //
+        let def_id = tcx
+            .lang_items()
+            .drop_trait()
+            .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
+        let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef {
+            def_id: def_id,
+            args: List::empty(),
+        });
+        let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
+        let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
+        instance.args = tcx.mk_args_trait(self_ty, List::empty());
+    } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def {
+        // Transform self into a trait object of the trait that defines the method for virtual
+        // functions to match the type erasure done below.
+        let upcast_ty = match tcx.trait_of_item(def_id) {
+            Some(trait_id) => trait_object_ty(
+                tcx,
+                ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)),
+            ),
+            // drop_in_place won't have a defining trait, skip the upcast
+            None => instance.args.type_at(0),
+        };
+        let ty::Dynamic(preds, lifetime, kind) = upcast_ty.kind() else {
+            bug!("Tried to remove autotraits from non-dynamic type {upcast_ty}");
+        };
+        let self_ty = if preds.principal().is_some() {
+            let filtered_preds =
+                tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| {
+                    !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..))
+                }));
+            Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind)
+        } else {
+            // If there's no principal type, re-encode it as a unit, since we don't know anything
+            // about it. This technically discards the knowledge that it was a type that was made
+            // into a trait object at some point, but that's not a lot.
+            tcx.types.unit
+        };
+        instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1));
+    } else if let ty::InstanceDef::VTableShim(def_id) = instance.def
+        && let Some(trait_id) = tcx.trait_of_item(def_id)
+    {
+        // Adjust the type ids of VTableShims to the type id expected in the call sites for the
+        // entry in the vtable (i.e., by using the signature of the closure passed as an argument
+        // to the shim, or by just removing self).
+        let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args);
+        let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
+        instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
+    }
+
+    if !options.contains(TransformTyOptions::USE_CONCRETE_SELF) {
+        // Perform type erasure for calls on trait objects by transforming self into a trait object
+        // of the trait that defines the method.
+        if let Some(impl_id) = tcx.impl_of_method(instance.def_id())
+            && let Some(trait_ref) = tcx.impl_trait_ref(impl_id)
+        {
+            let impl_method = tcx.associated_item(instance.def_id());
+            let method_id = impl_method
+                .trait_item_def_id
+                .expect("Part of a trait implementation, but not linked to the def_id?");
+            let trait_method = tcx.associated_item(method_id);
+            let trait_id = trait_ref.skip_binder().def_id;
+            if traits::is_vtable_safe_method(tcx, trait_id, trait_method)
+                && tcx.object_safety_violations(trait_id).is_empty()
+            {
+                // Trait methods will have a Self polymorphic parameter, where the concreteized
+                // implementatation will not. We need to walk back to the more general trait method
+                let trait_ref = tcx.instantiate_and_normalize_erasing_regions(
+                    instance.args,
+                    ty::ParamEnv::reveal_all(),
+                    trait_ref,
+                );
+                let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
+
+                // At the call site, any call to this concrete function through a vtable will be
+                // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the
+                // original method id, and we've recovered the trait arguments, we can make the callee
+                // instance we're computing the alias set for match the caller instance.
+                //
+                // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder.
+                // If we ever *do* start encoding the vtable index, we will need to generate an alias set
+                // based on which vtables we are putting this method into, as there will be more than one
+                // index value when supertraits are involved.
+                instance.def = ty::InstanceDef::Virtual(method_id, 0);
+                let abstract_trait_args =
+                    tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
+                instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args);
+            }
+        } else if tcx.is_closure_like(instance.def_id()) {
+            // We're either a closure or a coroutine. Our goal is to find the trait we're defined on,
+            // instantiate it, and take the type of its only method as our own.
+            let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+            let (trait_id, inputs) = match closure_ty.kind() {
+                ty::Closure(..) => {
+                    let closure_args = instance.args.as_closure();
+                    let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap();
+                    let tuple_args =
+                        tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0];
+                    (trait_id, Some(tuple_args))
+                }
+                ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() {
+                    hir::CoroutineKind::Coroutine(..) => (
+                        tcx.require_lang_item(LangItem::Coroutine, None),
+                        Some(instance.args.as_coroutine().resume_ty()),
+                    ),
+                    hir::CoroutineKind::Desugared(desugaring, _) => {
+                        let lang_item = match desugaring {
+                            hir::CoroutineDesugaring::Async => LangItem::Future,
+                            hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator,
+                            hir::CoroutineDesugaring::Gen => LangItem::Iterator,
+                        };
+                        (tcx.require_lang_item(lang_item, None), None)
+                    }
+                },
+                ty::CoroutineClosure(..) => (
+                    tcx.require_lang_item(LangItem::FnOnce, None),
+                    Some(
+                        tcx.instantiate_bound_regions_with_erased(
+                            instance.args.as_coroutine_closure().coroutine_closure_sig(),
+                        )
+                        .tupled_inputs_ty,
+                    ),
+                ),
+                x => bug!("Unexpected type kind for closure-like: {x:?}"),
+            };
+            let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into));
+            let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args);
+            let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref));
+            let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1));
+            // There should be exactly one method on this trait, and it should be the one we're
+            // defining.
+            let call = tcx
+                .associated_items(trait_id)
+                .in_definition_order()
+                .find(|it| it.kind == ty::AssocKind::Fn)
+                .expect("No call-family function on closure-like Fn trait?")
+                .def_id;
+
+            instance.def = ty::InstanceDef::Virtual(call, 0);
+            instance.args = abstract_args;
+        }
+    }
+
+    instance
+}
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs
new file mode 100644
index 00000000000..ad8b1804439
--- /dev/null
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs
@@ -0,0 +1,54 @@
+//! Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI
+//! support for the Rust compiler.
+//!
+//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+//! see design document in the tracking issue #89653.
+use bitflags::bitflags;
+use rustc_middle::ty::{Instance, Ty, TyCtxt};
+use rustc_target::abi::call::FnAbi;
+
+bitflags! {
+    /// Options for typeid_for_fnabi.
+    #[derive(Clone, Copy, Debug)]
+    pub struct TypeIdOptions: u32 {
+        /// Generalizes pointers for compatibility with Clang
+        /// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI
+        /// support.
+        const GENERALIZE_POINTERS = 1;
+        /// Generalizes repr(C) user-defined type for extern function types with the "C" calling
+        /// convention (or extern types) for cross-language LLVM CFI and  KCFI support.
+        const GENERALIZE_REPR_C = 2;
+        /// Normalizes integers for compatibility with Clang
+        /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM
+        /// CFI and  KCFI support.
+        const NORMALIZE_INTEGERS = 4;
+        /// Do not perform self type erasure for attaching a secondary type id to methods with their
+        /// concrete self so they can be used as function pointers.
+        ///
+        /// (This applies to typeid_for_instance only and should be used to attach a secondary type
+        /// id to methods during their declaration/definition so they match the type ids returned by
+        /// either typeid_for_instance or typeid_for_fnabi at call sites during code generation for
+        /// type membership tests when methods are used as function pointers.)
+        const USE_CONCRETE_SELF = 8;
+    }
+}
+
+pub mod itanium_cxx_abi;
+
+/// Returns a type metadata identifier for the specified FnAbi.
+pub fn typeid_for_fnabi<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+    options: TypeIdOptions,
+) -> String {
+    itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options)
+}
+
+/// Returns a type metadata identifier for the specified Instance.
+pub fn typeid_for_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    options: TypeIdOptions,
+) -> String {
+    itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
+}
diff --git a/compiler/rustc_sanitizers/src/kcfi/mod.rs b/compiler/rustc_sanitizers/src/kcfi/mod.rs
new file mode 100644
index 00000000000..a8b632940b0
--- /dev/null
+++ b/compiler/rustc_sanitizers/src/kcfi/mod.rs
@@ -0,0 +1,7 @@
+//! LLVM Kernel Control Flow Integrity (KCFI) and cross-language LLVM KCFI support for the Rust
+//! compiler.
+//!
+//! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler,
+//! see the tracking issue #123479.
+pub mod typeid;
+pub use crate::kcfi::typeid::{typeid_for_fnabi, typeid_for_instance, TypeIdOptions};
diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs
new file mode 100644
index 00000000000..436c398e39b
--- /dev/null
+++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs
@@ -0,0 +1,55 @@
+//! Type metadata identifiers for LLVM Kernel Control Flow Integrity (KCFI) and cross-language LLVM
+//! KCFI support for the Rust compiler.
+//!
+//! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler,
+//! see the tracking issue #123479.
+use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt};
+use rustc_target::abi::call::FnAbi;
+use std::hash::Hasher;
+use twox_hash::XxHash64;
+
+pub use crate::cfi::typeid::{itanium_cxx_abi, TypeIdOptions};
+
+/// Returns a KCFI type metadata identifier for the specified FnAbi.
+pub fn typeid_for_fnabi<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+    options: TypeIdOptions,
+) -> u32 {
+    // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+    // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+    let mut hash: XxHash64 = Default::default();
+    hash.write(itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes());
+    hash.finish() as u32
+}
+
+/// Returns a KCFI type metadata identifier for the specified Instance.
+pub fn typeid_for_instance<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    mut options: TypeIdOptions,
+) -> u32 {
+    // KCFI support for Rust shares most of its implementation with the CFI support, with some key
+    // differences:
+    //
+    // 1. KCFI performs type tests differently and are implemented as different LLVM passes than CFI
+    //    to not require LTO.
+    // 2. KCFI has the limitation that a function or method may have one type id assigned only.
+    //
+    // Because of the limitation listed above (2), the current KCFI implementation (not CFI) does
+    // reifying of types (i.e., adds shims/trampolines for indirect calls in these cases) for:
+    //
+    // * Supporting casting between function items, closures, and Fn trait objects.
+    // * Supporting methods being cast as function pointers.
+    //
+    // This was implemented for KCFI support in #123106 and #123052 (which introduced the
+    // ReifyReason). The tracking issue for KCFI support for Rust is #123479.
+    if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) {
+        options.insert(TypeIdOptions::USE_CONCRETE_SELF);
+    }
+    // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+    // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+    let mut hash: XxHash64 = Default::default();
+    hash.write(itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
+    hash.finish() as u32
+}
diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs
new file mode 100644
index 00000000000..1f73e255490
--- /dev/null
+++ b/compiler/rustc_sanitizers/src/lib.rs
@@ -0,0 +1,7 @@
+#![feature(let_chains)]
+//! Sanitizers support for the Rust compiler.
+//!
+//! This crate contains the source code for providing support for the sanitizers to the Rust
+//! compiler.
+pub mod cfi;
+pub mod kcfi;
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index a0f5eb59b6a..cb6656bae06 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -4,12 +4,10 @@
 
 use crate::search_paths::PathKind;
 use crate::utils::NativeLibKind;
-use crate::Session;
 use rustc_ast as ast;
 use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
-use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
@@ -220,22 +218,6 @@ pub trait CrateStore: std::fmt::Debug {
     fn crate_name(&self, cnum: CrateNum) -> Symbol;
     fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId;
     fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum;
-
-    /// Fetch a DefId from a DefPathHash for a foreign crate.
-    fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId;
-    fn expn_hash_to_expn_id(
-        &self,
-        sess: &Session,
-        cnum: CrateNum,
-        index_guess: u32,
-        hash: ExpnHash,
-    ) -> ExpnId;
-
-    /// Imports all `SourceFile`s from the given crate into the current session.
-    /// This normally happens automatically when we decode a `Span` from
-    /// that crate's metadata - however, the incr comp cache needs
-    /// to trigger this manually when decoding a foreign `Span`
-    fn import_source_files(&self, sess: &Session, cnum: CrateNum);
 }
 
 pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend;
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index e8cc41cc886..0893bc31bfa 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -10,12 +10,12 @@ use rustc_span::Symbol;
 use stable_mir::abi::Layout;
 use stable_mir::mir::alloc::AllocId;
 use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
-use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety};
+use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety};
 use stable_mir::ty::{
     Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
     DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig,
-    GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
-    TraitRef, Ty, UintTy, VariantDef, VariantIdx,
+    GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Pattern, Region, RigidTy, Span,
+    TermKind, TraitRef, Ty, UintTy, VariantDef, VariantIdx,
 };
 use stable_mir::{CrateItem, CrateNum, DefId};
 
@@ -76,6 +76,19 @@ impl RustcInternal for Ty {
     }
 }
 
+impl RustcInternal for Pattern {
+    type T<'tcx> = rustc_ty::Pattern<'tcx>;
+    fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+        tcx.mk_pat(match self {
+            Pattern::Range { start, end, include_end } => rustc_ty::PatternKind::Range {
+                start: start.as_ref().map(|c| ty_const(c, tables, tcx)),
+                end: end.as_ref().map(|c| ty_const(c, tables, tcx)),
+                include_end: *include_end,
+            },
+        })
+    }
+}
+
 impl RustcInternal for RigidTy {
     type T<'tcx> = rustc_ty::TyKind<'tcx>;
 
@@ -90,6 +103,9 @@ impl RustcInternal for RigidTy {
             RigidTy::Array(ty, cnst) => {
                 rustc_ty::TyKind::Array(ty.internal(tables, tcx), ty_const(cnst, tables, tcx))
             }
+            RigidTy::Pat(ty, pat) => {
+                rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx))
+            }
             RigidTy::Adt(def, args) => {
                 rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx))
             }
@@ -535,6 +551,38 @@ impl RustcInternal for ProjectionElem {
     }
 }
 
+impl RustcInternal for BinOp {
+    type T<'tcx> = rustc_middle::mir::BinOp;
+
+    fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
+        match self {
+            BinOp::Add => rustc_middle::mir::BinOp::Add,
+            BinOp::AddUnchecked => rustc_middle::mir::BinOp::AddUnchecked,
+            BinOp::Sub => rustc_middle::mir::BinOp::Sub,
+            BinOp::SubUnchecked => rustc_middle::mir::BinOp::SubUnchecked,
+            BinOp::Mul => rustc_middle::mir::BinOp::Mul,
+            BinOp::MulUnchecked => rustc_middle::mir::BinOp::MulUnchecked,
+            BinOp::Div => rustc_middle::mir::BinOp::Div,
+            BinOp::Rem => rustc_middle::mir::BinOp::Rem,
+            BinOp::BitXor => rustc_middle::mir::BinOp::BitXor,
+            BinOp::BitAnd => rustc_middle::mir::BinOp::BitAnd,
+            BinOp::BitOr => rustc_middle::mir::BinOp::BitOr,
+            BinOp::Shl => rustc_middle::mir::BinOp::Shl,
+            BinOp::ShlUnchecked => rustc_middle::mir::BinOp::ShlUnchecked,
+            BinOp::Shr => rustc_middle::mir::BinOp::Shr,
+            BinOp::ShrUnchecked => rustc_middle::mir::BinOp::ShrUnchecked,
+            BinOp::Eq => rustc_middle::mir::BinOp::Eq,
+            BinOp::Lt => rustc_middle::mir::BinOp::Lt,
+            BinOp::Le => rustc_middle::mir::BinOp::Le,
+            BinOp::Ne => rustc_middle::mir::BinOp::Ne,
+            BinOp::Ge => rustc_middle::mir::BinOp::Ge,
+            BinOp::Gt => rustc_middle::mir::BinOp::Gt,
+            BinOp::Cmp => rustc_middle::mir::BinOp::Cmp,
+            BinOp::Offset => rustc_middle::mir::BinOp::Offset,
+        }
+    }
+}
+
 impl<T> RustcInternal for &T
 where
     T: RustcInternal,
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 7c12168b809..61bbedf9eec 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape};
 use stable_mir::compiler_interface::Context;
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::mono::{InstanceDef, StaticDef};
-use stable_mir::mir::{Body, Place};
+use stable_mir::mir::{BinOp, Body, Place};
 use stable_mir::target::{MachineInfo, MachineSize};
 use stable_mir::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -668,6 +668,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let tcx = tables.tcx;
         format!("{:?}", place.internal(&mut *tables, tcx))
     }
+
+    fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        let rhs_internal = rhs.internal(&mut *tables, tcx);
+        let lhs_internal = lhs.internal(&mut *tables, tcx);
+        let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal);
+        ty.stable(&mut *tables)
+    }
 }
 
 pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 2ad8f350f10..112e44f674e 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -330,6 +330,9 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
             ty::Array(ty, constant) => {
                 TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables)))
             }
+            ty::Pat(ty, pat) => {
+                TyKind::RigidTy(RigidTy::Pat(ty.stable(tables), pat.stable(tables)))
+            }
             ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))),
             ty::RawPtr(ty, mutbl) => {
                 TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables)))
@@ -385,6 +388,20 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
     }
 }
 
+impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> {
+    type T = stable_mir::ty::Pattern;
+
+    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+        match **self {
+            ty::PatternKind::Range { start, end, include_end } => stable_mir::ty::Pattern::Range {
+                start: start.stable(tables),
+                end: end.stable(tables),
+                include_end,
+            },
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for ty::Const<'tcx> {
     type T = stable_mir::ty::Const;
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 7a5647e979a..bfd0f77c237 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1009,6 +1009,7 @@ symbols! {
         io_stderr,
         io_stdout,
         irrefutable_let_patterns,
+        is,
         is_val_statically_known,
         isa_attribute,
         isize,
@@ -1347,6 +1348,8 @@ symbols! {
         path,
         pattern_complexity,
         pattern_parentheses,
+        pattern_type,
+        pattern_types,
         phantom_data,
         pic,
         pie,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 1c8f1d03670..65aa9e40c8b 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -5,7 +5,6 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
-bitflags = "2.4.1"
 punycode = "0.4.0"
 rustc-demangle = "0.1.21"
 rustc_data_structures = { path = "../rustc_data_structures" }
@@ -15,7 +14,5 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-rustc_trait_selection = { path = "../rustc_trait_selection" }
 tracing = "0.1"
-twox-hash = "1.6.3"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 0588af9bda7..b9509478702 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -114,7 +114,6 @@ mod v0;
 
 pub mod errors;
 pub mod test;
-pub mod typeid;
 
 /// This function computes the symbol name for the given `instance` and the
 /// given instantiating crate. That is, if you know that instance X is
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
deleted file mode 100644
index 7bd998294dd..00000000000
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-/// Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI
-/// support.
-///
-/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
-/// see design document in the tracking issue #89653.
-use bitflags::bitflags;
-use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt};
-use rustc_target::abi::call::FnAbi;
-use std::hash::Hasher;
-use twox_hash::XxHash64;
-
-bitflags! {
-    /// Options for typeid_for_fnabi.
-    #[derive(Clone, Copy, Debug)]
-    pub struct TypeIdOptions: u32 {
-        /// Generalizes pointers for compatibility with Clang
-        /// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI
-        /// support.
-        const GENERALIZE_POINTERS = 1;
-        /// Generalizes repr(C) user-defined type for extern function types with the "C" calling
-        /// convention (or extern types) for cross-language LLVM CFI and  KCFI support.
-        const GENERALIZE_REPR_C = 2;
-        /// Normalizes integers for compatibility with Clang
-        /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM
-        /// CFI and  KCFI support.
-        const NORMALIZE_INTEGERS = 4;
-        /// Do not perform self type erasure for attaching a secondary type id to methods with their
-        /// concrete self so they can be used as function pointers.
-        ///
-        /// (This applies to typeid_for_instance only and should be used to attach a secondary type
-        /// id to methods during their declaration/definition so they match the type ids returned by
-        /// either typeid_for_instance or typeid_for_fnabi at call sites during code generation for
-        /// type membership tests when methods are used as function pointers.)
-        const USE_CONCRETE_SELF = 8;
-    }
-}
-
-mod typeid_itanium_cxx_abi;
-
-/// Returns a type metadata identifier for the specified FnAbi.
-pub fn typeid_for_fnabi<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
-    options: TypeIdOptions,
-) -> String {
-    typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options)
-}
-
-/// Returns a type metadata identifier for the specified Instance.
-pub fn typeid_for_instance<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-    options: TypeIdOptions,
-) -> String {
-    typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
-}
-
-/// Returns a KCFI type metadata identifier for the specified FnAbi.
-pub fn kcfi_typeid_for_fnabi<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
-    options: TypeIdOptions,
-) -> u32 {
-    // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
-    // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
-    let mut hash: XxHash64 = Default::default();
-    hash.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes());
-    hash.finish() as u32
-}
-
-/// Returns a KCFI type metadata identifier for the specified Instance.
-pub fn kcfi_typeid_for_instance<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: Instance<'tcx>,
-    mut options: TypeIdOptions,
-) -> u32 {
-    // KCFI support for Rust shares most of its implementation with the CFI support, with some key
-    // differences:
-    //
-    // 1. KCFI performs type tests differently and are implemented as different LLVM passes than CFI
-    //    to not require LTO.
-    // 2. KCFI has the limitation that a function or method may have one type id assigned only.
-    //
-    // Because of the limitation listed above (2), the current KCFI implementation (not CFI) does
-    // reifying of types (i.e., adds shims/trampolines for indirect calls in these cases) for:
-    //
-    // * Supporting casting between function items, closures, and Fn trait objects.
-    // * Supporting methods being cast as function pointers.
-    //
-    // This was implemented for KCFI support in #123106 and #123052 (which introduced the
-    // ReifyReason). The tracking issue for KCFI support for Rust is #123479.
-    if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) {
-        options.insert(TypeIdOptions::USE_CONCRETE_SELF);
-    }
-    // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
-    // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
-    let mut hash: XxHash64 = Default::default();
-    hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
-    hash.finish() as u32
-}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 8cb5370bb4a..cb255fabfe2 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -45,8 +45,8 @@ pub(super) fn mangle<'tcx>(
         ty::InstanceDef::ThreadLocalShim(_) => Some("tls"),
         ty::InstanceDef::VTableShim(_) => Some("vtable"),
         ty::InstanceDef::ReifyShim(_, None) => Some("reify"),
-        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify-fnptr"),
-        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify-vtable"),
+        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"),
+        ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"),
 
         ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
         | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"),
@@ -371,6 +371,25 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                 ty.print(self)?;
             }
 
+            ty::Pat(ty, pat) => match *pat {
+                ty::PatternKind::Range { start, end, include_end } => {
+                    let consts = [
+                        start.unwrap_or(self.tcx.consts.unit),
+                        end.unwrap_or(self.tcx.consts.unit),
+                        ty::Const::from_bool(self.tcx, include_end).into(),
+                    ];
+                    // HACK: Represent as tuple until we have something better.
+                    // HACK: constants are used in arrays, even if the types don't match.
+                    self.push("T");
+                    ty.print(self)?;
+                    for ct in consts {
+                        Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct)
+                            .print(self)?;
+                    }
+                    self.push("E");
+                }
+            },
+
             ty::Array(ty, len) => {
                 self.push("A");
                 ty.print(self)?;
diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs
index f99f6a3b721..04020d13f22 100644
--- a/compiler/rustc_target/src/abi/call/aarch64.rs
+++ b/compiler/rustc_target/src/abi/call/aarch64.rs
@@ -31,7 +31,7 @@ where
             RegKind::Vector => size.bits() == 64 || size.bits() == 128,
         };
 
-        valid_unit.then_some(Uniform { unit, total: size })
+        valid_unit.then_some(Uniform::consecutive(unit, size))
     })
 }
 
@@ -60,7 +60,7 @@ where
     let size = ret.layout.size;
     let bits = size.bits();
     if bits <= 128 {
-        ret.cast_to(Uniform { unit: Reg::i64(), total: size });
+        ret.cast_to(Uniform::new(Reg::i64(), size));
         return;
     }
     ret.make_indirect();
@@ -100,9 +100,9 @@ where
     };
     if size.bits() <= 128 {
         if align.bits() == 128 {
-            arg.cast_to(Uniform { unit: Reg::i128(), total: size });
+            arg.cast_to(Uniform::new(Reg::i128(), size));
         } else {
-            arg.cast_to(Uniform { unit: Reg::i64(), total: size });
+            arg.cast_to(Uniform::new(Reg::i64(), size));
         }
         return;
     }
diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs
index 95f6691d42a..9371e1b3958 100644
--- a/compiler/rustc_target/src/abi/call/arm.rs
+++ b/compiler/rustc_target/src/abi/call/arm.rs
@@ -21,7 +21,7 @@ where
             RegKind::Vector => size.bits() == 64 || size.bits() == 128,
         };
 
-        valid_unit.then_some(Uniform { unit, total: size })
+        valid_unit.then_some(Uniform::consecutive(unit, size))
     })
 }
 
@@ -49,7 +49,7 @@ where
     let size = ret.layout.size;
     let bits = size.bits();
     if bits <= 32 {
-        ret.cast_to(Uniform { unit: Reg::i32(), total: size });
+        ret.cast_to(Uniform::new(Reg::i32(), size));
         return;
     }
     ret.make_indirect();
@@ -78,7 +78,7 @@ where
 
     let align = arg.layout.align.abi.bytes();
     let total = arg.layout.size;
-    arg.cast_to(Uniform { unit: if align <= 4 { Reg::i32() } else { Reg::i64() }, total });
+    arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total));
 }
 
 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/abi/call/csky.rs
index 8b4328db52e..7951f28beea 100644
--- a/compiler/rustc_target/src/abi/call/csky.rs
+++ b/compiler/rustc_target/src/abi/call/csky.rs
@@ -18,7 +18,7 @@ fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) {
         if total.bits() > 64 {
             arg.make_indirect();
         } else if total.bits() > 32 {
-            arg.cast_to(Uniform { unit: Reg::i32(), total });
+            arg.cast_to(Uniform::new(Reg::i32(), total));
         } else {
             arg.cast_to(Reg::i32());
         }
@@ -38,7 +38,7 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
     if arg.layout.is_aggregate() {
         let total = arg.layout.size;
         if total.bits() > 32 {
-            arg.cast_to(Uniform { unit: Reg::i32(), total });
+            arg.cast_to(Uniform::new(Reg::i32(), total));
         } else {
             arg.cast_to(Reg::i32());
         }
diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs
index 35d4b331cb4..943b12a9fbf 100644
--- a/compiler/rustc_target/src/abi/call/loongarch.rs
+++ b/compiler/rustc_target/src/abi/call/loongarch.rs
@@ -195,7 +195,7 @@ where
         if total.bits() <= xlen {
             arg.cast_to(xlen_reg);
         } else {
-            arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) });
+            arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2)));
         }
         return false;
     }
@@ -278,10 +278,10 @@ fn classify_arg<'a, Ty, C>(
     if total.bits() > xlen {
         let align_regs = align > xlen;
         if is_loongarch_aggregate(arg) {
-            arg.cast_to(Uniform {
-                unit: if align_regs { double_xlen_reg } else { xlen_reg },
-                total: Size::from_bits(xlen * 2),
-            });
+            arg.cast_to(Uniform::new(
+                if align_regs { double_xlen_reg } else { xlen_reg },
+                Size::from_bits(xlen * 2),
+            ));
         }
         if align_regs && is_vararg {
             *avail_gprs -= *avail_gprs % 2;
diff --git a/compiler/rustc_target/src/abi/call/mips.rs b/compiler/rustc_target/src/abi/call/mips.rs
index 57ccfe2152b..0e5a7f37a09 100644
--- a/compiler/rustc_target/src/abi/call/mips.rs
+++ b/compiler/rustc_target/src/abi/call/mips.rs
@@ -27,7 +27,7 @@ where
 
     if arg.layout.is_aggregate() {
         let pad_i32 = !offset.is_aligned(align);
-        arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32);
+        arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32);
     } else {
         arg.extend_integer_width_to(32);
     }
diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs
index 2700f67b209..b2a2c34b980 100644
--- a/compiler/rustc_target/src/abi/call/mips64.rs
+++ b/compiler/rustc_target/src/abi/call/mips64.rs
@@ -68,7 +68,7 @@ where
         }
 
         // Cast to a uniform int structure
-        ret.cast_to(Uniform { unit: Reg::i64(), total: size });
+        ret.cast_to(Uniform::new(Reg::i64(), size));
     } else {
         ret.make_indirect();
     }
@@ -139,7 +139,7 @@ where
     let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
     arg.cast_to(CastTarget {
         prefix,
-        rest: Uniform { unit: Reg::i64(), total: rest_size },
+        rest: Uniform::new(Reg::i64(), rest_size),
         attrs: ArgAttributes {
             regular: ArgAttribute::default(),
             arg_ext: ArgExtension::None,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index cdd3f0afd79..4502df339d1 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -255,11 +255,16 @@ pub struct Uniform {
     ///   for 64-bit integers with a total size of 20 bytes. When the argument is actually passed,
     ///   this size will be rounded up to the nearest multiple of `unit.size`.
     pub total: Size,
+
+    /// Indicate that the argument is consecutive, in the sense that either all values need to be
+    /// passed in register, or all on the stack. If they are passed on the stack, there should be
+    /// no additional padding between elements.
+    pub is_consecutive: bool,
 }
 
 impl From<Reg> for Uniform {
     fn from(unit: Reg) -> Uniform {
-        Uniform { unit, total: unit.size }
+        Uniform { unit, total: unit.size, is_consecutive: false }
     }
 }
 
@@ -267,6 +272,18 @@ impl Uniform {
     pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
         self.unit.align(cx)
     }
+
+    /// Pass using one or more values of the given type, without requiring them to be consecutive.
+    /// That is, some values may be passed in register and some on the stack.
+    pub fn new(unit: Reg, total: Size) -> Self {
+        Uniform { unit, total, is_consecutive: false }
+    }
+
+    /// Pass using one or more consecutive values of the given type. Either all values will be
+    /// passed in registers, or all on the stack.
+    pub fn consecutive(unit: Reg, total: Size) -> Self {
+        Uniform { unit, total, is_consecutive: true }
+    }
 }
 
 /// Describes the type used for `PassMode::Cast`.
diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs
index 5c040ce9c3b..f85fa2419f0 100644
--- a/compiler/rustc_target/src/abi/call/nvptx64.rs
+++ b/compiler/rustc_target/src/abi/call/nvptx64.rs
@@ -35,7 +35,7 @@ where
             16 => Reg::i128(),
             _ => unreachable!("Align is given as power of 2 no larger than 16 bytes"),
         };
-        arg.cast_to(Uniform { unit, total: Size::from_bytes(2 * align_bytes) });
+        arg.cast_to(Uniform::new(unit, Size::from_bytes(2 * align_bytes)));
     } else {
         // FIXME: find a better way to do this. See https://github.com/rust-lang/rust/issues/117271.
         arg.make_direct_deprecated();
diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs
index 2d41f77e50e..11a6cb52bab 100644
--- a/compiler/rustc_target/src/abi/call/powerpc64.rs
+++ b/compiler/rustc_target/src/abi/call/powerpc64.rs
@@ -2,7 +2,7 @@
 // Alignment of 128 bit types is not currently handled, this will
 // need to be fixed when PowerPC vector support is added.
 
-use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
+use crate::abi::call::{Align, ArgAbi, FnAbi, Reg, RegKind, Uniform};
 use crate::abi::{Endian, HasDataLayout, TyAbiInterface};
 use crate::spec::HasTargetSpec;
 
@@ -37,7 +37,7 @@ where
             RegKind::Vector => arg.layout.size.bits() == 128,
         };
 
-        valid_unit.then_some(Uniform { unit, total: arg.layout.size })
+        valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size))
     })
 }
 
@@ -81,7 +81,7 @@ where
             Reg::i64()
         };
 
-        ret.cast_to(Uniform { unit, total: size });
+        ret.cast_to(Uniform::new(unit, size));
         return;
     }
 
@@ -108,18 +108,20 @@ where
     }
 
     let size = arg.layout.size;
-    let (unit, total) = if size.bits() <= 64 {
+    if size.bits() <= 64 {
         // Aggregates smaller than a doubleword should appear in
         // the least-significant bits of the parameter doubleword.
-        (Reg { kind: RegKind::Integer, size }, size)
+        arg.cast_to(Reg { kind: RegKind::Integer, size })
     } else {
-        // Aggregates larger than a doubleword should be padded
-        // at the tail to fill out a whole number of doublewords.
-        let reg_i64 = Reg::i64();
-        (reg_i64, size.align_to(reg_i64.align(cx)))
+        // Aggregates larger than i64 should be padded at the tail to fill out a whole number
+        // of i64s or i128s, depending on the aggregate alignment. Always use an array for
+        // this, even if there is only a single element.
+        let reg = if arg.layout.align.abi.bytes() > 8 { Reg::i128() } else { Reg::i64() };
+        arg.cast_to(Uniform::consecutive(
+            reg,
+            size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()),
+        ))
     };
-
-    arg.cast_to(Uniform { unit, total });
 }
 
 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs
index 6a38496dc57..5d4b3a9d245 100644
--- a/compiler/rustc_target/src/abi/call/riscv.rs
+++ b/compiler/rustc_target/src/abi/call/riscv.rs
@@ -201,7 +201,7 @@ where
         if total.bits() <= xlen {
             arg.cast_to(xlen_reg);
         } else {
-            arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) });
+            arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2)));
         }
         return false;
     }
@@ -284,10 +284,10 @@ fn classify_arg<'a, Ty, C>(
     if total.bits() > xlen {
         let align_regs = align > xlen;
         if is_riscv_aggregate(arg) {
-            arg.cast_to(Uniform {
-                unit: if align_regs { double_xlen_reg } else { xlen_reg },
-                total: Size::from_bits(xlen * 2),
-            });
+            arg.cast_to(Uniform::new(
+                if align_regs { double_xlen_reg } else { xlen_reg },
+                Size::from_bits(xlen * 2),
+            ));
         }
         if align_regs && is_vararg {
             *avail_gprs -= *avail_gprs % 2;
diff --git a/compiler/rustc_target/src/abi/call/sparc.rs b/compiler/rustc_target/src/abi/call/sparc.rs
index 57ccfe2152b..0e5a7f37a09 100644
--- a/compiler/rustc_target/src/abi/call/sparc.rs
+++ b/compiler/rustc_target/src/abi/call/sparc.rs
@@ -27,7 +27,7 @@ where
 
     if arg.layout.is_aggregate() {
         let pad_i32 = !offset.is_aligned(align);
-        arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32);
+        arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32);
     } else {
         arg.extend_integer_width_to(32);
     }
diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs
index cbed5b4afc1..acdcd5cc0d4 100644
--- a/compiler/rustc_target/src/abi/call/sparc64.rs
+++ b/compiler/rustc_target/src/abi/call/sparc64.rs
@@ -192,7 +192,7 @@ where
 
                 arg.cast_to(CastTarget {
                     prefix: data.prefix,
-                    rest: Uniform { unit: Reg::i64(), total: rest_size },
+                    rest: Uniform::new(Reg::i64(), rest_size),
                     attrs: ArgAttributes {
                         regular: data.arg_attribute,
                         arg_ext: ArgExtension::None,
@@ -205,7 +205,7 @@ where
         }
     }
 
-    arg.cast_to(Uniform { unit: Reg::i64(), total });
+    arg.cast_to(Uniform::new(Reg::i64(), total));
 }
 
 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs
index a7a2b314a94..a773fb1e814 100644
--- a/compiler/rustc_target/src/abi/call/wasm.rs
+++ b/compiler/rustc_target/src/abi/call/wasm.rs
@@ -1,4 +1,4 @@
-use crate::abi::call::{ArgAbi, FnAbi, Uniform};
+use crate::abi::call::{ArgAbi, FnAbi};
 use crate::abi::{HasDataLayout, TyAbiInterface};
 
 fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool
@@ -10,7 +10,7 @@ where
         if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) {
             let size = val.layout.size;
             if unit.size == size {
-                val.cast_to(Uniform { unit, total: size });
+                val.cast_to(unit);
                 return true;
             }
         }
diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs
index 96da0b6fd1f..021457b145f 100644
--- a/compiler/rustc_target/src/spec/base/apple/mod.rs
+++ b/compiler/rustc_target/src/spec/base/apple/mod.rs
@@ -368,6 +368,11 @@ fn watchos_deployment_target() -> (u32, u32) {
     from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
 }
 
+pub fn watchos_llvm_target(arch: Arch) -> String {
+    let (major, minor) = watchos_deployment_target();
+    format!("{}-apple-watchos{}.{}.0", arch.target_name(), major, minor)
+}
+
 pub fn watchos_sim_llvm_target(arch: Arch) -> String {
     let (major, minor) = watchos_deployment_target();
     format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor)
diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
index 9bf09b4376d..f842a834c05 100644
--- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
@@ -1,10 +1,11 @@
-use crate::spec::base::apple::{opts, Arch};
+use crate::spec::base::apple::{opts, watchos_llvm_target, Arch};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::Arm64_32);
+    let arch = Arch::Arm64_32;
+    let base = opts("watchos", arch);
     Target {
-        llvm_target: "arm64_32-apple-watchos".into(),
+        llvm_target: watchos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
             tier: None,
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 7056288e758..0595e82b39e 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,5 +1,5 @@
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::{self, DefiningAnchor, ObligationCtxt, SelectionContext};
+use crate::traits::{self, ObligationCtxt, SelectionContext};
 
 use crate::traits::TraitEngineExt as _;
 use rustc_hir::def_id::DefId;
@@ -132,9 +132,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         R: Debug + TypeFoldable<TyCtxt<'tcx>>,
         Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
     {
-        let (infcx, key, canonical_inference_vars) = self
-            .with_opaque_type_inference(DefiningAnchor::Bubble)
-            .build_with_canonical(DUMMY_SP, canonical_key);
+        let (infcx, key, canonical_inference_vars) =
+            self.build_with_canonical(DUMMY_SP, canonical_key);
         let ocx = ObligationCtxt::new(&infcx);
         let value = operation(&ocx, key)?;
         ocx.make_canonicalized_query_response(canonical_inference_vars, value)
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 35f7d1d7151..8b5c029428c 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -363,6 +363,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Foreign(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
@@ -596,6 +597,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Foreign(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
@@ -684,6 +686,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Foreign(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
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 00cd4b48797..8a96d810134 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -50,7 +50,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
             Ok(vec![ty::Binder::dummy(element_ty)])
         }
 
-        ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]),
+        ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => {
+            Ok(vec![ty::Binder::dummy(element_ty)])
+        }
 
         ty::Tuple(tys) => {
             // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
@@ -114,6 +116,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
         | ty::Coroutine(..)
         | ty::CoroutineWitness(..)
         | ty::Array(..)
+        | ty::Pat(..)
         | ty::Closure(..)
         | ty::CoroutineClosure(..)
         | ty::Never
@@ -177,6 +180,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         | ty::Ref(_, _, Mutability::Not)
         | ty::Array(..) => Err(NoSolution),
 
+        // Cannot implement in core, as we can't be generic over patterns yet,
+        // so we'd have to list all patterns and type combinations.
+        ty::Pat(ty, ..) => Ok(vec![ty::Binder::dummy(ty)]),
+
         ty::Dynamic(..)
         | ty::Str
         | ty::Slice(_)
@@ -347,6 +354,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         | ty::CoroutineWitness(..)
         | ty::Never
         | ty::Tuple(_)
+        | ty::Pat(_, _)
         | ty::Alias(_, _)
         | ty::Param(_)
         | ty::Placeholder(..)
@@ -526,6 +534,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
         | ty::Foreign(_)
         | ty::Str
         | ty::Array(_, _)
+        | ty::Pat(_, _)
         | ty::Slice(_)
         | ty::RawPtr(_, _)
         | ty::Ref(_, _, _)
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 4a4efb6884f..0b37163d597 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -68,7 +68,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             &mut orig_values,
             QueryInput {
                 goal,
-                anchor: self.infcx.defining_use_anchor,
                 predefined_opaques_in_body: self
                     .tcx()
                     .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }),
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 1739bd70e7b..0154aff12b6 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_infer::infer::at::ToTrace;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -230,7 +230,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             .infer_ctxt()
             .intercrate(intercrate)
             .with_next_trait_solver(true)
-            .with_opaque_type_inference(canonical_input.value.anchor)
             .build_with_canonical(DUMMY_SP, &canonical_input);
 
         let mut ecx = EvalCtxt {
@@ -936,8 +935,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         }
     }
 
-    pub(super) fn can_define_opaque_ty(&self, def_id: LocalDefId) -> bool {
-        self.infcx.opaque_type_origin(def_id).is_some()
+    pub(super) fn can_define_opaque_ty(&self, def_id: impl Into<DefId>) -> bool {
+        self.infcx.can_define_opaque_ty(def_id)
     }
 
     pub(super) fn insert_hidden_type(
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 8294a8a67b1..da5cd15a10d 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -316,5 +316,6 @@ fn response_no_constraints_raw<'tcx>(
             external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()),
             certainty,
         },
+        defining_opaque_types: Default::default(),
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index fb296d55100..befde8f768a 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -533,6 +533,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
                 | ty::Uint(..)
                 | ty::Float(..)
                 | ty::Array(..)
+                | ty::Pat(..)
                 | ty::RawPtr(..)
                 | ty::Ref(..)
                 | ty::FnDef(..)
@@ -768,6 +769,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             | ty::Uint(..)
             | ty::Float(..)
             | ty::Array(..)
+            | ty::Pat(..)
             | ty::RawPtr(..)
             | ty::Ref(..)
             | ty::FnDef(..)
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index eb3ad0aa782..e522339358a 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -155,10 +155,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
         if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
             if matches!(goal.param_env.reveal(), Reveal::All)
                 || matches!(ecx.solver_mode(), SolverMode::Coherence)
-                || opaque_ty
-                    .def_id
-                    .as_local()
-                    .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id))
+                || ecx.can_define_opaque_ty(opaque_ty.def_id)
             {
                 return Err(NoSolution);
             }
@@ -1051,6 +1048,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             | ty::Float(_)
             | ty::Str
             | ty::Array(_, _)
+            | ty::Pat(_, _)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8625ad378f7..77eaa4fd03e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -883,6 +883,7 @@ where
             | ty::Float(..)
             | ty::Str
             | ty::FnDef(..)
+            | ty::Pat(..)
             | ty::FnPtr(_)
             | ty::Array(..)
             | ty::Slice(..)
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 10c03387a5b..837b784f272 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -40,7 +40,7 @@ pub struct ImplCandidate<'tcx> {
 
 enum GetSafeTransmuteErrorAndReason {
     Silent,
-    Error { err_msg: String, safe_transmute_explanation: String },
+    Error { err_msg: String, safe_transmute_explanation: Option<String> },
 }
 
 struct UnsatisfiedConst(pub bool);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 144971b63c0..1b8b09ddda1 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -558,7 +558,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 GetSafeTransmuteErrorAndReason::Error {
                                     err_msg,
                                     safe_transmute_explanation,
-                                } => (err_msg, Some(safe_transmute_explanation)),
+                                } => (err_msg, safe_transmute_explanation),
                             }
                         } else {
                             (err_msg, None)
@@ -1804,6 +1804,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 ty::Foreign(..) => Some(19),
                 ty::CoroutineWitness(..) => Some(20),
                 ty::CoroutineClosure(..) => Some(21),
+                ty::Pat(..) => Some(22),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
@@ -3067,28 +3068,33 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             return GetSafeTransmuteErrorAndReason::Silent;
         };
 
+        let dst = trait_ref.args.type_at(0);
+        let src = trait_ref.args.type_at(1);
+        let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
+
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
             obligation.cause,
             src_and_dst,
             assume,
         ) {
             Answer::No(reason) => {
-                let dst = trait_ref.args.type_at(0);
-                let src = trait_ref.args.type_at(1);
-                let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
                 let safe_transmute_explanation = match reason {
                     rustc_transmute::Reason::SrcIsNotYetSupported => {
-                        format!("analyzing the transmutability of `{src}` is not yet supported.")
+                        format!("analyzing the transmutability of `{src}` is not yet supported")
                     }
 
                     rustc_transmute::Reason::DstIsNotYetSupported => {
-                        format!("analyzing the transmutability of `{dst}` is not yet supported.")
+                        format!("analyzing the transmutability of `{dst}` is not yet supported")
                     }
 
                     rustc_transmute::Reason::DstIsBitIncompatible => {
                         format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
                     }
 
+                    rustc_transmute::Reason::DstUninhabited => {
+                        format!("`{dst}` is uninhabited")
+                    }
+
                     rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
                         format!("`{dst}` may carry safety invariants")
                     }
@@ -3134,14 +3140,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         format!("`{dst}` has an unknown layout")
                     }
                 };
-                GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation }
+                GetSafeTransmuteErrorAndReason::Error {
+                    err_msg,
+                    safe_transmute_explanation: Some(safe_transmute_explanation),
+                }
             }
             // Should never get a Yes at this point! We already ran it before, and did not get a Yes.
             Answer::Yes => span_bug!(
                 span,
                 "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
             ),
-            other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"),
+            // Reached when a different obligation (namely `Freeze`) causes the
+            // transmutability analysis to fail. In this case, silence the
+            // transmutability error message in favor of that more specific
+            // error.
+            Answer::If(_) => {
+                GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None }
+            }
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 2c8116b779b..98d5b466cd0 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -119,7 +119,9 @@ pub fn predicates_for_generics<'tcx>(
 
 /// Determines whether the type `ty` is known to meet `bound` and
 /// returns true if so. Returns false if `ty` either does not meet
-/// `bound` or is not known to meet bound.
+/// `bound` or is not known to meet bound (note that this is
+/// conservative towards *no impl*, which is the opposite of the
+/// `evaluate` methods).
 pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -127,8 +129,50 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
     def_id: DefId,
 ) -> bool {
     let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
-    let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, trait_ref);
-    infcx.predicate_must_hold_modulo_regions(&obligation)
+    pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref)
+}
+
+/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist?
+///
+/// Ping me on zulip if you want to use this method and need help with finding
+/// an appropriate replacement.
+#[instrument(level = "debug", skip(infcx, param_env, pred), ret)]
+fn pred_known_to_hold_modulo_regions<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    pred: impl ToPredicate<'tcx>,
+) -> bool {
+    let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
+
+    let result = infcx.evaluate_obligation_no_overflow(&obligation);
+    debug!(?result);
+
+    if result.must_apply_modulo_regions() {
+        true
+    } else if result.may_apply() {
+        // Sometimes obligations are ambiguous because the recursive evaluator
+        // is not smart enough, so we fall back to fulfillment when we're not certain
+        // that an obligation holds or not. Even still, we must make sure that
+        // the we do no inference in the process of checking this obligation.
+        let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
+        infcx.probe(|_| {
+            let ocx = ObligationCtxt::new(infcx);
+            ocx.register_obligation(obligation);
+
+            let errors = ocx.select_all_or_error();
+            match errors.as_slice() {
+                // Only known to hold if we did no inference.
+                [] => infcx.shallow_resolve(goal) == goal,
+
+                errors => {
+                    debug!(?errors);
+                    false
+                }
+            }
+        })
+    } else {
+        false
+    }
 }
 
 #[instrument(level = "debug", skip(tcx, elaborated_env))]
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 56b25b0fe6c..8d04fd45940 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1048,6 +1048,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Foreign(_)
                         | ty::Str
                         | ty::Array(..)
+                        | ty::Pat(..)
                         | ty::Slice(_)
                         | ty::RawPtr(..)
                         | ty::Ref(..)
@@ -1099,6 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         | ty::Float(_)
                         | ty::Str
                         | ty::Array(..)
+                        | ty::Pat(..)
                         | ty::Slice(_)
                         | ty::RawPtr(..)
                         | ty::Ref(..)
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index aaa38d14d6e..326c68e01db 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -42,8 +42,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Foreign(..)
         | ty::Error(_) => true,
 
-        // [T; N] and [T] have same properties as T.
-        ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
+        // `T is PAT`, `[T; N]`, and `[T]` have same properties as T.
+        ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
 
         // (T1..Tn) and closures have same properties as T1..Tn --
         // check if *all* of them are trivial.
@@ -222,7 +222,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             // these types never have a destructor
         }
 
-        ty::Array(ety, _) | ty::Slice(ety) => {
+        ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => {
             // single-element containers, behave like their element
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
                 dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints)
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index faf218131b8..ae4cdb9258e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -159,53 +159,70 @@ where
             .0);
         }
 
+        let mut error_info = None;
         let mut region_constraints = QueryRegionConstraints::default();
-        let (output, error_info, mut obligations, _) =
-            Q::fully_perform_into(self, infcx, &mut region_constraints, span).map_err(|_| {
-                infcx.dcx().span_delayed_bug(span, format!("error performing {self:?}"))
-            })?;
-
-        // Typically, instantiating NLL query results does not
-        // create obligations. However, in some cases there
-        // are unresolved type variables, and unify them *can*
-        // create obligations. In that case, we have to go
-        // fulfill them. We do this via a (recursive) query.
-        while !obligations.is_empty() {
-            trace!("{:#?}", obligations);
-            let mut progress = false;
-            for obligation in std::mem::take(&mut obligations) {
-                let obligation = infcx.resolve_vars_if_possible(obligation);
-                match ProvePredicate::fully_perform_into(
-                    obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
-                    infcx,
-                    &mut region_constraints,
-                    span,
-                ) {
-                    Ok(((), _, new, certainty)) => {
-                        obligations.extend(new);
-                        progress = true;
-                        if let Certainty::Ambiguous = certainty {
-                            obligations.push(obligation);
+
+        // HACK(type_alias_impl_trait): When moving an opaque type to hidden type mapping from the query to the current inferctxt,
+        // we sometimes end up with `Opaque<'a> = Opaque<'b>` instead of an actual hidden type. In that case we don't register a
+        // hidden type but just equate the lifetimes. Thus we need to scrape the region constraints even though we're also manually
+        // collecting region constraints via `region_constraints`.
+        let (mut output, _) = scrape_region_constraints(
+            infcx,
+            |_ocx| {
+                let (output, ei, mut obligations, _) =
+                    Q::fully_perform_into(self, infcx, &mut region_constraints, span)?;
+                error_info = ei;
+
+                // Typically, instantiating NLL query results does not
+                // create obligations. However, in some cases there
+                // are unresolved type variables, and unify them *can*
+                // create obligations. In that case, we have to go
+                // fulfill them. We do this via a (recursive) query.
+                while !obligations.is_empty() {
+                    trace!("{:#?}", obligations);
+                    let mut progress = false;
+                    for obligation in std::mem::take(&mut obligations) {
+                        let obligation = infcx.resolve_vars_if_possible(obligation);
+                        match ProvePredicate::fully_perform_into(
+                            obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
+                            infcx,
+                            &mut region_constraints,
+                            span,
+                        ) {
+                            Ok(((), _, new, certainty)) => {
+                                obligations.extend(new);
+                                progress = true;
+                                if let Certainty::Ambiguous = certainty {
+                                    obligations.push(obligation);
+                                }
+                            }
+                            Err(_) => obligations.push(obligation),
                         }
                     }
-                    Err(_) => obligations.push(obligation),
+                    if !progress {
+                        infcx.dcx().span_bug(
+                            span,
+                            format!("ambiguity processing {obligations:?} from {self:?}"),
+                        );
+                    }
                 }
-            }
-            if !progress {
-                infcx
-                    .dcx()
-                    .span_bug(span, format!("ambiguity processing {obligations:?} from {self:?}"));
-            }
-        }
-
-        Ok(TypeOpOutput {
-            output,
-            constraints: if region_constraints.is_empty() {
-                None
-            } else {
-                Some(infcx.tcx.arena.alloc(region_constraints))
+                Ok(output)
             },
-            error_info,
-        })
+            "fully_perform",
+            span,
+        )?;
+        output.error_info = error_info;
+        if let Some(constraints) = output.constraints {
+            region_constraints
+                .member_constraints
+                .extend(constraints.member_constraints.iter().cloned());
+            region_constraints.outlives.extend(constraints.outlives.iter().cloned());
+        }
+        output.constraints = if region_constraints.is_empty() {
+            None
+        } else {
+            Some(infcx.tcx.arena.alloc(region_constraints))
+        };
+        Ok(output)
     }
 }
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 c6ea596b819..c1f340dfc7c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -670,6 +670,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Foreign(_)
                 | ty::Str
                 | ty::Array(_, _)
+                | ty::Pat(_, _)
                 | ty::Slice(_)
                 | ty::RawPtr(_, _)
                 | ty::Ref(_, _, _)
@@ -803,6 +804,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 | ty::Float(_)
                 | ty::Str
                 | ty::Array(_, _)
+                | ty::Pat(_, _)
                 | ty::Slice(_)
                 | ty::Adt(..)
                 | ty::RawPtr(_, _)
@@ -1193,6 +1195,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Never
             | ty::Foreign(_)
             | ty::Array(..)
+            | ty::Pat(..)
             | ty::Slice(_)
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
@@ -1270,6 +1273,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::RawPtr(_, _)
             | ty::Ref(_, _, _)
             | ty::FnDef(_, _)
+            | ty::Pat(_, _)
             | ty::FnPtr(_)
             | ty::Dynamic(_, _, _)
             | ty::Closure(..)
@@ -1329,6 +1333,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             | ty::Foreign(..)
             | ty::Str
             | ty::Array(..)
+            | ty::Pat(..)
             | ty::Slice(_)
             | ty::RawPtr(_, _)
             | ty::Ref(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 0459246553b..25ba985397e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -314,12 +314,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .flat_map(|cond| flatten_answer_tree(tcx, obligation, predicate, cond))
                     .collect(),
                 Condition::IfTransmutable { src, dst } => {
-                    let trait_def_id = obligation.predicate.def_id();
+                    let transmute_trait = obligation.predicate.def_id();
                     let assume_const = predicate.trait_ref.args.const_at(2);
-                    let make_obl = |from_ty, to_ty| {
-                        let trait_ref1 = ty::TraitRef::new(
+                    let make_transmute_obl = |from_ty, to_ty| {
+                        let trait_ref = ty::TraitRef::new(
                             tcx,
-                            trait_def_id,
+                            transmute_trait,
                             [
                                 ty::GenericArg::from(to_ty),
                                 ty::GenericArg::from(from_ty),
@@ -331,17 +331,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             obligation.cause.clone(),
                             obligation.recursion_depth + 1,
                             obligation.param_env,
-                            trait_ref1,
+                            trait_ref,
                         )
                     };
 
+                    let make_freeze_obl = |ty| {
+                        let trait_ref = ty::TraitRef::new(
+                            tcx,
+                            tcx.lang_items().freeze_trait().unwrap(),
+                            [ty::GenericArg::from(ty)],
+                        );
+                        Obligation::with_depth(
+                            tcx,
+                            obligation.cause.clone(),
+                            obligation.recursion_depth + 1,
+                            obligation.param_env,
+                            trait_ref,
+                        )
+                    };
+
+                    let mut obls = vec![];
+
+                    // If the source is a shared reference, it must be `Freeze`;
+                    // otherwise, transmuting could lead to data races.
+                    if src.mutability == Mutability::Not {
+                        obls.extend([make_freeze_obl(src.ty), make_freeze_obl(dst.ty)])
+                    }
+
                     // If Dst is mutable, check bidirectionally.
                     // For example, transmuting bool -> u8 is OK as long as you can't update that u8
                     // to be > 1, because you could later transmute the u8 back to a bool and get UB.
                     match dst.mutability {
-                        Mutability::Not => vec![make_obl(src.ty, dst.ty)],
-                        Mutability::Mut => vec![make_obl(src.ty, dst.ty), make_obl(dst.ty, src.ty)],
+                        Mutability::Not => obls.push(make_transmute_obl(src.ty, dst.ty)),
+                        Mutability::Mut => obls.extend([
+                            make_transmute_obl(src.ty, dst.ty),
+                            make_transmute_obl(dst.ty, src.ty),
+                        ]),
                     }
+
+                    obls
                 }
             }
         }
@@ -1417,7 +1445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
                 // These types are built-in, so we can fast-track by registering
                 // nested predicates for their constituent type(s)
-                ty::Array(ty, _) | ty::Slice(ty) => {
+                ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => {
                     stack.push(ty);
                 }
                 ty::Tuple(tys) => {
@@ -1469,7 +1497,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // If we have any other type (e.g. an ADT), just register a nested obligation
                 // since it's either not `const Drop` (and we raise an error during selection),
                 // or it's an ADT (and we need to check for a custom impl during selection)
-                _ => {
+                ty::Error(_)
+                | ty::Dynamic(..)
+                | ty::CoroutineClosure(..)
+                | ty::Param(_)
+                | ty::Bound(..)
+                | ty::Adt(..)
+                | ty::Alias(ty::Opaque | ty::Weak, _)
+                | ty::Infer(_)
+                | ty::Placeholder(_) => {
                     let predicate = self_ty.rebind(ty::TraitPredicate {
                         trait_ref: ty::TraitRef::from_lang_item(
                             self.tcx(),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 5e9a28b5cce..e363119393a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2142,6 +2142,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
             ),
 
+            ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])),
+
             ty::Adt(def, args) => {
                 if let Some(sized_crit) = def.sized_constraint(self.tcx()) {
                     // (*) binder moved here
@@ -2202,6 +2204,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 Where(obligation.predicate.rebind(tys.iter().collect()))
             }
 
+            ty::Pat(ty, _) => {
+                // (*) binder moved here
+                Where(obligation.predicate.rebind(vec![ty]))
+            }
+
             ty::Coroutine(coroutine_def_id, args) => {
                 match self.tcx().coroutine_movability(coroutine_def_id) {
                     hir::Movability::Static => None,
@@ -2340,7 +2347,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
             ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]),
 
-            ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]),
+            ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]),
 
             ty::Tuple(tys) => {
                 // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index b89406ca023..6778ac81aea 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -126,7 +126,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
                 return ControlFlow::Continue(());
             }
 
-            ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
+            ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                 // First check all contained types and then tell the caller to continue searching.
                 return ty.super_visit_with(self);
             }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index a44a5ae0e6b..5553490542b 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -681,6 +681,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // Note that we handle the len is implicitly checked while walking `arg`.
             }
 
+            ty::Pat(subty, _) => {
+                self.require_sized(subty, traits::MiscObligation);
+            }
+
             ty::Tuple(tys) => {
                 if let Some((_last, rest)) = tys.split_last() {
                     for &elem in rest {
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
index b8922696e30..77d5a48f158 100644
--- a/compiler/rustc_transmute/src/layout/dfa.rs
+++ b/compiler/rustc_transmute/src/layout/dfa.rs
@@ -35,6 +35,7 @@ impl<R> Transitions<R>
 where
     R: Ref,
 {
+    #[allow(dead_code)]
     fn insert(&mut self, transition: Transition<R>, state: State) {
         match transition {
             Transition::Byte(b) => {
@@ -82,6 +83,7 @@ impl<R> Dfa<R>
 where
     R: Ref,
 {
+    #[allow(dead_code)]
     pub(crate) fn unit() -> Self {
         let transitions: Map<State, Transitions<R>> = Map::default();
         let start = State::new();
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
index 78fcceb5f2c..3c5963202c6 100644
--- a/compiler/rustc_transmute/src/layout/nfa.rs
+++ b/compiler/rustc_transmute/src/layout/nfa.rs
@@ -160,6 +160,7 @@ where
         Self { transitions, start, accepting }
     }
 
+    #[allow(dead_code)]
     pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
         self.transitions.get(&start)
     }
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index f6bc224c7e7..12c984f1603 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -173,16 +173,20 @@ pub(crate) mod rustc {
     use super::Tree;
     use crate::layout::rustc::{Def, Ref};
 
+    use rustc_middle::ty::layout::HasTyCtxt;
+    use rustc_middle::ty::layout::LayoutCx;
     use rustc_middle::ty::layout::LayoutError;
+    use rustc_middle::ty::layout::LayoutOf;
     use rustc_middle::ty::AdtDef;
-    use rustc_middle::ty::GenericArgsRef;
-    use rustc_middle::ty::ParamEnv;
+    use rustc_middle::ty::AdtKind;
+    use rustc_middle::ty::List;
     use rustc_middle::ty::ScalarInt;
-    use rustc_middle::ty::VariantDef;
     use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
     use rustc_span::ErrorGuaranteed;
-    use rustc_target::abi::Align;
-    use std::alloc;
+    use rustc_target::abi::FieldsShape;
+    use rustc_target::abi::Size;
+    use rustc_target::abi::TyAndLayout;
+    use rustc_target::abi::Variants;
 
     #[derive(Debug, Copy, Clone)]
     pub(crate) enum Err {
@@ -206,176 +210,64 @@ pub(crate) mod rustc {
         }
     }
 
-    trait LayoutExt {
-        fn clamp_align(&self, min_align: Align, max_align: Align) -> Self;
-    }
-
-    impl LayoutExt for alloc::Layout {
-        fn clamp_align(&self, min_align: Align, max_align: Align) -> Self {
-            let min_align = min_align.bytes().try_into().unwrap();
-            let max_align = max_align.bytes().try_into().unwrap();
-            Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap()
-        }
-    }
-
-    struct LayoutSummary {
-        total_align: Align,
-        total_size: usize,
-        discriminant_size: usize,
-        discriminant_align: Align,
-    }
-
-    impl LayoutSummary {
-        fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> {
-            use rustc_middle::ty::ParamEnvAnd;
-            use rustc_target::abi::{TyAndLayout, Variants};
-
-            let param_env = ParamEnv::reveal_all();
-            let param_env_and_type = ParamEnvAnd { param_env, value: ty };
-            let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
-
-            let total_size: usize = layout.size().bytes_usize();
-            let total_align: Align = layout.align().abi;
-            let discriminant_align: Align;
-            let discriminant_size: usize;
-
-            if let Variants::Multiple { tag, .. } = layout.variants() {
-                discriminant_align = tag.align(&ctx).abi;
-                discriminant_size = tag.size(&ctx).bytes_usize();
-            } else {
-                discriminant_align = Align::ONE;
-                discriminant_size = 0;
-            };
-
-            Ok(Self { total_align, total_size, discriminant_align, discriminant_size })
-        }
-
-        fn into(&self) -> alloc::Layout {
-            alloc::Layout::from_size_align(
-                self.total_size,
-                self.total_align.bytes().try_into().unwrap(),
-            )
-            .unwrap()
-        }
-    }
-
     impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
-        pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> {
-            use rustc_middle::ty::FloatTy::*;
-            use rustc_middle::ty::IntTy::*;
-            use rustc_middle::ty::UintTy::*;
+        pub fn from_ty(
+            ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
+            cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+        ) -> Result<Self, Err> {
             use rustc_target::abi::HasDataLayout;
 
-            if let Err(e) = ty.error_reported() {
+            if let Err(e) = ty_and_layout.ty.error_reported() {
                 return Err(Err::TypeError(e));
             }
 
-            let target = tcx.data_layout();
+            let target = cx.tcx.data_layout();
+            let pointer_size = target.pointer_size;
 
-            match ty.kind() {
+            match ty_and_layout.ty.kind() {
                 ty::Bool => Ok(Self::bool()),
 
-                ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()),
-                ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)),
-                ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)),
-                ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)),
-                ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)),
-                ty::Int(Isize) | ty::Uint(Usize) => {
-                    Ok(Self::number(target.pointer_size.bytes_usize()))
+                ty::Float(nty) => {
+                    let width = nty.bit_width() / 8;
+                    Ok(Self::number(width as _))
                 }
 
-                ty::Tuple(members) => {
-                    if members.len() == 0 {
-                        Ok(Tree::unit())
-                    } else {
-                        Err(Err::NotYetSupported)
-                    }
+                ty::Int(nty) => {
+                    let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
+                    Ok(Self::number(width as _))
                 }
 
-                ty::Array(ty, len) => {
-                    let len = len
-                        .try_eval_target_usize(tcx, ParamEnv::reveal_all())
-                        .ok_or(Err::NotYetSupported)?;
-                    let elt = Tree::from_ty(*ty, tcx)?;
-                    Ok(std::iter::repeat(elt)
-                        .take(len as usize)
-                        .fold(Tree::unit(), |tree, elt| tree.then(elt)))
+                ty::Uint(nty) => {
+                    let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
+                    Ok(Self::number(width as _))
                 }
 
-                ty::Adt(adt_def, args_ref) => {
-                    use rustc_middle::ty::AdtKind;
+                ty::Tuple(members) => Self::from_tuple(ty_and_layout, members, cx),
 
-                    // If the layout is ill-specified, halt.
-                    if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
+                ty::Array(inner_ty, len) => {
+                    let FieldsShape::Array { stride, count } = &ty_and_layout.fields else {
                         return Err(Err::NotYetSupported);
-                    }
+                    };
+                    let inner_ty_and_layout = cx.layout_of(*inner_ty)?;
+                    assert_eq!(*stride, inner_ty_and_layout.size);
+                    let elt = Tree::from_ty(inner_ty_and_layout, cx)?;
+                    Ok(std::iter::repeat(elt)
+                        .take(*count as usize)
+                        .fold(Tree::unit(), |tree, elt| tree.then(elt)))
+                }
 
-                    // Compute a summary of the type's layout.
-                    let layout_summary = LayoutSummary::from_ty(ty, tcx)?;
-
-                    // The layout begins with this adt's visibility.
-                    let vis = Self::def(Def::Adt(*adt_def));
-
-                    // And is followed the layout(s) of its variants
-                    Ok(vis.then(match adt_def.adt_kind() {
-                        AdtKind::Struct => Self::from_repr_c_variant(
-                            ty,
-                            *adt_def,
-                            args_ref,
-                            &layout_summary,
-                            None,
-                            adt_def.non_enum_variant(),
-                            tcx,
-                        )?,
-                        AdtKind::Enum => {
-                            trace!(?adt_def, "treeifying enum");
-                            let mut tree = Tree::uninhabited();
-
-                            for (idx, variant) in adt_def.variants().iter_enumerated() {
-                                let tag = tcx.tag_for_variant((ty, idx));
-                                tree = tree.or(Self::from_repr_c_variant(
-                                    ty,
-                                    *adt_def,
-                                    args_ref,
-                                    &layout_summary,
-                                    tag,
-                                    variant,
-                                    tcx,
-                                )?);
-                            }
-
-                            tree
-                        }
-                        AdtKind::Union => {
-                            // is the layout well-defined?
-                            if !adt_def.repr().c() {
-                                return Err(Err::NotYetSupported);
-                            }
-
-                            let ty_layout = layout_of(tcx, ty)?;
-
-                            let mut tree = Tree::uninhabited();
-
-                            for field in adt_def.all_fields() {
-                                let variant_ty = field.ty(tcx, args_ref);
-                                let variant_layout = layout_of(tcx, variant_ty)?;
-                                let padding_needed = ty_layout.size() - variant_layout.size();
-                                let variant = Self::def(Def::Field(field))
-                                    .then(Self::from_ty(variant_ty, tcx)?)
-                                    .then(Self::padding(padding_needed));
-
-                                tree = tree.or(variant);
-                            }
-
-                            tree
-                        }
-                    }))
+                ty::Adt(adt_def, _args_ref) if !ty_and_layout.ty.is_box() => {
+                    match adt_def.adt_kind() {
+                        AdtKind::Struct => Self::from_struct(ty_and_layout, *adt_def, cx),
+                        AdtKind::Enum => Self::from_enum(ty_and_layout, *adt_def, cx),
+                        AdtKind::Union => Self::from_union(ty_and_layout, *adt_def, cx),
+                    }
                 }
 
                 ty::Ref(lifetime, ty, mutability) => {
-                    let layout = layout_of(tcx, *ty)?;
-                    let align = layout.align();
-                    let size = layout.size();
+                    let ty_and_layout = cx.layout_of(*ty)?;
+                    let align = ty_and_layout.align.abi.bytes() as usize;
+                    let size = ty_and_layout.size.bytes_usize();
                     Ok(Tree::Ref(Ref {
                         lifetime: *lifetime,
                         ty: *ty,
@@ -389,80 +281,143 @@ pub(crate) mod rustc {
             }
         }
 
-        fn from_repr_c_variant(
-            ty: Ty<'tcx>,
-            adt_def: AdtDef<'tcx>,
-            args_ref: GenericArgsRef<'tcx>,
-            layout_summary: &LayoutSummary,
-            tag: Option<ScalarInt>,
-            variant_def: &'tcx VariantDef,
-            tcx: TyCtxt<'tcx>,
+        /// Constructs a `Tree` from a tuple.
+        fn from_tuple(
+            ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
+            members: &'tcx List<Ty<'tcx>>,
+            cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
         ) -> Result<Self, Err> {
-            let mut tree = Tree::unit();
-
-            let repr = adt_def.repr();
-            let min_align = repr.align.unwrap_or(Align::ONE);
-            let max_align = repr.pack.unwrap_or(Align::MAX);
-
-            let variant_span = trace_span!(
-                "treeifying variant",
-                min_align = ?min_align,
-                max_align = ?max_align,
-            )
-            .entered();
-
-            let mut variant_layout = alloc::Layout::from_size_align(
-                0,
-                layout_summary.total_align.bytes().try_into().unwrap(),
-            )
-            .unwrap();
-
-            // The layout of the variant is prefixed by the tag, if any.
-            if let Some(tag) = tag {
-                let tag_layout =
-                    alloc::Layout::from_size_align(tag.size().bytes_usize(), 1).unwrap();
-                tree = tree.then(Self::from_tag(tag, tcx));
-                variant_layout = variant_layout.extend(tag_layout).unwrap().0;
+            match &ty_and_layout.fields {
+                FieldsShape::Primitive => {
+                    assert_eq!(members.len(), 1);
+                    let inner_ty = members[0];
+                    let inner_ty_and_layout = cx.layout_of(inner_ty)?;
+                    assert_eq!(ty_and_layout.layout, inner_ty_and_layout.layout);
+                    Self::from_ty(inner_ty_and_layout, cx)
+                }
+                FieldsShape::Arbitrary { offsets, .. } => {
+                    assert_eq!(offsets.len(), members.len());
+                    Self::from_variant(Def::Primitive, None, ty_and_layout, ty_and_layout.size, cx)
+                }
+                FieldsShape::Array { .. } | FieldsShape::Union(_) => Err(Err::NotYetSupported),
+            }
+        }
+
+        /// Constructs a `Tree` from a struct.
+        ///
+        /// # Panics
+        ///
+        /// Panics if `def` is not a struct definition.
+        fn from_struct(
+            ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
+            def: AdtDef<'tcx>,
+            cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+        ) -> Result<Self, Err> {
+            assert!(def.is_struct());
+            let def = Def::Adt(def);
+            Self::from_variant(def, None, ty_and_layout, ty_and_layout.size, cx)
+        }
+
+        /// Constructs a `Tree` from an enum.
+        ///
+        /// # Panics
+        ///
+        /// Panics if `def` is not an enum definition.
+        fn from_enum(
+            ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
+            def: AdtDef<'tcx>,
+            cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+        ) -> Result<Self, Err> {
+            assert!(def.is_enum());
+            let layout = ty_and_layout.layout;
+
+            if let Variants::Multiple { tag_field, .. } = layout.variants() {
+                // For enums (but not coroutines), the tag field is
+                // currently always the first field of the layout.
+                assert_eq!(*tag_field, 0);
             }
 
-            // Next come fields.
-            let fields_span = trace_span!("treeifying fields").entered();
-            for field_def in variant_def.fields.iter() {
-                let field_ty = field_def.ty(tcx, args_ref);
-                let _span = trace_span!("treeifying field", field = ?field_ty).entered();
+            let variants = def.discriminants(cx.tcx()).try_fold(
+                Self::uninhabited(),
+                |variants, (idx, ref discriminant)| {
+                    let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, idx));
+                    let variant_def = Def::Variant(def.variant(idx));
+                    let variant_ty_and_layout = ty_and_layout.for_variant(&cx, idx);
+                    let variant = Self::from_variant(
+                        variant_def,
+                        tag,
+                        variant_ty_and_layout,
+                        layout.size,
+                        cx,
+                    )?;
+                    Result::<Self, Err>::Ok(variants.or(variant))
+                },
+            )?;
 
-                // begin with the field's visibility
-                tree = tree.then(Self::def(Def::Field(field_def)));
+            return Ok(Self::def(Def::Adt(def)).then(variants));
+        }
 
-                // compute the field's layout characteristics
-                let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align);
+        /// Constructs a `Tree` from a 'variant-like' layout.
+        ///
+        /// A 'variant-like' layout includes those of structs and, of course,
+        /// enum variants. Pragmatically speaking, this method supports anything
+        /// with `FieldsShape::Arbitrary`.
+        ///
+        /// Note: This routine assumes that the optional `tag` is the first
+        /// field, and enum callers should check that `tag_field` is, in fact,
+        /// `0`.
+        fn from_variant(
+            def: Def<'tcx>,
+            tag: Option<ScalarInt>,
+            ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
+            total_size: Size,
+            cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+        ) -> Result<Self, Err> {
+            // This constructor does not support non-`FieldsShape::Arbitrary`
+            // layouts.
+            let FieldsShape::Arbitrary { offsets, memory_index } = ty_and_layout.layout.fields()
+            else {
+                return Err(Err::NotYetSupported);
+            };
 
-                // next comes the field's padding
-                let padding_needed = variant_layout.padding_needed_for(field_layout.align());
-                if padding_needed > 0 {
-                    tree = tree.then(Self::padding(padding_needed));
-                }
+            // When this function is invoked with enum variants,
+            // `ty_and_layout.size` does not encompass the entire size of the
+            // enum. We rely on `total_size` for this.
+            assert!(ty_and_layout.size <= total_size);
 
-                // finally, the field's layout
-                tree = tree.then(Self::from_ty(field_ty, tcx)?);
+            let mut size = Size::ZERO;
+            let mut struct_tree = Self::def(def);
 
-                // extend the variant layout with the field layout
-                variant_layout = variant_layout.extend(field_layout).unwrap().0;
+            // If a `tag` is provided, place it at the start of the layout.
+            if let Some(tag) = tag {
+                size += tag.size();
+                struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx));
             }
-            drop(fields_span);
 
-            // finally: padding
-            let padding_span = trace_span!("adding trailing padding").entered();
-            if layout_summary.total_size > variant_layout.size() {
-                let padding_needed = layout_summary.total_size - variant_layout.size();
-                tree = tree.then(Self::padding(padding_needed));
-            };
-            drop(padding_span);
-            drop(variant_span);
-            Ok(tree)
+            // Append the fields, in memory order, to the layout.
+            let inverse_memory_index = memory_index.invert_bijective_mapping();
+            for (memory_idx, field_idx) in inverse_memory_index.iter_enumerated() {
+                // Add interfield padding.
+                let padding_needed = offsets[*field_idx] - size;
+                let padding = Self::padding(padding_needed.bytes_usize());
+
+                let field_ty_and_layout = ty_and_layout.field(&cx, field_idx.as_usize());
+                let field_tree = Self::from_ty(field_ty_and_layout, cx)?;
+
+                struct_tree = struct_tree.then(padding).then(field_tree);
+
+                size += padding_needed + field_ty_and_layout.size;
+            }
+
+            // Add trailing padding.
+            let padding_needed = total_size - size;
+            let trailing_padding = Self::padding(padding_needed.bytes_usize());
+
+            Ok(struct_tree.then(trailing_padding))
         }
 
-        pub fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
+        /// Constructs a `Tree` representing the value of a enum tag.
+        fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
             use rustc_target::abi::Endian;
             let size = tag.size();
             let bits = tag.to_bits(size).unwrap();
@@ -479,24 +434,42 @@ pub(crate) mod rustc {
             };
             Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect())
         }
-    }
 
-    fn layout_of<'tcx>(
-        ctx: TyCtxt<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Result<alloc::Layout, &'tcx LayoutError<'tcx>> {
-        use rustc_middle::ty::ParamEnvAnd;
-        use rustc_target::abi::TyAndLayout;
-
-        let param_env = ParamEnv::reveal_all();
-        let param_env_and_type = ParamEnvAnd { param_env, value: ty };
-        let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
-        let layout = alloc::Layout::from_size_align(
-            layout.size().bytes_usize(),
-            layout.align().abi.bytes().try_into().unwrap(),
-        )
-        .unwrap();
-        trace!(?ty, ?layout, "computed layout for type");
-        Ok(layout)
+        /// Constructs a `Tree` from a union.
+        ///
+        /// # Panics
+        ///
+        /// Panics if `def` is not a union definition.
+        fn from_union(
+            ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
+            def: AdtDef<'tcx>,
+            cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
+        ) -> Result<Self, Err> {
+            assert!(def.is_union());
+
+            let union_layout = ty_and_layout.layout;
+
+            // This constructor does not support non-`FieldsShape::Union`
+            // layouts. Fields of this shape are all placed at offset 0.
+            let FieldsShape::Union(fields) = union_layout.fields() else {
+                return Err(Err::NotYetSupported);
+            };
+
+            let fields = &def.non_enum_variant().fields;
+            let fields = fields.iter_enumerated().try_fold(
+                Self::uninhabited(),
+                |fields, (idx, ref field_def)| {
+                    let field_def = Def::Field(field_def);
+                    let field_ty_and_layout = ty_and_layout.field(&cx, idx.as_usize());
+                    let field = Self::from_ty(field_ty_and_layout, cx)?;
+                    let trailing_padding_needed = union_layout.size - field_ty_and_layout.size;
+                    let trailing_padding = Self::padding(trailing_padding_needed.bytes_usize());
+                    let field_and_padding = field.then(trailing_padding);
+                    Result::<Self, Err>::Ok(fields.or(field_and_padding))
+                },
+            )?;
+
+            Ok(Self::def(Def::Adt(def)).then(fields))
+        }
     }
 }
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index b6f937ebe47..12312271646 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -1,6 +1,6 @@
 #![feature(alloc_layout_extra)]
 #![feature(never_type)]
-#![allow(dead_code, unused_variables)]
+#![allow(unused_variables)]
 
 #[macro_use]
 extern crate tracing;
@@ -49,6 +49,8 @@ pub enum Reason<T> {
     DstIsNotYetSupported,
     /// The layout of the destination type is bit-incompatible with the source type.
     DstIsBitIncompatible,
+    /// The destination type is uninhabited.
+    DstUninhabited,
     /// The destination type may carry safety invariants.
     DstMayHaveSafetyInvariants,
     /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 16d15580a05..2789fe8f6b1 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -33,6 +33,9 @@ mod rustc {
     use super::*;
     use crate::layout::tree::rustc::Err;
 
+    use rustc_middle::ty::layout::LayoutCx;
+    use rustc_middle::ty::layout::LayoutOf;
+    use rustc_middle::ty::ParamEnv;
     use rustc_middle::ty::Ty;
     use rustc_middle::ty::TyCtxt;
 
@@ -43,12 +46,20 @@ mod rustc {
         pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
             let Self { src, dst, assume, context } = self;
 
+            let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() };
+            let layout_of = |ty| {
+                layout_cx
+                    .layout_of(ty)
+                    .map_err(|_| Err::NotYetSupported)
+                    .and_then(|tl| Tree::from_ty(tl, layout_cx))
+            };
+
             // Convert `src` and `dst` from their rustc representations, to `Tree`-based
             // representations. If these conversions fail, conclude that the transmutation is
             // unacceptable; the layouts of both the source and destination types must be
             // well-defined.
-            let src = Tree::from_ty(src, context);
-            let dst = Tree::from_ty(dst, context);
+            let src = layout_of(src);
+            let dst = layout_of(dst);
 
             match (src, dst) {
                 (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => {
@@ -86,6 +97,10 @@ where
         // references.
         let src = src.prune(&|def| false);
 
+        if src.is_inhabited() && !dst.is_inhabited() {
+            return Answer::No(Reason::DstUninhabited);
+        }
+
         trace!(?src, "pruned src");
 
         // Remove all `Def` nodes from `dst`, additionally...
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
index 54ed03d44e6..1ccb6f36c8e 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
@@ -5,8 +5,6 @@ pub(crate) trait QueryContext {
     type Def: layout::Def;
     type Ref: layout::Ref;
     type Scope: Copy;
-
-    fn min_align(&self, reference: Self::Ref) -> usize;
 }
 
 #[cfg(test)]
@@ -31,10 +29,6 @@ pub(crate) mod test {
         type Def = Def;
         type Ref = !;
         type Scope = ();
-
-        fn min_align(&self, reference: !) -> usize {
-            unimplemented!()
-        }
     }
 }
 
@@ -48,9 +42,5 @@ mod rustc {
         type Ref = layout::rustc::Ref<'tcx>;
 
         type Scope = Ty<'tcx>;
-
-        fn min_align(&self, reference: Self::Ref) -> usize {
-            unimplemented!()
-        }
     }
 }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 509727cdeab..77cd4662ae5 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -126,6 +126,39 @@ fn layout_of_uncached<'tcx>(
     debug_assert!(!ty.has_non_region_infer());
 
     Ok(match *ty.kind() {
+        ty::Pat(ty, pat) => {
+            let layout = cx.layout_of(ty)?.layout;
+            let mut layout = LayoutS::clone(&layout.0);
+            match *pat {
+                ty::PatternKind::Range { start, end, include_end } => {
+                    if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi {
+                        if let Some(start) = start {
+                            scalar.valid_range_mut().start = start.eval_bits(tcx, param_env);
+                        }
+                        if let Some(end) = end {
+                            let mut end = end.eval_bits(tcx, param_env);
+                            if !include_end {
+                                end = end.wrapping_sub(1);
+                            }
+                            scalar.valid_range_mut().end = end;
+                        }
+
+                        let niche = Niche {
+                            offset: Size::ZERO,
+                            value: scalar.primitive(),
+                            valid_range: scalar.valid_range(cx),
+                        };
+
+                        layout.largest_niche = Some(niche);
+
+                        tcx.mk_layout(layout)
+                    } else {
+                        bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}")
+                    }
+                }
+            }
+        }
+
         // Basic scalars.
         ty::Bool => tcx.mk_layout(LayoutS::scalar(
             cx,
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 48339e6120a..ee930a78e77 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -221,6 +221,7 @@ where
                     | ty::Ref(..)
                     | ty::RawPtr(..)
                     | ty::FnDef(..)
+                    | ty::Pat(..)
                     | ty::FnPtr(..)
                     | ty::Tuple(_)
                     | ty::Bound(..)
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 547a3cb5a8c..f33234122c9 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -36,6 +36,8 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'
         // these are never sized
         Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty),
 
+        Pat(ty, _) => sized_constraint_for_ty(tcx, *ty),
+
         Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)),
 
         // recursive case
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index ad18ef24984..06a5051956a 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -16,6 +16,8 @@ use crate::{Interner, PlaceholderLike, UniverseIndex};
 pub struct Canonical<I: Interner, V> {
     pub value: V,
     pub max_universe: UniverseIndex,
+    // FIXME(lcnr, oli-obk): try moving this into the query inputs instead
+    pub defining_opaque_types: I::DefiningOpaqueTypes,
     pub variables: I::CanonicalVars,
 }
 
@@ -44,8 +46,8 @@ impl<I: Interner, V> Canonical<I, V> {
     /// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty));
     /// ```
     pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> {
-        let Canonical { max_universe, variables, value } = self;
-        Canonical { max_universe, variables, value: map_op(value) }
+        let Canonical { defining_opaque_types, max_universe, variables, value } = self;
+        Canonical { defining_opaque_types, max_universe, variables, value: map_op(value) }
     }
 
     /// Allows you to map the `value` of a canonical while keeping the same set of
@@ -54,8 +56,8 @@ impl<I: Interner, V> Canonical<I, V> {
     /// **WARNING:** This function is very easy to mis-use, hence the name! See
     /// the comment of [Canonical::unchecked_map] for more details.
     pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> {
-        let Canonical { max_universe, variables, value: _ } = self;
-        Canonical { max_universe, variables, value }
+        let Canonical { defining_opaque_types, max_universe, variables, value: _ } = self;
+        Canonical { defining_opaque_types, max_universe, variables, value }
     }
 }
 
@@ -63,28 +65,32 @@ impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
 
 impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
     fn eq(&self, other: &Self) -> bool {
-        self.value == other.value
-            && self.max_universe == other.max_universe
-            && self.variables == other.variables
+        let Self { value, max_universe, variables, defining_opaque_types } = self;
+        *value == other.value
+            && *max_universe == other.max_universe
+            && *variables == other.variables
+            && *defining_opaque_types == other.defining_opaque_types
     }
 }
 
 impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self { value, max_universe, variables, defining_opaque_types } = self;
         write!(
             f,
-            "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}",
-            self.value, self.max_universe, self.variables
+            "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?}, defining_opaque_types: {defining_opaque_types:?} }}",
         )
     }
 }
 
 impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self { value, max_universe, variables, defining_opaque_types } = self;
         f.debug_struct("Canonical")
-            .field("value", &self.value)
-            .field("max_universe", &self.max_universe)
-            .field("variables", &self.variables)
+            .field("value", &value)
+            .field("max_universe", &max_universe)
+            .field("variables", &variables)
+            .field("defining_opaque_types", &defining_opaque_types)
             .finish()
     }
 }
@@ -100,6 +106,7 @@ where
             value: self.value.try_fold_with(folder)?,
             max_universe: self.max_universe.try_fold_with(folder)?,
             variables: self.variables.try_fold_with(folder)?,
+            defining_opaque_types: self.defining_opaque_types,
         })
     }
 }
@@ -109,9 +116,11 @@ where
     I::CanonicalVars: TypeVisitable<I>,
 {
     fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> F::Result {
-        try_visit!(self.value.visit_with(folder));
-        try_visit!(self.max_universe.visit_with(folder));
-        self.variables.visit_with(folder)
+        let Self { value, max_universe, variables, defining_opaque_types } = self;
+        try_visit!(value.visit_with(folder));
+        try_visit!(max_universe.visit_with(folder));
+        try_visit!(defining_opaque_types.visit_with(folder));
+        variables.visit_with(folder)
     }
 }
 
diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs
index 9c8e45b4338..9298360f749 100644
--- a/compiler/rustc_type_ir/src/debug.rs
+++ b/compiler/rustc_type_ir/src/debug.rs
@@ -43,6 +43,10 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> {
     fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> {
         None
     }
+
+    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes {
+        Default::default()
+    }
 }
 
 pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs
index 28b71f0ea13..a53287c1987 100644
--- a/compiler/rustc_type_ir/src/infcx.rs
+++ b/compiler/rustc_type_ir/src/infcx.rs
@@ -37,4 +37,6 @@ pub trait InferCtxtLike {
 
     /// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type.
     fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>;
+
+    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
 }
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 7d6862726f0..70f7e58be19 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -11,6 +11,7 @@ use crate::{
 
 pub trait Interner: Sized + Copy {
     type DefId: Copy + Debug + Hash + Eq;
+    type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
     type AdtDef: Copy + Debug + Hash + Eq;
 
     type GenericArgs: Copy
@@ -49,6 +50,7 @@ pub trait Interner: Sized + Copy {
     type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type AllocId: Copy + Debug + Hash + Eq;
+    type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>;
 
     // Kinds of consts
     type Const: Copy
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index fad67fe3cbb..8813955f2af 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -100,6 +100,13 @@ pub enum TyKind<I: Interner> {
     /// An array with the given length. Written as `[T; N]`.
     Array(I::Ty, I::Const),
 
+    /// A pattern newtype. Takes any type and restricts its valid values to its pattern.
+    /// This will also change the layout to take advantage of this restriction.
+    /// Only `Copy` and `Clone` will automatically get implemented for pattern types.
+    /// Auto-traits treat this as if it were an aggregate with a single nested type.
+    /// Only supports integer range patterns for now.
+    Pat(I::Ty, I::Pat),
+
     /// The pointee of an array slice. Written as `[T]`.
     Slice(I::Ty),
 
@@ -273,12 +280,13 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize {
         CoroutineWitness(_, _) => 18,
         Never => 19,
         Tuple(_) => 20,
-        Alias(_, _) => 21,
-        Param(_) => 22,
-        Bound(_, _) => 23,
-        Placeholder(_) => 24,
-        Infer(_) => 25,
-        Error(_) => 26,
+        Pat(_, _) => 21,
+        Alias(_, _) => 22,
+        Param(_) => 23,
+        Bound(_, _) => 24,
+        Placeholder(_) => 25,
+        Infer(_) => 26,
+        Error(_) => 27,
     }
 }
 
@@ -299,6 +307,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
             (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s,
             (Foreign(a_d), Foreign(b_d)) => a_d == b_d,
             (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c,
+            (Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c,
             (Slice(a_t), Slice(b_t)) => a_t == b_t,
             (RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m,
             (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m,
@@ -322,7 +331,7 @@ impl<I: Interner> PartialEq for TyKind<I> {
             _ => {
                 debug_assert!(
                     tykind_discriminant(self) != tykind_discriminant(other),
-                    "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+                    "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
                 );
                 false
             }
@@ -362,6 +371,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
             Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
             Str => write!(f, "str"),
             Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)),
+            Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)),
             Slice(t) => write!(f, "[{:?}]", &this.wrap(t)),
             RawPtr(ty, mutbl) => {
                 match mutbl {
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index 8ed34fab54d..94c552199bc 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -8,7 +8,7 @@ use std::cell::Cell;
 use crate::abi::{FnAbi, Layout, LayoutShape};
 use crate::mir::alloc::{AllocId, GlobalAlloc};
 use crate::mir::mono::{Instance, InstanceDef, StaticDef};
-use crate::mir::{Body, Place};
+use crate::mir::{BinOp, Body, Place};
 use crate::target::MachineInfo;
 use crate::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
@@ -211,6 +211,9 @@ pub trait Context {
 
     /// Get a debug string representation of a place.
     fn place_pretty(&self, place: &Place) -> String;
+
+    /// Get the resulting type of binary operation.
+    fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty;
 }
 
 // A thread local variable that stores a pointer to the tables mapping between TyCtxt
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index 593b1868f26..1ad05633d62 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -1,3 +1,4 @@
+use crate::compiler_interface::with;
 use crate::mir::pretty::function_body;
 use crate::ty::{
     AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind,
@@ -337,42 +338,7 @@ impl BinOp {
     /// Return the type of this operation for the given input Ty.
     /// This function does not perform type checking, and it currently doesn't handle SIMD.
     pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
-        match self {
-            BinOp::Add
-            | BinOp::AddUnchecked
-            | BinOp::Sub
-            | BinOp::SubUnchecked
-            | BinOp::Mul
-            | BinOp::MulUnchecked
-            | BinOp::Div
-            | BinOp::Rem
-            | BinOp::BitXor
-            | BinOp::BitAnd
-            | BinOp::BitOr => {
-                assert_eq!(lhs_ty, rhs_ty);
-                assert!(lhs_ty.kind().is_primitive());
-                lhs_ty
-            }
-            BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => {
-                assert!(lhs_ty.kind().is_primitive());
-                assert!(rhs_ty.kind().is_primitive());
-                lhs_ty
-            }
-            BinOp::Offset => {
-                assert!(lhs_ty.kind().is_raw_ptr());
-                assert!(rhs_ty.kind().is_integral());
-                lhs_ty
-            }
-            BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
-                assert_eq!(lhs_ty, rhs_ty);
-                let lhs_kind = lhs_ty.kind();
-                assert!(lhs_kind.is_primitive() || lhs_kind.is_raw_ptr() || lhs_kind.is_fn_ptr());
-                Ty::bool_ty()
-            }
-            BinOp::Cmp => {
-                unimplemented!("Should cmp::Ordering be a RigidTy?");
-            }
-        }
+        with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty))
     }
 }
 
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 3e8d186b97e..bc6fb34493a 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -99,6 +99,12 @@ impl Ty {
     }
 }
 
+/// Represents a pattern in the type system
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum Pattern {
+    Range { start: Option<Const>, end: Option<Const>, include_end: bool },
+}
+
 /// Represents a constant in MIR or from the Type system.
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct Const {
@@ -481,6 +487,7 @@ pub enum RigidTy {
     Foreign(ForeignDef),
     Str,
     Array(Ty, Const),
+    Pat(Ty, Pattern),
     Slice(Ty),
     RawPtr(Ty, Mutability),
     Ref(Region, Ty, Mutability),
diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs
index 65e42879d61..2d7159f87fe 100644
--- a/compiler/stable_mir/src/visitor.rs
+++ b/compiler/stable_mir/src/visitor.rs
@@ -139,6 +139,7 @@ impl Visitable for RigidTy {
                 t.visit(visitor)?;
                 c.visit(visitor)
             }
+            RigidTy::Pat(t, _p) => t.visit(visitor),
             RigidTy::Slice(inner) => inner.visit(visitor),
             RigidTy::RawPtr(ty, _) => ty.visit(visitor),
             RigidTy::Ref(reg, ty, _) => {
diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs
index 638f343fb24..0561f49c967 100644
--- a/library/alloc/benches/lib.rs
+++ b/library/alloc/benches/lib.rs
@@ -1,6 +1,8 @@
 // Disabling on android for the time being
 // See https://github.com/rust-lang/rust/issues/73535#event-3477699747
 #![cfg(not(target_os = "android"))]
+// Disabling in Miri as these would take too long.
+#![cfg(not(miri))]
 #![feature(btree_extract_if)]
 #![feature(iter_next_chunk)]
 #![feature(repr_simd)]
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index 0421a12b3a9..8b145b67bf1 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -4,10 +4,14 @@
 use crate::alloc::{self, Layout, LayoutError};
 use core::error::Error;
 use core::fmt::{self, Debug, Display, Formatter};
+#[cfg(not(no_global_oom_handling))]
+use core::intrinsics::const_allocate;
 use core::marker::PhantomData;
 #[cfg(not(no_global_oom_handling))]
 use core::marker::Unsize;
-use core::mem::{self, SizedTypeProperties};
+use core::mem;
+#[cfg(not(no_global_oom_handling))]
+use core::mem::SizedTypeProperties;
 use core::ops::{Deref, DerefMut};
 use core::ptr::Pointee;
 use core::ptr::{self, NonNull};
@@ -109,9 +113,14 @@ impl<Dyn: ?Sized> ThinBox<Dyn> {
     where
         T: Unsize<Dyn>,
     {
-        let meta = ptr::metadata(&value as &Dyn);
-        let ptr = WithOpaqueHeader::new(meta, value);
-        ThinBox { ptr, _marker: PhantomData }
+        if mem::size_of::<T>() == 0 {
+            let ptr = WithOpaqueHeader::new_unsize_zst::<Dyn, T>(value);
+            ThinBox { ptr, _marker: PhantomData }
+        } else {
+            let meta = ptr::metadata(&value as &Dyn);
+            let ptr = WithOpaqueHeader::new(meta, value);
+            ThinBox { ptr, _marker: PhantomData }
+        }
     }
 }
 
@@ -200,6 +209,16 @@ impl WithOpaqueHeader {
         Self(ptr.0)
     }
 
+    #[cfg(not(no_global_oom_handling))]
+    fn new_unsize_zst<Dyn, T>(value: T) -> Self
+    where
+        Dyn: ?Sized,
+        T: Unsize<Dyn>,
+    {
+        let ptr = WithHeader::<<Dyn as Pointee>::Metadata>::new_unsize_zst::<Dyn, T>(value);
+        Self(ptr.0)
+    }
+
     fn try_new<H, T>(header: H, value: T) -> Result<Self, core::alloc::AllocError> {
         WithHeader::try_new(header, value).map(|ptr| Self(ptr.0))
     }
@@ -288,6 +307,58 @@ impl<H> WithHeader<H> {
         }
     }
 
+    // `Dyn` is `?Sized` type like `[u32]`, and `T` is ZST type like `[u32; 0]`.
+    #[cfg(not(no_global_oom_handling))]
+    fn new_unsize_zst<Dyn, T>(value: T) -> WithHeader<H>
+    where
+        Dyn: Pointee<Metadata = H> + ?Sized,
+        T: Unsize<Dyn>,
+    {
+        assert!(mem::size_of::<T>() == 0);
+
+        const fn max(a: usize, b: usize) -> usize {
+            if a > b { a } else { b }
+        }
+
+        // Compute a pointer to the right metadata. This will point to the beginning
+        // of the header, past the padding, so the assigned type makes sense.
+        // It also ensures that the address at the end of the header is sufficiently
+        // aligned for T.
+        let alloc: &<Dyn as Pointee>::Metadata = const {
+            // FIXME: just call `WithHeader::alloc_layout` with size reset to 0.
+            // Currently that's blocked on `Layout::extend` not being `const fn`.
+
+            let alloc_align =
+                max(mem::align_of::<T>(), mem::align_of::<<Dyn as Pointee>::Metadata>());
+
+            let alloc_size =
+                max(mem::align_of::<T>(), mem::size_of::<<Dyn as Pointee>::Metadata>());
+
+            unsafe {
+                // SAFETY: align is power of two because it is the maximum of two alignments.
+                let alloc: *mut u8 = const_allocate(alloc_size, alloc_align);
+
+                let metadata_offset =
+                    alloc_size.checked_sub(mem::size_of::<<Dyn as Pointee>::Metadata>()).unwrap();
+                // SAFETY: adding offset within the allocation.
+                let metadata_ptr: *mut <Dyn as Pointee>::Metadata =
+                    alloc.add(metadata_offset).cast();
+                // SAFETY: `*metadata_ptr` is within the allocation.
+                metadata_ptr.write(ptr::metadata::<Dyn>(ptr::dangling::<T>() as *const Dyn));
+
+                // SAFETY: we have just written the metadata.
+                &*(metadata_ptr)
+            }
+        };
+
+        // SAFETY: `alloc` points to `<Dyn as Pointee>::Metadata`, so addition stays in-bounds.
+        let value_ptr =
+            unsafe { (alloc as *const <Dyn as Pointee>::Metadata).add(1) }.cast::<T>().cast_mut();
+        debug_assert!(value_ptr.is_aligned());
+        mem::forget(value);
+        WithHeader(NonNull::new(value_ptr.cast()).unwrap(), PhantomData)
+    }
+
     // Safety:
     // - Assumes that either `value` can be dereferenced, or is the
     //   `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
@@ -300,20 +371,19 @@ impl<H> WithHeader<H> {
 
         impl<H> Drop for DropGuard<H> {
             fn drop(&mut self) {
+                // All ZST are allocated statically.
+                if self.value_layout.size() == 0 {
+                    return;
+                }
+
                 unsafe {
                     // SAFETY: Layout must have been computable if we're in drop
                     let (layout, value_offset) =
                         WithHeader::<H>::alloc_layout(self.value_layout).unwrap_unchecked();
 
-                    // Note: Don't deallocate if the layout size is zero, because the pointer
-                    // didn't come from the allocator.
-                    if layout.size() != 0 {
-                        alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout);
-                    } else {
-                        debug_assert!(
-                            value_offset == 0 && H::IS_ZST && self.value_layout.size() == 0
-                        );
-                    }
+                    // Since we only allocate for non-ZSTs, the layout size cannot be zero.
+                    debug_assert!(layout.size() != 0);
+                    alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout);
                 }
             }
         }
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index e2fc320f280..693ecb0b6b4 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1614,7 +1614,10 @@ impl<T, A: Allocator> VecDeque<T, A> {
             let old_head = self.head;
             self.head = self.to_physical_idx(1);
             self.len -= 1;
-            Some(unsafe { self.buffer_read(old_head) })
+            unsafe {
+                core::hint::assert_unchecked(self.len < self.capacity());
+                Some(self.buffer_read(old_head))
+            }
         }
     }
 
@@ -1638,7 +1641,10 @@ impl<T, A: Allocator> VecDeque<T, A> {
             None
         } else {
             self.len -= 1;
-            Some(unsafe { self.buffer_read(self.to_physical_idx(self.len)) })
+            unsafe {
+                core::hint::assert_unchecked(self.len < self.capacity());
+                Some(self.buffer_read(self.to_physical_idx(self.len)))
+            }
         }
     }
 
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index e21479450c2..f638c5cf8c7 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -108,8 +108,10 @@
 #![feature(const_box)]
 #![feature(const_cow_is_borrowed)]
 #![feature(const_eval_select)]
+#![feature(const_heap)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_write)]
+#![feature(const_option)]
 #![feature(const_pin)]
 #![feature(const_refs_to_cell)]
 #![feature(const_size_of_val)]
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 4dea27221b7..6ae52cc7827 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1062,7 +1062,9 @@ impl<T, A: Allocator> Arc<T, A> {
     ///
     /// // Create a long list and clone it
     /// let mut x = LinkedList::new();
-    /// for i in 0..100000 {
+    /// let size = 100000;
+    /// # let size = if cfg!(miri) { 100 } else { size };
+    /// for i in 0..size {
     ///     x.push(i); // Adds i to the front of x
     /// }
     /// let y = x.clone();
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
index 4d14b930e41..32d15c386cb 100644
--- a/library/core/benches/lib.rs
+++ b/library/core/benches/lib.rs
@@ -1,5 +1,7 @@
 // wasm32 does not support benches (no time).
 #![cfg(not(target_arch = "wasm32"))]
+// Disabling in Miri as these would take too long.
+#![cfg(not(miri))]
 #![feature(flt2dec)]
 #![feature(test)]
 #![feature(trusted_random_access)]
diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs
index b8b96417d13..616dd0afc51 100644
--- a/library/core/src/iter/adapters/step_by.rs
+++ b/library/core/src/iter/adapters/step_by.rs
@@ -1,6 +1,7 @@
 use crate::{
     intrinsics,
     iter::{from_fn, TrustedLen, TrustedRandomAccess},
+    num::NonZeroUsize,
     ops::{Range, Try},
 };
 
@@ -22,7 +23,11 @@ pub struct StepBy<I> {
     /// Additionally this type-dependent preprocessing means specialized implementations
     /// cannot be used interchangeably.
     iter: I,
-    step: usize,
+    /// This field is `step - 1`, aka the correct amount to pass to `nth` when iterating.
+    /// It MUST NOT be `usize::MAX`, as `unsafe` code depends on being able to add one
+    /// without the risk of overflow.  (This is important so that length calculations
+    /// don't need to check for division-by-zero, for example.)
+    step_minus_one: usize,
     first_take: bool,
 }
 
@@ -31,7 +36,16 @@ impl<I> StepBy<I> {
     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 }
+        StepBy { iter, step_minus_one: step - 1, first_take: true }
+    }
+
+    /// The `step` that was originally passed to `Iterator::step_by(step)`,
+    /// aka `self.step_minus_one + 1`.
+    #[inline]
+    fn original_step(&self) -> NonZeroUsize {
+        // SAFETY: By type invariant, `step_minus_one` cannot be `MAX`, which
+        // means the addition cannot overflow and the result cannot be zero.
+        unsafe { NonZeroUsize::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) }
     }
 }
 
@@ -81,8 +95,8 @@ where
     // 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 }
+        let rem = self.iter.len() % self.original_step();
+        if self.first_take { if rem == 0 { self.step_minus_one } else { rem - 1 } } else { rem }
     }
 }
 
@@ -209,7 +223,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
 
     #[inline]
     default fn spec_next(&mut self) -> Option<I::Item> {
-        let step_size = if self.first_take { 0 } else { self.step };
+        let step_size = if self.first_take { 0 } else { self.step_minus_one };
         self.first_take = false;
         self.iter.nth(step_size)
     }
@@ -217,22 +231,22 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
     #[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) }
+        fn first_size(step: NonZeroUsize) -> impl Fn(usize) -> usize {
+            move |n| if n == 0 { 0 } else { 1 + (n - 1) / step }
         }
 
         #[inline]
-        fn other_size(step: usize) -> impl Fn(usize) -> usize {
-            move |n| n / (step + 1)
+        fn other_size(step: NonZeroUsize) -> impl Fn(usize) -> usize {
+            move |n| n / step
         }
 
         let (low, high) = self.iter.size_hint();
 
         if self.first_take {
-            let f = first_size(self.step);
+            let f = first_size(self.original_step());
             (f(low), high.map(f))
         } else {
-            let f = other_size(self.step);
+            let f = other_size(self.original_step());
             (f(low), high.map(f))
         }
     }
@@ -247,10 +261,9 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
             }
             n -= 1;
         }
-        // n and self.step are indices, we need to add 1 to get the amount of elements
+        // n and self.step_minus_one are indices, we need to add 1 to get the amount of elements
         // When calling `.nth`, we need to subtract 1 again to convert back to an index
-        // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1`
-        let mut step = self.step + 1;
+        let mut step = self.original_step().get();
         // n + 1 could overflow
         // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
         if n == usize::MAX {
@@ -288,8 +301,11 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
         R: Try<Output = Acc>,
     {
         #[inline]
-        fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
-            move || iter.nth(step)
+        fn nth<I: Iterator>(
+            iter: &mut I,
+            step_minus_one: usize,
+        ) -> impl FnMut() -> Option<I::Item> + '_ {
+            move || iter.nth(step_minus_one)
         }
 
         if self.first_take {
@@ -299,7 +315,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
                 Some(x) => acc = f(acc, x)?,
             }
         }
-        from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f)
+        from_fn(nth(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
     }
 
     default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc
@@ -307,8 +323,11 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
         F: FnMut(Acc, Self::Item) -> Acc,
     {
         #[inline]
-        fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
-            move || iter.nth(step)
+        fn nth<I: Iterator>(
+            iter: &mut I,
+            step_minus_one: usize,
+        ) -> impl FnMut() -> Option<I::Item> + '_ {
+            move || iter.nth(step_minus_one)
         }
 
         if self.first_take {
@@ -318,7 +337,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> {
                 Some(x) => acc = f(acc, x),
             }
         }
-        from_fn(nth(&mut self.iter, self.step)).fold(acc, f)
+        from_fn(nth(&mut self.iter, self.step_minus_one)).fold(acc, f)
     }
 }
 
@@ -336,7 +355,7 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St
         // is out of bounds because the length of `self.iter` does not exceed
         // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is
         // zero-indexed
-        let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index());
+        let n = n.saturating_mul(self.original_step().get()).saturating_add(self.next_back_index());
         self.iter.nth_back(n)
     }
 
@@ -348,16 +367,16 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St
         #[inline]
         fn nth_back<I: DoubleEndedIterator>(
             iter: &mut I,
-            step: usize,
+            step_minus_one: usize,
         ) -> impl FnMut() -> Option<I::Item> + '_ {
-            move || iter.nth_back(step)
+            move || iter.nth_back(step_minus_one)
         }
 
         match self.next_back() {
             None => try { init },
             Some(x) => {
                 let acc = f(init, x)?;
-                from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f)
+                from_fn(nth_back(&mut self.iter, self.step_minus_one)).try_fold(acc, f)
             }
         }
     }
@@ -371,16 +390,16 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St
         #[inline]
         fn nth_back<I: DoubleEndedIterator>(
             iter: &mut I,
-            step: usize,
+            step_minus_one: usize,
         ) -> impl FnMut() -> Option<I::Item> + '_ {
-            move || iter.nth_back(step)
+            move || iter.nth_back(step_minus_one)
         }
 
         match self.next_back() {
             None => init,
             Some(x) => {
                 let acc = f(init, x);
-                from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f)
+                from_fn(nth_back(&mut self.iter, self.step_minus_one)).fold(acc, f)
             }
         }
     }
@@ -424,8 +443,7 @@ macro_rules! spec_int_ranges {
             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 step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
                 let remaining = self.iter.end;
                 if remaining > 0 {
                     let val = self.iter.start;
@@ -474,7 +492,7 @@ macro_rules! spec_int_ranges {
             {
                 // 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 step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX);
                 let remaining = self.iter.end;
                 let mut acc = init;
                 let mut val = self.iter.start;
@@ -500,7 +518,7 @@ macro_rules! spec_int_ranges_r {
             fn spec_next_back(&mut self) -> Option<Self::Item>
                 where Range<$t>: DoubleEndedIterator + ExactSizeIterator,
             {
-                let step = (self.step + 1) as $t;
+                let step = self.original_step().get() as $t;
                 let remaining = self.iter.end;
                 if remaining > 0 {
                     let start = self.iter.start;
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index d2c9e1554b4..95c03043e3e 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1572,7 +1572,7 @@ pub trait Iterator {
     ///
     /// The returned iterator implements [`FusedIterator`], because once `self`
     /// returns `None`, even if it returns a `Some(T)` again in the next iterations,
-    /// we cannot put it into a contigious array buffer, and thus the returned iterator
+    /// we cannot put it into a contiguous array buffer, and thus the returned iterator
     /// should be fused.
     ///
     /// [`slice::windows()`]: slice::windows
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1e52d7ac412..0ba3a557a03 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -396,6 +396,9 @@ pub mod net;
 pub mod option;
 pub mod panic;
 pub mod panicking;
+#[cfg(not(bootstrap))]
+#[unstable(feature = "core_pattern_types", issue = "none")]
+pub mod pat;
 pub mod pin;
 pub mod result;
 pub mod sync;
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 3f8c8efd416..483f55b2070 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -310,7 +310,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     /// This should be implemented consistently with the `branch` method such
     /// that applying the `?` operator will get back an equivalent residual:
     /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.
-    /// (It must not be an *identical* residual when interconversion is involved.)
+    /// (The residual is not mandated to be *identical* when interconversion is involved.)
     ///
     /// # Examples
     ///
diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs
new file mode 100644
index 00000000000..a10c4593342
--- /dev/null
+++ b/library/core/src/pat.rs
@@ -0,0 +1,14 @@
+//! Helper module for exporting the `pattern_type` macro
+
+/// Creates a pattern type.
+/// ```ignore (cannot test this from within core yet)
+/// type Positive = std::pat::pattern_type!(i32 is 1..);
+/// ```
+#[macro_export]
+#[rustc_builtin_macro(pattern_type)]
+#[unstable(feature = "core_pattern_type", issue = "none")]
+macro_rules! pattern_type {
+    ($($arg:tt)*) => {
+        /* compiler built-in */
+    };
+}
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 672af752149..ba2d6f64496 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -1,6 +1,7 @@
 //! Trait implementations for `str`.
 
 use crate::cmp::Ordering;
+use crate::intrinsics::unchecked_sub;
 use crate::ops;
 use crate::ptr;
 use crate::slice::SliceIndex;
@@ -210,9 +211,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
 
         // SAFETY: the caller guarantees that `self` is in bounds of `slice`
         // which satisfies all the conditions for `add`.
-        let ptr = unsafe { slice.as_ptr().add(self.start) };
-        let len = self.end - self.start;
-        ptr::slice_from_raw_parts(ptr, len) as *const str
+        unsafe {
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str
+        }
     }
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
@@ -229,9 +231,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> {
         );
 
         // SAFETY: see comments for `get_unchecked`.
-        let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
-        let len = self.end - self.start;
-        ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
+        unsafe {
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str
+        }
     }
     #[inline]
     fn index(self, slice: &str) -> &Self::Output {
diff --git a/library/std/benches/lib.rs b/library/std/benches/lib.rs
index 4d1cf7fab7b..1b21c230a0b 100644
--- a/library/std/benches/lib.rs
+++ b/library/std/benches/lib.rs
@@ -1,3 +1,5 @@
+// Disabling in Miri as these would take too long.
+#![cfg(not(miri))]
 #![feature(test)]
 
 extern crate test;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index b509503ce4d..c713eefc72c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -576,6 +576,9 @@ pub mod net;
 pub mod num;
 pub mod os;
 pub mod panic;
+#[cfg(not(bootstrap))]
+#[unstable(feature = "core_pattern_types", issue = "none")]
+pub mod pat;
 pub mod path;
 pub mod process;
 pub mod sync;
diff --git a/library/std/src/pat.rs b/library/std/src/pat.rs
new file mode 100644
index 00000000000..aeddd84c2cb
--- /dev/null
+++ b/library/std/src/pat.rs
@@ -0,0 +1,3 @@
+//! Helper module for exporting the `pattern_type` macro
+
+pub use core::pattern_type;
diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs
index 5eb828fea1f..962577bb1ed 100644
--- a/library/std/src/sys/pal/hermit/fd.rs
+++ b/library/std/src/sys/pal/hermit/fd.rs
@@ -48,6 +48,11 @@ impl FileDesc {
     pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> {
         unsupported()
     }
+
+    pub fn fstat(&self, stat: *mut abi::stat) -> io::Result<()> {
+        cvt(unsafe { abi::fstat(self.fd.as_raw_fd(), stat) })?;
+        Ok(())
+    }
 }
 
 impl<'a> Read for &'a FileDesc {
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index d4da53fd3df..6519cc22f1f 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -1,12 +1,17 @@
-use super::abi::{self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY};
+use super::abi::{
+    self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT,
+    O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG,
+};
 use super::fd::FileDesc;
-use crate::ffi::{CStr, OsString};
+use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
-use crate::hash::{Hash, Hasher};
 use crate::io::{self, Error, ErrorKind};
 use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
+use crate::mem;
+use crate::os::hermit::ffi::OsStringExt;
 use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
 use crate::path::{Path, PathBuf};
+use crate::sync::Arc;
 use crate::sys::common::small_c_string::run_path_with_cstr;
 use crate::sys::cvt;
 use crate::sys::time::SystemTime;
@@ -14,16 +19,53 @@ use crate::sys::unsupported;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
 pub use crate::sys_common::fs::{copy, try_exists};
-//pub use crate::sys_common::fs::remove_dir_all;
 
 #[derive(Debug)]
 pub struct File(FileDesc);
+#[derive(Clone)]
+pub struct FileAttr {
+    stat_val: stat_struct,
+}
 
-pub struct FileAttr(!);
+impl FileAttr {
+    fn from_stat(stat_val: stat_struct) -> Self {
+        Self { stat_val }
+    }
+}
 
-pub struct ReadDir(!);
+// all DirEntry's will have a reference to this struct
+struct InnerReadDir {
+    root: PathBuf,
+    dir: Vec<u8>,
+}
 
-pub struct DirEntry(!);
+impl InnerReadDir {
+    pub fn new(root: PathBuf, dir: Vec<u8>) -> Self {
+        Self { root, dir }
+    }
+}
+
+pub struct ReadDir {
+    inner: Arc<InnerReadDir>,
+    pos: i64,
+}
+
+impl ReadDir {
+    fn new(inner: InnerReadDir) -> Self {
+        Self { inner: Arc::new(inner), pos: 0 }
+    }
+}
+
+pub struct DirEntry {
+    /// path to the entry
+    root: PathBuf,
+    /// 64-bit inode number
+    ino: u64,
+    /// File type
+    type_: u32,
+    /// name of the entry
+    name: OsString,
+}
 
 #[derive(Clone, Debug)]
 pub struct OpenOptions {
@@ -41,72 +83,87 @@ pub struct OpenOptions {
 #[derive(Copy, Clone, Debug, Default)]
 pub struct FileTimes {}
 
-pub struct FilePermissions(!);
-
-pub struct FileType(!);
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions {
+    mode: u32,
+}
 
-#[derive(Debug)]
-pub struct DirBuilder {}
+#[derive(Copy, Clone, Eq, Debug)]
+pub struct FileType {
+    mode: u32,
+}
 
-impl FileAttr {
-    pub fn size(&self) -> u64 {
-        self.0
+impl PartialEq for FileType {
+    fn eq(&self, other: &Self) -> bool {
+        self.mode == other.mode
     }
+}
 
-    pub fn perm(&self) -> FilePermissions {
-        self.0
+impl core::hash::Hash for FileType {
+    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+        self.mode.hash(state);
     }
+}
 
-    pub fn file_type(&self) -> FileType {
-        self.0
-    }
+#[derive(Debug)]
+pub struct DirBuilder {
+    mode: u32,
+}
 
+impl FileAttr {
     pub fn modified(&self) -> io::Result<SystemTime> {
-        self.0
+        Ok(SystemTime::new(
+            self.stat_val.st_mtime.try_into().unwrap(),
+            self.stat_val.st_mtime_nsec.try_into().unwrap(),
+        ))
     }
 
     pub fn accessed(&self) -> io::Result<SystemTime> {
-        self.0
+        Ok(SystemTime::new(
+            self.stat_val.st_atime.try_into().unwrap(),
+            self.stat_val.st_atime_nsec.try_into().unwrap(),
+        ))
     }
 
     pub fn created(&self) -> io::Result<SystemTime> {
-        self.0
+        Ok(SystemTime::new(
+            self.stat_val.st_ctime.try_into().unwrap(),
+            self.stat_val.st_ctime_nsec.try_into().unwrap(),
+        ))
     }
-}
 
-impl Clone for FileAttr {
-    fn clone(&self) -> FileAttr {
-        self.0
+    pub fn size(&self) -> u64 {
+        self.stat_val.st_size as u64
     }
-}
-
-impl FilePermissions {
-    pub fn readonly(&self) -> bool {
-        self.0
+    pub fn perm(&self) -> FilePermissions {
+        FilePermissions { mode: (self.stat_val.st_mode) }
     }
 
-    pub fn set_readonly(&mut self, _readonly: bool) {
-        self.0
+    pub fn file_type(&self) -> FileType {
+        let masked_mode = self.stat_val.st_mode & S_IFMT;
+        let mode = match masked_mode {
+            S_IFDIR => DT_DIR,
+            S_IFLNK => DT_LNK,
+            S_IFREG => DT_REG,
+            _ => DT_UNKNOWN,
+        };
+        FileType { mode: mode }
     }
 }
 
-impl Clone for FilePermissions {
-    fn clone(&self) -> FilePermissions {
-        self.0
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        // check if any class (owner, group, others) has write permission
+        self.mode & 0o222 == 0
     }
-}
 
-impl PartialEq for FilePermissions {
-    fn eq(&self, _other: &FilePermissions) -> bool {
-        self.0
+    pub fn set_readonly(&mut self, _readonly: bool) {
+        unimplemented!()
     }
-}
-
-impl Eq for FilePermissions {}
 
-impl fmt::Debug for FilePermissions {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
+    #[allow(dead_code)]
+    pub fn mode(&self) -> u32 {
+        self.mode as u32
     }
 }
 
@@ -117,49 +174,21 @@ impl FileTimes {
 
 impl FileType {
     pub fn is_dir(&self) -> bool {
-        self.0
+        self.mode == DT_DIR
     }
-
     pub fn is_file(&self) -> bool {
-        self.0
+        self.mode == DT_REG
     }
-
     pub fn is_symlink(&self) -> bool {
-        self.0
-    }
-}
-
-impl Clone for FileType {
-    fn clone(&self) -> FileType {
-        self.0
-    }
-}
-
-impl Copy for FileType {}
-
-impl PartialEq for FileType {
-    fn eq(&self, _other: &FileType) -> bool {
-        self.0
-    }
-}
-
-impl Eq for FileType {}
-
-impl Hash for FileType {
-    fn hash<H: Hasher>(&self, _h: &mut H) {
-        self.0
-    }
-}
-
-impl fmt::Debug for FileType {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
+        self.mode == DT_LNK
     }
 }
 
 impl fmt::Debug for ReadDir {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+        // Thus the result will be e.g. 'ReadDir("/home")'
+        fmt::Debug::fmt(&*self.inner.root, f)
     }
 }
 
@@ -167,25 +196,78 @@ impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
 
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
-        self.0
+        let mut counter: usize = 0;
+        let mut offset: i64 = 0;
+
+        // loop over all directory entries and search the entry for the current position
+        loop {
+            // leave function, if the loop reaches the of the buffer (with all entries)
+            if offset >= self.inner.dir.len().try_into().unwrap() {
+                return None;
+            }
+
+            let dir = unsafe {
+                &*(self.inner.dir.as_ptr().offset(offset.try_into().unwrap()) as *const dirent64)
+            };
+
+            if counter == self.pos.try_into().unwrap() {
+                self.pos += 1;
+
+                // After dirent64, the file name is stored. d_reclen represents the length of the dirent64
+                // plus the length of the file name. Consequently, file name has a size of d_reclen minus
+                // the size of dirent64. The file name is always a C string and terminated by `\0`.
+                // Consequently, we are able to ignore the last byte.
+                let name_bytes = unsafe {
+                    core::slice::from_raw_parts(
+                        &dir.d_name as *const _ as *const u8,
+                        dir.d_reclen as usize - core::mem::size_of::<dirent64>() - 1,
+                    )
+                    .to_vec()
+                };
+                let entry = DirEntry {
+                    root: self.inner.root.clone(),
+                    ino: dir.d_ino,
+                    type_: dir.d_type as u32,
+                    name: OsString::from_vec(name_bytes),
+                };
+
+                return Some(Ok(entry));
+            }
+
+            counter += 1;
+
+            // move to the next dirent64, which is directly stored after the previous one
+            offset = offset + dir.d_off;
+        }
     }
 }
 
 impl DirEntry {
     pub fn path(&self) -> PathBuf {
-        self.0
+        self.root.join(self.file_name_os_str())
     }
 
     pub fn file_name(&self) -> OsString {
-        self.0
+        self.file_name_os_str().to_os_string()
     }
 
     pub fn metadata(&self) -> io::Result<FileAttr> {
-        self.0
+        let mut path = self.path();
+        path.set_file_name(self.file_name_os_str());
+        lstat(&path)
     }
 
     pub fn file_type(&self) -> io::Result<FileType> {
-        self.0
+        Ok(FileType { mode: self.type_ as u32 })
+    }
+
+    #[allow(dead_code)]
+    pub fn ino(&self) -> u64 {
+        self.ino
+    }
+
+    pub fn file_name_os_str(&self) -> &OsStr {
+        self.name.as_os_str()
     }
 }
 
@@ -288,7 +370,9 @@ impl File {
     }
 
     pub fn file_attr(&self) -> io::Result<FileAttr> {
-        Err(Error::from_raw_os_error(22))
+        let mut stat_val: stat_struct = unsafe { mem::zeroed() };
+        self.0.fstat(&mut stat_val)?;
+        Ok(FileAttr::from_stat(stat_val))
     }
 
     pub fn fsync(&self) -> io::Result<()> {
@@ -357,11 +441,18 @@ impl File {
 
 impl DirBuilder {
     pub fn new() -> DirBuilder {
-        DirBuilder {}
+        DirBuilder { mode: 0o777 }
     }
 
-    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
-        unsupported()
+    pub fn mkdir(&self, path: &Path) -> io::Result<()> {
+        run_path_with_cstr(path, &|path| {
+            cvt(unsafe { abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ())
+        })
+    }
+
+    #[allow(dead_code)]
+    pub fn set_mode(&mut self, mode: u32) {
+        self.mode = mode as u32;
     }
 }
 
@@ -416,8 +507,43 @@ impl FromRawFd for File {
     }
 }
 
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
-    unsupported()
+pub fn readdir(path: &Path) -> io::Result<ReadDir> {
+    let fd_raw = run_path_with_cstr(path, &|path| cvt(unsafe { abi::opendir(path.as_ptr()) }))?;
+    let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) };
+    let root = path.to_path_buf();
+
+    // read all director entries
+    let mut vec: Vec<u8> = Vec::new();
+    let mut sz = 512;
+    loop {
+        // reserve memory to receive all directory entries
+        vec.resize(sz, 0);
+
+        let readlen =
+            unsafe { abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) };
+        if readlen > 0 {
+            // shrink down to the minimal size
+            vec.resize(readlen.try_into().unwrap(), 0);
+            break;
+        }
+
+        // if the buffer is too small, getdents64 returns EINVAL
+        // otherwise, getdents64 returns an error number
+        if readlen != (-abi::errno::EINVAL).into() {
+            return Err(Error::from_raw_os_error(readlen.try_into().unwrap()));
+        }
+
+        // we don't have enough memory => try to increase the vector size
+        sz = sz * 2;
+
+        // 1 MB for directory entries should be enough
+        // stop here to avoid an endless loop
+        if sz > 0x100000 {
+            return Err(Error::from(ErrorKind::Uncategorized));
+        }
+    }
+
+    Ok(ReadDir::new(InnerReadDir::new(root, vec)))
 }
 
 pub fn unlink(path: &Path) -> io::Result<()> {
@@ -428,17 +554,16 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
     unsupported()
 }
 
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
-    match perm.0 {}
+pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
+    Err(Error::from_raw_os_error(22))
 }
 
-pub fn rmdir(_p: &Path) -> io::Result<()> {
-    unsupported()
+pub fn rmdir(path: &Path) -> io::Result<()> {
+    run_path_with_cstr(path, &|path| cvt(unsafe { abi::rmdir(path.as_ptr()) }).map(|_| ()))
 }
 
 pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
-    //unsupported()
-    Ok(())
+    unsupported()
 }
 
 pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
@@ -453,12 +578,20 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
     unsupported()
 }
 
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
-    unsupported()
+pub fn stat(path: &Path) -> io::Result<FileAttr> {
+    run_path_with_cstr(path, &|path| {
+        let mut stat_val: stat_struct = unsafe { mem::zeroed() };
+        cvt(unsafe { abi::stat(path.as_ptr(), &mut stat_val) })?;
+        Ok(FileAttr::from_stat(stat_val))
+    })
 }
 
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
-    unsupported()
+pub fn lstat(path: &Path) -> io::Result<FileAttr> {
+    run_path_with_cstr(path, &|path| {
+        let mut stat_val: stat_struct = unsafe { mem::zeroed() };
+        cvt(unsafe { abi::lstat(path.as_ptr(), &mut stat_val) })?;
+        Ok(FileAttr::from_stat(stat_val))
+    })
 }
 
 pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index 319b835a768..d6f9e4c1476 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -18,6 +18,12 @@ impl Timespec {
         Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
     }
 
+    const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
+        assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64);
+        // SAFETY: The assert above checks tv_nsec is within the valid range
+        Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } }
+    }
+
     fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
         if self >= other {
             Ok(if self.t.tv_nsec >= other.t.tv_nsec {
@@ -195,6 +201,10 @@ pub struct SystemTime(Timespec);
 pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
 
 impl SystemTime {
+    pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
+        SystemTime(Timespec::new(tv_sec, tv_nsec))
+    }
+
     pub fn now() -> SystemTime {
         let mut time: Timespec = Timespec::zero();
         let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs
index 7dcc1141099..a9cd26389cd 100644
--- a/library/std/src/sys_common/thread_local_key.rs
+++ b/library/std/src/sys_common/thread_local_key.rs
@@ -1,4 +1,4 @@
-//! OS-based thread local storage
+//! OS-based thread local storage for non-Windows systems
 //!
 //! This module provides an implementation of OS-based thread local storage,
 //! using the native OS-provided facilities (think `TlsAlloc` or
@@ -11,6 +11,9 @@
 //! the OS-TLS key. The other is a type which does implement `Drop` and hence
 //! has a safe interface.
 //!
+//! Windows doesn't use this module at all; `sys::pal::windows::thread_local_key`
+//! gets imported in its stead.
+//!
 //! # Usage
 //!
 //! This module should likely not be used directly unless other primitives are
diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs
index 59f67f9901f..c56c111c37d 100644
--- a/library/std/tests/process_spawning.rs
+++ b/library/std/tests/process_spawning.rs
@@ -8,6 +8,7 @@ use std::str;
 mod common;
 
 #[test]
+#[cfg_attr(miri, ignore)] // Process spawning not supported by Miri
 fn issue_15149() {
     // If we're the parent, copy our own binary to a new directory.
     let my_path = env::current_exe().unwrap();
diff --git a/library/std/tests/switch-stdout.rs b/library/std/tests/switch-stdout.rs
index 27f3e8a9b96..0afe18088fa 100644
--- a/library/std/tests/switch-stdout.rs
+++ b/library/std/tests/switch-stdout.rs
@@ -51,6 +51,7 @@ fn switch_stdout_to(file: OwnedHandle) -> OwnedHandle {
 }
 
 #[test]
+#[cfg_attr(miri, ignore)] // dup/SetStdHandle not supported by Miri
 fn switch_stdout() {
     let temp = common::tmpdir();
     let path = temp.join("switch-stdout-output");
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index 4ce81f2846e..79a981d0b0d 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -5,7 +5,8 @@ use std::time::Duration;
 
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)]
-fn sleep() {
+#[cfg_attr(miri, ignore)] // Miri does not like the thread leak
+fn sleep_very_long() {
     let finished = Arc::new(Mutex::new(false));
     let t_finished = finished.clone();
     thread::spawn(move || {
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 0b67079917c..d6e60d52d63 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -52,6 +52,36 @@ check-aux:
 		src/tools/cargo \
 		src/tools/cargotest \
 		$(BOOTSTRAP_ARGS)
+	# Run standard library tests in Miri.
+	# We use a 64bit little-endian and a 32bit big-endian target for max coverage.
+	$(Q)BOOTSTRAP_SKIP_TARGET_SANITY=1 \
+		$(BOOTSTRAP) miri --stage 2 \
+		--target x86_64-unknown-linux-gnu,mips-unknown-linux-gnu \
+		library/core \
+		library/alloc \
+		--no-doc
+	# Some doctests have intentional memory leaks.
+	# Also, they work only on the host.
+	$(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \
+		$(BOOTSTRAP) miri --stage 2 \
+		library/core \
+		library/alloc \
+		--doc
+	# In `std` we cannot test everything.
+	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \
+		$(BOOTSTRAP) miri --stage 2 library/std \
+		--no-doc -- \
+		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
+	$(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \
+		$(BOOTSTRAP) miri --stage 2 library/std \
+		--doc -- \
+		--skip fs:: --skip net:: --skip process:: --skip sys::pal::
+	# Also test some very target-specific modules on other targets.
+	$(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \
+		$(BOOTSTRAP) miri --stage 2 library/std \
+		--target aarch64-apple-darwin,i686-pc-windows-gnu \
+		--no-doc -- \
+		time:: sync:: thread:: env::
 dist:
 	$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
 distcheck:
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 028e0f6d05f..1e68f8d276a 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2689,16 +2689,27 @@ impl Step for Crate {
 
         match mode {
             Mode::Std => {
-                compile::std_cargo(builder, target, compiler.stage, &mut cargo);
-                // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`,
-                // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`.
-                // Override it.
-                if builder.download_rustc() && compiler.stage > 0 {
-                    let sysroot = builder
-                        .out
-                        .join(compiler.host.triple)
-                        .join(format!("stage{}-test-sysroot", compiler.stage));
-                    cargo.env("RUSTC_SYSROOT", sysroot);
+                if builder.kind == Kind::Miri {
+                    // We can't use `std_cargo` as that uses `optimized-compiler-builtins` which
+                    // needs host tools for the given target. This is similar to what `compile::Std`
+                    // does when `is_for_mir_opt_tests` is true. There's probably a chance for
+                    // de-duplication here... `std_cargo` should support a mode that avoids needing
+                    // host tools.
+                    cargo
+                        .arg("--manifest-path")
+                        .arg(builder.src.join("library/sysroot/Cargo.toml"));
+                } else {
+                    compile::std_cargo(builder, target, compiler.stage, &mut cargo);
+                    // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`,
+                    // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`.
+                    // Override it.
+                    if builder.download_rustc() && compiler.stage > 0 {
+                        let sysroot = builder
+                            .out
+                            .join(compiler.host.triple)
+                            .join(format!("stage{}-test-sysroot", compiler.stage));
+                        cargo.env("RUSTC_SYSROOT", sysroot);
+                    }
                 }
             }
             Mode::Rustc => {
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index e8977a4b173..e3b27600c5e 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -645,27 +645,6 @@ pub enum Kind {
 }
 
 impl Kind {
-    pub fn parse(string: &str) -> Option<Kind> {
-        // these strings, including the one-letter aliases, must match the x.py help text
-        Some(match string {
-            "build" | "b" => Kind::Build,
-            "check" | "c" => Kind::Check,
-            "clippy" => Kind::Clippy,
-            "fix" => Kind::Fix,
-            "fmt" => Kind::Format,
-            "test" | "t" => Kind::Test,
-            "bench" => Kind::Bench,
-            "doc" | "d" => Kind::Doc,
-            "clean" => Kind::Clean,
-            "dist" => Kind::Dist,
-            "install" => Kind::Install,
-            "run" | "r" => Kind::Run,
-            "setup" => Kind::Setup,
-            "suggest" => Kind::Suggest,
-            _ => return None,
-        })
-    }
-
     pub fn as_str(&self) -> &'static str {
         match self {
             Kind::Build => "build",
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index bcb8260b15a..1a8322c0dfd 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1911,15 +1911,6 @@ impl Compiler {
     pub fn is_snapshot(&self, build: &Build) -> bool {
         self.stage == 0 && self.host == build.build
     }
-
-    /// Returns if this compiler should be treated as a final stage one in the
-    /// current build session.
-    /// This takes into account whether we're performing a full bootstrap or
-    /// not; don't directly compare the stage with `2`!
-    pub fn is_final_stage(&self, build: &Build) -> bool {
-        let final_stage = if build.config.full_bootstrap { 2 } else { 1 };
-        self.stage >= final_stage
-    }
 }
 
 fn envify(s: &str) -> String {
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
index e08c4e1e8b7..a74db2250fc 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
@@ -25,5 +25,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
+# Miri is just too slow with full assertions
+ENV NO_DEBUG_ASSERTIONS=1
+ENV NO_OVERFLOW_CHECKS=1
+
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
 ENV RUST_CHECK_TARGET check-aux
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index 6f720569898..a3e8f6176a3 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -78,16 +78,6 @@ ENV PATH="$NODE_FOLDER:${PATH}"
 
 COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/
 
-# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
-# to create a new folder. For reference:
-# https://github.com/puppeteer/puppeteer/issues/375
-#
-# We also specify the version in case we need to update it to go around cache limitations.
-#
-# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case
-# the local version of the package is different than the one used by the CI.
-RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true
-
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json \
@@ -100,6 +90,14 @@ COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/
 
 RUN /scripts/build-gccjit.sh /scripts
 
+# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
+# to create a new folder. For reference:
+# https://github.com/puppeteer/puppeteer/issues/375
+#
+# We also specify the version in case we need to update it to go around cache limitations.
+#
+# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case
+# the local version of the package is different than the one used by the CI.
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
-  NODE_PATH=`npm root -g` python3 ../x.py test tests/rustdoc-gui --stage 2 \
-    --test-args "'--no-sandbox --jobs 1'"
+  npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \
+  python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--no-sandbox --jobs 1'"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
index 14a8c245756..50c2e5e29f0 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version
@@ -1 +1 @@
-0.17.1
\ No newline at end of file
+0.17.2
\ No newline at end of file
diff --git a/src/doc/book b/src/doc/book
-Subproject 19c40bfd2d57641d962f3119a1c343355f1b3c5
+Subproject 3131aa4642c627a24f523c82566b94a7d920f68
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 98b33e9a441457b0a491fe1be90e7de64eafc3e
+Subproject eb3eb80e106d03250c1fb7c5666b1c8c5967286
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 2e95fc2fd31d669947e993aa07ef10dc9828bee
+Subproject aa7d4b0b4653ddb47cb1de2036d090ec2ba9dab
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 6bc2415218d4dd0cb01433d8320f5ccf79c343a
+Subproject 0d5f88475fe285affa6dbbc806e9e44d730797c
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 984b36eca4b9293df04d5ba4eb5c4f77db0f51d
+Subproject 55694913b1301cc809f9bf4a1ad1b3d6920efbd
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 7601e0c5ad29d5bd3b518700ea63fddfff5915a
+Subproject 60d34b5fd33db1346f9aabfc0c9d0bda6c8e42b
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject ffa246b7fd95a96e1cd54883e613aed42c32547
+Subproject b77a34bd46399687b4ce6a17198e9f316c98879
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 217f6bb550b..daf63998461 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -168,7 +168,7 @@ fn clean_param_env<'tcx>(
 
     // FIXME(#111101): Incorporate the explicit predicates of the item here...
     let item_predicates: FxIndexSet<_> =
-        tcx.predicates_of(item_def_id).predicates.iter().map(|(pred, _)| pred).collect();
+        tcx.param_env(item_def_id).caller_bounds().iter().collect();
     let where_predicates = param_env
         .caller_bounds()
         .iter()
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 72d4cc7c465..8ed6ee014f3 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,141 +1,130 @@
-use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_hir as hir;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
 use rustc_infer::traits;
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, ToPredicate};
+use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 
-use super::*;
+use thin_vec::ThinVec;
 
-pub(crate) struct BlanketImplFinder<'a, 'tcx> {
-    pub(crate) cx: &'a mut core::DocContext<'tcx>,
-}
+use crate::clean;
+use crate::clean::{
+    clean_middle_assoc_item, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty_generics,
+};
+use crate::core::DocContext;
+
+#[instrument(level = "debug", skip(cx))]
+pub(crate) fn synthesize_blanket_impls(
+    cx: &mut DocContext<'_>,
+    item_def_id: DefId,
+) -> Vec<clean::Item> {
+    let tcx = cx.tcx;
+    let ty = tcx.type_of(item_def_id);
 
-impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
-    pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> {
-        let cx = &mut self.cx;
-        let ty = cx.tcx.type_of(item_def_id);
+    let mut blanket_impls = Vec::new();
+    for trait_def_id in tcx.all_traits() {
+        if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id)
+            || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some()
+        {
+            continue;
+        }
+        // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
+        let trait_impls = tcx.trait_impls_of(trait_def_id);
+        'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
+            trace!("considering impl `{impl_def_id:?}` for trait `{trait_def_id:?}`");
 
-        trace!("get_blanket_impls({ty:?})");
-        let mut impls = Vec::new();
-        for trait_def_id in cx.tcx.all_traits() {
-            if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id)
-                || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some()
-            {
+            let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+            if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
                 continue;
             }
-            // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
-            let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
-            'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() {
-                trace!(
-                    "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
-                    trait_def_id,
-                    impl_def_id
-                );
-                let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
-                if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
-                    continue;
-                }
-                let infcx = cx.tcx.infer_ctxt().build();
-                let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);
-                let impl_ty = ty.instantiate(infcx.tcx, args);
-                let param_env = ty::ParamEnv::empty();
+            let infcx = tcx.infer_ctxt().build();
+            let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);
+            let impl_ty = ty.instantiate(tcx, args);
+            let param_env = ty::ParamEnv::empty();
 
-                let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
-                let impl_trait_ref = trait_ref.instantiate(infcx.tcx, impl_args);
+            let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id);
+            let impl_trait_ref = trait_ref.instantiate(tcx, impl_args);
 
-                // Require the type the impl is implemented on to match
-                // our type, and ignore the impl if there was a mismatch.
-                let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(
-                    DefineOpaqueTypes::Yes,
-                    impl_trait_ref.self_ty(),
-                    impl_ty,
-                ) else {
-                    continue;
-                };
-                let InferOk { value: (), obligations } = eq_result;
-                // FIXME(eddyb) ignoring `obligations` might cause false positives.
-                drop(obligations);
+            // Require the type the impl is implemented on to match
+            // our type, and ignore the impl if there was a mismatch.
+            let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq(
+                DefineOpaqueTypes::Yes,
+                impl_trait_ref.self_ty(),
+                impl_ty,
+            ) else {
+                continue;
+            };
+            let InferOk { value: (), obligations } = eq_result;
+            // FIXME(eddyb) ignoring `obligations` might cause false positives.
+            drop(obligations);
 
-                trace!(
-                    "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}",
+            let predicates = tcx
+                .predicates_of(impl_def_id)
+                .instantiate(tcx, impl_args)
+                .predicates
+                .into_iter()
+                .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(tcx)));
+            for predicate in predicates {
+                let obligation = traits::Obligation::new(
+                    tcx,
+                    traits::ObligationCause::dummy(),
                     param_env,
-                    impl_trait_ref,
-                    impl_ty
+                    predicate,
                 );
-                let predicates = cx
-                    .tcx
-                    .predicates_of(impl_def_id)
-                    .instantiate(cx.tcx, impl_args)
-                    .predicates
-                    .into_iter()
-                    .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx)));
-                for predicate in predicates {
-                    debug!("testing predicate {predicate:?}");
-                    let obligation = traits::Obligation::new(
-                        infcx.tcx,
-                        traits::ObligationCause::dummy(),
-                        param_env,
-                        predicate,
-                    );
-                    match infcx.evaluate_obligation(&obligation) {
-                        Ok(eval_result) if eval_result.may_apply() => {}
-                        Err(traits::OverflowError::Canonical) => {}
-                        _ => continue 'blanket_impls,
-                    }
+                match infcx.evaluate_obligation(&obligation) {
+                    Ok(eval_result) if eval_result.may_apply() => {}
+                    Err(traits::OverflowError::Canonical) => {}
+                    _ => continue 'blanket_impls,
                 }
-                debug!(
-                    "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}",
-                    trait_ref, ty
-                );
+            }
+            debug!("found applicable impl for trait ref {trait_ref:?}");
 
-                cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id));
+            cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id));
 
-                impls.push(Item {
-                    name: None,
-                    attrs: Default::default(),
-                    item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
-                    kind: Box::new(ImplItem(Box::new(Impl {
-                        unsafety: hir::Unsafety::Normal,
-                        generics: clean_ty_generics(
-                            cx,
-                            cx.tcx.generics_of(impl_def_id),
-                            cx.tcx.explicit_predicates_of(impl_def_id),
-                        ),
-                        // FIXME(eddyb) compute both `trait_` and `for_` from
-                        // the post-inference `trait_ref`, as it's more accurate.
-                        trait_: Some(clean_trait_ref_with_bindings(
-                            cx,
-                            ty::Binder::dummy(trait_ref.instantiate_identity()),
-                            ThinVec::new(),
-                        )),
-                        for_: clean_middle_ty(
-                            ty::Binder::dummy(ty.instantiate_identity()),
-                            cx,
-                            None,
-                            None,
-                        ),
-                        items: cx
-                            .tcx
-                            .associated_items(impl_def_id)
-                            .in_definition_order()
-                            .filter(|item| !item.is_impl_trait_in_trait())
-                            .map(|item| clean_middle_assoc_item(item, cx))
-                            .collect::<Vec<_>>(),
-                        polarity: ty::ImplPolarity::Positive,
-                        kind: ImplKind::Blanket(Box::new(clean_middle_ty(
-                            ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()),
-                            cx,
-                            None,
-                            None,
-                        ))),
-                    }))),
-                    cfg: None,
-                    inline_stmt_id: None,
-                });
-            }
+            blanket_impls.push(clean::Item {
+                name: None,
+                attrs: Default::default(),
+                item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
+                kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
+                    unsafety: hir::Unsafety::Normal,
+                    generics: clean_ty_generics(
+                        cx,
+                        tcx.generics_of(impl_def_id),
+                        tcx.explicit_predicates_of(impl_def_id),
+                    ),
+                    // FIXME(eddyb) compute both `trait_` and `for_` from
+                    // the post-inference `trait_ref`, as it's more accurate.
+                    trait_: Some(clean_trait_ref_with_bindings(
+                        cx,
+                        ty::Binder::dummy(trait_ref.instantiate_identity()),
+                        ThinVec::new(),
+                    )),
+                    for_: clean_middle_ty(
+                        ty::Binder::dummy(ty.instantiate_identity()),
+                        cx,
+                        None,
+                        None,
+                    ),
+                    items: tcx
+                        .associated_items(impl_def_id)
+                        .in_definition_order()
+                        .filter(|item| !item.is_impl_trait_in_trait())
+                        .map(|item| clean_middle_assoc_item(item, cx))
+                        .collect(),
+                    polarity: ty::ImplPolarity::Positive,
+                    kind: clean::ImplKind::Blanket(Box::new(clean_middle_ty(
+                        ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()),
+                        cx,
+                        None,
+                        None,
+                    ))),
+                }))),
+                cfg: None,
+                inline_stmt_id: None,
+            });
         }
-
-        impls
     }
+
+    blanket_impls
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a25a506d9c5..12f45fe4979 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -29,7 +29,7 @@ use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{self, ExpnKind};
+use rustc_span::ExpnKind;
 use rustc_trait_selection::traits::wf::object_region_bounds;
 
 use std::borrow::Cow;
@@ -37,14 +37,14 @@ use std::collections::BTreeMap;
 use std::mem;
 use thin_vec::ThinVec;
 
-use crate::core::{self, DocContext};
+use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
 use crate::visit_ast::Module as DocModule;
 
 use utils::*;
 
 pub(crate) use self::types::*;
-pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
+pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls};
 
 pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
     let mut items: Vec<Item> = vec![];
@@ -1782,6 +1782,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
         }
         TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
+        TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()),
         TyKind::Array(ty, ref length) => {
             let length = match length {
                 hir::ArrayLen::Infer(..) => "_".to_string(),
@@ -2008,6 +2009,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
         ty::Float(float_ty) => Primitive(float_ty.into()),
         ty::Str => Primitive(PrimitiveType::Str),
         ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
+        ty::Pat(ty, pat) => Type::Pat(
+            Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)),
+            format!("{pat:?}").into_boxed_str(),
+        ),
         ty::Array(ty, mut n) => {
             n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all());
             let n = print_const(cx, n);
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6793ea9f485..b592bd76e4c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -23,6 +23,7 @@ use rustc_hir::{BodyId, Mutability};
 use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
 use rustc_index::IndexVec;
 use rustc_metadata::rendered_const;
+use rustc_middle::span_bug;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt, Visibility};
 use rustc_resolve::rustdoc::{
@@ -266,8 +267,15 @@ impl ExternalCrate {
         let as_primitive = |res: Res<!>| {
             let Res::Def(DefKind::Mod, def_id) = res else { return None };
             tcx.get_attrs(def_id, sym::rustc_doc_primitive).find_map(|attr| {
-                // FIXME: should warn on unknown primitives?
-                Some((def_id, PrimitiveType::from_symbol(attr.value_str()?)?))
+                let attr_value = attr.value_str().expect("syntax should already be validated");
+                let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
+                    span_bug!(
+                        attr.span,
+                        "primitive `{attr_value}` is not a member of `PrimitiveType`"
+                    );
+                };
+
+                Some((def_id, prim))
             })
         };
 
@@ -1475,7 +1483,9 @@ pub(crate) enum Type {
     ///
     /// This is mostly Rustdoc's version of [`hir::Path`].
     /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics.
-    Path { path: Path },
+    Path {
+        path: Path,
+    },
     /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static`
     DynTrait(Vec<PolyTrait>, Option<Lifetime>),
     /// A type parameter.
@@ -1492,10 +1502,15 @@ pub(crate) enum Type {
     ///
     /// The `String` field is a stringified version of the array's length parameter.
     Array(Box<Type>, Box<str>),
+    Pat(Box<Type>, Box<str>),
     /// A raw pointer type: `*const i32`, `*mut i32`
     RawPointer(Mutability, Box<Type>),
     /// A reference type: `&i32`, `&'a mut Foo`
-    BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> },
+    BorrowedRef {
+        lifetime: Option<Lifetime>,
+        mutability: Mutability,
+        type_: Box<Type>,
+    },
 
     /// A qualified path to an associated item: `<Type as Trait>::Name`
     QPath(Box<QPathData>),
@@ -1692,6 +1707,7 @@ impl Type {
             BareFunction(..) => PrimitiveType::Fn,
             Slice(..) => PrimitiveType::Slice,
             Array(..) => PrimitiveType::Array,
+            Type::Pat(..) => PrimitiveType::Pat,
             RawPointer(..) => PrimitiveType::RawPointer,
             QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache),
             Generic(_) | Infer | ImplTrait(_) => return None,
@@ -1745,6 +1761,7 @@ pub(crate) enum PrimitiveType {
     Str,
     Slice,
     Array,
+    Pat,
     Tuple,
     Unit,
     RawPointer,
@@ -1797,8 +1814,10 @@ impl PrimitiveType {
             sym::bool => Some(PrimitiveType::Bool),
             sym::char => Some(PrimitiveType::Char),
             sym::str => Some(PrimitiveType::Str),
+            sym::f16 => Some(PrimitiveType::F16),
             sym::f32 => Some(PrimitiveType::F32),
             sym::f64 => Some(PrimitiveType::F64),
+            sym::f128 => Some(PrimitiveType::F128),
             sym::array => Some(PrimitiveType::Array),
             sym::slice => Some(PrimitiveType::Slice),
             sym::tuple => Some(PrimitiveType::Tuple),
@@ -1831,8 +1850,10 @@ impl PrimitiveType {
                 U32 => single(SimplifiedType::Uint(UintTy::U32)),
                 U64 => single(SimplifiedType::Uint(UintTy::U64)),
                 U128 => single(SimplifiedType::Uint(UintTy::U128)),
+                F16 => single(SimplifiedType::Float(FloatTy::F16)),
                 F32 => single(SimplifiedType::Float(FloatTy::F32)),
                 F64 => single(SimplifiedType::Float(FloatTy::F64)),
+                F128 => single(SimplifiedType::Float(FloatTy::F128)),
                 Str => single(SimplifiedType::Str),
                 Bool => single(SimplifiedType::Bool),
                 Char => single(SimplifiedType::Char),
@@ -1895,6 +1916,7 @@ impl PrimitiveType {
             Bool => sym::bool,
             Char => sym::char,
             Array => sym::array,
+            Pat => sym::pat,
             Slice => sym::slice,
             Tuple => sym::tuple,
             Unit => sym::unit,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index d5e0e83696f..dc62fbb5edb 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,5 +1,5 @@
 use crate::clean::auto_trait::synthesize_auto_trait_impls;
-use crate::clean::blanket_impl::BlanketImplFinder;
+use crate::clean::blanket_impl::synthesize_blanket_impls;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
     clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate,
@@ -477,8 +477,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
     }
 }
 
-// FIXME(fmease): Update the `get_*` terminology to the `synthesize_` one.
-pub(crate) fn get_auto_trait_and_blanket_impls(
+pub(crate) fn synthesize_auto_trait_and_blanket_impls(
     cx: &mut DocContext<'_>,
     item_def_id: DefId,
 ) -> impl Iterator<Item = Item> {
@@ -490,8 +489,8 @@ pub(crate) fn get_auto_trait_and_blanket_impls(
     let blanket_impls = cx
         .sess()
         .prof
-        .generic_activity("get_blanket_impls")
-        .run(|| BlanketImplFinder { cx }.get_blanket_impls(item_def_id));
+        .generic_activity("synthesize_blanket_impls")
+        .run(|| synthesize_blanket_impls(cx, item_def_id));
     auto_impls.into_iter().chain(blanket_impls)
 }
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 312765d3e6d..f82b89fdd5f 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1071,6 +1071,10 @@ fn fmt_type<'cx>(
                 write!(f, "]")
             }
         },
+        clean::Type::Pat(ref t, ref pat) => {
+            fmt::Display::fmt(&t.print(cx), f)?;
+            write!(f, " is {pat}")
+        }
         clean::Array(ref t, ref n) => match **t {
             clean::Generic(name) if !f.alternate() => primitive_link(
                 f,
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 51f90e45500..7083999de68 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -668,7 +668,7 @@ fn get_index_type_id(
             }
         }
         // Not supported yet
-        clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
+        clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None,
     }
 }
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index cb50a27326f..35b99ab46f0 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -573,6 +573,10 @@ impl FromWithTcx<clean::Type> for Type {
             Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
             Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
             Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() },
+            clean::Type::Pat(t, p) => Type::Pat {
+                type_: Box::new((*t).into_tcx(tcx)),
+                __pat_unstable_do_not_use: p.to_string(),
+            },
             ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
             Infer => Type::Infer,
             RawPointer(mutability, type_) => Type::RawPointer {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index a5c26429013..1ba4e6cbdf0 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -491,6 +491,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             ty::Str => Res::Primitive(Str),
             ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
             ty::Tuple(_) => Res::Primitive(Tuple),
+            ty::Pat(..) => Res::Primitive(Pat),
             ty::Array(..) => Res::Primitive(Array),
             ty::Slice(_) => Res::Primitive(Slice),
             ty::RawPtr(_, _) => Res::Primitive(RawPointer),
@@ -536,8 +537,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             I64 => tcx.types.i64,
             I128 => tcx.types.i128,
             Isize => tcx.types.isize,
+            F16 => tcx.types.f16,
             F32 => tcx.types.f32,
             F64 => tcx.types.f64,
+            F128 => tcx.types.f128,
             U8 => tcx.types.u8,
             U16 => tcx.types.u16,
             U32 => tcx.types.u32,
@@ -2196,8 +2199,10 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> {
         "u32" => U32,
         "u64" => U64,
         "u128" => U128,
+        "f16" => F16,
         "f32" => F32,
         "f64" => F64,
+        "f128" => F128,
         "char" => Char,
         "bool" | "true" | "false" => Bool,
         "str" | "&str" => Str,
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index fbbb6152cfe..c92cf9d3e80 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -122,7 +122,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
                         _ => true,
                     }
                 }) {
-                    let impls = get_auto_trait_and_blanket_impls(cx, def_id);
+                    let impls = synthesize_auto_trait_and_blanket_impls(cx, def_id);
                     new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
                 }
             }
@@ -230,8 +230,10 @@ impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> {
         if i.is_struct() || i.is_enum() || i.is_union() {
             // FIXME(eddyb) is this `doc(hidden)` check needed?
             if !self.cx.tcx.is_doc_hidden(i.item_id.expect_def_id()) {
-                self.impls
-                    .extend(get_auto_trait_and_blanket_impls(self.cx, i.item_id.expect_def_id()));
+                self.impls.extend(synthesize_auto_trait_and_blanket_impls(
+                    self.cx,
+                    i.item_id.expect_def_id(),
+                ));
             }
         }
 
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 164f88faa31..89d6f8d67f1 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
 
 /// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 28;
+pub const FORMAT_VERSION: u32 = 29;
 
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
@@ -562,6 +562,13 @@ pub enum Type {
         type_: Box<Type>,
         len: String,
     },
+    /// `u32 is 1..`
+    Pat {
+        #[serde(rename = "type")]
+        type_: Box<Type>,
+        #[doc(hidden)]
+        __pat_unstable_do_not_use: String,
+    },
     /// `impl TraitA + TraitB + ...`
     ImplTrait(Vec<GenericBound>),
     /// `_`
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 560b2acc1c7..f83fb1b9019 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -821,6 +821,7 @@ impl TyCoercionStability {
                 | TyKind::Array(..)
                 | TyKind::Ptr(_)
                 | TyKind::BareFn(_)
+                | TyKind::Pat(..)
                 | TyKind::Never
                 | TyKind::Tup(_)
                 | TyKind::Path(_) => Self::Deref,
@@ -869,6 +870,7 @@ impl TyCoercionStability {
                 | ty::Int(_)
                 | ty::Uint(_)
                 | ty::Array(..)
+                | ty::Pat(..)
                 | ty::Float(_)
                 | ty::RawPtr(..)
                 | ty::FnPtr(_)
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 23fc323446e..d3347466be9 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
@@ -12,7 +12,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
-use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::Mutability;
@@ -437,9 +436,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
             Node::Item(item) => {
                 if let ItemKind::Fn(_, _, body_id) = &item.kind
                     && let output_ty = return_ty(cx, item.owner_id)
-                    && let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id)
-                    && let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id)
-                    && fn_ctxt.can_coerce(ty, output_ty)
+                    && rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty)
                 {
                     if has_lifetime(output_ty) && has_lifetime(ty) {
                         return false;
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index f5ce8dd29b1..3cf054e7207 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -66,7 +66,7 @@ declare_clippy_lint! {
     ///
     /// ### Known problems
     /// The lint does not work properly with desugaring and
-    /// macro, it has been allowed in the mean time.
+    /// macro, it has been allowed in the meantime.
     ///
     /// ### Example
     /// ```no_run
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index 6f5ac625e35..a6a6e9a3bac 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -1,4 +1,4 @@
-use super::utils::check_cast;
+use rustc_hir_typeck::cast::check_cast;
 use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
@@ -22,7 +22,7 @@ pub(super) fn check<'tcx>(
 ) -> bool {
     use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast};
     let mut app = Applicability::MachineApplicable;
-    let mut sugg = match check_cast(cx, e, from_ty, to_ty) {
+    let mut sugg = match check_cast(cx.tcx, cx.param_env, e, from_ty, to_ty) {
         Some(FnPtrAddrCast | PtrAddrCast) if const_context => return false,
         Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => {
             Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
index 15f1890aa39..e8ccd35b4da 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs
@@ -1,10 +1,5 @@
-use rustc_hir as hir;
-use rustc_hir::Expr;
-use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt};
 use rustc_lint::LateContext;
-use rustc_middle::ty::cast::CastKind;
 use rustc_middle::ty::Ty;
-use rustc_span::DUMMY_SP;
 
 // check if the component types of the transmuted collection and the result have different ABI,
 // size or alignment
@@ -20,35 +15,3 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx
         false
     }
 }
-
-/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of
-/// the cast. In certain cases, including some invalid casts from array references
-/// to pointers, this may cause additional errors to be emitted and/or ICE error
-/// messages. This function will panic if that occurs.
-pub(super) fn check_cast<'tcx>(
-    cx: &LateContext<'tcx>,
-    e: &'tcx Expr<'_>,
-    from_ty: Ty<'tcx>,
-    to_ty: Ty<'tcx>,
-) -> Option<CastKind> {
-    let hir_id = e.hir_id;
-    let local_def_id = hir_id.owner.def_id;
-
-    let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id);
-    let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id);
-
-    if let Ok(check) = cast::CastCheck::new(
-        &fn_ctxt,
-        e,
-        from_ty,
-        to_ty,
-        // We won't show any error to the user, so we don't care what the span is here.
-        DUMMY_SP,
-        DUMMY_SP,
-        hir::Constness::NotConst,
-    ) {
-        check.do_check(&fn_ctxt).ok()
-    } else {
-        None
-    }
-}
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index f8bbe997774..6c3d9329932 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1068,6 +1068,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_ty(ty);
                 self.hash_array_length(len);
             },
+            TyKind::Pat(ty, pat) => {
+                self.hash_ty(ty);
+                self.hash_pat(pat);
+            },
             TyKind::Ptr(ref mut_ty) => {
                 self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index b84f4e87e07..763ce59ba1d 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -4,7 +4,7 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 error: the compiler unexpectedly panicked. this is a bug.
 
-note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the mean time
+note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the meantime
   |
   = note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists
   = note: if the problem still persists, we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 689fdc5dfeb..327e34ea36b 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -752,6 +752,19 @@ impl<'test> TestCx<'test> {
             Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?:  \|)+  Branch \()[0-9]+:").unwrap());
         let coverage = BRANCH_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:");
 
+        // `  |---> MC/DC Decision Region (1:30) to (2:`     => `  |---> MC/DC Decision Region (LL:30) to (LL:`
+        static MCDC_DECISION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| {
+            Regex::new(r"(?m:^)(?<prefix>(?:  \|)+---> MC/DC Decision Region \()[0-9]+:(?<middle>[0-9]+\) to \()[0-9]+:").unwrap()
+        });
+        let coverage =
+            MCDC_DECISION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:${middle}LL:");
+
+        // `  |     Condition C1 --> (1:`     => `  |     Condition C1 --> (LL:`
+        static MCDC_CONDITION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| {
+            Regex::new(r"(?m:^)(?<prefix>(?:  \|)+     Condition C[0-9]+ --> \()[0-9]+:").unwrap()
+        });
+        let coverage = MCDC_CONDITION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:");
+
         coverage.into_owned()
     }
 
@@ -2354,6 +2367,11 @@ impl<'test> TestCx<'test> {
             "ignore-directory-in-diagnostics-source-blocks={}",
             home::cargo_home().expect("failed to find cargo home").to_str().unwrap()
         ));
+        // Similarly, vendored sources shouldn't be shown when running from a dist tarball.
+        rustc.arg("-Z").arg(format!(
+            "ignore-directory-in-diagnostics-source-blocks={}",
+            self.config.find_rust_src_root().unwrap().join("vendor").display(),
+        ));
 
         // Optionally prevent default --sysroot if specified in test compile-flags.
         if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot"))
@@ -4252,7 +4270,7 @@ impl<'test> TestCx<'test> {
         if self.props.run_rustfix && self.config.compare_mode.is_none() {
             // And finally, compile the fixed code and make sure it both
             // succeeds and has no diagnostics.
-            let rustc = self.make_compile_args(
+            let mut rustc = self.make_compile_args(
                 &self.expected_output_path(UI_FIXED),
                 TargetLocation::ThisFile(self.make_exe_name()),
                 emit_metadata,
@@ -4260,6 +4278,26 @@ impl<'test> TestCx<'test> {
                 LinkToAux::Yes,
                 Vec::new(),
             );
+
+            // If a test is revisioned, it's fixed source file can be named "a.foo.fixed", which,
+            // well, "a.foo" isn't a valid crate name. So we explicitly mangle the test name
+            // (including the revision) here to avoid the test writer having to manually specify a
+            // `#![crate_name = "..."]` as a workaround. This is okay since we're only checking if
+            // the fixed code is compilable.
+            if self.revision.is_some() {
+                let crate_name =
+                    self.testpaths.file.file_stem().expect("test must have a file stem");
+                // crate name must be alphanumeric or `_`.
+                let crate_name =
+                    crate_name.to_str().expect("crate name implies file name must be valid UTF-8");
+                // replace `a.foo` -> `a__foo` for crate name purposes.
+                // replace `revision-name-with-dashes` -> `revision_name_with_underscore`
+                let crate_name = crate_name.replace(".", "__");
+                let crate_name = crate_name.replace("-", "_");
+                rustc.arg("--crate-name");
+                rustc.arg(crate_name);
+            }
+
             let res = self.compose_and_run_compiler(rustc, None);
             if !res.status.success() {
                 self.fatal_proc_rec("failed to compile fixed code", &res);
diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs
index ee42243e83d..817b56109a5 100644
--- a/src/tools/compiletest/src/runtest/tests.rs
+++ b/src/tools/compiletest/src/runtest/tests.rs
@@ -50,72 +50,68 @@ fn normalize_platform_differences() {
 }
 
 /// Test for anonymizing line numbers in coverage reports, especially for
-/// branch regions.
+/// MC/DC regions.
 ///
-/// FIXME(#119681): This test can be removed when we have examples of branch
+/// FIXME(#123409): This test can be removed when we have examples of MC/DC
 /// coverage in the actual coverage test suite.
 #[test]
 fn anonymize_coverage_line_numbers() {
     let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage);
 
     let input = r#"
-    6|      3|fn print_size<T>() {
-    7|      3|    if std::mem::size_of::<T>() > 4 {
+    7|      2|fn mcdc_check_neither(a: bool, b: bool) {
+    8|      2|    if a && b {
+                          ^0
   ------------------
-  |  Branch (7:8): [True: 0, False: 1]
-  |  Branch (7:8): [True: 0, False: 1]
-  |  Branch (7:8): [True: 1, False: 0]
+  |---> MC/DC Decision Region (8:8) to (8:14)
+  |
+  |  Number of Conditions: 2
+  |     Condition C1 --> (8:8)
+  |     Condition C2 --> (8:13)
+  |
+  |  Executed MC/DC Test Vectors:
+  |
+  |     C1, C2    Result
+  |  1 { F,  -  = F      }
+  |
+  |  C1-Pair: not covered
+  |  C2-Pair: not covered
+  |  MC/DC Coverage for Decision: 0.00%
+  |
   ------------------
-    8|      1|        println!("size > 4");
+    9|      0|        say("a and b");
+   10|      2|    } else {
+   11|      2|        say("not both");
+   12|      2|    }
+   13|      2|}
 "#;
 
     let expected = r#"
-   LL|      3|fn print_size<T>() {
-   LL|      3|    if std::mem::size_of::<T>() > 4 {
+   LL|      2|fn mcdc_check_neither(a: bool, b: bool) {
+   LL|      2|    if a && b {
+                          ^0
   ------------------
-  |  Branch (LL:8): [True: 0, False: 1]
-  |  Branch (LL:8): [True: 0, False: 1]
-  |  Branch (LL:8): [True: 1, False: 0]
-  ------------------
-   LL|      1|        println!("size > 4");
-"#;
-
-    assert_eq!(anon(input), expected);
-
-    //////////
-
-    let input = r#"
-   12|      3|}
-  ------------------
-  | branch_generics::print_size::<()>:
-  |    6|      1|fn print_size<T>() {
-  |    7|      1|    if std::mem::size_of::<T>() > 4 {
-  |  ------------------
-  |  |  Branch (7:8): [True: 0, False: 1]
-  |  ------------------
-  |    8|      0|        println!("size > 4");
-  |    9|      1|    } else {
-  |   10|      1|        println!("size <= 4");
-  |   11|      1|    }
-  |   12|      1|}
-  ------------------
-"#;
-
-    let expected = r#"
-   LL|      3|}
-  ------------------
-  | branch_generics::print_size::<()>:
-  |   LL|      1|fn print_size<T>() {
-  |   LL|      1|    if std::mem::size_of::<T>() > 4 {
-  |  ------------------
-  |  |  Branch (LL:8): [True: 0, False: 1]
-  |  ------------------
-  |   LL|      0|        println!("size > 4");
-  |   LL|      1|    } else {
-  |   LL|      1|        println!("size <= 4");
-  |   LL|      1|    }
-  |   LL|      1|}
+  |---> MC/DC Decision Region (LL:8) to (LL:14)
+  |
+  |  Number of Conditions: 2
+  |     Condition C1 --> (LL:8)
+  |     Condition C2 --> (LL:13)
+  |
+  |  Executed MC/DC Test Vectors:
+  |
+  |     C1, C2    Result
+  |  1 { F,  -  = F      }
+  |
+  |  C1-Pair: not covered
+  |  C2-Pair: not covered
+  |  MC/DC Coverage for Decision: 0.00%
+  |
   ------------------
+   LL|      0|        say("a and b");
+   LL|      2|    } else {
+   LL|      2|        say("not both");
+   LL|      2|    }
+   LL|      2|}
 "#;
 
     assert_eq!(anon(input), expected);
diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs
index 49e3a6ed583..b308c8de14f 100644
--- a/src/tools/coverage-dump/src/covfun.rs
+++ b/src/tools/coverage-dump/src/covfun.rs
@@ -70,7 +70,8 @@ pub(crate) fn dump_covfun_mappings(
                     }
                     // If the mapping is a branch region, print both of its arms
                     // in resolved form (even if they aren't expressions).
-                    MappingKind::Branch { r#true, r#false } => {
+                    MappingKind::Branch { r#true, r#false }
+                    | MappingKind::MCDCBranch { r#true, r#false, .. } => {
                         println!("    true  = {}", expression_resolver.format_term(r#true));
                         println!("    false = {}", expression_resolver.format_term(r#false));
                     }
@@ -164,6 +165,26 @@ impl<'a> Parser<'a> {
                     let r#false = self.read_simple_term()?;
                     Ok(MappingKind::Branch { r#true, r#false })
                 }
+                5 => {
+                    let bitmap_idx = self.read_uleb128_u32()?;
+                    let conditions_num = self.read_uleb128_u32()?;
+                    Ok(MappingKind::MCDCDecision { bitmap_idx, conditions_num })
+                }
+                6 => {
+                    let r#true = self.read_simple_term()?;
+                    let r#false = self.read_simple_term()?;
+                    let condition_id = self.read_uleb128_u32()?;
+                    let true_next_id = self.read_uleb128_u32()?;
+                    let false_next_id = self.read_uleb128_u32()?;
+                    Ok(MappingKind::MCDCBranch {
+                        r#true,
+                        r#false,
+                        condition_id,
+                        true_next_id,
+                        false_next_id,
+                    })
+                }
+
                 _ => Err(anyhow!("unknown mapping kind: {raw_mapping_kind:#x}")),
             }
         }
@@ -224,7 +245,28 @@ enum MappingKind {
     // Using raw identifiers here makes the dump output a little bit nicer
     // (via the derived Debug), at the expense of making this tool's source
     // code a little bit uglier.
-    Branch { r#true: CovTerm, r#false: CovTerm },
+    Branch {
+        r#true: CovTerm,
+        r#false: CovTerm,
+    },
+    MCDCBranch {
+        r#true: CovTerm,
+        r#false: CovTerm,
+        // These attributes are printed in Debug but not used directly.
+        #[allow(dead_code)]
+        condition_id: u32,
+        #[allow(dead_code)]
+        true_next_id: u32,
+        #[allow(dead_code)]
+        false_next_id: u32,
+    },
+    MCDCDecision {
+        // These attributes are printed in Debug but not used directly.
+        #[allow(dead_code)]
+        bitmap_idx: u32,
+        #[allow(dead_code)]
+        conditions_num: u32,
+    },
 }
 
 struct MappingRegion {
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 592e97310a4..9e08f7e5f9b 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -262,6 +262,7 @@ impl<'a> Validator<'a> {
             Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait),
             Type::Generic(_) => {}
             Type::Primitive(_) => {}
+            Type::Pat { type_, __pat_unstable_do_not_use: _ } => self.check_type(type_),
             Type::FunctionPointer(fp) => self.check_function_pointer(&**fp),
             Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)),
             Type::Slice(inner) => self.check_type(&**inner),
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index 50ff0d26bbb..217da36ccc7 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -1,5 +1,5 @@
 use std::env;
-use std::ffi::OsStr;
+use std::ffi::{OsStr, OsString};
 use std::path::Path;
 use std::process::{Command, Output};
 
@@ -86,6 +86,33 @@ impl Rustc {
         self
     }
 
+    /// Specify number of codegen units
+    pub fn codegen_units(&mut self, units: usize) -> &mut Self {
+        self.cmd.arg(format!("-Ccodegen-units={units}"));
+        self
+    }
+
+    /// Specify directory path used for incremental cache
+    pub fn incremental<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        let mut arg = OsString::new();
+        arg.push("-Cincremental=");
+        arg.push(path.as_ref());
+        self.cmd.arg(&arg);
+        self
+    }
+
+    /// Specify error format to use
+    pub fn error_format(&mut self, format: &str) -> &mut Self {
+        self.cmd.arg(format!("--error-format={format}"));
+        self
+    }
+
+    /// Specify json messages printed by the compiler
+    pub fn json(&mut self, items: &str) -> &mut Self {
+        self.cmd.arg(format!("--json={items}"));
+        self
+    }
+
     /// Specify target triple.
     pub fn target(&mut self, target: &str) -> &mut Self {
         assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces");
@@ -94,13 +121,7 @@ impl Rustc {
     }
 
     /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
-    /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>`
-    /// is passed (note the space).
-    pub fn arg(&mut self, arg: &str) -> &mut Self {
-        assert!(
-            !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")),
-            "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`"
-        );
+    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
         self.cmd.arg(arg);
         self
     }
@@ -120,16 +141,7 @@ impl Rustc {
     }
 
     /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
-    /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>`
-    /// is passed (note the space).
-    pub fn args(&mut self, args: &[&str]) -> &mut Self {
-        for arg in args {
-            assert!(
-                !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")),
-                "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`"
-            );
-        }
-
+    pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Self {
         self.cmd.args(args);
         self
     }
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 7f220a456a8..10a87f6e698 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -867,6 +867,11 @@ impl Rewrite for ast::Ty {
                 self.span,
                 shape,
             ),
+            ast::TyKind::Pat(ref ty, ref pat) => {
+                let ty = ty.rewrite(context, shape)?;
+                let pat = pat.rewrite(context, shape)?;
+                Some(format!("{ty} is {pat}"))
+            }
         }
     }
 }
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index 6fc65e56901..39f7e70b693 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -71,10 +71,12 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
     let path = root_path.join(Path::new(ERROR_CODES_PATH));
     let file =
         fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}"));
+    let path = path.display();
 
     let mut error_codes = Vec::new();
 
-    for line in file.lines() {
+    for (line_index, line) in file.lines().enumerate() {
+        let line_index = line_index + 1;
         let line = line.trim();
 
         if line.starts_with('E') {
@@ -82,39 +84,54 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
 
             // Extract the error code from the line. Emit a fatal error if it is not in the correct
             // format.
-            let err_code = if let Some(err_code) = split_line {
-                err_code.0.to_owned()
-            } else {
+            let Some(split_line) = split_line else {
                 errors.push(format!(
-                    "Expected a line with the format `Eabcd: abcd, \
+                    "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
                     but got \"{}\" without a `:` delimiter",
                     line,
                 ));
                 continue;
             };
 
+            let err_code = split_line.0.to_owned();
+
             // If this is a duplicate of another error code, emit a fatal error.
             if error_codes.contains(&err_code) {
-                errors.push(format!("Found duplicate error code: `{}`", err_code));
+                errors.push(format!(
+                    "{path}:{line_index}: Found duplicate error code: `{}`",
+                    err_code
+                ));
                 continue;
             }
 
             let mut chars = err_code.chars();
-            chars.next();
+            assert_eq!(chars.next(), Some('E'));
             let error_num_as_str = chars.as_str();
 
             // Ensure that the line references the correct markdown file.
-            let expected_filename = format!(" {},", error_num_as_str);
-            if expected_filename != split_line.unwrap().1 {
+            let rest = split_line.1.split_once(',');
+            let Some(rest) = rest else {
+                errors.push(format!(
+                    "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
+                    but got \"{}\" without a `,` delimiter",
+                    line,
+                ));
+                continue;
+            };
+            if error_num_as_str != rest.0.trim() {
                 errors.push(format!(
-                    "`{}:` should be followed by `{}` but instead found `{}` in \
+                    "{path}:{line_index}: `{}:` should be followed by `{},` but instead found `{}` in \
                     `compiler/rustc_error_codes/src/lib.rs`",
                     err_code,
-                    expected_filename,
-                    split_line.unwrap().1,
+                    error_num_as_str,
+                    split_line.1,
                 ));
                 continue;
             }
+            if !rest.1.trim().is_empty() && !rest.1.trim().starts_with("//") {
+                errors.push(format!("{path}:{line_index}: should only have one error per line"));
+                continue;
+            }
 
             error_codes.push(err_code);
         }
@@ -146,14 +163,14 @@ fn check_error_codes_docs(
             return;
         }
 
-        // Make sure that the file is referenced in `error_codes.rs`
+        // Make sure that the file is referenced in `rustc_error_codes/src/lib.rs`
         let filename = path.file_name().unwrap().to_str().unwrap().split_once('.');
         let err_code = filename.unwrap().0; // `unwrap` is ok because we know the filename is in the correct format.
 
         if error_codes.iter().all(|e| e != err_code) {
             errors.push(format!(
                 "Found valid file `{}` in error code docs directory without corresponding \
-                entry in `error_code.rs`",
+                entry in `rustc_error_codes/src/lib.rs`",
                 path.display()
             ));
             return;
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 9be10528a64..e14932ad99d 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1380,18 +1380,12 @@ ui/issues/auxiliary/issue-11224.rs
 ui/issues/auxiliary/issue-11508.rs
 ui/issues/auxiliary/issue-11529.rs
 ui/issues/auxiliary/issue-11680.rs
-ui/issues/auxiliary/issue-12133-dylib.rs
-ui/issues/auxiliary/issue-12133-dylib2.rs
-ui/issues/auxiliary/issue-12133-rlib.rs
 ui/issues/auxiliary/issue-12612-1.rs
 ui/issues/auxiliary/issue-12612-2.rs
 ui/issues/auxiliary/issue-12660-aux.rs
 ui/issues/auxiliary/issue-13507.rs
 ui/issues/auxiliary/issue-13620-1.rs
 ui/issues/auxiliary/issue-13620-2.rs
-ui/issues/auxiliary/issue-13872-1.rs
-ui/issues/auxiliary/issue-13872-2.rs
-ui/issues/auxiliary/issue-13872-3.rs
 ui/issues/auxiliary/issue-14344-1.rs
 ui/issues/auxiliary/issue-14344-2.rs
 ui/issues/auxiliary/issue-14421.rs
@@ -1510,9 +1504,6 @@ ui/issues/issue-11958.rs
 ui/issues/issue-12033.rs
 ui/issues/issue-12041.rs
 ui/issues/issue-12127.rs
-ui/issues/issue-12133-1.rs
-ui/issues/issue-12133-2.rs
-ui/issues/issue-12133-3.rs
 ui/issues/issue-12187-1.rs
 ui/issues/issue-12187-2.rs
 ui/issues/issue-12285.rs
@@ -1556,7 +1547,6 @@ ui/issues/issue-13775.rs
 ui/issues/issue-13808.rs
 ui/issues/issue-13847.rs
 ui/issues/issue-13867.rs
-ui/issues/issue-13872.rs
 ui/issues/issue-14082.rs
 ui/issues/issue-14091-2.rs
 ui/issues/issue-14091.rs
@@ -1726,10 +1716,6 @@ ui/issues/issue-19127.rs
 ui/issues/issue-19129-1.rs
 ui/issues/issue-19129-2.rs
 ui/issues/issue-19135.rs
-ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs
-ui/issues/issue-1920-absolute-paths/issue-1920-1.rs
-ui/issues/issue-1920-absolute-paths/issue-1920-2.rs
-ui/issues/issue-1920-absolute-paths/issue-1920-3.rs
 ui/issues/issue-19244-1.rs
 ui/issues/issue-19244-2.rs
 ui/issues/issue-19293.rs
@@ -1878,9 +1864,6 @@ ui/issues/issue-23217.rs
 ui/issues/issue-23253.rs
 ui/issues/issue-23261.rs
 ui/issues/issue-23281.rs
-ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs
-ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs
-ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs
 ui/issues/issue-23304-1.rs
 ui/issues/issue-23304-2.rs
 ui/issues/issue-23311.rs
@@ -1897,9 +1880,6 @@ ui/issues/issue-23543.rs
 ui/issues/issue-23544.rs
 ui/issues/issue-23550.rs
 ui/issues/issue-23589.rs
-ui/issues/issue-23649-1.rs
-ui/issues/issue-23649-2.rs
-ui/issues/issue-23649-3.rs
 ui/issues/issue-23699.rs
 ui/issues/issue-2380-b.rs
 ui/issues/issue-23808.rs
@@ -1970,7 +1950,6 @@ ui/issues/issue-25901.rs
 ui/issues/issue-26056.rs
 ui/issues/issue-26093.rs
 ui/issues/issue-26095.rs
-ui/issues/issue-2611-3.rs
 ui/issues/issue-26127.rs
 ui/issues/issue-26186.rs
 ui/issues/issue-26205.rs
@@ -2268,10 +2247,6 @@ ui/issues/issue-40350.rs
 ui/issues/issue-40402-ref-hints/issue-40402-1.rs
 ui/issues/issue-40402-ref-hints/issue-40402-2.rs
 ui/issues/issue-40408.rs
-ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs
-ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs
-ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs
-ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs
 ui/issues/issue-40610.rs
 ui/issues/issue-40749.rs
 ui/issues/issue-40782.rs
@@ -2764,8 +2739,14 @@ ui/limits/issue-55878.rs
 ui/limits/issue-56762.rs
 ui/limits/issue-69485-var-size-diffs-too-large.rs
 ui/limits/issue-75158-64.rs
+ui/linkage-attr/auxiliary/issue-12133-dylib.rs
+ui/linkage-attr/auxiliary/issue-12133-dylib2.rs
+ui/linkage-attr/auxiliary/issue-12133-rlib.rs
 ui/linkage-attr/issue-10755.rs
 ui/linkage-attr/issue-109144.rs
+ui/linkage-attr/issue-12133-1.rs
+ui/linkage-attr/issue-12133-2.rs
+ui/linkage-attr/issue-12133-3.rs
 ui/lint/dead-code/issue-41883.rs
 ui/lint/dead-code/issue-59003.rs
 ui/lint/dead-code/issue-68408-false-positive.rs
@@ -3051,7 +3032,15 @@ ui/mismatched_types/issue-84976.rs
 ui/missing-trait-bounds/auxiliary/issue-69725.rs
 ui/missing-trait-bounds/issue-35677.rs
 ui/missing-trait-bounds/issue-69725.rs
+ui/modules/auxiliary/issue-13872-1.rs
+ui/modules/auxiliary/issue-13872-2.rs
+ui/modules/auxiliary/issue-13872-3.rs
+ui/modules/auxiliary/issue-1920.rs
 ui/modules/issue-107649.rs
+ui/modules/issue-13872.rs
+ui/modules/issue-1920-1.rs
+ui/modules/issue-1920-2.rs
+ui/modules/issue-1920-3.rs
 ui/modules/issue-56411-aux.rs
 ui/modules/issue-56411.rs
 ui/moves/issue-22536-copy-mustnt-zero.rs
@@ -3092,6 +3081,10 @@ ui/nll/issue-30438-b.rs
 ui/nll/issue-30438-c.rs
 ui/nll/issue-31567.rs
 ui/nll/issue-32382-index-assoc-type-with-lifetime.rs
+ui/nll/issue-40510-1.rs
+ui/nll/issue-40510-2.rs
+ui/nll/issue-40510-3.rs
+ui/nll/issue-40510-4.rs
 ui/nll/issue-42574-diagnostic-in-nested-closure.rs
 ui/nll/issue-43058.rs
 ui/nll/issue-45157.rs
@@ -3621,6 +3614,9 @@ ui/reachable/issue-11225-1.rs
 ui/reachable/issue-11225-2.rs
 ui/reachable/issue-11225-3.rs
 ui/reachable/issue-948.rs
+ui/recursion/issue-23302-1.rs
+ui/recursion/issue-23302-2.rs
+ui/recursion/issue-23302-3.rs
 ui/recursion/issue-26548-recursion-via-normalize.rs
 ui/recursion/issue-38591-non-regular-dropck-recursion.rs
 ui/recursion/issue-83150.rs
@@ -4039,6 +4035,7 @@ ui/traits/issue-23003-overflow.rs
 ui/traits/issue-23003.rs
 ui/traits/issue-23825.rs
 ui/traits/issue-24010.rs
+ui/traits/issue-2611-3.rs
 ui/traits/issue-26339.rs
 ui/traits/issue-28576.rs
 ui/traits/issue-32963.rs
@@ -4135,7 +4132,6 @@ ui/type-alias-impl-trait/issue-52843.rs
 ui/type-alias-impl-trait/issue-53092-2.rs
 ui/type-alias-impl-trait/issue-53092.rs
 ui/type-alias-impl-trait/issue-53096.rs
-ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
 ui/type-alias-impl-trait/issue-53598.rs
 ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs
 ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs
@@ -4350,6 +4346,9 @@ ui/unsized-locals/issue-50940.rs
 ui/unsized-locals/issue-67981.rs
 ui/unsized/issue-115203.rs
 ui/unsized/issue-115809.rs
+ui/unsized/issue-23649-1.rs
+ui/unsized/issue-23649-2.rs
+ui/unsized/issue-23649-3.rs
 ui/unsized/issue-30355.rs
 ui/unsized/issue-40231-1.rs
 ui/unsized/issue-40231-2.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 65ea685b37c..4fae7572ffb 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use std::path::{Path, PathBuf};
 const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: usize = 1733;
+const ISSUES_ENTRY_LIMIT: usize = 1722;
 const ROOT_ENTRY_LIMIT: usize = 861;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
diff --git a/tests/codegen/enum/enum-early-otherwise-branch.rs b/tests/codegen/enum/enum-early-otherwise-branch.rs
new file mode 100644
index 00000000000..6c7548912da
--- /dev/null
+++ b/tests/codegen/enum/enum-early-otherwise-branch.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: -O
+//@ min-llvm-version: 18
+
+#![crate_type = "lib"]
+
+pub enum Enum {
+    A(u32),
+    B(u32),
+    C(u32),
+}
+
+#[no_mangle]
+pub fn foo(lhs: &Enum, rhs: &Enum) -> bool {
+    // CHECK-LABEL: define{{.*}}i1 @foo(
+    // CHECK-NOT: switch
+    // CHECK-NOT: br
+    // CHECK: [[SELECT:%.*]] = select
+    // CHECK-NEXT: ret i1 [[SELECT]]
+    // CHECK-NEXT: }
+    match (lhs, rhs) {
+        (Enum::A(lhs), Enum::A(rhs)) => lhs == rhs,
+        (Enum::B(lhs), Enum::B(rhs)) => lhs == rhs,
+        (Enum::C(lhs), Enum::C(rhs)) => lhs == rhs,
+        _ => false,
+    }
+}
diff --git a/tests/codegen/issues/issue-122805.rs b/tests/codegen/issues/issue-122805.rs
index 3bfffcd4a96..6a5be39238f 100644
--- a/tests/codegen/issues/issue-122805.rs
+++ b/tests/codegen/issues/issue-122805.rs
@@ -20,6 +20,7 @@
 // CHECK-NEXT: store <8 x i16>
 // CHECK-NEXT: ret void
 #[no_mangle]
+#[cfg(target_endian = "little")]
 pub fn convert(value: [u16; 8]) -> [u8; 16] {
     let addr16 = [
         value[0].to_be(),
diff --git a/tests/codegen/match-optimized.rs b/tests/codegen/match-optimized.rs
index 09907edf8f2..5cecafb9f29 100644
--- a/tests/codegen/match-optimized.rs
+++ b/tests/codegen/match-optimized.rs
@@ -26,12 +26,12 @@ pub fn exhaustive_match(e: E) -> u8 {
 // CHECK-NEXT: store i8 1, ptr %_0, align 1
 // CHECK-NEXT: br label %[[EXIT]]
 // CHECK: [[C]]:
-// CHECK-NEXT: store i8 2, ptr %_0, align 1
+// CHECK-NEXT: store i8 3, ptr %_0, align 1
 // CHECK-NEXT: br label %[[EXIT]]
     match e {
         E::A => 0,
         E::B => 1,
-        E::C => 2,
+        E::C => 3,
     }
 }
 
diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs
new file mode 100644
index 00000000000..dfe83443348
--- /dev/null
+++ b/tests/codegen/pattern_type_symbols.rs
@@ -0,0 +1,23 @@
+//! Check that symbol names with pattern types in them are
+//! different from the same symbol with the base type
+
+//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib
+
+#![feature(pattern_types)]
+#![feature(core_pattern_types)]
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999);
+
+fn foo<T>() {}
+
+pub fn bar() {
+    // CHECK: call pattern_type_symbols::foo::<u32>
+    // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_
+    foo::<u32>();
+    // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])>
+    // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_
+    foo::<NanoU32>();
+}
diff --git a/tests/codegen/powerpc64le-struct-align-128.rs b/tests/codegen/powerpc64le-struct-align-128.rs
new file mode 100644
index 00000000000..0096c6d3138
--- /dev/null
+++ b/tests/codegen/powerpc64le-struct-align-128.rs
@@ -0,0 +1,93 @@
+// Test that structs aligned to 128 bits are passed with the correct ABI on powerpc64le.
+// This is similar to aarch64-struct-align-128.rs, but for ppc.
+
+//@ compile-flags: --target powerpc64le-unknown-linux-gnu
+//@ needs-llvm-components: powerpc
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+#[lang="freeze"]
+trait Freeze { }
+#[lang="copy"]
+trait Copy { }
+
+#[repr(C)]
+pub struct Align8 {
+    pub a: u64,
+    pub b: u64,
+}
+
+#[repr(transparent)]
+pub struct Transparent8 {
+    a: Align8
+}
+
+#[repr(C)]
+pub struct Wrapped8 {
+    a: Align8,
+}
+
+extern "C" {
+    // CHECK: declare void @test_8([2 x i64], [2 x i64], [2 x i64])
+    fn test_8(a: Align8, b: Transparent8, c: Wrapped8);
+}
+
+#[repr(C)]
+#[repr(align(16))]
+pub struct Align16 {
+    pub a: u64,
+    pub b: u64,
+}
+
+#[repr(transparent)]
+pub struct Transparent16 {
+    a: Align16
+}
+
+#[repr(C)]
+pub struct Wrapped16 {
+    pub a: Align16,
+}
+
+extern "C" {
+    // It's important that this produces [1 x i128]  rather than just i128!
+    // CHECK: declare void @test_16([1 x i128], [1 x i128], [1 x i128])
+    fn test_16(a: Align16, b: Transparent16, c: Wrapped16);
+}
+
+#[repr(C)]
+#[repr(align(32))]
+pub struct Align32 {
+    pub a: u64,
+    pub b: u64,
+    pub c: u64,
+}
+
+#[repr(transparent)]
+pub struct Transparent32 {
+    a: Align32
+}
+
+#[repr(C)]
+pub struct Wrapped32 {
+    pub a: Align32,
+}
+
+extern "C" {
+    // CHECK: declare void @test_32([2 x i128], [2 x i128], [2 x i128])
+    fn test_32(a: Align32, b: Transparent32, c: Wrapped32);
+}
+
+pub unsafe fn main(
+    a1: Align8, a2: Transparent8, a3: Wrapped8,
+    b1: Align16, b2: Transparent16, b3: Wrapped16,
+    c1: Align32, c2: Transparent32, c3: Wrapped32,
+) {
+    test_8(a1, a2, a3);
+    test_16(b1, b2, b3);
+    test_32(c1, c2, c3);
+}
diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs
index ecce9201071..3d284148db2 100644
--- a/tests/codegen/slice-indexing.rs
+++ b/tests/codegen/slice-indexing.rs
@@ -32,3 +32,31 @@ pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut
     // CHECK: sub nuw i64
     x.get_unchecked_mut(r)
 }
+
+// CHECK-LABEL: @str_index_by_range(
+#[no_mangle]
+pub fn str_index_by_range(x: &str, r: Range<usize>) -> &str {
+    // CHECK: sub nuw i64
+    &x[r]
+}
+
+// CHECK-LABEL: @str_get_unchecked_by_range(
+#[no_mangle]
+pub unsafe fn str_get_unchecked_by_range(x: &str, r: Range<usize>) -> &str {
+    // CHECK: sub nuw i64
+    x.get_unchecked(r)
+}
+
+// CHECK-LABEL: @str_index_mut_by_range(
+#[no_mangle]
+pub fn str_index_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str {
+    // CHECK: sub nuw i64
+    &mut x[r]
+}
+
+// CHECK-LABEL: @str_get_unchecked_mut_by_range(
+#[no_mangle]
+pub unsafe fn str_get_unchecked_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str {
+    // CHECK: sub nuw i64
+    x.get_unchecked_mut(r)
+}
diff --git a/tests/codegen/step_by-overflow-checks.rs b/tests/codegen/step_by-overflow-checks.rs
new file mode 100644
index 00000000000..43e8514a8b7
--- /dev/null
+++ b/tests/codegen/step_by-overflow-checks.rs
@@ -0,0 +1,26 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+use std::iter::StepBy;
+use std::slice::Iter;
+
+// The constructor for `StepBy` ensures we can never end up needing to do zero
+// checks on denominators, so check that the code isn't emitting panic paths.
+
+// CHECK-LABEL: @step_by_len_std
+#[no_mangle]
+pub fn step_by_len_std(x: &StepBy<Iter<i32>>) -> usize {
+    // CHECK-NOT: div_by_zero
+    // CHECK: udiv
+    // CHECK-NOT: div_by_zero
+    x.len()
+}
+
+// CHECK-LABEL: @step_by_len_naive
+#[no_mangle]
+pub fn step_by_len_naive(x: Iter<i32>, step_minus_one: usize) -> usize {
+    // CHECK: udiv
+    // CHECK: call{{.+}}div_by_zero
+    x.len() / (step_minus_one + 1)
+}
diff --git a/tests/codegen/vecdeque_pop_push.rs b/tests/codegen/vecdeque_pop_push.rs
new file mode 100644
index 00000000000..040d5a279dc
--- /dev/null
+++ b/tests/codegen/vecdeque_pop_push.rs
@@ -0,0 +1,67 @@
+//@ compile-flags: -O
+
+#![crate_type = "lib"]
+
+use std::collections::VecDeque;
+
+#[no_mangle]
+// CHECK-LABEL: @noop_back(
+pub fn noop_back(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_back() {
+        v.push_back(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @noop_front(
+pub fn noop_front(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_front() {
+        v.push_front(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @move_byte_front_to_back(
+pub fn move_byte_front_to_back(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_front() {
+        v.push_back(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @move_byte_back_to_front(
+pub fn move_byte_back_to_front(v: &mut VecDeque<u8>) {
+    // CHECK-NOT: grow
+    // CHECK: tail call void @llvm.assume
+    // CHECK-NOT: grow
+    // CHECK: ret
+    if let Some(x) = v.pop_back() {
+        v.push_front(x);
+    }
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_back_byte(
+pub fn push_back_byte(v: &mut VecDeque<u8>) {
+    // CHECK: call {{.*}}grow
+    v.push_back(3);
+}
+
+#[no_mangle]
+// CHECK-LABEL: @push_front_byte(
+pub fn push_front_byte(v: &mut VecDeque<u8>) {
+    // CHECK: call {{.*}}grow
+    v.push_front(3);
+}
diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
index 76938c14e1e..cb72ad3d253 100644
--- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -1,36 +1,36 @@
 // MIR for `address_of_reborrow` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:8:5: 8:18, inferred_ty: *const [i32; 10]
-| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:10:5: 10:25, inferred_ty: *const dyn std::marker::Send
-| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
-| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
-| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
-| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
-| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
-| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
-| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
-| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
-| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:19:5: 19:18, inferred_ty: *const [i32; 10]
-| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:21:5: 21:25, inferred_ty: *const dyn std::marker::Send
-| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
-| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
-| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
-| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
-| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
-| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
-| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
-| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
-| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:29:5: 29:16, inferred_ty: *mut [i32; 10]
-| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:31:5: 31:23, inferred_ty: *mut dyn std::marker::Send
-| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
-| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
-| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
-| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
-| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
-| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
-| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32]
-| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32]
+| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:8:5: 8:18, inferred_ty: *const [i32; 10]
+| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:10:5: 10:25, inferred_ty: *const dyn std::marker::Send
+| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
+| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
+| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
+| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
+| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
+| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
+| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:19:5: 19:18, inferred_ty: *const [i32; 10]
+| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:21:5: 21:25, inferred_ty: *const dyn std::marker::Send
+| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
+| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
+| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
+| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
+| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
+| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
+| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:29:5: 29:16, inferred_ty: *mut [i32; 10]
+| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:31:5: 31:23, inferred_ty: *mut dyn std::marker::Send
+| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
+| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
+| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
+| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
+| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32]
+| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32]
 |
 fn address_of_reborrow() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
index 5df6633880e..5c0d1e9b93f 100644
--- a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
-| 1: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
+| 0: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
+| 1: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir
index 19a777cb03b..0f7917dbb5c 100644
--- a/tests/mir-opt/building/issue_101867.main.built.after.mir
+++ b/tests/mir-opt/building/issue_101867.main.built.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8>
-| 1: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8>
+| 0: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8>
+| 1: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8>
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
index e07c2b6fa9d..1855bb0787d 100644
--- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
+++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir
@@ -1,10 +1,10 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test
-| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test
-| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
-| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
+| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test
+| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test
+| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
+| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
index 7a374c5675a..4af3ed3e1d1 100644
--- a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
@@ -12,8 +12,6 @@
       let mut _7: isize;
       let _8: u32;
       let _9: u32;
-+     let mut _10: isize;
-+     let mut _11: bool;
       scope 1 {
           debug a => _8;
           debug b => _9;
@@ -29,28 +27,20 @@
           StorageDead(_5);
           StorageDead(_4);
           _7 = discriminant((_3.0: std::option::Option<u32>));
--         switchInt(move _7) -> [1: bb2, otherwise: bb1];
-+         StorageLive(_10);
-+         _10 = discriminant((_3.1: std::option::Option<u32>));
-+         StorageLive(_11);
-+         _11 = Ne(_7, move _10);
-+         StorageDead(_10);
-+         switchInt(move _11) -> [0: bb4, otherwise: bb1];
+          switchInt(move _7) -> [1: bb2, 0: bb1, otherwise: bb5];
       }
   
       bb1: {
-+         StorageDead(_11);
           _0 = const 1_u32;
--         goto -> bb4;
-+         goto -> bb3;
+          goto -> bb4;
       }
   
       bb2: {
--         _6 = discriminant((_3.1: std::option::Option<u32>));
--         switchInt(move _6) -> [1: bb3, otherwise: bb1];
--     }
-- 
--     bb3: {
+          _6 = discriminant((_3.1: std::option::Option<u32>));
+          switchInt(move _6) -> [1: bb3, 0: bb1, otherwise: bb5];
+      }
+  
+      bb3: {
           StorageLive(_8);
           _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
           StorageLive(_9);
@@ -58,19 +48,16 @@
           _0 = const 0_u32;
           StorageDead(_9);
           StorageDead(_8);
--         goto -> bb4;
-+         goto -> bb3;
+          goto -> bb4;
       }
   
--     bb4: {
-+     bb3: {
+      bb4: {
           StorageDead(_3);
           return;
-+     }
-+ 
-+     bb4: {
-+         StorageDead(_11);
-+         switchInt(_7) -> [1: bb2, otherwise: bb1];
+      }
+  
+      bb5: {
+          unreachable;
       }
   }
   
diff --git a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
index 1348bdd739a..7776ff0fde7 100644
--- a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
@@ -13,8 +13,6 @@
       let mut _8: isize;
       let _9: u32;
       let _10: u32;
-+     let mut _11: isize;
-+     let mut _12: bool;
       scope 1 {
           debug a => _9;
           debug b => _10;
@@ -30,33 +28,25 @@
           StorageDead(_5);
           StorageDead(_4);
           _8 = discriminant((_3.0: std::option::Option<u32>));
--         switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1];
-+         StorageLive(_11);
-+         _11 = discriminant((_3.1: std::option::Option<u32>));
-+         StorageLive(_12);
-+         _12 = Ne(_8, move _11);
-+         StorageDead(_11);
-+         switchInt(move _12) -> [0: bb5, otherwise: bb1];
+          switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb7];
       }
   
       bb1: {
-+         StorageDead(_12);
           _0 = const 1_u32;
--         goto -> bb6;
-+         goto -> bb4;
+          goto -> bb6;
       }
   
       bb2: {
--         _6 = discriminant((_3.1: std::option::Option<u32>));
--         switchInt(move _6) -> [1: bb4, otherwise: bb1];
--     }
-- 
--     bb3: {
--         _7 = discriminant((_3.1: std::option::Option<u32>));
--         switchInt(move _7) -> [0: bb5, otherwise: bb1];
--     }
-- 
--     bb4: {
+          _6 = discriminant((_3.1: std::option::Option<u32>));
+          switchInt(move _6) -> [1: bb4, 0: bb1, otherwise: bb7];
+      }
+  
+      bb3: {
+          _7 = discriminant((_3.1: std::option::Option<u32>));
+          switchInt(move _7) -> [0: bb5, 1: bb1, otherwise: bb7];
+      }
+  
+      bb4: {
           StorageLive(_9);
           _9 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
           StorageLive(_10);
@@ -64,26 +54,21 @@
           _0 = const 0_u32;
           StorageDead(_10);
           StorageDead(_9);
--         goto -> bb6;
-+         goto -> bb4;
+          goto -> bb6;
       }
   
--     bb5: {
-+     bb3: {
-          _0 = const 0_u32;
--         goto -> bb6;
-+         goto -> bb4;
+      bb5: {
+          _0 = const 2_u32;
+          goto -> bb6;
       }
   
--     bb6: {
-+     bb4: {
+      bb6: {
           StorageDead(_3);
           return;
-+     }
-+ 
-+     bb5: {
-+         StorageDead(_12);
-+         switchInt(_8) -> [0: bb3, 1: bb2, otherwise: bb1];
+      }
+  
+      bb7: {
+          unreachable;
       }
   }
   
diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
index e058c409cb5..b41e952d80f 100644
--- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
@@ -1,76 +1,107 @@
 - // MIR for `opt3` before EarlyOtherwiseBranch
 + // MIR for `opt3` after EarlyOtherwiseBranch
   
-  fn opt3(_1: Option<u32>, _2: Option<bool>) -> u32 {
+  fn opt3(_1: Option2<u32>, _2: Option2<bool>) -> u32 {
       debug x => _1;
       debug y => _2;
       let mut _0: u32;
-      let mut _3: (std::option::Option<u32>, std::option::Option<bool>);
-      let mut _4: std::option::Option<u32>;
-      let mut _5: std::option::Option<bool>;
+      let mut _3: (Option2<u32>, Option2<bool>);
+      let mut _4: Option2<u32>;
+      let mut _5: Option2<bool>;
       let mut _6: isize;
       let mut _7: isize;
-      let _8: u32;
-      let _9: bool;
-+     let mut _10: isize;
-+     let mut _11: bool;
+      let mut _8: isize;
+      let mut _9: isize;
+      let _10: u32;
+      let _11: bool;
++     let mut _12: isize;
++     let mut _13: bool;
       scope 1 {
-          debug a => _8;
-          debug b => _9;
+          debug a => _10;
+          debug b => _11;
       }
   
       bb0: {
           StorageLive(_3);
           StorageLive(_4);
-          _4 = _1;
+          _4 = move _1;
           StorageLive(_5);
-          _5 = _2;
+          _5 = move _2;
           _3 = (move _4, move _5);
           StorageDead(_5);
           StorageDead(_4);
-          _7 = discriminant((_3.0: std::option::Option<u32>));
--         switchInt(move _7) -> [1: bb2, otherwise: bb1];
-+         StorageLive(_10);
-+         _10 = discriminant((_3.1: std::option::Option<bool>));
-+         StorageLive(_11);
-+         _11 = Ne(_7, move _10);
-+         StorageDead(_10);
-+         switchInt(move _11) -> [0: bb4, otherwise: bb1];
+          _9 = discriminant((_3.0: Option2<u32>));
+-         switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
++         StorageLive(_12);
++         _12 = discriminant((_3.1: Option2<bool>));
++         StorageLive(_13);
++         _13 = Ne(_9, move _12);
++         StorageDead(_12);
++         switchInt(move _13) -> [0: bb7, otherwise: bb1];
       }
   
       bb1: {
-+         StorageDead(_11);
++         StorageDead(_13);
           _0 = const 1_u32;
--         goto -> bb4;
-+         goto -> bb3;
+-         goto -> bb8;
++         goto -> bb5;
       }
   
       bb2: {
--         _6 = discriminant((_3.1: std::option::Option<bool>));
--         switchInt(move _6) -> [1: bb3, otherwise: bb1];
+-         _6 = discriminant((_3.1: Option2<bool>));
+-         switchInt(move _6) -> [0: bb5, otherwise: bb1];
 -     }
 - 
 -     bb3: {
-          StorageLive(_8);
-          _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
-          StorageLive(_9);
-          _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool);
+-         _7 = discriminant((_3.1: Option2<bool>));
+-         switchInt(move _7) -> [1: bb6, otherwise: bb1];
+-     }
+- 
+-     bb4: {
+-         _8 = discriminant((_3.1: Option2<bool>));
+-         switchInt(move _8) -> [2: bb7, otherwise: bb1];
+-     }
+- 
+-     bb5: {
+          StorageLive(_10);
+          _10 = (((_3.0: Option2<u32>) as Some).0: u32);
+          StorageLive(_11);
+          _11 = (((_3.1: Option2<bool>) as Some).0: bool);
           _0 = const 0_u32;
-          StorageDead(_9);
-          StorageDead(_8);
--         goto -> bb4;
-+         goto -> bb3;
+          StorageDead(_11);
+          StorageDead(_10);
+-         goto -> bb8;
++         goto -> bb5;
       }
   
--     bb4: {
+-     bb6: {
 +     bb3: {
+          _0 = const 2_u32;
+-         goto -> bb8;
++         goto -> bb5;
+      }
+  
+-     bb7: {
++     bb4: {
+          _0 = const 3_u32;
+-         goto -> bb8;
++         goto -> bb5;
+      }
+  
+-     bb8: {
++     bb5: {
           StorageDead(_3);
           return;
+      }
+  
+-     bb9: {
++     bb6: {
+          unreachable;
 +     }
 + 
-+     bb4: {
-+         StorageDead(_11);
-+         switchInt(_7) -> [1: bb2, otherwise: bb1];
++     bb7: {
++         StorageDead(_13);
++         switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6];
       }
   }
   
diff --git a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff
new file mode 100644
index 00000000000..18dea56f430
--- /dev/null
+++ b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff
@@ -0,0 +1,107 @@
+- // MIR for `opt4` before EarlyOtherwiseBranch
++ // MIR for `opt4` after EarlyOtherwiseBranch
+  
+  fn opt4(_1: Option2<u32>, _2: Option2<u32>) -> u32 {
+      debug x => _1;
+      debug y => _2;
+      let mut _0: u32;
+      let mut _3: (Option2<u32>, Option2<u32>);
+      let mut _4: Option2<u32>;
+      let mut _5: Option2<u32>;
+      let mut _6: isize;
+      let mut _7: isize;
+      let mut _8: isize;
+      let mut _9: isize;
+      let _10: u32;
+      let _11: u32;
++     let mut _12: isize;
++     let mut _13: bool;
+      scope 1 {
+          debug a => _10;
+          debug b => _11;
+      }
+  
+      bb0: {
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = move _1;
+          StorageLive(_5);
+          _5 = move _2;
+          _3 = (move _4, move _5);
+          StorageDead(_5);
+          StorageDead(_4);
+          _9 = discriminant((_3.0: Option2<u32>));
+-         switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
++         StorageLive(_12);
++         _12 = discriminant((_3.1: Option2<u32>));
++         StorageLive(_13);
++         _13 = Ne(_9, move _12);
++         StorageDead(_12);
++         switchInt(move _13) -> [0: bb7, otherwise: bb1];
+      }
+  
+      bb1: {
++         StorageDead(_13);
+          _0 = const 1_u32;
+-         goto -> bb8;
++         goto -> bb5;
+      }
+  
+      bb2: {
+-         _6 = discriminant((_3.1: Option2<u32>));
+-         switchInt(move _6) -> [0: bb5, otherwise: bb1];
+-     }
+- 
+-     bb3: {
+-         _7 = discriminant((_3.1: Option2<u32>));
+-         switchInt(move _7) -> [1: bb6, otherwise: bb1];
+-     }
+- 
+-     bb4: {
+-         _8 = discriminant((_3.1: Option2<u32>));
+-         switchInt(move _8) -> [2: bb7, otherwise: bb1];
+-     }
+- 
+-     bb5: {
+          StorageLive(_10);
+          _10 = (((_3.0: Option2<u32>) as Some).0: u32);
+          StorageLive(_11);
+          _11 = (((_3.1: Option2<u32>) as Some).0: u32);
+          _0 = const 0_u32;
+          StorageDead(_11);
+          StorageDead(_10);
+-         goto -> bb8;
++         goto -> bb5;
+      }
+  
+-     bb6: {
++     bb3: {
+          _0 = const 2_u32;
+-         goto -> bb8;
++         goto -> bb5;
+      }
+  
+-     bb7: {
++     bb4: {
+          _0 = const 3_u32;
+-         goto -> bb8;
++         goto -> bb5;
+      }
+  
+-     bb8: {
++     bb5: {
+          StorageDead(_3);
+          return;
+      }
+  
+-     bb9: {
++     bb6: {
+          unreachable;
++     }
++ 
++     bb7: {
++         StorageDead(_13);
++         switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6];
+      }
+  }
+  
diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs
index c984c271ccd..bfeb1f7bbc6 100644
--- a/tests/mir-opt/early_otherwise_branch.rs
+++ b/tests/mir-opt/early_otherwise_branch.rs
@@ -1,27 +1,79 @@
-// skip-filecheck
 //@ unit-test: EarlyOtherwiseBranch
+//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching
+
+enum Option2<T> {
+    Some(T),
+    None,
+    Other,
+}
+
+// We can't optimize it because y may be an invalid value.
 // EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>) -> u32 {
+    // CHECK-LABEL: fn opt1(
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK-NOT: Ne
+    // CHECK-NOT: discriminant
+    // CHECK: switchInt(move [[LOCAL1]]) -> [
+    // CHECK-NEXT: }
     match (x, y) {
         (Some(a), Some(b)) => 0,
         _ => 1,
     }
 }
 
+// FIXME: `switchInt` will have three targets after `UnreachableEnumBranching`,
+// otherwise is unreachable. We can consume the UB fact to transform back to if else pattern.
 // EMIT_MIR early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
 fn opt2(x: Option<u32>, y: Option<u32>) -> u32 {
+    // CHECK-LABEL: fn opt2(
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK-NOT: Ne
+    // CHECK-NOT: discriminant
+    // CHECK: switchInt(move [[LOCAL1]]) -> [
+    // CHECK-NEXT: }
     match (x, y) {
         (Some(a), Some(b)) => 0,
-        (None, None) => 0,
+        (None, None) => 2,
         _ => 1,
     }
 }
 
 // optimize despite different types
 // EMIT_MIR early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
-fn opt3(x: Option<u32>, y: Option<bool>) -> u32 {
+fn opt3(x: Option2<u32>, y: Option2<bool>) -> u32 {
+    // CHECK-LABEL: fn opt3(
+    // CHECK: let mut [[CMP_LOCAL:_.*]]: bool;
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}});
+    // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]);
+    // CHECK: switchInt(move [[CMP_LOCAL]]) -> [
+    // CHECK-NEXT: }
     match (x, y) {
-        (Some(a), Some(b)) => 0,
+        (Option2::Some(a), Option2::Some(b)) => 0,
+        (Option2::None, Option2::None) => 2,
+        (Option2::Other, Option2::Other) => 3,
+        _ => 1,
+    }
+}
+
+// EMIT_MIR early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff
+fn opt4(x: Option2<u32>, y: Option2<u32>) -> u32 {
+    // CHECK-LABEL: fn opt4(
+    // CHECK: let mut [[CMP_LOCAL:_.*]]: bool;
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}});
+    // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]);
+    // CHECK: switchInt(move [[CMP_LOCAL]]) -> [
+    // CHECK-NEXT: }
+    match (x, y) {
+        (Option2::Some(a), Option2::Some(b)) => 0,
+        (Option2::None, Option2::None) => 2,
+        (Option2::Other, Option2::Other) => 3,
         _ => 1,
     }
 }
@@ -29,5 +81,6 @@ fn opt3(x: Option<u32>, y: Option<bool>) -> u32 {
 fn main() {
     opt1(None, Some(0));
     opt2(None, Some(0));
-    opt3(None, Some(false));
+    opt3(Option2::None, Option2::Some(false));
+    opt4(Option2::None, Option2::Some(0));
 }
diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
index f98d68e6ffc..4c3c717b522 100644
--- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
@@ -13,17 +13,15 @@
       let mut _8: isize;
       let mut _9: isize;
       let mut _10: isize;
-      let _11: u32;
-      let _12: u32;
+      let mut _11: isize;
+      let mut _12: isize;
       let _13: u32;
-+     let mut _14: isize;
-+     let mut _15: bool;
-+     let mut _16: isize;
-+     let mut _17: bool;
+      let _14: u32;
+      let _15: u32;
       scope 1 {
-          debug a => _11;
-          debug b => _12;
-          debug c => _13;
+          debug a => _13;
+          debug b => _14;
+          debug c => _15;
       }
   
       bb0: {
@@ -38,60 +36,61 @@
           StorageDead(_7);
           StorageDead(_6);
           StorageDead(_5);
-          _10 = discriminant((_4.0: std::option::Option<u32>));
--         switchInt(move _10) -> [1: bb2, otherwise: bb1];
-+         StorageLive(_14);
-+         _14 = discriminant((_4.1: std::option::Option<u32>));
-+         StorageLive(_15);
-+         _15 = Ne(_10, move _14);
-+         StorageDead(_14);
-+         switchInt(move _15) -> [0: bb5, otherwise: bb1];
+          _12 = discriminant((_4.0: std::option::Option<u32>));
+          switchInt(move _12) -> [0: bb4, 1: bb2, otherwise: bb9];
       }
   
       bb1: {
-+         StorageDead(_17);
-+         StorageDead(_15);
           _0 = const 1_u32;
--         goto -> bb5;
-+         goto -> bb4;
+          goto -> bb8;
       }
   
       bb2: {
--         _9 = discriminant((_4.1: std::option::Option<u32>));
--         switchInt(move _9) -> [1: bb3, otherwise: bb1];
--     }
-- 
--     bb3: {
+          _9 = discriminant((_4.1: std::option::Option<u32>));
+          switchInt(move _9) -> [1: bb3, 0: bb1, otherwise: bb9];
+      }
+  
+      bb3: {
           _8 = discriminant((_4.2: std::option::Option<u32>));
--         switchInt(move _8) -> [1: bb4, otherwise: bb1];
-+         switchInt(move _8) -> [1: bb3, otherwise: bb1];
+          switchInt(move _8) -> [1: bb6, 0: bb1, otherwise: bb9];
+      }
+  
+      bb4: {
+          _11 = discriminant((_4.1: std::option::Option<u32>));
+          switchInt(move _11) -> [0: bb5, 1: bb1, otherwise: bb9];
+      }
+  
+      bb5: {
+          _10 = discriminant((_4.2: std::option::Option<u32>));
+          switchInt(move _10) -> [0: bb7, 1: bb1, otherwise: bb9];
       }
   
--     bb4: {
-+     bb3: {
-          StorageLive(_11);
-          _11 = (((_4.0: std::option::Option<u32>) as Some).0: u32);
-          StorageLive(_12);
-          _12 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
+      bb6: {
           StorageLive(_13);
-          _13 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
+          _13 = (((_4.0: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_14);
+          _14 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
+          StorageLive(_15);
+          _15 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
           _0 = const 0_u32;
+          StorageDead(_15);
+          StorageDead(_14);
           StorageDead(_13);
-          StorageDead(_12);
-          StorageDead(_11);
--         goto -> bb5;
-+         goto -> bb4;
+          goto -> bb8;
+      }
+  
+      bb7: {
+          _0 = const 2_u32;
+          goto -> bb8;
       }
   
--     bb5: {
-+     bb4: {
+      bb8: {
           StorageDead(_4);
           return;
-+     }
-+ 
-+     bb5: {
-+         StorageDead(_15);
-+         switchInt(_10) -> [1: bb2, otherwise: bb1];
+      }
+  
+      bb9: {
+          unreachable;
       }
   }
   
diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff
new file mode 100644
index 00000000000..0ea7a10baaa
--- /dev/null
+++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff
@@ -0,0 +1,141 @@
+- // MIR for `opt2` before EarlyOtherwiseBranch
++ // MIR for `opt2` after EarlyOtherwiseBranch
+  
+  fn opt2(_1: Option2<u32>, _2: Option2<u32>, _3: Option2<u32>) -> u32 {
+      debug x => _1;
+      debug y => _2;
+      debug z => _3;
+      let mut _0: u32;
+      let mut _4: (Option2<u32>, Option2<u32>, Option2<u32>);
+      let mut _5: Option2<u32>;
+      let mut _6: Option2<u32>;
+      let mut _7: Option2<u32>;
+      let mut _8: isize;
+      let mut _9: isize;
+      let mut _10: isize;
+      let mut _11: isize;
+      let mut _12: isize;
+      let mut _13: isize;
+      let mut _14: isize;
+      let _15: u32;
+      let _16: u32;
+      let _17: u32;
++     let mut _18: isize;
++     let mut _19: bool;
+      scope 1 {
+          debug a => _15;
+          debug b => _16;
+          debug c => _17;
+      }
+  
+      bb0: {
+          StorageLive(_4);
+          StorageLive(_5);
+          _5 = move _1;
+          StorageLive(_6);
+          _6 = move _2;
+          StorageLive(_7);
+          _7 = move _3;
+          _4 = (move _5, move _6, move _7);
+          StorageDead(_7);
+          StorageDead(_6);
+          StorageDead(_5);
+          _14 = discriminant((_4.0: Option2<u32>));
+-         switchInt(move _14) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb12];
++         StorageLive(_18);
++         _18 = discriminant((_4.1: Option2<u32>));
++         StorageLive(_19);
++         _19 = Ne(_14, move _18);
++         StorageDead(_18);
++         switchInt(move _19) -> [0: bb10, otherwise: bb1];
+      }
+  
+      bb1: {
++         StorageDead(_19);
+          _0 = const 1_u32;
+-         goto -> bb11;
++         goto -> bb8;
+      }
+  
+      bb2: {
+-         _9 = discriminant((_4.1: Option2<u32>));
+-         switchInt(move _9) -> [0: bb3, otherwise: bb1];
+-     }
+- 
+-     bb3: {
+          _8 = discriminant((_4.2: Option2<u32>));
+-         switchInt(move _8) -> [0: bb8, otherwise: bb1];
++         switchInt(move _8) -> [0: bb5, otherwise: bb1];
+      }
+  
+-     bb4: {
+-         _11 = discriminant((_4.1: Option2<u32>));
+-         switchInt(move _11) -> [1: bb5, otherwise: bb1];
+-     }
+- 
+-     bb5: {
++     bb3: {
+          _10 = discriminant((_4.2: Option2<u32>));
+-         switchInt(move _10) -> [1: bb9, otherwise: bb1];
++         switchInt(move _10) -> [1: bb6, otherwise: bb1];
+      }
+  
+-     bb6: {
+-         _13 = discriminant((_4.1: Option2<u32>));
+-         switchInt(move _13) -> [2: bb7, otherwise: bb1];
+-     }
+- 
+-     bb7: {
++     bb4: {
+          _12 = discriminant((_4.2: Option2<u32>));
+-         switchInt(move _12) -> [2: bb10, otherwise: bb1];
++         switchInt(move _12) -> [2: bb7, otherwise: bb1];
+      }
+  
+-     bb8: {
++     bb5: {
+          StorageLive(_15);
+          _15 = (((_4.0: Option2<u32>) as Some).0: u32);
+          StorageLive(_16);
+          _16 = (((_4.1: Option2<u32>) as Some).0: u32);
+          StorageLive(_17);
+          _17 = (((_4.2: Option2<u32>) as Some).0: u32);
+          _0 = const 0_u32;
+          StorageDead(_17);
+          StorageDead(_16);
+          StorageDead(_15);
+-         goto -> bb11;
++         goto -> bb8;
+      }
+  
+-     bb9: {
++     bb6: {
+          _0 = const 2_u32;
+-         goto -> bb11;
++         goto -> bb8;
+      }
+  
+-     bb10: {
++     bb7: {
+          _0 = const 3_u32;
+-         goto -> bb11;
++         goto -> bb8;
+      }
+  
+-     bb11: {
++     bb8: {
+          StorageDead(_4);
+          return;
+      }
+  
+-     bb12: {
++     bb9: {
+          unreachable;
++     }
++ 
++     bb10: {
++         StorageDead(_19);
++         switchInt(_14) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
+      }
+  }
+  
diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs b/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs
index 32081347558..2d215621bbd 100644
--- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs
+++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs
@@ -1,14 +1,49 @@
-// skip-filecheck
 //@ unit-test: EarlyOtherwiseBranch
+//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching
 
+enum Option2<T> {
+    Some(T),
+    None,
+    Other,
+}
+
+// FIXME: `switchInt` will have three targets after `UnreachableEnumBranching`,
+// otherwise is unreachable. We can consume the UB fact to transform back to if else pattern.
 // EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>, z: Option<u32>) -> u32 {
+    // CHECK-LABEL: fn opt1(
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK-NOT: Ne
+    // CHECK-NOT: discriminant
+    // CHECK: switchInt(move [[LOCAL1]]) -> [
+    // CHECK-NEXT: }
     match (x, y, z) {
         (Some(a), Some(b), Some(c)) => 0,
+        (None, None, None) => 2,
+        _ => 1,
+    }
+}
+
+// EMIT_MIR early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff
+fn opt2(x: Option2<u32>, y: Option2<u32>, z: Option2<u32>) -> u32 {
+    // CHECK-LABEL: fn opt2(
+    // CHECK: let mut [[CMP_LOCAL:_.*]]: bool;
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}});
+    // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]);
+    // CHECK: switchInt(move [[CMP_LOCAL]]) -> [
+    // CHECK-NEXT: }
+    match (x, y, z) {
+        (Option2::Some(a), Option2::Some(b), Option2::Some(c)) => 0,
+        (Option2::None, Option2::None, Option2::None) => 2,
+        (Option2::Other, Option2::Other, Option2::Other) => 3,
         _ => 1,
     }
 }
 
 fn main() {
     opt1(None, Some(0), None);
+    opt2(Option2::None, Option2::Some(0), Option2::None);
 }
diff --git a/tests/mir-opt/early_otherwise_branch_68867.rs b/tests/mir-opt/early_otherwise_branch_68867.rs
index 805d21533c5..59bc19ceecc 100644
--- a/tests/mir-opt/early_otherwise_branch_68867.rs
+++ b/tests/mir-opt/early_otherwise_branch_68867.rs
@@ -1,5 +1,5 @@
-// skip-filecheck
 //@ unit-test: EarlyOtherwiseBranch
+//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching
 
 // FIXME: This test was broken by the derefer change.
 
@@ -19,6 +19,13 @@ pub extern "C" fn try_sum(
     x: &ViewportPercentageLength,
     other: &ViewportPercentageLength,
 ) -> Result<ViewportPercentageLength, ()> {
+    // CHECK-LABEL: fn try_sum(
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK-NOT: Ne
+    // CHECK-NOT: discriminant
+    // CHECK: switchInt(move [[LOCAL1]]) -> [
+    // CHECK-NEXT: }
     use self::ViewportPercentageLength::*;
     Ok(match (x, other) {
         (&Vw(one), &Vw(other)) => Vw(one + other),
diff --git a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
index a5b5659a31a..de12fe8f120 100644
--- a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
@@ -78,7 +78,7 @@
           StorageDead(_5);
           _34 = deref_copy (_4.0: &ViewportPercentageLength);
           _11 = discriminant((*_34));
-          switchInt(move _11) -> [0: bb2, 1: bb3, 2: bb4, 3: bb5, otherwise: bb1];
+          switchInt(move _11) -> [0: bb2, 1: bb3, 2: bb4, 3: bb5, otherwise: bb12];
       }
   
       bb1: {
@@ -213,5 +213,9 @@
       bb11: {
           return;
       }
+  
+      bb12: {
+          unreachable;
+      }
   }
   
diff --git a/tests/mir-opt/early_otherwise_branch_noopt.rs b/tests/mir-opt/early_otherwise_branch_noopt.rs
index 648089e2df1..6b48393e6b9 100644
--- a/tests/mir-opt/early_otherwise_branch_noopt.rs
+++ b/tests/mir-opt/early_otherwise_branch_noopt.rs
@@ -1,11 +1,18 @@
-// skip-filecheck
 //@ unit-test: EarlyOtherwiseBranch
+//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching
 
 // must not optimize as it does not follow the pattern of
 // left and right hand side being the same variant
 
 // EMIT_MIR early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff
 fn noopt1(x: Option<u32>, y: Option<u32>) -> u32 {
+    // CHECK-LABEL: fn noopt1(
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK-NOT: Ne
+    // CHECK-NOT: discriminant
+    // CHECK: switchInt(move [[LOCAL1]]) -> [
+    // CHECK-NEXT: }
     match (x, y) {
         (Some(a), Some(b)) => 0,
         (Some(a), None) => 1,
diff --git a/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
index b24ff6ec74b..8eab59823f4 100644
--- a/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
@@ -14,7 +14,7 @@
   
       bb0: {
           _3 = discriminant(_1);
-          switchInt(move _3) -> [1: bb2, otherwise: bb1];
+          switchInt(move _3) -> [1: bb2, 0: bb1, otherwise: bb6];
       }
   
       bb1: {
@@ -24,7 +24,7 @@
   
       bb2: {
           _4 = discriminant((*_2));
-          switchInt(move _4) -> [1: bb4, otherwise: bb3];
+          switchInt(move _4) -> [1: bb4, 0: bb3, otherwise: bb6];
       }
   
       bb3: {
@@ -43,5 +43,9 @@
       bb5: {
           return;
       }
+  
+      bb6: {
+          unreachable;
+      }
   }
   
diff --git a/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
index c3ea975ce03..6a4c947b882 100644
--- a/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
@@ -12,13 +12,13 @@
   
       bb0: {
           _3 = discriminant((*_1));
-          switchInt(move _3) -> [1: bb1, otherwise: bb3];
+          switchInt(move _3) -> [1: bb1, 0: bb3, otherwise: bb5];
       }
   
       bb1: {
           _4 = deref_copy (((*_1) as Some).0: &E<'_>);
           _2 = discriminant((*_4));
-          switchInt(move _2) -> [1: bb2, otherwise: bb3];
+          switchInt(move _2) -> [1: bb2, 0: bb3, otherwise: bb5];
       }
   
       bb2: {
@@ -34,5 +34,9 @@
       bb4: {
           return;
       }
+  
+      bb5: {
+          unreachable;
+      }
   }
   
diff --git a/tests/mir-opt/early_otherwise_branch_soundness.rs b/tests/mir-opt/early_otherwise_branch_soundness.rs
index b4f5821c420..74a2af884c0 100644
--- a/tests/mir-opt/early_otherwise_branch_soundness.rs
+++ b/tests/mir-opt/early_otherwise_branch_soundness.rs
@@ -1,5 +1,5 @@
-// skip-filecheck
 //@ unit-test: EarlyOtherwiseBranch
+//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching
 
 // Tests various cases that the `early_otherwise_branch` opt should *not* optimize
 
@@ -11,12 +11,26 @@ enum E<'a> {
 
 // EMIT_MIR early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
 fn no_downcast(e: &E) -> u32 {
+    // CHECK-LABEL: fn no_downcast(
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK-NOT: Ne
+    // CHECK-NOT: discriminant
+    // CHECK: switchInt(move [[LOCAL1]]) -> [
+    // CHECK-NEXT: }
     if let E::Some(E::Some(_)) = e { 1 } else { 2 }
 }
 
 // SAFETY: if `a` is `Some`, `b` must point to a valid, initialized value
 // EMIT_MIR early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
 unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 {
+    // CHECK-LABEL: fn no_deref_ptr(
+    // CHECK: bb0: {
+    // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}});
+    // CHECK-NOT: Ne
+    // CHECK-NOT: discriminant
+    // CHECK: switchInt(move [[LOCAL1]]) -> [
+    // CHECK-NEXT: }
     match a {
         // `*b` being correct depends on `a == Some(_)`
         Some(_) => match *b {
diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir
index ae0dc9a0b6a..e8ad5cd8d16 100644
--- a/tests/mir-opt/issue_72181_1.main.built.after.mir
+++ b/tests/mir-opt/issue_72181_1.main.built.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void
-| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void
+| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void
+| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
index c8039dc4735..0b0bac73e9f 100644
--- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
index c8039dc4735..0b0bac73e9f 100644
--- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir
+++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after built
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
 |
 fn main() -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..31ce51dc6de
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff
@@ -0,0 +1,47 @@
+- // MIR for `match_i128_u128` before MatchBranchSimplification
++ // MIR for `match_i128_u128` after MatchBranchSimplification
+  
+  fn match_i128_u128(_1: EnumAi128) -> u128 {
+      debug i => _1;
+      let mut _0: u128;
+      let mut _2: i128;
++     let mut _3: i128;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [1: bb3, 2: bb4, 3: bb5, 340282366920938463463374607431768211455: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const core::num::<impl u128>::MAX;
+-         goto -> bb6;
+-     }
+- 
+-     bb3: {
+-         _0 = const 1_u128;
+-         goto -> bb6;
+-     }
+- 
+-     bb4: {
+-         _0 = const 2_u128;
+-         goto -> bb6;
+-     }
+- 
+-     bb5: {
+-         _0 = const 3_u128;
+-         goto -> bb6;
+-     }
+- 
+-     bb6: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u128 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..e1b537b1b71
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_i16_i8` before MatchBranchSimplification
++ // MIR for `match_i16_i8` after MatchBranchSimplification
+  
+  fn match_i16_i8(_1: EnumAi16) -> i8 {
+      debug i => _1;
+      let mut _0: i8;
+      let mut _2: i16;
++     let mut _3: i16;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [65535: bb3, 2: bb4, 65533: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const -3_i8;
+-         goto -> bb5;
+-     }
+- 
+-     bb3: {
+-         _0 = const -1_i8;
+-         goto -> bb5;
+-     }
+- 
+-     bb4: {
+-         _0 = const 2_i8;
+-         goto -> bb5;
+-     }
+- 
+-     bb5: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i8 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..cabc5a44cd8
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_i8_i16` before MatchBranchSimplification
++ // MIR for `match_i8_i16` after MatchBranchSimplification
+  
+  fn match_i8_i16(_1: EnumAi8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: i8;
++     let mut _3: i8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const -3_i16;
+-         goto -> bb5;
+-     }
+- 
+-     bb3: {
+-         _0 = const -1_i16;
+-         goto -> bb5;
+-     }
+- 
+-     bb4: {
+-         _0 = const 2_i16;
+-         goto -> bb5;
+-     }
+- 
+-     bb5: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i16 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..b0217792294
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff
@@ -0,0 +1,37 @@
+- // MIR for `match_i8_i16_failed` before MatchBranchSimplification
++ // MIR for `match_i8_i16_failed` after MatchBranchSimplification
+  
+  fn match_i8_i16_failed(_1: EnumAi8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: i8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 3_i16;
+          goto -> bb5;
+      }
+  
+      bb3: {
+          _0 = const -1_i16;
+          goto -> bb5;
+      }
+  
+      bb4: {
+          _0 = const 2_i16;
+          goto -> bb5;
+      }
+  
+      bb5: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..9ee01a87a91
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff
@@ -0,0 +1,37 @@
+- // MIR for `match_u8_i16` before MatchBranchSimplification
++ // MIR for `match_u8_i16` after MatchBranchSimplification
+  
+  fn match_u8_i16(_1: EnumAu8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: u8;
++     let mut _3: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 2_i16;
+-         goto -> bb4;
+-     }
+- 
+-     bb3: {
+-         _0 = const 1_i16;
+-         goto -> bb4;
+-     }
+- 
+-     bb4: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i16 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..3333cd765a8
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff
@@ -0,0 +1,26 @@
+- // MIR for `match_u8_i16_2` before MatchBranchSimplification
++ // MIR for `match_u8_i16_2` after MatchBranchSimplification
+  
+  fn match_u8_i16_2(_1: EnumAu8) -> i16 {
+      let mut _0: i16;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(_2) -> [1: bb3, 2: bb1, otherwise: bb2];
+      }
+  
+      bb1: {
+          _0 = const 2_i16;
+          goto -> bb3;
+      }
+  
+      bb2: {
+          unreachable;
+      }
+  
+      bb3: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..6da19e46dab
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff
@@ -0,0 +1,32 @@
+- // MIR for `match_u8_i16_failed` before MatchBranchSimplification
++ // MIR for `match_u8_i16_failed` after MatchBranchSimplification
+  
+  fn match_u8_i16_failed(_1: EnumAu8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          unreachable;
+      }
+  
+      bb2: {
+          _0 = const 3_i16;
+          goto -> bb4;
+      }
+  
+      bb3: {
+          _0 = const 1_i16;
+          goto -> bb4;
+      }
+  
+      bb4: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..8fa497fe890
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff
@@ -0,0 +1,31 @@
+- // MIR for `match_u8_i16_fallback` before MatchBranchSimplification
++ // MIR for `match_u8_i16_fallback` after MatchBranchSimplification
+  
+  fn match_u8_i16_fallback(_1: u8) -> i16 {
+      debug i => _1;
+      let mut _0: i16;
+  
+      bb0: {
+          switchInt(_1) -> [1: bb2, 2: bb3, otherwise: bb1];
+      }
+  
+      bb1: {
+          _0 = const 3_i16;
+          goto -> bb4;
+      }
+  
+      bb2: {
+          _0 = const 1_i16;
+          goto -> bb4;
+      }
+  
+      bb3: {
+          _0 = const 2_i16;
+          goto -> bb4;
+      }
+  
+      bb4: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..aa9fcc60a3e
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff
@@ -0,0 +1,42 @@
+- // MIR for `match_u8_u16` before MatchBranchSimplification
++ // MIR for `match_u8_u16` after MatchBranchSimplification
+  
+  fn match_u8_u16(_1: EnumBu8) -> u16 {
+      debug i => _1;
+      let mut _0: u16;
+      let mut _2: u8;
++     let mut _3: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+-         switchInt(move _2) -> [1: bb3, 2: bb4, 5: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 5_u16;
+-         goto -> bb5;
+-     }
+- 
+-     bb3: {
+-         _0 = const 1_u16;
+-         goto -> bb5;
+-     }
+- 
+-     bb4: {
+-         _0 = const 2_u16;
+-         goto -> bb5;
+-     }
+- 
+-     bb5: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u16 (IntToInt);
++         StorageDead(_3);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff
new file mode 100644
index 00000000000..b47de6a52b7
--- /dev/null
+++ b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff
@@ -0,0 +1,37 @@
+- // MIR for `match_u8_u16_2` before MatchBranchSimplification
++ // MIR for `match_u8_u16_2` after MatchBranchSimplification
+  
+  fn match_u8_u16_2(_1: EnumBu8) -> i16 {
+      let mut _0: i16;
+      let mut _2: u8;
+  
+      bb0: {
+          _2 = discriminant(_1);
+          switchInt(_2) -> [1: bb1, 2: bb2, 5: bb3, otherwise: bb4];
+      }
+  
+      bb1: {
+          _0 = const 1_i16;
+          goto -> bb5;
+      }
+  
+      bb2: {
+          _0 = const 2_i16;
+          goto -> bb5;
+      }
+  
+      bb3: {
+          _0 = const 5_i16;
+          _0 = const 5_i16;
+          goto -> bb5;
+      }
+  
+      bb4: {
+          unreachable;
+      }
+  
+      bb5: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs
index 4bf14e5a7bd..ca3e5f747d1 100644
--- a/tests/mir-opt/matches_reduce_branches.rs
+++ b/tests/mir-opt/matches_reduce_branches.rs
@@ -1,18 +1,28 @@
-// skip-filecheck
 //@ unit-test: MatchBranchSimplification
 
+#![feature(repr128)]
+#![feature(core_intrinsics)]
+#![feature(custom_mir)]
 
-// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
-// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
-// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
+use std::intrinsics::mir::*;
 
+// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff
 fn foo(bar: Option<()>) {
+    // CHECK-LABEL: fn foo(
+    // CHECK: = Eq(
+    // CHECK: switchInt
+    // CHECK-NOT: switchInt
     if matches!(bar, None) {
         ()
     }
 }
 
+// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff
 fn bar(i: i32) -> (bool, bool, bool, bool) {
+    // CHECK-LABEL: fn bar(
+    // CHECK: = Ne(
+    // CHECK: = Eq(
+    // CHECK-NOT: switchInt
     let a;
     let b;
     let c;
@@ -38,7 +48,10 @@ fn bar(i: i32) -> (bool, bool, bool, bool) {
     (a, b, c, d)
 }
 
+// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff
 fn match_nested_if() -> bool {
+    // CHECK-LABEL: fn match_nested_if(
+    // CHECK-NOT: switchInt
     let val = match () {
         () if if if if true { true } else { false } { true } else { false } {
             true
@@ -53,9 +66,221 @@ fn match_nested_if() -> bool {
     val
 }
 
+#[repr(u8)]
+enum EnumAu8 {
+    A = 1,
+    B = 2,
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff
+fn match_u8_i16(i: EnumAu8) -> i16 {
+    // CHECK-LABEL: fn match_u8_i16(
+    // CHECK-NOT: switchInt
+    // CHECK: _0 = _3 as i16 (IntToInt);
+    // CHECH: return
+    match i {
+        EnumAu8::A => 1,
+        EnumAu8::B => 2,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff
+// Check for different instruction lengths
+#[custom_mir(dialect = "built")]
+fn match_u8_i16_2(i: EnumAu8) -> i16 {
+    // CHECK-LABEL: fn match_u8_i16_2(
+    // CHECK: switchInt
+    mir!(
+        {
+            let a = Discriminant(i);
+            match a {
+                1 => bb1,
+                2 => bb2,
+                _ => unreachable_bb,
+            }
+        }
+        bb1 = {
+            Goto(ret)
+        }
+        bb2 = {
+            RET = 2;
+            Goto(ret)
+        }
+        unreachable_bb = {
+            Unreachable()
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff
+fn match_u8_i16_failed(i: EnumAu8) -> i16 {
+    // CHECK-LABEL: fn match_u8_i16_failed(
+    // CHECK: switchInt
+    match i {
+        EnumAu8::A => 1,
+        EnumAu8::B => 3,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff
+fn match_u8_i16_fallback(i: u8) -> i16 {
+    // CHECK-LABEL: fn match_u8_i16_fallback(
+    // CHECK: switchInt
+    match i {
+        1 => 1,
+        2 => 2,
+        _ => 3,
+    }
+}
+
+#[repr(u8)]
+enum EnumBu8 {
+    A = 1,
+    B = 2,
+    C = 5,
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff
+fn match_u8_u16(i: EnumBu8) -> u16 {
+    // CHECK-LABEL: fn match_u8_u16(
+    // CHECK-NOT: switchInt
+    // CHECK: _0 = _3 as u16 (IntToInt);
+    // CHECH: return
+    match i {
+        EnumBu8::A => 1,
+        EnumBu8::B => 2,
+        EnumBu8::C => 5,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff
+// Check for different instruction lengths
+#[custom_mir(dialect = "built")]
+fn match_u8_u16_2(i: EnumBu8) -> i16 {
+    // CHECK-LABEL: fn match_u8_u16_2(
+    // CHECK: switchInt
+    mir!(
+        {
+            let a = Discriminant(i);
+            match a {
+                1 => bb1,
+                2 => bb2,
+                5 => bb5,
+                _ => unreachable_bb,
+            }
+        }
+        bb1 = {
+            RET = 1;
+            Goto(ret)
+        }
+        bb2 = {
+            RET = 2;
+            Goto(ret)
+        }
+        bb5 = {
+            RET = 5;
+            RET = 5;
+            Goto(ret)
+        }
+        unreachable_bb = {
+            Unreachable()
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+#[repr(i8)]
+enum EnumAi8 {
+    A = -1,
+    B = 2,
+    C = -3,
+}
+
+// EMIT_MIR matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff
+fn match_i8_i16(i: EnumAi8) -> i16 {
+    // CHECK-LABEL: fn match_i8_i16(
+    // CHECK-NOT: switchInt
+    // CHECK: _0 = _3 as i16 (IntToInt);
+    // CHECH: return
+    match i {
+        EnumAi8::A => -1,
+        EnumAi8::B => 2,
+        EnumAi8::C => -3,
+    }
+}
+
+// EMIT_MIR matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff
+fn match_i8_i16_failed(i: EnumAi8) -> i16 {
+    // CHECK-LABEL: fn match_i8_i16_failed(
+    // CHECK: switchInt
+    match i {
+        EnumAi8::A => -1,
+        EnumAi8::B => 2,
+        EnumAi8::C => 3,
+    }
+}
+
+#[repr(i16)]
+enum EnumAi16 {
+    A = -1,
+    B = 2,
+    C = -3,
+}
+
+// EMIT_MIR matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff
+fn match_i16_i8(i: EnumAi16) -> i8 {
+    // CHECK-LABEL: fn match_i16_i8(
+    // CHECK-NOT: switchInt
+    // CHECK: _0 = _3 as i8 (IntToInt);
+    // CHECH: return
+    match i {
+        EnumAi16::A => -1,
+        EnumAi16::B => 2,
+        EnumAi16::C => -3,
+    }
+}
+
+#[repr(i128)]
+enum EnumAi128 {
+    A = 1,
+    B = 2,
+    C = 3,
+    D = -1,
+}
+
+// EMIT_MIR matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff
+fn match_i128_u128(i: EnumAi128) -> u128 {
+    // CHECK-LABEL: fn match_i128_u128(
+    // CHECK-NOT: switchInt
+    // CHECK: _0 = _3 as u128 (IntToInt);
+    // CHECH: return
+    match i {
+        EnumAi128::A => 1,
+        EnumAi128::B => 2,
+        EnumAi128::C => 3,
+        EnumAi128::D => u128::MAX,
+    }
+}
+
 fn main() {
     let _ = foo(None);
     let _ = foo(Some(()));
     let _ = bar(0);
     let _ = match_nested_if();
+    let _ = match_u8_i16(EnumAu8::A);
+    let _ = match_u8_i16_2(EnumAu8::A);
+    let _ = match_u8_i16_failed(EnumAu8::A);
+    let _ = match_u8_i16_fallback(1);
+    let _ = match_u8_u16(EnumBu8::A);
+    let _ = match_u8_u16_2(EnumBu8::A);
+    let _ = match_i8_i16(EnumAi8::A);
+    let _ = match_i8_i16_failed(EnumAi8::A);
+    let _ = match_i8_i16(EnumAi8::A);
+    let _ = match_i16_i8(EnumAi16::A);
+    let _ = match_i128_u128(EnumAi128::A);
 }
diff --git a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
index 157f9c98353..11a18f58e3a 100644
--- a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
+++ b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff
@@ -5,27 +5,32 @@
       debug e => _1;
       let mut _0: u8;
       let mut _2: isize;
++     let mut _3: isize;
   
       bb0: {
           _2 = discriminant(_1);
-          switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 1_u8;
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _0 = const 0_u8;
-          goto -> bb4;
-      }
-  
-      bb4: {
+-         switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 1_u8;
+-         goto -> bb4;
+-     }
+- 
+-     bb3: {
+-         _0 = const 0_u8;
+-         goto -> bb4;
+-     }
+- 
+-     bb4: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as u8 (IntToInt);
++         StorageDead(_3);
           return;
       }
   }
diff --git a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
index 19083771fd9..809badc41ba 100644
--- a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
+++ b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff
@@ -5,27 +5,32 @@
       debug e => _1;
       let mut _0: i8;
       let mut _2: isize;
++     let mut _3: isize;
   
       bb0: {
           _2 = discriminant(_1);
-          switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          unreachable;
-      }
-  
-      bb2: {
-          _0 = const 1_i8;
-          goto -> bb4;
-      }
-  
-      bb3: {
-          _0 = const 0_i8;
-          goto -> bb4;
-      }
-  
-      bb4: {
+-         switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+-         unreachable;
+-     }
+- 
+-     bb2: {
+-         _0 = const 1_i8;
+-         goto -> bb4;
+-     }
+- 
+-     bb3: {
+-         _0 = const 0_i8;
+-         goto -> bb4;
+-     }
+- 
+-     bb4: {
++         StorageLive(_3);
++         _3 = move _2;
++         _0 = _3 as i8 (IntToInt);
++         StorageDead(_3);
           return;
       }
   }
diff --git a/tests/run-make/artifact-incr-cache/lib.rs b/tests/run-make/artifact-incr-cache/lib.rs
new file mode 100644
index 00000000000..fa4048594e3
--- /dev/null
+++ b/tests/run-make/artifact-incr-cache/lib.rs
@@ -0,0 +1,6 @@
+#![crate_name = "foo"]
+
+#[inline(never)]
+pub fn add(a: u32, b: u32) -> u32 {
+    a + b
+}
diff --git a/tests/run-make/artifact-incr-cache/rmake.rs b/tests/run-make/artifact-incr-cache/rmake.rs
new file mode 100644
index 00000000000..bb651368081
--- /dev/null
+++ b/tests/run-make/artifact-incr-cache/rmake.rs
@@ -0,0 +1,25 @@
+// rustc should be able to emit required files (asm, llvm-*, etc) during incremental
+// compilation on the first pass by running the code gen as well as on subsequent runs -
+// extracting them from the cache
+//
+// Fixes: rust-lang/rust#89149
+// Fixes: rust-lang/rust#88829
+// Also see discussion at
+// <https://internals.rust-lang.org/t/interaction-between-incremental-compilation-and-emit/20551>
+
+extern crate run_make_support;
+
+use run_make_support::{rustc, tmp_dir};
+
+fn main() {
+    let inc_dir = tmp_dir();
+
+    for _ in 0..=1 {
+        rustc()
+            .input("lib.rs")
+            .crate_type("lib")
+            .emit("obj,asm,dep-info,link,mir,llvm-ir,llvm-bc")
+            .incremental(&inc_dir)
+            .run();
+    }
+}
diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index fc80932caba..348ce0c992f 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -2,23 +2,25 @@
 include: "utils.goml"
 go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
 
-// Otherwise, we can't check text color
-show-text: true
-
 // We check that without this setting, there is no line number displayed.
 assert-false: "pre.example-line-numbers"
 
+// We set the setting to show the line numbers on code examples.
+set-local-storage: {"rustdoc-line-numbers": "true"}
+reload:
+// We wait for the line numbers to be added into the DOM by the JS...
+wait-for: "pre.example-line-numbers"
+
+// Otherwise, we can't check text color
+show-text: true
+
 // Let's now check some CSS properties...
 define-function: (
     "check-colors",
     [theme, color],
     block {
-        // We now set the setting to show the line numbers on code examples.
-        set-local-storage: {"rustdoc-line-numbers": "true"}
         // Page will be reloaded in "switch-theme".
         call-function: ("switch-theme", {"theme": |theme|})
-        // We wait for the line numbers to be added into the DOM by the JS...
-        wait-for: "pre.example-line-numbers"
         // If the test didn't fail, it means that it was found!
         assert-css: (
             "pre.example-line-numbers",
diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml
index a9d37048188..441895a7c0e 100644
--- a/tests/rustdoc-gui/scrape-examples-toggle.goml
+++ b/tests/rustdoc-gui/scrape-examples-toggle.goml
@@ -9,6 +9,7 @@ define-function: (
     [theme, toggle_line_color, toggle_line_hover_color],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
+        reload:
 
         // Clicking "More examples..." will open additional examples
         assert-attribute-false: (".more-examples-toggle", {"open": ""})
@@ -21,6 +22,8 @@ define-function: (
             ".toggle-line:hover .toggle-line-inner",
             {"background-color": |toggle_line_hover_color|},
         )
+        // We put the toggle in the original state.
+        click: ".more-examples-toggle"
         // Moving cursor away from the toggle line to prevent disrupting next test.
         move-cursor-to: ".search-input"
     },
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index fd0b86af3ea..9825f92b453 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -210,24 +210,21 @@ call-function: ("check-search-color", {
 
 // Check the alias.
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
-// If the text isn't displayed, the browser doesn't compute color style correctly...
-show-text: true
+
+write-into: (".search-input", "thisisanalias")
+// To be SURE that the search will be run.
+press-key: 'Enter'
+// Waiting for the search results to appear...
+wait-for: "#search-tabs"
 
 define-function: (
     "check-alias",
     [theme, alias, grey],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
-        write-into: (".search-input", "thisisanalias")
-        // To be SURE that the search will be run.
-        press-key: 'Enter'
-        // Waiting for the search results to appear...
-        wait-for: "#search-tabs"
         // Checking that the colors for the alias element are the ones expected.
         assert-css: (".result-name .path .alias", {"color": |alias|})
         assert-css: (".result-name .path .alias > .grey", {"color": |grey|})
-        // Leave the search results to prevent reloading with an already filled search input.
-        press-key: "Escape"
     },
 )
 
diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml
index 56d0f8624e8..0011e44ca59 100644
--- a/tests/rustdoc-gui/settings.goml
+++ b/tests/rustdoc-gui/settings.goml
@@ -36,7 +36,12 @@ wait-for: "#alternative-display #search"
 assert: "#main-content.hidden"
 
 // Now let's check the content of the settings menu.
-call-function: ("switch-theme", {"theme": "dark"})
+// If we are on the settings page, the menu doesn't work the same so we set
+// the theme manually.
+set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+
 click: "#settings-menu"
 wait-for: "#settings"
 
diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml
index d9f8726ec53..844dc98a537 100644
--- a/tests/rustdoc-gui/utils.goml
+++ b/tests/rustdoc-gui/utils.goml
@@ -4,8 +4,15 @@ define-function: (
     [theme],
     block {
         // Set the theme.
-        set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
-        // We reload the page so the local storage settings are being used.
-        reload:
+        // Open the settings menu.
+        click: "#settings-menu"
+        // Wait for the popover to appear...
+        wait-for: "#settings"
+        // Change the setting.
+        click: "#theme-"+ |theme|
+        // Close the popover.
+        click: "#settings-menu"
+        // Ensure that the local storage was correctly updated.
+        assert-local-storage: {"rustdoc-theme": |theme|}
     },
 )
diff --git a/tests/rustdoc/primitive/primitive.rs b/tests/rustdoc/primitive/primitive.rs
index 32af2636c18..4b89fd9dfb7 100644
--- a/tests/rustdoc/primitive/primitive.rs
+++ b/tests/rustdoc/primitive/primitive.rs
@@ -1,6 +1,8 @@
 #![crate_name = "foo"]
 
 #![feature(rustc_attrs)]
+#![feature(f16)]
+#![feature(f128)]
 
 // @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types'
 // @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32'
@@ -13,9 +15,19 @@
 // @!has foo/index.html '//span' '🔒'
 #[rustc_doc_primitive = "i32"]
 /// this is a test!
-mod i32{}
+mod i32 {}
 
 // @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
 #[rustc_doc_primitive = "bool"]
 /// hello
 mod bool {}
+
+// @has foo/primitive.f16.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
+#[rustc_doc_primitive = "f16"]
+/// hello
+mod f16 {}
+
+// @has foo/primitive.f128.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello'
+#[rustc_doc_primitive = "f128"]
+/// hello
+mod f128 {}
diff --git a/tests/rustdoc/synthetic_auto/supertrait-bounds.rs b/tests/rustdoc/synthetic_auto/supertrait-bounds.rs
new file mode 100644
index 00000000000..503e65d0f4f
--- /dev/null
+++ b/tests/rustdoc/synthetic_auto/supertrait-bounds.rs
@@ -0,0 +1,14 @@
+// Check that we don't add bounds to synthetic auto trait impls that are
+// already implied by the item (like supertrait bounds).
+
+// In this case we don't want to add the bounds `T: Copy` and `T: 'static`
+// to the auto trait impl because they're implied by the bound `T: Bound`
+// on the implementor `Type`.
+
+pub struct Type<T: Bound>(T);
+
+// @has supertrait_bounds/struct.Type.html
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \
+// "impl<T> Send for Type<T>where T: Send,"
+
+pub trait Bound: Copy + 'static {}
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
index 3152bf23ca5..f77b318039d 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs
@@ -22,6 +22,7 @@ fn main() {
         TyKind::Foreign(..) => (),          //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Str => (),                  //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Array(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
+        TyKind::Pat(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Slice(..) => (),            //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::RawPtr(..) => (),           //~ ERROR usage of `ty::TyKind::<kind>`
         TyKind::Ref(..) => (),              //~ ERROR usage of `ty::TyKind::<kind>`
diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
index 2ff5aad95dd..53bf5cb1a82 100644
--- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
+++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr
@@ -67,119 +67,125 @@ LL |         TyKind::Array(..) => (),
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:25:9
    |
-LL |         TyKind::Slice(..) => (),
+LL |         TyKind::Pat(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:26:9
    |
-LL |         TyKind::RawPtr(..) => (),
+LL |         TyKind::Slice(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:27:9
    |
-LL |         TyKind::Ref(..) => (),
+LL |         TyKind::RawPtr(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:28:9
    |
-LL |         TyKind::FnDef(..) => (),
+LL |         TyKind::Ref(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:29:9
    |
-LL |         TyKind::FnPtr(..) => (),
+LL |         TyKind::FnDef(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:30:9
    |
-LL |         TyKind::Dynamic(..) => (),
+LL |         TyKind::FnPtr(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:31:9
    |
-LL |         TyKind::Closure(..) => (),
+LL |         TyKind::Dynamic(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:32:9
    |
-LL |         TyKind::CoroutineClosure(..) => (),
+LL |         TyKind::Closure(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:33:9
    |
-LL |         TyKind::Coroutine(..) => (),
+LL |         TyKind::CoroutineClosure(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:34:9
    |
-LL |         TyKind::CoroutineWitness(..) => (),
+LL |         TyKind::Coroutine(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:35:9
    |
-LL |         TyKind::Never => (),
+LL |         TyKind::CoroutineWitness(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:36:9
    |
-LL |         TyKind::Tuple(..) => (),
+LL |         TyKind::Never => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:37:9
    |
-LL |         TyKind::Alias(..) => (),
+LL |         TyKind::Tuple(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:38:9
    |
-LL |         TyKind::Param(..) => (),
+LL |         TyKind::Alias(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:39:9
    |
-LL |         TyKind::Bound(..) => (),
+LL |         TyKind::Param(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:40:9
    |
-LL |         TyKind::Placeholder(..) => (),
+LL |         TyKind::Bound(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:41:9
    |
-LL |         TyKind::Infer(..) => (),
+LL |         TyKind::Placeholder(..) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
   --> $DIR/ty_tykind_usage.rs:42:9
    |
+LL |         TyKind::Infer(..) => (),
+   |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
+
+error: usage of `ty::TyKind::<kind>`
+  --> $DIR/ty_tykind_usage.rs:43:9
+   |
 LL |         TyKind::Error(_) => (),
    |         ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:47:12
+  --> $DIR/ty_tykind_usage.rs:48:12
    |
 LL |     if let TyKind::Int(int_ty) = kind {}
    |            ^^^^^^ help: try using `ty::<kind>` directly: `ty`
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:49:24
+  --> $DIR/ty_tykind_usage.rs:50:24
    |
 LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    |                        ^^^^^^^^^^
@@ -187,7 +193,7 @@ LL |     fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {}
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:51:37
+  --> $DIR/ty_tykind_usage.rs:52:37
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                     ^^^^^^^^^^^
@@ -195,7 +201,7 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind`
-  --> $DIR/ty_tykind_usage.rs:51:53
+  --> $DIR/ty_tykind_usage.rs:52:53
    |
 LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    |                                                     ^^^^^^^^^^^
@@ -203,12 +209,12 @@ LL |     fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> {
    = help: try using `Ty` instead
 
 error: usage of `ty::TyKind::<kind>`
-  --> $DIR/ty_tykind_usage.rs:54:9
+  --> $DIR/ty_tykind_usage.rs:55:9
    |
 LL |         IrTyKind::Bool
    |         --------^^^^^^
    |         |
    |         help: try using `ty::<kind>` directly: `ty`
 
-error: aborting due to 33 previous errors
+error: aborting due to 34 previous errors
 
diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs
new file mode 100644
index 00000000000..3b52d88de3c
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_binop.rs
@@ -0,0 +1,147 @@
+//@ run-pass
+//! Test information regarding binary operations.
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+
+#![feature(rustc_private)]
+
+extern crate rustc_hir;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use rustc_smir::rustc_internal;
+use stable_mir::mir::mono::Instance;
+use stable_mir::mir::visit::{Location, MirVisitor};
+use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind};
+use stable_mir::ty::{RigidTy, TyKind};
+use std::collections::HashSet;
+use std::convert::TryFrom;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+/// This function tests that we can correctly get type information from binary operations.
+fn test_binops() -> ControlFlow<()> {
+    // Find items in the local crate.
+    let items = stable_mir::all_local_items();
+    let mut instances =
+        items.into_iter().map(|item| Instance::try_from(item).unwrap()).collect::<Vec<_>>();
+    while let Some(instance) = instances.pop() {
+        // The test below shouldn't have recursion in it.
+        let Some(body) = instance.body() else {
+            continue;
+        };
+        let mut visitor = Visitor { locals: body.locals(), calls: Default::default() };
+        visitor.visit_body(&body);
+        instances.extend(visitor.calls.into_iter());
+    }
+    ControlFlow::Continue(())
+}
+
+struct Visitor<'a> {
+    locals: &'a [LocalDecl],
+    calls: HashSet<Instance>,
+}
+
+impl<'a> MirVisitor for Visitor<'a> {
+    fn visit_statement(&mut self, stmt: &Statement, _loc: Location) {
+        match &stmt.kind {
+            StatementKind::Assign(place, Rvalue::BinaryOp(op, rhs, lhs)) => {
+                let ret_ty = place.ty(self.locals).unwrap();
+                let op_ty = op.ty(rhs.ty(self.locals).unwrap(), lhs.ty(self.locals).unwrap());
+                assert_eq!(ret_ty, op_ty, "Operation type should match the assigned place type");
+            }
+            _ => {}
+        }
+    }
+
+    fn visit_terminator(&mut self, term: &Terminator, _loc: Location) {
+        match &term.kind {
+            TerminatorKind::Call { func, .. } => {
+                let TyKind::RigidTy(RigidTy::FnDef(def, args)) =
+                    func.ty(self.locals).unwrap().kind()
+                    else {
+                        return;
+                    };
+                self.calls.insert(Instance::resolve(def, &args).unwrap());
+            }
+            _ => {}
+        }
+    }
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "binop_input.rs";
+    generate_input(&path).unwrap();
+    let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()];
+    run!(args, test_binops).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        macro_rules! binop_int {{
+            ($fn:ident, $typ:ty) => {{
+                pub fn $fn(lhs: $typ, rhs: $typ) {{
+                    let eq = lhs == rhs;
+                    let lt = lhs < rhs;
+                    let le = lhs <= rhs;
+
+                    let sum = lhs + rhs;
+                    let mult = lhs * sum;
+                    let shift = mult << 2;
+                    let bit_or = shift | rhs;
+                    let cmp = lhs.cmp(&bit_or);
+
+                    // Try to avoid the results above being pruned
+                    std::hint::black_box(((eq, lt, le), cmp));
+                }}
+            }}
+        }}
+
+        binop_int!(binop_u8, u8);
+        binop_int!(binop_i64, i64);
+
+        pub fn binop_bool(lhs: bool, rhs: bool) {{
+            let eq = lhs == rhs;
+            let or = lhs | eq;
+            let lt = lhs < or;
+            let cmp = lhs.cmp(&rhs);
+
+            // Try to avoid the results above being pruned
+            std::hint::black_box((lt, cmp));
+        }}
+
+        pub fn binop_char(lhs: char, rhs: char) {{
+            let eq = lhs == rhs;
+            let lt = lhs < rhs;
+            let cmp = lhs.cmp(&rhs);
+
+            // Try to avoid the results above being pruned
+            std::hint::black_box(([eq, lt], cmp));
+        }}
+
+        pub fn binop_ptr(lhs: *const char, rhs: *const char) {{
+            let eq = lhs == rhs;
+            let lt = lhs < rhs;
+            let cmp = lhs.cmp(&rhs);
+            let off = unsafe {{ lhs.offset(2) }};
+
+            // Try to avoid the results above being pruned
+            std::hint::black_box(([eq, lt], cmp, off));
+        }}
+        "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs
index 6da1b89ed67..4a98d37aca0 100644
--- a/tests/ui/asm/inline-syntax.rs
+++ b/tests/ui/asm/inline-syntax.rs
@@ -16,7 +16,7 @@
 #![feature(no_core, lang_items, rustc_attrs)]
 #![crate_type = "rlib"]
 #![no_core]
-#![cfg_attr(x86_64_allowed, allow(bad_asm_style))]
+
 
 #[rustc_builtin_macro]
 macro_rules! asm {
diff --git a/tests/ui/async-await/async-closures/mut-ref-reborrow.rs b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs
new file mode 100644
index 00000000000..9f2cbd7ce1c
--- /dev/null
+++ b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs
@@ -0,0 +1,27 @@
+//@ aux-build:block-on.rs
+//@ run-pass
+//@ check-run-results
+//@ revisions: e2021 e2018
+//@[e2018] edition:2018
+//@[e2021] edition:2021
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+async fn call_once(f: impl async FnOnce()) { f().await; }
+
+pub async fn async_closure(x: &mut i32) {
+    let c = async move || {
+        *x += 1;
+    };
+    call_once(c).await;
+}
+
+fn main() {
+    block_on::block_on(async {
+        let mut x = 0;
+        async_closure(&mut x).await;
+        assert_eq!(x, 1);
+    });
+}
diff --git a/tests/ui/async-await/async-closures/overlapping-projs.rs b/tests/ui/async-await/async-closures/overlapping-projs.rs
new file mode 100644
index 00000000000..6dd00b16103
--- /dev/null
+++ b/tests/ui/async-await/async-closures/overlapping-projs.rs
@@ -0,0 +1,27 @@
+//@ aux-build:block-on.rs
+//@ edition:2021
+//@ run-pass
+//@ check-run-results
+
+#![feature(async_closure)]
+
+extern crate block_on;
+
+async fn call_once(f: impl async FnOnce()) {
+    f().await;
+}
+
+async fn async_main() {
+    let x = &mut 0;
+    let y = &mut 0;
+    let c = async || {
+        *x = 1;
+        *y = 2;
+    };
+    call_once(c).await;
+    println!("{x} {y}");
+}
+
+fn main() {
+    block_on::block_on(async_main());
+}
diff --git a/tests/ui/async-await/async-closures/overlapping-projs.run.stdout b/tests/ui/async-await/async-closures/overlapping-projs.run.stdout
new file mode 100644
index 00000000000..8d04f961a03
--- /dev/null
+++ b/tests/ui/async-await/async-closures/overlapping-projs.run.stdout
@@ -0,0 +1 @@
+1 2
diff --git a/tests/ui/async-await/async-closures/precise-captures.call.run.stdout b/tests/ui/async-await/async-closures/precise-captures.call.run.stdout
new file mode 100644
index 00000000000..6062556837c
--- /dev/null
+++ b/tests/ui/async-await/async-closures/precise-captures.call.run.stdout
@@ -0,0 +1,29 @@
+after call
+after await
+fixed
+uncaptured
+
+after call
+after await
+fixed
+uncaptured
+
+after call
+after await
+fixed
+uncaptured
+
+after call
+after await
+fixed
+untouched
+
+after call
+drop first
+after await
+uncaptured
+
+after call
+drop first
+after await
+uncaptured
diff --git a/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout b/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout
new file mode 100644
index 00000000000..ddb02d47600
--- /dev/null
+++ b/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout
@@ -0,0 +1,29 @@
+after call
+after await
+fixed
+uncaptured
+
+after call
+after await
+fixed
+uncaptured
+
+after call
+fixed
+after await
+uncaptured
+
+after call
+after await
+fixed
+untouched
+
+after call
+drop first
+after await
+uncaptured
+
+after call
+drop first
+after await
+uncaptured
diff --git a/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout b/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout
new file mode 100644
index 00000000000..ddb02d47600
--- /dev/null
+++ b/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout
@@ -0,0 +1,29 @@
+after call
+after await
+fixed
+uncaptured
+
+after call
+after await
+fixed
+uncaptured
+
+after call
+fixed
+after await
+uncaptured
+
+after call
+after await
+fixed
+untouched
+
+after call
+drop first
+after await
+uncaptured
+
+after call
+drop first
+after await
+uncaptured
diff --git a/tests/ui/async-await/async-closures/precise-captures.rs b/tests/ui/async-await/async-closures/precise-captures.rs
new file mode 100644
index 00000000000..e82dd1dbaf0
--- /dev/null
+++ b/tests/ui/async-await/async-closures/precise-captures.rs
@@ -0,0 +1,157 @@
+//@ aux-build:block-on.rs
+//@ edition:2021
+//@ run-pass
+//@ check-run-results
+//@ revisions: call call_once force_once
+
+// call - Call the closure regularly.
+// call_once - Call the closure w/ `async FnOnce`, so exercising the by_move shim.
+// force_once - Force the closure mode to `FnOnce`, so exercising what was fixed
+//   in <https://github.com/rust-lang/rust/pull/123350>.
+
+#![feature(async_closure)]
+#![allow(unused_mut)]
+
+extern crate block_on;
+
+#[cfg(any(call, force_once))]
+macro_rules! call {
+    ($c:expr) => { ($c)() }
+}
+
+#[cfg(call_once)]
+async fn call_once(f: impl async FnOnce()) {
+    f().await
+}
+
+#[cfg(call_once)]
+macro_rules! call {
+    ($c:expr) => { call_once($c) }
+}
+
+#[cfg(not(force_once))]
+macro_rules! guidance {
+    ($c:expr) => { $c }
+}
+
+#[cfg(force_once)]
+fn infer_fnonce(c: impl async FnOnce()) -> impl async FnOnce() { c }
+
+#[cfg(force_once)]
+macro_rules! guidance {
+    ($c:expr) => { infer_fnonce($c) }
+}
+
+#[derive(Debug)]
+struct Drop(&'static str);
+
+impl std::ops::Drop for Drop {
+    fn drop(&mut self) {
+        println!("{}", self.0);
+    }
+}
+
+struct S {
+    a: i32,
+    b: Drop,
+    c: Drop,
+}
+
+async fn async_main() {
+    // Precise capture struct
+    {
+        let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
+        let mut c = guidance!(async || {
+            s.a = 2;
+            let w = &mut s.b;
+            w.0 = "fixed";
+        });
+        s.c.0 = "uncaptured";
+        let fut = call!(c);
+        println!("after call");
+        fut.await;
+        println!("after await");
+    }
+    println!();
+
+    // Precise capture &mut struct
+    {
+        let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
+        let mut c = guidance!(async || {
+            s.a = 2;
+            let w = &mut s.b;
+            w.0 = "fixed";
+        });
+        s.c.0 = "uncaptured";
+        let fut = call!(c);
+        println!("after call");
+        fut.await;
+        println!("after await");
+    }
+    println!();
+
+    // Precise capture struct by move
+    {
+        let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
+        let mut c = guidance!(async move || {
+            s.a = 2;
+            let w = &mut s.b;
+            w.0 = "fixed";
+        });
+        s.c.0 = "uncaptured";
+        let fut = call!(c);
+        println!("after call");
+        fut.await;
+        println!("after await");
+    }
+    println!();
+
+    // Precise capture &mut struct by move
+    {
+        let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") };
+        let mut c = guidance!(async move || {
+            s.a = 2;
+            let w = &mut s.b;
+            w.0 = "fixed";
+        });
+        // `s` is still captured fully as `&mut S`.
+        let fut = call!(c);
+        println!("after call");
+        fut.await;
+        println!("after await");
+    }
+    println!();
+
+    // Precise capture struct, consume field
+    {
+        let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") };
+        let c = guidance!(async move || {
+            // s.a = 2; // FIXME(async_closures): Figure out why this fails
+            drop(s.b);
+        });
+        s.c.0 = "uncaptured";
+        let fut = call!(c);
+        println!("after call");
+        fut.await;
+        println!("after await");
+    }
+    println!();
+
+    // Precise capture struct by move, consume field
+    {
+        let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") };
+        let c = guidance!(async move || {
+            // s.a = 2; // FIXME(async_closures): Figure out why this fails
+            drop(s.b);
+        });
+        s.c.0 = "uncaptured";
+        let fut = call!(c);
+        println!("after call");
+        fut.await;
+        println!("after await");
+    }
+}
+
+fn main() {
+    block_on::block_on(async_main());
+}
diff --git a/tests/ui/cfg/cfg-attr-cfg.rs b/tests/ui/cfg/cfg-attr-cfg.rs
index 5b49966d544..67d97e760d7 100644
--- a/tests/ui/cfg/cfg-attr-cfg.rs
+++ b/tests/ui/cfg/cfg-attr-cfg.rs
@@ -4,5 +4,5 @@
 
 //@ pretty-expanded FIXME #23616
 
-#[cfg_attr(foo, cfg(bar))]
+#[cfg_attr(FALSE, cfg(bar))]
 fn main() { }
diff --git a/tests/ui/cfg/cfg-attr-crate.rs b/tests/ui/cfg/cfg-attr-crate.rs
index 7868b006e27..444704d132a 100644
--- a/tests/ui/cfg/cfg-attr-crate.rs
+++ b/tests/ui/cfg/cfg-attr-crate.rs
@@ -3,6 +3,6 @@
 
 //@ pretty-expanded FIXME #23616
 
-#![cfg_attr(not_used, no_core)]
+#![cfg_attr(FALSE, no_core)]
 
 fn main() { }
diff --git a/tests/ui/cfg/cfg-macros-notfoo.rs b/tests/ui/cfg/cfg-macros-notfoo.rs
index c47f4332aa3..9feb06be73e 100644
--- a/tests/ui/cfg/cfg-macros-notfoo.rs
+++ b/tests/ui/cfg/cfg-macros-notfoo.rs
@@ -1,11 +1,9 @@
 //@ run-pass
-//@ compile-flags:
 
 // check that cfg correctly chooses between the macro impls (see also
 // cfg-macros-foo.rs)
 
-
-#[cfg(foo)]
+#[cfg(FALSE)]
 #[macro_use]
 mod foo {
     macro_rules! bar {
@@ -13,7 +11,7 @@ mod foo {
     }
 }
 
-#[cfg(not(foo))]
+#[cfg(not(FALSE))]
 #[macro_use]
 mod foo {
     macro_rules! bar {
diff --git a/tests/ui/cfg/cfg-match-arm.rs b/tests/ui/cfg/cfg-match-arm.rs
index a41337a19a3..e646a63b8fb 100644
--- a/tests/ui/cfg/cfg-match-arm.rs
+++ b/tests/ui/cfg/cfg-match-arm.rs
@@ -10,9 +10,9 @@ enum Foo {
 fn foo(f: Foo) {
     match f {
         Foo::Bar => {},
-        #[cfg(not(asdfa))]
+        #[cfg(not(FALSE))]
         Foo::Baz => {},
-        #[cfg(afsd)]
+        #[cfg(FALSE)]
         Basdfwe => {}
     }
 }
diff --git a/tests/ui/cfg/cfg-panic-abort.rs b/tests/ui/cfg/cfg-panic-abort.rs
index 49adfd55c68..448fde21086 100644
--- a/tests/ui/cfg/cfg-panic-abort.rs
+++ b/tests/ui/cfg/cfg-panic-abort.rs
@@ -2,15 +2,11 @@
 //@ compile-flags: -C panic=abort
 //@ no-prefer-dynamic
 
-
 #[cfg(panic = "unwind")]
 pub fn bad() -> i32 { }
 
 #[cfg(not(panic = "abort"))]
 pub fn bad() -> i32 { }
 
-#[cfg(panic = "some_imaginary_future_panic_handler")]
-pub fn bad() -> i32 { }
-
 #[cfg(panic = "abort")]
 pub fn main() { }
diff --git a/tests/ui/cfg/cfg-panic.rs b/tests/ui/cfg/cfg-panic.rs
index 0f1f539ebe3..4e3ed0cd9c2 100644
--- a/tests/ui/cfg/cfg-panic.rs
+++ b/tests/ui/cfg/cfg-panic.rs
@@ -2,15 +2,11 @@
 //@ compile-flags: -C panic=unwind
 //@ needs-unwind
 
-
 #[cfg(panic = "abort")]
 pub fn bad() -> i32 { }
 
 #[cfg(not(panic = "unwind"))]
 pub fn bad() -> i32 { }
 
-#[cfg(panic = "some_imaginary_future_panic_handler")]
-pub fn bad() -> i32 { }
-
 #[cfg(panic = "unwind")]
 pub fn main() { }
diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs
index 6de5eb5c4c6..9245f6d9757 100644
--- a/tests/ui/cfg/cfg_stmt_expr.rs
+++ b/tests/ui/cfg/cfg_stmt_expr.rs
@@ -7,49 +7,49 @@
 
 fn main() {
     let a = 413;
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     let a = ();
     assert_eq!(a, 413);
 
     let mut b = 612;
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     {
         b = 1111;
     }
     assert_eq!(b, 612);
 
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     undefined_fn();
 
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     undefined_macro!();
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     undefined_macro![];
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     undefined_macro!{};
 
     // pretty printer bug...
-    // #[cfg(unset)]
+    // #[cfg(FALSE)]
     // undefined_macro!{}
 
-    let () = (#[cfg(unset)] 341,); // Should this also work on parens?
-    let t = (1, #[cfg(unset)] 3, 4);
+    let () = (#[cfg(FALSE)] 341,); // Should this also work on parens?
+    let t = (1, #[cfg(FALSE)] 3, 4);
     assert_eq!(t, (1, 4));
 
     let f = |_: u32, _: u32| ();
-    f(2, 1, #[cfg(unset)] 6);
+    f(2, 1, #[cfg(FALSE)] 6);
 
-    let _: u32 = a.clone(#[cfg(unset)] undefined);
+    let _: u32 = a.clone(#[cfg(FALSE)] undefined);
 
-    let _: [(); 0] = [#[cfg(unset)] 126];
-    let t = [#[cfg(unset)] 1, 2, 6];
+    let _: [(); 0] = [#[cfg(FALSE)] 126];
+    let t = [#[cfg(FALSE)] 1, 2, 6];
     assert_eq!(t, [2, 6]);
 
     {
         let r;
-        #[cfg(unset)]
+        #[cfg(FALSE)]
         (r = 5);
-        #[cfg(not(unset))]
+        #[cfg(not(FALSE))]
         (r = 10);
         assert_eq!(r, 10);
     }
@@ -69,13 +69,13 @@ fn main() {
         }
     }
 
-    let n = if_cfg!(unset? {
+    let n = if_cfg!(FALSE? {
         413
     } else {
         612
     });
 
-    assert_eq!((#[cfg(unset)] 1, #[cfg(not(unset))] 2), (2,));
+    assert_eq!((#[cfg(FALSE)] 1, #[cfg(not(FALSE))] 2), (2,));
     assert_eq!(n, 612);
 
     // check that lints work
diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs
index f39663adda2..a4f334dd696 100644
--- a/tests/ui/cfg/conditional-compile.rs
+++ b/tests/ui/cfg/conditional-compile.rs
@@ -6,31 +6,31 @@
 
 // Crate use statements
 
-#[cfg(bogus)]
+#[cfg(FALSE)]
 use flippity;
 
-#[cfg(bogus)]
+#[cfg(FALSE)]
 static b: bool = false;
 
 static b: bool = true;
 
 mod rustrt {
-    #[cfg(bogus)]
+    #[cfg(FALSE)]
     extern "C" {
         // This symbol doesn't exist and would be a link error if this
         // module was codegened
-        pub fn bogus();
+        pub fn FALSE();
     }
 
     extern "C" {}
 }
 
-#[cfg(bogus)]
+#[cfg(FALSE)]
 type t = isize;
 
 type t = bool;
 
-#[cfg(bogus)]
+#[cfg(FALSE)]
 enum tg {
     foo,
 }
@@ -39,12 +39,12 @@ enum tg {
     bar,
 }
 
-#[cfg(bogus)]
+#[cfg(FALSE)]
 struct r {
     i: isize,
 }
 
-#[cfg(bogus)]
+#[cfg(FALSE)]
 fn r(i: isize) -> r {
     r { i: i }
 }
@@ -57,11 +57,11 @@ fn r(i: isize) -> r {
     r { i: i }
 }
 
-#[cfg(bogus)]
+#[cfg(FALSE)]
 mod m {
     // This needs to parse but would fail in typeck. Since it's not in
     // the current config it should not be typechecked.
-    pub fn bogus() {
+    pub fn FALSE() {
         return 0;
     }
 }
@@ -69,22 +69,22 @@ mod m {
 mod m {
     // Submodules have slightly different code paths than the top-level
     // module, so let's make sure this jazz works here as well
-    #[cfg(bogus)]
+    #[cfg(FALSE)]
     pub fn f() {}
 
     pub fn f() {}
 }
 
-// Since the bogus configuration isn't defined main will just be
+// Since the FALSE configuration isn't defined main will just be
 // parsed, but nothing further will be done with it
-#[cfg(bogus)]
+#[cfg(FALSE)]
 pub fn main() {
     panic!()
 }
 
 pub fn main() {
     // Exercise some of the configured items in ways that wouldn't be possible
-    // if they had the bogus definition
+    // if they had the FALSE definition
     assert!((b));
     let _x: t = true;
     let _y: tg = tg::bar;
@@ -93,14 +93,14 @@ pub fn main() {
 }
 
 fn test_in_fn_ctxt() {
-    #[cfg(bogus)]
+    #[cfg(FALSE)]
     fn f() {
         panic!()
     }
     fn f() {}
     f();
 
-    #[cfg(bogus)]
+    #[cfg(FALSE)]
     static i: isize = 0;
     static i: isize = 1;
     assert_eq!(i, 1);
@@ -109,7 +109,7 @@ fn test_in_fn_ctxt() {
 mod test_foreign_items {
     pub mod rustrt {
         extern "C" {
-            #[cfg(bogus)]
+            #[cfg(FALSE)]
             pub fn write() -> String;
             pub fn write() -> String;
         }
@@ -117,7 +117,7 @@ mod test_foreign_items {
 }
 
 mod test_use_statements {
-    #[cfg(bogus)]
+    #[cfg(FALSE)]
     use flippity_foo;
 }
 
@@ -127,24 +127,24 @@ mod test_methods {
     }
 
     impl Fooable for Foo {
-        #[cfg(bogus)]
+        #[cfg(FALSE)]
         fn what(&self) {}
 
         fn what(&self) {}
 
-        #[cfg(bogus)]
+        #[cfg(FALSE)]
         fn the(&self) {}
 
         fn the(&self) {}
     }
 
     trait Fooable {
-        #[cfg(bogus)]
+        #[cfg(FALSE)]
         fn what(&self);
 
         fn what(&self);
 
-        #[cfg(bogus)]
+        #[cfg(FALSE)]
         fn the(&self);
 
         fn the(&self);
diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs
index b9548e91183..9b3208cb87c 100644
--- a/tests/ui/cfg/diagnostics-reexport.rs
+++ b/tests/ui/cfg/diagnostics-reexport.rs
@@ -14,7 +14,7 @@ pub use a::x;
 //~| NOTE no `x` in `a`
 
 mod a {
-    #[cfg(no)]
+    #[cfg(FALSE)]
     pub fn x() {}
     //~^ NOTE found an item that was configured out
 }
@@ -25,10 +25,10 @@ pub use b::{x, y};
 //~| NOTE no `y` in `b`
 
 mod b {
-    #[cfg(no)]
+    #[cfg(FALSE)]
     pub fn x() {}
     //~^ NOTE found an item that was configured out
-    #[cfg(no)]
+    #[cfg(FALSE)]
     pub fn y() {}
     //~^ NOTE found an item that was configured out
 }
diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed
new file mode 100644
index 00000000000..0fa6ac1dd99
--- /dev/null
+++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed
@@ -0,0 +1,9 @@
+// Check that revisioned `run-rustfix` does not fail with issues related to `.` in crate name.
+//@ revisions: foo
+//@[foo] run-rustfix
+#![deny(unused_variables)]
+
+fn main() {
+    let _x = 0usize;
+    //~^ ERROR unused variable: `x`
+}
diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr
new file mode 100644
index 00000000000..74384ef24af
--- /dev/null
+++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr
@@ -0,0 +1,14 @@
+error: unused variable: `x`
+  --> $DIR/run-rustfix-revisions.rs:7:9
+   |
+LL |     let x = 0usize;
+   |         ^ help: if this is intentional, prefix it with an underscore: `_x`
+   |
+note: the lint level is defined here
+  --> $DIR/run-rustfix-revisions.rs:4:9
+   |
+LL | #![deny(unused_variables)]
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.rs b/tests/ui/compiletest-self-test/run-rustfix-revisions.rs
new file mode 100644
index 00000000000..84c5b7a2d0a
--- /dev/null
+++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.rs
@@ -0,0 +1,9 @@
+// Check that revisioned `run-rustfix` does not fail with issues related to `.` in crate name.
+//@ revisions: foo
+//@[foo] run-rustfix
+#![deny(unused_variables)]
+
+fn main() {
+    let x = 0usize;
+    //~^ ERROR unused variable: `x`
+}
diff --git a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs
index 72b0db5da84..bca29f0da2b 100644
--- a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs
@@ -1,13 +1,11 @@
 // Check that `#[cfg_attr($PREDICATE,)]` triggers the `unused_attribute` lint.
 
-//@ compile-flags: --cfg TRUE
-
 #![deny(unused)]
 
 #[cfg_attr(FALSE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes
 fn _f() {}
 
-#[cfg_attr(TRUE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes
+#[cfg_attr(not(FALSE),)] //~ ERROR `#[cfg_attr]` does not expand to any attributes
 fn _g() {}
 
 fn main() {}
diff --git a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr
index 87b69881353..a858afe2f2b 100644
--- a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr
@@ -1,21 +1,21 @@
 error: `#[cfg_attr]` does not expand to any attributes
-  --> $DIR/cfg-attr-empty-is-unused.rs:7:1
+  --> $DIR/cfg-attr-empty-is-unused.rs:5:1
    |
 LL | #[cfg_attr(FALSE,)]
    | ^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/cfg-attr-empty-is-unused.rs:5:9
+  --> $DIR/cfg-attr-empty-is-unused.rs:3:9
    |
 LL | #![deny(unused)]
    |         ^^^^^^
    = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
 
 error: `#[cfg_attr]` does not expand to any attributes
-  --> $DIR/cfg-attr-empty-is-unused.rs:10:1
+  --> $DIR/cfg-attr-empty-is-unused.rs:8:1
    |
-LL | #[cfg_attr(TRUE,)]
-   | ^^^^^^^^^^^^^^^^^^
+LL | #[cfg_attr(not(FALSE),)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.rs b/tests/ui/conditional-compilation/cfg-in-crate-1.rs
index 59be27a065e..ecd3722bf4c 100644
--- a/tests/ui/conditional-compilation/cfg-in-crate-1.rs
+++ b/tests/ui/conditional-compilation/cfg-in-crate-1.rs
@@ -1,3 +1,3 @@
 //@ error-pattern: `main` function not found
 
-#![cfg(bar)]
+#![cfg(FALSE)]
diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr
index 98be6d01f1b..6067a3a921c 100644
--- a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr
+++ b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr
@@ -1,8 +1,8 @@
 error[E0601]: `main` function not found in crate `cfg_in_crate_1`
-  --> $DIR/cfg-in-crate-1.rs:3:13
+  --> $DIR/cfg-in-crate-1.rs:3:15
    |
-LL | #![cfg(bar)]
-   |             ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
+LL | #![cfg(FALSE)]
+   |               ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs
index 0ddbd8a156d..ae85f38e645 100644
--- a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs
+++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs
@@ -2,10 +2,10 @@
 #![feature(custom_test_frameworks)]
 
 fn main() {
-    let _ = #[cfg(unset)] ();
+    let _ = #[cfg(FALSE)] ();
     //~^ ERROR removing an expression is not supported in this position
-    let _ = 1 + 2 + #[cfg(unset)] 3;
+    let _ = 1 + 2 + #[cfg(FALSE)] 3;
     //~^ ERROR removing an expression is not supported in this position
-    let _ = [1, 2, 3][#[cfg(unset)] 1];
+    let _ = [1, 2, 3][#[cfg(FALSE)] 1];
     //~^ ERROR removing an expression is not supported in this position
 }
diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr
index 933b7dc184a..06eaa59efdd 100644
--- a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr
+++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr
@@ -1,19 +1,19 @@
 error: removing an expression is not supported in this position
   --> $DIR/cfg-non-opt-expr.rs:5:13
    |
-LL |     let _ = #[cfg(unset)] ();
+LL |     let _ = #[cfg(FALSE)] ();
    |             ^^^^^^^^^^^^^
 
 error: removing an expression is not supported in this position
   --> $DIR/cfg-non-opt-expr.rs:7:21
    |
-LL |     let _ = 1 + 2 + #[cfg(unset)] 3;
+LL |     let _ = 1 + 2 + #[cfg(FALSE)] 3;
    |                     ^^^^^^^^^^^^^
 
 error: removing an expression is not supported in this position
   --> $DIR/cfg-non-opt-expr.rs:9:23
    |
-LL |     let _ = [1, 2, 3][#[cfg(unset)] 1];
+LL |     let _ = [1, 2, 3][#[cfg(FALSE)] 1];
    |                       ^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs
new file mode 100644
index 00000000000..dd0b1e8c9f7
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs
@@ -0,0 +1,15 @@
+// ICE unknown alias DefKind: AnonConst
+// issue: rust-lang/rust#116710
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct A<const N: u32 = 1, const M: u32 = u8>;
+//~^ ERROR expected value, found builtin type `u8`
+
+trait Trait {}
+impl<const N: u32> Trait for A<N> {}
+
+impl<const N: u32> Trait for A<N> {}
+//~^ ERROR conflicting implementations of trait `Trait` for type `A<_>`
+
+pub fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr
new file mode 100644
index 00000000000..80ac96d4870
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr
@@ -0,0 +1,19 @@
+error[E0423]: expected value, found builtin type `u8`
+  --> $DIR/unknown-alias-defkind-anonconst-ice-116710.rs:6:43
+   |
+LL | struct A<const N: u32 = 1, const M: u32 = u8>;
+   |                                           ^^ not a value
+
+error[E0119]: conflicting implementations of trait `Trait` for type `A<_>`
+  --> $DIR/unknown-alias-defkind-anonconst-ice-116710.rs:12:1
+   |
+LL | impl<const N: u32> Trait for A<N> {}
+   | --------------------------------- first implementation here
+LL |
+LL | impl<const N: u32> Trait for A<N> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A<_>`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0119, E0423.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.rs b/tests/ui/editions/edition-raw-pointer-method-2018.rs
index b346953e187..ad47553d5b7 100644
--- a/tests/ui/editions/edition-raw-pointer-method-2018.rs
+++ b/tests/ui/editions/edition-raw-pointer-method-2018.rs
@@ -6,6 +6,6 @@
 fn main() {
     let x = 0;
     let y = &x as *const _;
+    //~^ error: type annotations needed
     let _ = y.is_null();
-    //~^ error: cannot call a method on a raw pointer with an unknown pointee type [E0699]
 }
diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.stderr b/tests/ui/editions/edition-raw-pointer-method-2018.stderr
index 663843ad7bc..2792d1e7400 100644
--- a/tests/ui/editions/edition-raw-pointer-method-2018.stderr
+++ b/tests/ui/editions/edition-raw-pointer-method-2018.stderr
@@ -1,9 +1,17 @@
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
-  --> $DIR/edition-raw-pointer-method-2018.rs:9:15
+error[E0282]: type annotations needed for `*const _`
+  --> $DIR/edition-raw-pointer-method-2018.rs:8:9
    |
+LL |     let y = &x as *const _;
+   |         ^
+LL |
 LL |     let _ = y.is_null();
-   |               ^^^^^^^
+   |               ------- cannot call a method on a raw pointer with an unknown pointee type
+   |
+help: consider giving `y` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let y: *const _ = &x as *const _;
+   |          ++++++++++
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0699`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
index 72d83215ade..c139b347d99 100644
--- a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
+++ b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
@@ -25,7 +25,7 @@ fn bar() {
         let x: () = true; // Should not error due to the #[cfg(FALSE)]
     }
 
-    #[cfg_attr(not(unset_attr), cfg(FALSE))]
+    #[cfg_attr(not(FALSE), cfg(FALSE))]
     if true {
         let a: () = true; // Should not error due to the applied #[cfg(FALSE)]
     }
diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs b/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs
deleted file mode 100644
index c537fc419f6..00000000000
--- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-//@ check-pass
-
-#![warn(unnameable_types)] //~ WARN unknown lint
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr b/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr
deleted file mode 100644
index 72ac3792fff..00000000000
--- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-warning: unknown lint: `unnameable_types`
-  --> $DIR/feature-gate-type_privacy_lints.rs:3:1
-   |
-LL | #![warn(unnameable_types)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: the `unnameable_types` lint is unstable
-   = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information
-   = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: `#[warn(unknown_lints)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/filter-block-view-items.rs
index edb9ce38006..f582c51a3a6 100644
--- a/tests/ui/filter-block-view-items.rs
+++ b/tests/ui/filter-block-view-items.rs
@@ -4,5 +4,5 @@
 pub fn main() {
     // Make sure that this view item is filtered out because otherwise it would
     // trigger a compilation error
-    #[cfg(not_present)] use bar as foo;
+    #[cfg(FALSE)] use bar as foo;
 }
diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs
new file mode 100644
index 00000000000..2607013ec63
--- /dev/null
+++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs
@@ -0,0 +1,19 @@
+// ICE: assertion failed: !value.has_infer()
+// issue: rust-lang/rust#115806
+#![feature(associated_const_equality)]
+#![allow(incomplete_features)]
+
+pub struct NoPin;
+
+impl<TA> Pins<TA> for NoPin {}
+
+pub trait PinA<PER> {
+    const A: &'static () = &();
+}
+
+pub trait Pins<USART> {}
+
+impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {}
+//~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin`
+
+pub fn main() {}
diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr
new file mode 100644
index 00000000000..9a9baaddcba
--- /dev/null
+++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin`
+  --> $DIR/assoc-const-no-infer-ice-115806.rs:16:1
+   |
+LL | impl<TA> Pins<TA> for NoPin {}
+   | --------------------------- first implementation here
+...
+LL | impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin`
+   |
+   = note: downstream crates may implement trait `PinA<_>` for type `NoPin`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/impl-trait/different_where_bounds.rs b/tests/ui/impl-trait/different_where_bounds.rs
new file mode 100644
index 00000000000..87ae6db2822
--- /dev/null
+++ b/tests/ui/impl-trait/different_where_bounds.rs
@@ -0,0 +1,27 @@
+//! This test checks that the param env canonicalization cache
+//! does not end up with inconsistent values.
+
+//@ check-pass
+
+pub fn poison1() -> impl Sized
+where
+    (): 'static,
+{
+}
+pub fn poison2() -> impl Sized
+where
+    (): 'static,
+{
+    define_by_query((poison2, ()));
+}
+pub fn poison3() -> impl Sized
+where
+    (): 'static,
+{
+}
+
+trait Query {}
+impl<Out, F: Fn() -> Out> Query for (F, Out) {}
+fn define_by_query(_: impl Query) {}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr
deleted file mode 100644
index e4c8aec3973..00000000000
--- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-note: no errors encountered even though delayed bugs were created
-
-note: those delayed bugs will now be shown as internal compiler errors
-
-error: internal compiler error: {OpaqueTypeKey { def_id: DefId(rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }) } }}
-   |
-   = 
-           
-
-error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }))), bound_vars: [] } } }
-  --> $DIR/equality-in-canonical-query.rs:21:5
-   |
-LL |     same_output(foo, rpit);
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-   |
-
-  --> $DIR/equality-in-canonical-query.rs:21:5
-   |
-LL |     same_output(foo, rpit);
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-query stack during panic:
-end of query stack
diff --git a/tests/ui/impl-trait/equality-in-canonical-query.rs b/tests/ui/impl-trait/equality-in-canonical-query.rs
index 6a32f4bec76..2b8f6ce1b07 100644
--- a/tests/ui/impl-trait/equality-in-canonical-query.rs
+++ b/tests/ui/impl-trait/equality-in-canonical-query.rs
@@ -1,15 +1,6 @@
 // issue: #116877
 //@ revisions: sized clone
-//@[sized] check-pass
-//@[clone] known-bug: #108498
-//@[clone] failure-status: 101
-//@[clone] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId("
-//@[clone] normalize-stderr-test: "(?m)note: we would appreciate a bug report.*\n\n" -> ""
-//@[clone] normalize-stderr-test: "(?m)note: rustc.*running on.*\n\n" -> ""
-//@[clone] normalize-stderr-test: "(?m)note: compiler flags.*\n\n" -> ""
-//@[clone] normalize-stderr-test: "(?m)note: delayed at.*$" -> ""
-//@[clone] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> ""
-//@[clone] normalize-stderr-test: "(?m)^ *at .*\n" -> ""
+//@ check-pass
 
 #[cfg(sized)] fn rpit() -> impl Sized {}
 #[cfg(clone)] fn rpit() -> impl Clone {}
diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs
new file mode 100644
index 00000000000..994a5073947
--- /dev/null
+++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs
@@ -0,0 +1,42 @@
+// ICE failed to resolve instance for <fn() -> impl MyFnOnce  ...
+// issue: rust-lang/rust#105488
+//@ build-fail
+//~^^^ ERROR overflow evaluating the requirement `fn() -> impl MyFnOnce
+
+pub trait MyFnOnce {
+    type Output;
+
+    fn call_my_fn_once(self) -> Self::Output;
+}
+
+pub struct WrapFnOnce<F>(F);
+
+impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for WrapFnOnce<F> {
+    type Output = D::Output;
+
+    fn call_my_fn_once(self) -> Self::Output {
+        D::call_my_fn_once(self.0())
+    }
+}
+
+impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for F {
+    type Output = D::Output;
+
+    fn call_my_fn_once(self) -> Self::Output {
+        D::call_my_fn_once(self())
+    }
+}
+
+pub fn my_fn_1() -> impl MyFnOnce {
+    my_fn_2
+}
+
+pub fn my_fn_2() -> impl MyFnOnce {
+    WrapFnOnce(my_fn_1)
+}
+
+fn main() {
+    let v = my_fn_1();
+
+    let _ = v.call_my_fn_once();
+}
diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr
new file mode 100644
index 00000000000..c2782b79d90
--- /dev/null
+++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr
@@ -0,0 +1,16 @@
+error[E0275]: overflow evaluating the requirement `fn() -> impl MyFnOnce {my_fn_2}: MyFnOnce`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`failed_to_resolve_instance_ice_105488`)
+note: required for `WrapFnOnce<fn() -> impl MyFnOnce {my_fn_1}>` to implement `MyFnOnce`
+  --> $DIR/failed-to-resolve-instance-ice-105488.rs:14:37
+   |
+LL | impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for WrapFnOnce<F> {
+   |                           --------  ^^^^^^^^     ^^^^^^^^^^^^^
+   |                           |
+   |                           unsatisfied trait bound introduced here
+   = note: 126 redundant requirements hidden
+   = note: required for `WrapFnOnce<fn() -> impl MyFnOnce {my_fn_1}>` to implement `MyFnOnce`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs
new file mode 100644
index 00000000000..977827f3b55
--- /dev/null
+++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs
@@ -0,0 +1,20 @@
+// ICE failed to resolve instance for ...
+// issue: rust-lang/rust#123145
+//@ build-fail
+//~^^^ ERROR overflow evaluating the requirement `(fn() -> impl Handler
+
+trait Handler {
+    fn handle(&self) {}
+}
+
+impl<H: Handler, F: Fn() -> H> Handler for F {}
+
+impl<L: Handler> Handler for (L,) {}
+
+fn one() -> impl Handler {
+    (one,)
+}
+
+fn main() {
+    one.handle();
+}
diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr
new file mode 100644
index 00000000000..f61e8c2f8df
--- /dev/null
+++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr
@@ -0,0 +1,15 @@
+error[E0275]: overflow evaluating the requirement `(fn() -> impl Handler {one},): Handler`
+   |
+note: required for `fn() -> impl Handler {one}` to implement `Handler`
+  --> $DIR/failed-to-resolve-instance-ice-123145.rs:10:32
+   |
+LL | impl<H: Handler, F: Fn() -> H> Handler for F {}
+   |         -------                ^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: 2 redundant requirements hidden
+   = note: required for `fn() -> impl Handler {one}` to implement `Handler`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/impl-trait/nested-hkl-lifetime.rs b/tests/ui/impl-trait/nested-hkl-lifetime.rs
new file mode 100644
index 00000000000..089ceca6777
--- /dev/null
+++ b/tests/ui/impl-trait/nested-hkl-lifetime.rs
@@ -0,0 +1,32 @@
+//@ check-pass
+
+use std::iter::FromIterator;
+
+struct DynamicAlt<P>(P);
+
+impl<P> FromIterator<P> for DynamicAlt<P> {
+    fn from_iter<T: IntoIterator<Item = P>>(_iter: T) -> Self {
+        loop {}
+    }
+}
+
+fn owned_context<I, F>(_: F) -> impl FnMut(I) -> I {
+    |i| i
+}
+
+trait Parser<I> {}
+
+impl<T, I> Parser<I> for T where T: FnMut(I) -> I {}
+
+fn alt<I, P: Parser<I>>(_: DynamicAlt<P>) -> impl FnMut(I) -> I {
+    |i| i
+}
+
+fn rule_to_parser<'c>() -> impl Parser<&'c str> {
+    move |input| {
+        let v: Vec<()> = vec![];
+        alt(v.iter().map(|()| owned_context(rule_to_parser())).collect::<DynamicAlt<_>>())(input)
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs
index a696e1710f0..9b18aceb4a7 100644
--- a/tests/ui/impl-trait/nested-rpit-hrtb.rs
+++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs
@@ -44,7 +44,7 @@ fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized
 
 // This should resolve.
 fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {}
-//~^ ERROR type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>`
+//~^ ERROR the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied
 
 // This should resolve.
 fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {}
diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr
index 64f801ea685..2fa036f35fa 100644
--- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr
+++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr
@@ -86,13 +86,12 @@ note: lifetime declared here
 LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {}
    |                                            ^^
 
-error[E0283]: type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>`
+error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied
   --> $DIR/nested-rpit-hrtb.rs:46:79
    |
 LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {}
-   |                                                                               ^^^^^^^^^^^^
+   |                                                                               ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()`
    |
-   = note: cannot satisfy `for<'a> &'a (): Qux<'b>`
    = help: the trait `Qux<'_>` is implemented for `()`
    = help: for that trait implementation, expected `()`, found `&'a ()`
 
@@ -125,5 +124,5 @@ LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Si
 
 error: aborting due to 11 previous errors
 
-Some errors have detailed explanations: E0261, E0277, E0283, E0657.
+Some errors have detailed explanations: E0261, E0277, E0657.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/imports/unused-import-issue-87973.rs b/tests/ui/imports/unused-import-issue-87973.rs
index b04bec07d18..1b016ff814c 100644
--- a/tests/ui/imports/unused-import-issue-87973.rs
+++ b/tests/ui/imports/unused-import-issue-87973.rs
@@ -4,7 +4,7 @@
 // Check that attributes get removed too. See #87973.
 #[deprecated]
 #[allow(unsafe_code)]
-#[cfg(not(foo))]
+#[cfg(not(FALSE))]
 use std::fs;
 //~^ ERROR unused import
 
diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr
index 523ca229b06..c772225be75 100644
--- a/tests/ui/inference/issue-80409.no-compat.stderr
+++ b/tests/ui/inference/issue-80409.no-compat.stderr
@@ -1,4 +1,4 @@
-error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } }
+error: internal compiler error: error performing operation: fully_perform
   --> $DIR/issue-80409.rs:49:30
    |
 LL |     builder.state().on_entry(|_| {});
diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs
index 1c94169a2e5..75f406232e2 100644
--- a/tests/ui/inner-attrs-on-impl.rs
+++ b/tests/ui/inner-attrs-on-impl.rs
@@ -3,16 +3,16 @@
 struct Foo;
 
 impl Foo {
-    #![cfg(cfg_that_surely_doesnt_exist)]
+    #![cfg(FALSE)]
 
     fn method(&self) -> bool { false }
 }
 
 impl Foo {
-    #![cfg(not(cfg_that_surely_doesnt_exist))]
+    #![cfg(not(FALSE))]
 
     // check that we don't eat attributes too eagerly.
-    #[cfg(cfg_that_surely_doesnt_exist)]
+    #[cfg(FALSE)]
     fn method(&self) -> bool { false }
 
     fn method(&self) -> bool { true }
diff --git a/tests/ui/instrument-coverage/off-values.rs b/tests/ui/instrument-coverage/off-values.rs
index bd13e5d7495..60222d43b23 100644
--- a/tests/ui/instrument-coverage/off-values.rs
+++ b/tests/ui/instrument-coverage/off-values.rs
@@ -1,9 +1,9 @@
 //@ check-pass
-//@ revisions: n no off false zero
+//@ revisions: n no off _false zero
 //@ [n] compile-flags: -Cinstrument-coverage=n
 //@ [no] compile-flags: -Cinstrument-coverage=no
 //@ [off] compile-flags: -Cinstrument-coverage=off
-//@ [false] compile-flags: -Cinstrument-coverage=false
+//@ [_false] compile-flags: -Cinstrument-coverage=false
 //@ [zero] compile-flags: -Cinstrument-coverage=0
 
 fn main() {}
diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/issues/issue-11004.rs
index 10ef1f5e3b5..09d5476dbe6 100644
--- a/tests/ui/issues/issue-11004.rs
+++ b/tests/ui/issues/issue-11004.rs
@@ -2,14 +2,14 @@ use std::mem;
 
 struct A { x: i32, y: f64 }
 
-#[cfg(not(works))]
+#[cfg(not(FALSE))]
 unsafe fn access(n:*mut A) -> (i32, f64) {
     let x : i32 = n.x; //~ no field `x` on type `*mut A`
     let y : f64 = n.y; //~ no field `y` on type `*mut A`
     (x, y)
 }
 
-#[cfg(works)]
+#[cfg(FALSE)]
 unsafe fn access(n:*mut A) -> (i32, f64) {
     let x : i32 = (*n).x;
     let y : f64 = (*n).y;
diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/issues/issue-11085.rs
index c4a9f5f69bd..300be10226c 100644
--- a/tests/ui/issues/issue-11085.rs
+++ b/tests/ui/issues/issue-11085.rs
@@ -5,7 +5,7 @@
 //@ pretty-expanded FIXME #23616
 
 struct Foo {
-    #[cfg(fail)]
+    #[cfg(FALSE)]
     bar: baz,
     foo: isize,
 }
@@ -17,18 +17,18 @@ struct Foo2 {
 
 enum Bar1 {
     Bar1_1,
-    #[cfg(fail)]
+    #[cfg(FALSE)]
     Bar1_2(NotAType),
 }
 
 enum Bar2 {
-    #[cfg(fail)]
+    #[cfg(FALSE)]
     Bar2_1(NotAType),
 }
 
 enum Bar3 {
     Bar3_1 {
-        #[cfg(fail)]
+        #[cfg(FALSE)]
         foo: isize,
         bar: isize,
     }
diff --git a/tests/ui/issues/issue-16819.rs b/tests/ui/issues/issue-16819.rs
index 320695118d5..e2b10909177 100644
--- a/tests/ui/issues/issue-16819.rs
+++ b/tests/ui/issues/issue-16819.rs
@@ -3,7 +3,7 @@
 // `#[cfg]` on struct field permits empty unusable struct
 
 struct S {
-    #[cfg(untrue)]
+    #[cfg(FALSE)]
     a: int,
 }
 
diff --git a/tests/ui/issues/issue-21763.rs b/tests/ui/issues/issue-21763.rs
index a349253063c..1d0a0705cbb 100644
--- a/tests/ui/issues/issue-21763.rs
+++ b/tests/ui/issues/issue-21763.rs
@@ -1,6 +1,6 @@
 // Regression test for HashMap only impl'ing Send/Sync if its contents do
 
-//@ normalize-stderr-test: "\S+hashbrown-\S+" -> "$$HASHBROWN_SRC_LOCATION"
+//@ normalize-stderr-test: "\S+[\\/]hashbrown\S+" -> "$$HASHBROWN_SRC_LOCATION"
 
 use std::collections::HashMap;
 use std::rc::Rc;
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.rs b/tests/ui/layout/base-layout-is-sized-ice-123078.rs
new file mode 100644
index 00000000000..b1c33e15075
--- /dev/null
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs
@@ -0,0 +1,17 @@
+// ICE !base.layout().is_sized()
+// issue: rust-lang/rust#123078
+
+struct S {
+    a: [u8],
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    b: (),
+}
+
+const C: S = unsafe { std::mem::transmute(()) };
+//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types
+const _: [(); {
+    C;
+    0
+}] = [];
+
+pub fn main() {}
diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
new file mode 100644
index 00000000000..7e0a41a4367
--- /dev/null
+++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/base-layout-is-sized-ice-123078.rs:5:8
+   |
+LL |     a: [u8],
+   |        ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     a: &[u8],
+   |        +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     a: Box<[u8]>,
+   |        ++++    +
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/base-layout-is-sized-ice-123078.rs:10:23
+   |
+LL | const C: S = unsafe { std::mem::transmute(()) };
+   |                       ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `()` (0 bits)
+   = note: target type: `S` (this type does not have a fixed size)
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0512.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs
new file mode 100644
index 00000000000..96c993035ef
--- /dev/null
+++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs
@@ -0,0 +1,10 @@
+// ICE Unexpected unsized type tail: &ReStatic [u8]
+// issue: rust-lang/rust#122488
+use std::ops::Deref;
+
+struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U);
+//~^ ERROR the size for values of type `V` cannot be known at compilation time
+
+const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut();
+
+pub fn main() {}
diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr
new file mode 100644
index 00000000000..f39cb29868a
--- /dev/null
+++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr
@@ -0,0 +1,27 @@
+error[E0277]: the size for values of type `V` cannot be known at compilation time
+  --> $DIR/issue-unsized-tail-restatic-ice-122488.rs:5:61
+   |
+LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U);
+   |                           --------------------------------  ^ doesn't have a size known at compile-time
+   |                           |
+   |                           this type parameter needs to be `Sized`
+   |
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U);
+LL + struct ArenaSet<U: Deref, V = <U as Deref>::Target>(V, U);
+   |
+help: borrowed types always have a statically known size
+   |
+LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(&V, U);
+   |                                                             +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(Box<V>, U);
+   |                                                             ++++ +
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/issues/auxiliary/issue-12133-dylib.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib.rs
index 8bd2b3353b8..8bd2b3353b8 100644
--- a/tests/ui/issues/auxiliary/issue-12133-dylib.rs
+++ b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib.rs
diff --git a/tests/ui/issues/auxiliary/issue-12133-dylib2.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib2.rs
index 42e13ad6908..42e13ad6908 100644
--- a/tests/ui/issues/auxiliary/issue-12133-dylib2.rs
+++ b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib2.rs
diff --git a/tests/ui/issues/auxiliary/issue-12133-rlib.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-rlib.rs
index 1adaf2b0379..1adaf2b0379 100644
--- a/tests/ui/issues/auxiliary/issue-12133-rlib.rs
+++ b/tests/ui/linkage-attr/auxiliary/issue-12133-rlib.rs
diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr
index 5cb4d391437..23e017cb012 100644
--- a/tests/ui/linkage-attr/framework.omit.stderr
+++ b/tests/ui/linkage-attr/framework.omit.stderr
@@ -1,4 +1,4 @@
-error: linking with `cc` failed: exit status: 1
+error: linking with `LINKER` failed: exit status: 1
    |
            ld: Undefined symbols:
              _CFRunLoopGetTypeID, referenced from:
diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs
index 662ef4c429d..824adf62206 100644
--- a/tests/ui/linkage-attr/framework.rs
+++ b/tests/ui/linkage-attr/framework.rs
@@ -6,8 +6,10 @@
 //@ [weak]run-pass
 //@ [both]run-pass
 
-// The linker's exact error output changes between Xcode versions.
+// The linker's exact error output changes between Xcode versions, depends on
+// linker invocation details, and the linker sometimes outputs more warnings.
 //@ compare-output-lines-by-subset
+//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed"
 //@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:"
 //@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID,"
 
diff --git a/tests/ui/issues/issue-12133-1.rs b/tests/ui/linkage-attr/issue-12133-1.rs
index dc3f7f33da1..dc3f7f33da1 100644
--- a/tests/ui/issues/issue-12133-1.rs
+++ b/tests/ui/linkage-attr/issue-12133-1.rs
diff --git a/tests/ui/issues/issue-12133-2.rs b/tests/ui/linkage-attr/issue-12133-2.rs
index 55742a1b383..55742a1b383 100644
--- a/tests/ui/issues/issue-12133-2.rs
+++ b/tests/ui/linkage-attr/issue-12133-2.rs
diff --git a/tests/ui/issues/issue-12133-3.rs b/tests/ui/linkage-attr/issue-12133-3.rs
index a34c075d64d..a34c075d64d 100644
--- a/tests/ui/issues/issue-12133-3.rs
+++ b/tests/ui/linkage-attr/issue-12133-3.rs
diff --git a/tests/ui/lint/unused_braces_macro.rs b/tests/ui/lint/unused_braces_macro.rs
index d0b42a12ff5..f9da4ed4e49 100644
--- a/tests/ui/lint/unused_braces_macro.rs
+++ b/tests/ui/lint/unused_braces_macro.rs
@@ -2,5 +2,5 @@
 pub fn foo<const BAR: bool> () {}
 
 fn main() {
-    foo::<{cfg!(feature = "foo")}>();
+    foo::<{cfg!(FALSE)}>();
 }
diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs
index 57ba0d3bf56..83290790766 100644
--- a/tests/ui/macros/macro-attributes.rs
+++ b/tests/ui/macros/macro-attributes.rs
@@ -9,7 +9,7 @@ macro_rules! compiles_fine {
 
         // check that the attributes are recognised by requiring this
         // to be removed to avoid a compile error
-        #[cfg(always_remove)]
+        #[cfg(FALSE)]
         static MISTYPED: () = "foo";
     }
 }
diff --git a/tests/ui/macros/macro-error.rs b/tests/ui/macros/macro-error.rs
index 59ed79e91f0..4984b92911e 100644
--- a/tests/ui/macros/macro-error.rs
+++ b/tests/ui/macros/macro-error.rs
@@ -5,5 +5,5 @@ macro_rules! foo {
 fn main() {
     foo!(0); // Check that we report errors at macro definition, not expansion.
 
-    let _: cfg!(foo) = (); //~ ERROR non-type macro in type position
+    let _: cfg!(FALSE) = (); //~ ERROR non-type macro in type position
 }
diff --git a/tests/ui/macros/macro-error.stderr b/tests/ui/macros/macro-error.stderr
index 2539a6d5156..fcf8d922d65 100644
--- a/tests/ui/macros/macro-error.stderr
+++ b/tests/ui/macros/macro-error.stderr
@@ -7,8 +7,8 @@ LL |     ($a:expr) => a;
 error: non-type macro in type position: cfg
   --> $DIR/macro-error.rs:8:12
    |
-LL |     let _: cfg!(foo) = ();
-   |            ^^^^^^^^^
+LL |     let _: cfg!(FALSE) = ();
+   |            ^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs
index a8cda23075b..6dbfce21359 100644
--- a/tests/ui/macros/macro-inner-attributes.rs
+++ b/tests/ui/macros/macro-inner-attributes.rs
@@ -5,11 +5,11 @@ macro_rules! test { ($nm:ident,
                      $i:item) => (mod $nm { #![$a] $i }); }
 
 test!(a,
-      #[cfg(qux)],
+      #[cfg(FALSE)],
       pub fn bar() { });
 
 test!(b,
-      #[cfg(not(qux))],
+      #[cfg(not(FALSE))],
       pub fn bar() { });
 
 #[rustc_dummy]
diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs
index 0752f7e3153..8c79683f49a 100644
--- a/tests/ui/macros/macro-outer-attributes.rs
+++ b/tests/ui/macros/macro-outer-attributes.rs
@@ -5,11 +5,11 @@ macro_rules! test { ($nm:ident,
                      $i:item) => (mod $nm { #[$a] $i }); }
 
 test!(a,
-      #[cfg(qux)],
+      #[cfg(FALSE)],
       pub fn bar() { });
 
 test!(b,
-      #[cfg(not(qux))],
+      #[cfg(not(FALSE))],
       pub fn bar() { });
 
 // test1!(#[bar])
diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs
index 3ff26025206..37188e45ad3 100644
--- a/tests/ui/macros/macro-with-attrs2.rs
+++ b/tests/ui/macros/macro-with-attrs2.rs
@@ -1,9 +1,9 @@
 //@ run-pass
 
-#[cfg(foo)]
+#[cfg(FALSE)]
 macro_rules! foo { () => (1) }
 
-#[cfg(not(foo))]
+#[cfg(not(FALSE))]
 macro_rules! foo { () => (2) }
 
 pub fn main() {
diff --git a/tests/ui/methods/call_method_unknown_pointee.rs b/tests/ui/methods/call_method_unknown_pointee.rs
index 1643b6bfa18..a144e855ae3 100644
--- a/tests/ui/methods/call_method_unknown_pointee.rs
+++ b/tests/ui/methods/call_method_unknown_pointee.rs
@@ -8,10 +8,10 @@ fn main() {
     let ptr = &val as *const u32;
     unsafe {
         let _a: i32 = (ptr as *const _).read();
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        //~^ ERROR type annotations needed
         let b = ptr as *const _;
+        //~^ ERROR type annotations needed
         let _b: u8 = b.read();
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
         let _c = (ptr as *const u8).read(); // we know the type here
     }
 
@@ -19,10 +19,10 @@ fn main() {
     let ptr = &mut val as *mut u32;
     unsafe {
         let _a: i32 = (ptr as *mut _).read();
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        //~^ ERROR type annotations needed
         let b = ptr as *mut _;
+        //~^ ERROR type annotations needed
         b.write(10);
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
         (ptr as *mut i32).write(1000); // we know the type here
     }
 }
diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr
index 84ecf046e7a..9d0f38cf6b5 100644
--- a/tests/ui/methods/call_method_unknown_pointee.stderr
+++ b/tests/ui/methods/call_method_unknown_pointee.stderr
@@ -1,27 +1,49 @@
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+error[E0282]: type annotations needed
   --> $DIR/call_method_unknown_pointee.rs:10:41
    |
 LL |         let _a: i32 = (ptr as *const _).read();
    |                                         ^^^^
+   |                                         |
+   |                                         cannot infer type
+   |                                         cannot call a method on a raw pointer with an unknown pointee type
 
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
-  --> $DIR/call_method_unknown_pointee.rs:13:24
+error[E0282]: type annotations needed for `*const _`
+  --> $DIR/call_method_unknown_pointee.rs:12:13
    |
+LL |         let b = ptr as *const _;
+   |             ^
+LL |
 LL |         let _b: u8 = b.read();
-   |                        ^^^^
+   |                        ---- cannot call a method on a raw pointer with an unknown pointee type
+   |
+help: consider giving `b` an explicit type, where the placeholders `_` are specified
+   |
+LL |         let b: *const _ = ptr as *const _;
+   |              ++++++++++
 
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+error[E0282]: type annotations needed
   --> $DIR/call_method_unknown_pointee.rs:21:39
    |
 LL |         let _a: i32 = (ptr as *mut _).read();
    |                                       ^^^^
+   |                                       |
+   |                                       cannot infer type
+   |                                       cannot call a method on a raw pointer with an unknown pointee type
 
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
-  --> $DIR/call_method_unknown_pointee.rs:24:11
+error[E0282]: type annotations needed for `*mut _`
+  --> $DIR/call_method_unknown_pointee.rs:23:13
    |
+LL |         let b = ptr as *mut _;
+   |             ^
+LL |
 LL |         b.write(10);
-   |           ^^^^^
+   |           ----- cannot call a method on a raw pointer with an unknown pointee type
+   |
+help: consider giving `b` an explicit type, where the placeholders `_` are specified
+   |
+LL |         let b: *mut _ = ptr as *mut _;
+   |              ++++++++
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0699`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/issues/auxiliary/issue-13872-1.rs b/tests/ui/modules/auxiliary/issue-13872-1.rs
index fa9258834c7..fa9258834c7 100644
--- a/tests/ui/issues/auxiliary/issue-13872-1.rs
+++ b/tests/ui/modules/auxiliary/issue-13872-1.rs
diff --git a/tests/ui/issues/auxiliary/issue-13872-2.rs b/tests/ui/modules/auxiliary/issue-13872-2.rs
index 8c64f16e3f9..8c64f16e3f9 100644
--- a/tests/ui/issues/auxiliary/issue-13872-2.rs
+++ b/tests/ui/modules/auxiliary/issue-13872-2.rs
diff --git a/tests/ui/issues/auxiliary/issue-13872-3.rs b/tests/ui/modules/auxiliary/issue-13872-3.rs
index d31d52eb847..d31d52eb847 100644
--- a/tests/ui/issues/auxiliary/issue-13872-3.rs
+++ b/tests/ui/modules/auxiliary/issue-13872-3.rs
diff --git a/tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs b/tests/ui/modules/auxiliary/issue-1920.rs
index 1548cb99563..1548cb99563 100644
--- a/tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs
+++ b/tests/ui/modules/auxiliary/issue-1920.rs
diff --git a/tests/ui/issues/issue-13872.rs b/tests/ui/modules/issue-13872.rs
index 5589d2d4f68..5589d2d4f68 100644
--- a/tests/ui/issues/issue-13872.rs
+++ b/tests/ui/modules/issue-13872.rs
diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs b/tests/ui/modules/issue-1920-1.rs
index 763d07db2cd..763d07db2cd 100644
--- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs
+++ b/tests/ui/modules/issue-1920-1.rs
diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr b/tests/ui/modules/issue-1920-1.stderr
index b7c7da00672..b7c7da00672 100644
--- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr
+++ b/tests/ui/modules/issue-1920-1.stderr
diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs b/tests/ui/modules/issue-1920-2.rs
index b5a90b2c8e8..b5a90b2c8e8 100644
--- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs
+++ b/tests/ui/modules/issue-1920-2.rs
diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr b/tests/ui/modules/issue-1920-2.stderr
index 844cb0ff199..844cb0ff199 100644
--- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr
+++ b/tests/ui/modules/issue-1920-2.stderr
diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs b/tests/ui/modules/issue-1920-3.rs
index 372c8b1511c..372c8b1511c 100644
--- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs
+++ b/tests/ui/modules/issue-1920-3.rs
diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr b/tests/ui/modules/issue-1920-3.stderr
index 525ca4685bb..525ca4685bb 100644
--- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr
+++ b/tests/ui/modules/issue-1920-3.stderr
diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/nested-cfg-attrs.rs
index c988d423373..0af28fc3d8e 100644
--- a/tests/ui/nested-cfg-attrs.rs
+++ b/tests/ui/nested-cfg-attrs.rs
@@ -1,4 +1,4 @@
-#[cfg_attr(all(), cfg_attr(all(), cfg(foo)))]
+#[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))]
 fn f() {}
 
 fn main() { f() } //~ ERROR cannot find function `f` in this scope
diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs b/tests/ui/nll/issue-40510-1.rs
index ca53dcd9b41..ca53dcd9b41 100644
--- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs
+++ b/tests/ui/nll/issue-40510-1.rs
diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr b/tests/ui/nll/issue-40510-1.stderr
index 81fed1305cb..81fed1305cb 100644
--- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr
+++ b/tests/ui/nll/issue-40510-1.stderr
diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs b/tests/ui/nll/issue-40510-2.rs
index 9ce54862265..9ce54862265 100644
--- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs
+++ b/tests/ui/nll/issue-40510-2.rs
diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs b/tests/ui/nll/issue-40510-3.rs
index 181263adcbf..181263adcbf 100644
--- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs
+++ b/tests/ui/nll/issue-40510-3.rs
diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr b/tests/ui/nll/issue-40510-3.stderr
index 43e8a73b819..43e8a73b819 100644
--- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr
+++ b/tests/ui/nll/issue-40510-3.stderr
diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs b/tests/ui/nll/issue-40510-4.rs
index 771502894f1..771502894f1 100644
--- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs
+++ b/tests/ui/nll/issue-40510-4.rs
diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed
index aee05f5e512..4f5310082e1 100644
--- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed
+++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed
@@ -2,8 +2,6 @@
 //@[old] edition:2015
 //@[new] edition:2021
 //@[new] run-rustfix
-// FIXME: the test suite tries to create a crate called `bare_trait_dont_suggest_dyn.new`
-#![crate_name="bare_trait_dont_suggest_dyn"]
 #![deny(bare_trait_objects)]
 fn ord_prefer_dot(s: String) -> impl Ord {
     //~^ ERROR the trait `Ord` cannot be made into an object
diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr
index 52db31d620c..efddab6dff6 100644
--- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr
+++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr
@@ -1,5 +1,5 @@
 error[E0038]: the trait `Ord` cannot be made into an object
-  --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33
+  --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33
    |
 LL | fn ord_prefer_dot(s: String) -> Ord {
    |                                 ^^^ `Ord` cannot be made into an object
diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr
index f795e910d21..0545a1afcc1 100644
--- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr
+++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr
@@ -1,5 +1,5 @@
 error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33
+  --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33
    |
 LL | fn ord_prefer_dot(s: String) -> Ord {
    |                                 ^^^
@@ -7,7 +7,7 @@ LL | fn ord_prefer_dot(s: String) -> Ord {
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
 note: the lint level is defined here
-  --> $DIR/bare-trait-dont-suggest-dyn.rs:7:9
+  --> $DIR/bare-trait-dont-suggest-dyn.rs:5:9
    |
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL | fn ord_prefer_dot(s: String) -> dyn Ord {
    |                                 +++
 
 error[E0038]: the trait `Ord` cannot be made into an object
-  --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33
+  --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33
    |
 LL | fn ord_prefer_dot(s: String) -> Ord {
    |                                 ^^^ `Ord` cannot be made into an object
diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs
index e927b510b9d..cb5a305eab0 100644
--- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs
+++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs
@@ -2,8 +2,6 @@
 //@[old] edition:2015
 //@[new] edition:2021
 //@[new] run-rustfix
-// FIXME: the test suite tries to create a crate called `bare_trait_dont_suggest_dyn.new`
-#![crate_name="bare_trait_dont_suggest_dyn"]
 #![deny(bare_trait_objects)]
 fn ord_prefer_dot(s: String) -> Ord {
     //~^ ERROR the trait `Ord` cannot be made into an object
diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs
index d97f24a3d29..33671df9492 100644
--- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs
+++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs
@@ -1,9 +1,9 @@
 #![feature(stmt_expr_attributes)]
 
 fn foo() -> String {
-    #[cfg(feature = "validation")]
+    #[cfg(FALSE)]
     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() //~ ERROR expected `;`, found `#`
-    #[cfg(not(feature = "validation"))]
+    #[cfg(not(FALSE))]
     String::new()
 }
 
diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr
index a71253a5e42..6266718162f 100644
--- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr
+++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr
@@ -1,11 +1,11 @@
 error: expected `;`, found `#`
   --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
    |
-LL |     #[cfg(feature = "validation")]
-   |     ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute
+LL |     #[cfg(FALSE)]
+   |     ------------- only `;` terminated statements or tail expressions are allowed after this attribute
 LL |     [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
    |                                                                ^ expected `;` here
-LL |     #[cfg(not(feature = "validation"))]
+LL |     #[cfg(not(FALSE))]
    |     - unexpected token
    |
 help: add `;` here
@@ -18,9 +18,9 @@ LL |     { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() }
    |     +                                                             +
 help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
    |
-LL ~     if cfg!(feature = "validation") {
+LL ~     if cfg!(FALSE) {
 LL ~         [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
-LL ~     } else if cfg!(not(feature = "validation")) {
+LL ~     } else if cfg!(not(FALSE)) {
 LL ~         String::new()
 LL +     }
    |
diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs
index ad9e7ad707b..e2a62922bcc 100644
--- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs
+++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs
@@ -5,7 +5,7 @@ macro_rules! the_macro {
         #[cfg()]
         $foo //~ ERROR expected `;`, found `#`
 
-        #[cfg(bar)]
+        #[cfg(FALSE)]
         $bar
     };
 }
diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr
index 7b9b8319674..fa4409f73fa 100644
--- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr
+++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr
@@ -6,7 +6,7 @@ LL |         #[cfg()]
 LL |         $foo
    |             ^ expected `;` here
 LL |
-LL |         #[cfg(bar)]
+LL |         #[cfg(FALSE)]
    |         - unexpected token
 ...
 LL |     the_macro!( (); (); );
diff --git a/tests/ui/parser/issues/issue-103381.fixed b/tests/ui/parser/issues/issue-103381.fixed
index 9b63bf206a0..87c308789a1 100644
--- a/tests/ui/parser/issues/issue-103381.fixed
+++ b/tests/ui/parser/issues/issue-103381.fixed
@@ -37,21 +37,6 @@ fn should_ok_3() {
     if true && if true { true } else { false } {}
 }
 
-fn shoule_match_ok() {
-    #[cfg(feature = "full")]
-    {
-        let a = 1;
-        let b = 2;
-        if match a {
-            1 if b == 1 => true,
-            _ => false,
-        } && if a > 1 { true } else { false }
-        {
-            true
-        }
-    }
-}
-
 fn should_ok_in_nested() {
     if true && if true { true } else { false } { true } else { false };
 }
diff --git a/tests/ui/parser/issues/issue-103381.rs b/tests/ui/parser/issues/issue-103381.rs
index a44a7410aaf..ccbc40e5d02 100644
--- a/tests/ui/parser/issues/issue-103381.rs
+++ b/tests/ui/parser/issues/issue-103381.rs
@@ -37,21 +37,6 @@ fn should_ok_3() {
     if true && if true { true } else { false } {}
 }
 
-fn shoule_match_ok() {
-    #[cfg(feature = "full")]
-    {
-        let a = 1;
-        let b = 2;
-        if match a {
-            1 if b == 1 => true,
-            _ => false,
-        } && if a > 1 { true } else { false }
-        {
-            true
-        }
-    }
-}
-
 fn should_ok_in_nested() {
     if true && if true { true } else { false } { true } else { false };
 }
diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs
index c6c5561c3c4..e82bfd0477f 100644
--- a/tests/ui/privacy/unnameable_types.rs
+++ b/tests/ui/privacy/unnameable_types.rs
@@ -1,4 +1,3 @@
-#![feature(type_privacy_lints)]
 #![deny(unnameable_types)]
 
 mod m {
diff --git a/tests/ui/privacy/unnameable_types.stderr b/tests/ui/privacy/unnameable_types.stderr
index d68a11c9728..a1bc60ef9c2 100644
--- a/tests/ui/privacy/unnameable_types.stderr
+++ b/tests/ui/privacy/unnameable_types.stderr
@@ -1,23 +1,23 @@
 error: struct `PubStruct` is reachable but cannot be named
-  --> $DIR/unnameable_types.rs:5:5
+  --> $DIR/unnameable_types.rs:4:5
    |
 LL |     pub struct PubStruct(pub i32);
    |     ^^^^^^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)`
    |
 note: the lint level is defined here
-  --> $DIR/unnameable_types.rs:2:9
+  --> $DIR/unnameable_types.rs:1:9
    |
 LL | #![deny(unnameable_types)]
    |         ^^^^^^^^^^^^^^^^
 
 error: enum `PubE` is reachable but cannot be named
-  --> $DIR/unnameable_types.rs:7:5
+  --> $DIR/unnameable_types.rs:6:5
    |
 LL |     pub enum PubE {
    |     ^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)`
 
 error: trait `PubTr` is reachable but cannot be named
-  --> $DIR/unnameable_types.rs:11:5
+  --> $DIR/unnameable_types.rs:10:5
    |
 LL |     pub trait PubTr {
    |     ^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)`
diff --git a/tests/ui/proc-macro/modify-ast.rs b/tests/ui/proc-macro/modify-ast.rs
index 86a7d6a7772..4c125c1c6e8 100644
--- a/tests/ui/proc-macro/modify-ast.rs
+++ b/tests/ui/proc-macro/modify-ast.rs
@@ -7,7 +7,7 @@ use modify_ast::*;
 
 #[derive(Foo)]
 pub struct MyStructc {
-    #[cfg_attr(my_cfg, foo)]
+    #[cfg_attr(FALSE, foo)]
     _a: i32,
 }
 
diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs b/tests/ui/recursion/issue-23302-1.rs
index 24e79dc5811..24e79dc5811 100644
--- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs
+++ b/tests/ui/recursion/issue-23302-1.rs
diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr b/tests/ui/recursion/issue-23302-1.stderr
index 234060ab5c8..234060ab5c8 100644
--- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr
+++ b/tests/ui/recursion/issue-23302-1.stderr
diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs b/tests/ui/recursion/issue-23302-2.rs
index e89c7eab503..e89c7eab503 100644
--- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs
+++ b/tests/ui/recursion/issue-23302-2.rs
diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr b/tests/ui/recursion/issue-23302-2.stderr
index 9bd95239c83..9bd95239c83 100644
--- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr
+++ b/tests/ui/recursion/issue-23302-2.stderr
diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs b/tests/ui/recursion/issue-23302-3.rs
index da75f330798..da75f330798 100644
--- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs
+++ b/tests/ui/recursion/issue-23302-3.rs
diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr b/tests/ui/recursion/issue-23302-3.stderr
index 8a152f58966..8a152f58966 100644
--- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr
+++ b/tests/ui/recursion/issue-23302-3.stderr
diff --git a/tests/ui/sanitizer/cfg-kasan.rs b/tests/ui/sanitizer/cfg-kasan.rs
index 394bf216581..491eaf3acc1 100644
--- a/tests/ui/sanitizer/cfg-kasan.rs
+++ b/tests/ui/sanitizer/cfg-kasan.rs
@@ -2,7 +2,7 @@
 // the `#[cfg(sanitize = "address")]` attribute is configured.
 
 //@ check-pass
-//@ compile-flags: -Zsanitizer=kernel-address --cfg kernel_address
+//@ compile-flags: -Zsanitizer=kernel-address
 //@ revisions: aarch64 riscv64imac riscv64gc x86_64
 //@[aarch64] compile-flags: --target aarch64-unknown-none
 //@[aarch64] needs-llvm-components: aarch64
@@ -22,5 +22,5 @@ trait Sized {}
 
 const _: fn() -> () = main;
 
-#[cfg(all(sanitize = "address", kernel_address))]
+#[cfg(sanitize = "address")]
 fn main() {}
diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-fn-ptr.rs
index 8f79de11748..505b4b8e7f0 100644
--- a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs
+++ b/tests/ui/sanitizer/cfi-fn-ptr.rs
@@ -1,4 +1,4 @@
-// Verifies that casting a method to a function pointer works.
+// Verifies that casting to a function pointer works.
 
 //@ revisions: cfi kcfi
 // FIXME(#122848) Remove only-linux once OSX CFI binaries work
@@ -46,6 +46,8 @@ impl Trait1 for Type1 {
     fn foo(&self) {}
 }
 
+fn foo<T>(_: &T) {}
+
 fn main() {
     let type1 = Type1 {};
     let f = <Type1 as Trait1>::foo;
@@ -53,5 +55,7 @@ fn main() {
     // Check again with different optimization barriers
     S2 { f: <S as Foo>::foo }.foo(&S);
     // Check mismatched #[track_caller]
-    S2 { f: <S as Foo>::bar }.foo(&S)
+    S2 { f: <S as Foo>::bar }.foo(&S);
+    // Check non-method functions
+    S2 { f: foo }.foo(&S)
 }
diff --git a/tests/ui/sanitizer/kcfi-mangling.rs b/tests/ui/sanitizer/kcfi-mangling.rs
new file mode 100644
index 00000000000..fde7b5451b6
--- /dev/null
+++ b/tests/ui/sanitizer/kcfi-mangling.rs
@@ -0,0 +1,30 @@
+// Check KCFI extra mangling works correctly on v0
+
+//@ needs-sanitizer-kcfi
+//@ no-prefer-dynamic
+//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0
+//@ build-pass
+
+trait Foo {
+    fn foo(&self);
+}
+
+struct Bar;
+impl Foo for Bar {
+    fn foo(&self) {}
+}
+
+struct Baz;
+impl Foo for Baz {
+    #[track_caller]
+    fn foo(&self) {}
+}
+
+fn main() {
+    // Produces `ReifyShim(_, ReifyReason::FnPtr)`
+    let f: fn(&Bar) = Bar::foo;
+    f(&Bar);
+    // Produces `ReifyShim(_, ReifyReason::Vtable)`
+    let v: &dyn Foo = &Baz as _;
+    v.foo();
+}
diff --git a/tests/ui/stmt_expr_attrs_no_feature.rs b/tests/ui/stmt_expr_attrs_no_feature.rs
index 627c97da008..a160a9bb082 100644
--- a/tests/ui/stmt_expr_attrs_no_feature.rs
+++ b/tests/ui/stmt_expr_attrs_no_feature.rs
@@ -25,25 +25,25 @@ fn main() {
 
 // Check that cfg works right
 
-#[cfg(unset)]
+#[cfg(FALSE)]
 fn c() {
     #[rustc_dummy]
     5;
 }
 
-#[cfg(not(unset))]
+#[cfg(not(FALSE))]
 fn j() {
     #[rustc_dummy]
     5;
 }
 
-#[cfg_attr(not(unset), cfg(unset))]
+#[cfg_attr(not(FALSE), cfg(FALSE))]
 fn d() {
     #[rustc_dummy]
     8;
 }
 
-#[cfg_attr(not(unset), cfg(not(unset)))]
+#[cfg_attr(not(FALSE), cfg(not(FALSE)))]
 fn i() {
     #[rustc_dummy]
     8;
@@ -57,25 +57,25 @@ macro_rules! item_mac {
             #[rustc_dummy]
             42;
 
-            #[cfg(unset)]
+            #[cfg(FALSE)]
             fn f() {
                 #[rustc_dummy]
                 5;
             }
 
-            #[cfg(not(unset))]
+            #[cfg(not(FALSE))]
             fn k() {
                 #[rustc_dummy]
                 5;
             }
 
-            #[cfg_attr(not(unset), cfg(unset))]
+            #[cfg_attr(not(FALSE), cfg(FALSE))]
             fn g() {
                 #[rustc_dummy]
                 8;
             }
 
-            #[cfg_attr(not(unset), cfg(not(unset)))]
+            #[cfg_attr(not(FALSE), cfg(not(FALSE)))]
             fn h() {
                 #[rustc_dummy]
                 8;
@@ -90,42 +90,42 @@ item_mac!(e);
 // check that the gate visitor works right:
 
 extern "C" {
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     fn x(a: [u8; #[rustc_dummy] 5]);
     fn y(a: [u8; #[rustc_dummy] 5]); //~ ERROR attributes on expressions are experimental
 }
 
 struct Foo;
 impl Foo {
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     const X: u8 = #[rustc_dummy] 5;
     const Y: u8 = #[rustc_dummy] 5; //~ ERROR attributes on expressions are experimental
 }
 
 trait Bar {
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     const X: [u8; #[rustc_dummy] 5];
     const Y: [u8; #[rustc_dummy] 5]; //~ ERROR attributes on expressions are experimental
 }
 
 struct Joyce {
-    #[cfg(unset)]
+    #[cfg(FALSE)]
     field: [u8; #[rustc_dummy] 5],
     field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
 }
 
 struct Walky(
-    #[cfg(unset)] [u8; #[rustc_dummy] 5],
+    #[cfg(FALSE)] [u8; #[rustc_dummy] 5],
     [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
 );
 
 enum Mike {
     Happy(
-        #[cfg(unset)] [u8; #[rustc_dummy] 5],
+        #[cfg(FALSE)] [u8; #[rustc_dummy] 5],
         [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
     ),
     Angry {
-        #[cfg(unset)]
+        #[cfg(FALSE)]
         field: [u8; #[rustc_dummy] 5],
         field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
     }
@@ -133,7 +133,7 @@ enum Mike {
 
 fn pat() {
     match 5 {
-        #[cfg(unset)]
+        #[cfg(FALSE)]
         5 => #[rustc_dummy] (),
         6 => #[rustc_dummy] (), //~ ERROR attributes on expressions are experimental
         _ => (),
diff --git a/tests/ui/suggestions/option-to-bool.rs b/tests/ui/suggestions/option-to-bool.rs
index 2a1823b15f5..bbc5d1d71cb 100644
--- a/tests/ui/suggestions/option-to-bool.rs
+++ b/tests/ui/suggestions/option-to-bool.rs
@@ -1,5 +1,3 @@
-#![cfg_attr(let_chains, feature(let_chains))]
-
 fn foo(x: Option<i32>) {
     if true && x {}
     //~^ ERROR mismatched types
diff --git a/tests/ui/suggestions/option-to-bool.stderr b/tests/ui/suggestions/option-to-bool.stderr
index e16d829ca7a..ab97eae6c5c 100644
--- a/tests/ui/suggestions/option-to-bool.stderr
+++ b/tests/ui/suggestions/option-to-bool.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/option-to-bool.rs:4:16
+  --> $DIR/option-to-bool.rs:2:16
    |
 LL |     if true && x {}
    |        ----    ^ expected `bool`, found `Option<i32>`
diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr
index c1cbefac828..6ce0ae09195 100644
--- a/tests/ui/symbol-names/basic.legacy.stderr
+++ b/tests/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE)
+error: symbol-name(_ZN5basic4main17had874e876c8b1028E)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::h6fc0c8d27b1a289f)
+error: demangling(basic::main::had874e876c8b1028)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr
index 7dd68e6e3a8..cc4eec470fb 100644
--- a/tests/ui/symbol-names/issue-60925.legacy.stderr
+++ b/tests/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17haf0d0ad2255e29c6E)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hab58a402db4ebf3a)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::haf0d0ad2255e29c6)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/tests/ui/issues/issue-2611-3.rs b/tests/ui/traits/issue-2611-3.rs
index c95ebae33fa..c95ebae33fa 100644
--- a/tests/ui/issues/issue-2611-3.rs
+++ b/tests/ui/traits/issue-2611-3.rs
diff --git a/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs b/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs
new file mode 100644
index 00000000000..4e8c19d600d
--- /dev/null
+++ b/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs
@@ -0,0 +1,244 @@
+// This is a non-regression test for issues #108721 and its duplicate #123275 (hopefully, because
+// the test is still convoluted and the ICE is fiddly).
+//
+// `pred_known_to_hold_modulo_regions` prevented "unexpected unsized tail" ICEs with warp/hyper but
+// was unknowingly removed in #120463.
+
+//@ build-pass: the ICE happened in codegen
+
+use std::future::Future;
+trait TryFuture: Future {
+    type Ok;
+}
+impl<F, T> TryFuture for F
+where
+    F: ?Sized + Future<Output = Option<T>>,
+{
+    type Ok = T;
+}
+trait Executor {}
+struct Exec {}
+trait HttpBody {
+    type Data;
+}
+trait ConnStreamExec<F> {}
+impl<F> ConnStreamExec<F> for Exec where H2Stream<F>: Send {}
+impl<E, F> ConnStreamExec<F> for E where E: Executor {}
+struct H2Stream<F> {
+    _fut: F,
+}
+trait NewSvcExec<S, E, W: Watcher<S, E>> {
+    fn execute_new_svc(&mut self, _fut: NewSvcTask<S, E, W>) {
+        unimplemented!()
+    }
+}
+impl<S, E, W> NewSvcExec<S, E, W> for Exec where W: Watcher<S, E> {}
+trait Watcher<S, E> {
+    type Future;
+}
+struct NoopWatcher;
+impl<S, E> Watcher<S, E> for NoopWatcher
+where
+    S: HttpService,
+    E: ConnStreamExec<S::Future>,
+{
+    type Future = Option<<<S as HttpService>::ResBody as HttpBody>::Data>;
+}
+trait Service<Request> {
+    type Response;
+    type Future;
+}
+trait HttpService {
+    type ResBody: HttpBody;
+    type Future;
+}
+struct Body {}
+impl HttpBody for Body {
+    type Data = String;
+}
+impl<S> HttpService for S
+where
+    S: Service<(), Response = ()>,
+{
+    type ResBody = Body;
+    type Future = S::Future;
+}
+trait MakeServiceRef<Target> {
+    type ResBody;
+    type Service: HttpService<ResBody = Self::ResBody>;
+}
+impl<T, Target, S, F> MakeServiceRef<Target> for T
+where
+    T: for<'a> Service<&'a Target, Response = S, Future = F>,
+    S: HttpService,
+{
+    type Service = S;
+    type ResBody = S::ResBody;
+}
+fn make_service_fn<F, Target, Ret>(_f: F) -> MakeServiceFn<F>
+where
+    F: FnMut(&Target) -> Ret,
+    Ret: Future,
+{
+    unimplemented!()
+}
+struct MakeServiceFn<F> {
+    _func: F,
+}
+impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F>
+where
+    F: FnMut(&Target) -> Ret,
+    Ret: Future<Output = Option<Svc>>,
+{
+    type Response = Svc;
+    type Future = Option<()>;
+}
+struct AddrIncoming {}
+struct Server<I, S, E> {
+    _incoming: I,
+    _make_service: S,
+    _protocol: E,
+}
+impl<I, S, E, B> Server<I, S, E>
+where
+    S: MakeServiceRef<(), ResBody = B>,
+    B: HttpBody,
+    E: ConnStreamExec<<S::Service as HttpService>::Future>,
+    E: NewSvcExec<S::Service, E, NoopWatcher>,
+{
+    fn serve(&mut self) {
+        let fut = NewSvcTask::new();
+        self._protocol.execute_new_svc(fut);
+    }
+}
+fn serve<S>(_make_service: S) -> Server<AddrIncoming, S, Exec> {
+    unimplemented!()
+}
+struct NewSvcTask<S, E, W: Watcher<S, E>> {
+    _state: State<S, E, W>,
+}
+struct State<S, E, W: Watcher<S, E>> {
+    _fut: W::Future,
+}
+impl<S, E, W: Watcher<S, E>> NewSvcTask<S, E, W> {
+    fn new() -> Self {
+        unimplemented!()
+    }
+}
+trait Filter {
+    type Extract;
+    type Future;
+    fn map<F>(self, _fun: F) -> MapFilter<Self, F>
+    where
+        Self: Sized,
+    {
+        unimplemented!()
+    }
+    fn wrap_with<W>(self, _wrapper: W) -> W::Wrapped
+    where
+        Self: Sized,
+        W: Wrap<Self>,
+    {
+        unimplemented!()
+    }
+}
+fn service<F>(_filter: F) -> FilteredService<F>
+where
+    F: Filter,
+{
+    unimplemented!()
+}
+struct FilteredService<F> {
+    _filter: F,
+}
+impl<F> Service<()> for FilteredService<F>
+where
+    F: Filter,
+{
+    type Response = ();
+    type Future = FilteredFuture<F::Future>;
+}
+struct FilteredFuture<F> {
+    _fut: F,
+}
+struct MapFilter<T, F> {
+    _filter: T,
+    _func: F,
+}
+impl<T, F> Filter for MapFilter<T, F>
+where
+    T: Filter,
+    F: Func<T::Extract>,
+{
+    type Extract = F::Output;
+    type Future = MapFilterFuture<T, F>;
+}
+struct MapFilterFuture<T: Filter, F> {
+    _extract: T::Future,
+    _func: F,
+}
+trait Wrap<F> {
+    type Wrapped;
+}
+fn make_filter_fn<F, U>(_func: F) -> FilterFn<F>
+where
+    F: Fn() -> U,
+{
+    unimplemented!()
+}
+struct FilterFn<F> {
+    _func: F,
+}
+impl<F, U> Filter for FilterFn<F>
+where
+    F: Fn() -> U,
+    U: TryFuture,
+    U::Ok: Send,
+{
+    type Extract = U::Ok;
+    type Future = Option<U>;
+}
+fn trace<F>(_func: F) -> Trace<F>
+where
+    F: Fn(),
+{
+    unimplemented!()
+}
+struct Trace<F> {
+    _func: F,
+}
+impl<FN, F> Wrap<F> for Trace<FN> {
+    type Wrapped = WithTrace<FN, F>;
+}
+struct WithTrace<FN, F> {
+    _filter: F,
+    _trace: FN,
+}
+impl<FN, F> Filter for WithTrace<FN, F>
+where
+    F: Filter,
+{
+    type Extract = ();
+    type Future = (F::Future, fn(F::Extract));
+}
+trait Func<Args> {
+    type Output;
+}
+impl<F, R> Func<()> for F
+where
+    F: Fn() -> R,
+{
+    type Output = R;
+}
+fn main() {
+    let make_service = make_service_fn(|_| {
+        let tracer = trace(|| unimplemented!());
+        let filter = make_filter_fn(|| std::future::ready(Some(())))
+            .map(|| "Hello, world")
+            .wrap_with(tracer);
+        let svc = service(filter);
+        std::future::ready(Some(svc))
+    });
+    let mut server = serve(make_service);
+    server.serve();
+}
diff --git a/tests/ui/transmutability/arrays/huge-len.stderr b/tests/ui/transmutability/arrays/huge-len.stderr
index 37160c5c959..3fc652f47c1 100644
--- a/tests/ui/transmutability/arrays/huge-len.stderr
+++ b/tests/ui/transmutability/arrays/huge-len.stderr
@@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `ExplicitlyPadded`
   --> $DIR/huge-len.rs:21:41
    |
 LL |     assert::is_maybe_transmutable::<(), ExplicitlyPadded>();
-   |                                         ^^^^^^^^^^^^^^^^ values of the type `ExplicitlyPadded` are too big for the current architecture
+   |                                         ^^^^^^^^^^^^^^^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/huge-len.rs:8:14
@@ -17,7 +17,7 @@ error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()`
   --> $DIR/huge-len.rs:24:55
    |
 LL |     assert::is_maybe_transmutable::<ExplicitlyPadded, ()>();
-   |                                                       ^^ values of the type `ExplicitlyPadded` are too big for the current architecture
+   |                                                       ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/huge-len.rs:8:14
diff --git a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr
index e486928a445..b4cd70142c4 100644
--- a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr
+++ b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr
@@ -2,7 +2,7 @@ error[E0277]: `[String; 0]` cannot be safely transmuted into `()`
   --> $DIR/should_require_well_defined_layout.rs:25:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `[String; 0]` is not yet supported.
+   |                                                    ^^ analyzing the transmutability of `[String; 0]` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -23,7 +23,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 0]`
   --> $DIR/should_require_well_defined_layout.rs:26:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 0]` is not yet supported.
+   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 0]` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -44,7 +44,7 @@ error[E0277]: `[String; 1]` cannot be safely transmuted into `()`
   --> $DIR/should_require_well_defined_layout.rs:31:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `[String; 1]` is not yet supported.
+   |                                                    ^^ analyzing the transmutability of `[String; 1]` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -65,7 +65,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 1]`
   --> $DIR/should_require_well_defined_layout.rs:32:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 1]` is not yet supported.
+   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 1]` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -86,7 +86,7 @@ error[E0277]: `[String; 2]` cannot be safely transmuted into `()`
   --> $DIR/should_require_well_defined_layout.rs:37:52
    |
 LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `[String; 2]` is not yet supported.
+   |                                                    ^^ analyzing the transmutability of `[String; 2]` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
@@ -107,7 +107,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 2]`
   --> $DIR/should_require_well_defined_layout.rs:38:47
    |
 LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 2]` is not yet supported.
+   |                                               ^^^^^^^^^ analyzing the transmutability of `[String; 2]` is not yet supported
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/should_require_well_defined_layout.rs:12:14
diff --git a/tests/ui/transmutability/enums/niche_optimization.rs b/tests/ui/transmutability/enums/niche_optimization.rs
new file mode 100644
index 00000000000..23f57ecad75
--- /dev/null
+++ b/tests/ui/transmutability/enums/niche_optimization.rs
@@ -0,0 +1,156 @@
+//@ check-pass
+//! Checks that niche optimizations are encoded correctly.
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::{Assume, BikeshedIntrinsicFrom};
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, {
+            Assume {
+                alignment: false,
+                lifetimes: false,
+                safety: true,
+                validity: false,
+            }
+        }>
+    {}
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, {
+            Assume {
+                alignment: false,
+                lifetimes: false,
+                safety: true,
+                validity: true,
+            }
+        }>
+    {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+#[repr(u8)] enum V2 { V = 2 }
+#[repr(u8)] enum V253 { V = 253 }
+#[repr(u8)] enum V254 { V = 254 }
+#[repr(u8)] enum V255 { V = 255 }
+
+fn bool() {
+    enum OptionLike {
+        A(bool),
+        B,
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<OptionLike>() == 1);
+    };
+
+    assert::is_transmutable::<OptionLike, u8>();
+
+    assert::is_transmutable::<bool, OptionLike>();
+    assert::is_transmutable::<V0, OptionLike>();
+    assert::is_transmutable::<V1, OptionLike>();
+    assert::is_transmutable::<V2, OptionLike>();
+}
+
+fn one_niche() {
+    #[repr(u8)]
+    enum N1 {
+        S = 0,
+        E = 255 - 1,
+    }
+
+    enum OptionLike {
+        A(N1),
+        B,
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<OptionLike>() == 1);
+    };
+
+    assert::is_transmutable::<OptionLike, u8>();
+    assert::is_transmutable::<V0, OptionLike>();
+    assert::is_transmutable::<V254, OptionLike>();
+    assert::is_transmutable::<V255, OptionLike>();
+}
+
+fn one_niche_alt() {
+    #[repr(u8)]
+    enum N1 {
+        S = 1,
+        E = 255 - 1,
+    }
+
+    enum OptionLike {
+        A(N1),
+        B,
+        C,
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<OptionLike>() == 1);
+    };
+
+    assert::is_transmutable::<OptionLike, u8>();
+    assert::is_transmutable::<V0, OptionLike>();
+    assert::is_transmutable::<V254, OptionLike>();
+    assert::is_transmutable::<V255, OptionLike>();
+}
+
+fn two_niche() {
+    #[repr(u8)]
+    enum Niche {
+        S = 0,
+        E = 255 - 2,
+    }
+
+    enum OptionLike {
+        A(Niche),
+        B,
+        C,
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<OptionLike>() == 1);
+    };
+
+    assert::is_transmutable::<OptionLike, u8>();
+    assert::is_transmutable::<V0, OptionLike>();
+    assert::is_transmutable::<V253, OptionLike>();
+    assert::is_transmutable::<V254, OptionLike>();
+    assert::is_transmutable::<V255, OptionLike>();
+}
+
+fn no_niche() {
+    use std::mem::MaybeUninit;
+
+    #[repr(u8)]
+    enum Niche {
+        S = 0,
+        E = 255 - 1,
+    }
+
+    enum OptionLike {
+        A(Niche),
+        B,
+        C,
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<OptionLike>() == 2);
+    };
+
+    #[repr(C)]
+    struct Pair<T, U>(T, U);
+
+    assert::is_transmutable::<V0, Niche>();
+    assert::is_transmutable::<V254, Niche>();
+    assert::is_transmutable::<Pair<V0, Niche>, OptionLike>();
+    assert::is_transmutable::<Pair<V1, MaybeUninit<u8>>, OptionLike>();
+    assert::is_transmutable::<Pair<V2, MaybeUninit<u8>>, OptionLike>();
+}
diff --git a/tests/ui/transmutability/enums/repr/padding_differences.rs b/tests/ui/transmutability/enums/repr/padding_differences.rs
new file mode 100644
index 00000000000..d0e1502b5e2
--- /dev/null
+++ b/tests/ui/transmutability/enums/repr/padding_differences.rs
@@ -0,0 +1,80 @@
+//@ check-pass
+//! Adapted from https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html#explicit-repr-annotation-without-c-compatibility
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+use std::mem::MaybeUninit;
+
+mod assert {
+    use std::mem::{Assume, BikeshedIntrinsicFrom};
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, {
+            Assume {
+                alignment: false,
+                lifetimes: false,
+                safety: true,
+                validity: false,
+            }
+        }>
+    {}
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, {
+            Assume {
+                alignment: false,
+                lifetimes: false,
+                safety: true,
+                validity: true,
+            }
+        }>
+    {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+
+fn repr_u8() {
+    #[repr(u8)]
+    enum TwoCases {
+        A(u8, u16),     // 0x00 INIT INIT INIT
+        B(u16),         // 0x01 PADD INIT INIT
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<TwoCases>() == 4);
+    };
+
+    #[repr(C)] struct TwoCasesA(V0, u8, u8, u8);
+    #[repr(C)] struct TwoCasesB(V1, MaybeUninit<u8>, u8, u8);
+
+    assert::is_transmutable::<TwoCasesA, TwoCases>();
+    assert::is_transmutable::<TwoCasesB, TwoCases>();
+
+    assert::is_maybe_transmutable::<TwoCases, TwoCasesA>();
+    assert::is_maybe_transmutable::<TwoCases, TwoCasesB>();
+}
+
+fn repr_c_u8() {
+    #[repr(C, u8)]
+    enum TwoCases {
+        A(u8, u16),     // 0x00 PADD INIT PADD INIT INIT
+        B(u16),         // 0x01 PADD INIT INIT PADD PADD
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<TwoCases>() == 6);
+    };
+
+    #[repr(C)] struct TwoCasesA(V0, MaybeUninit<u8>, u8, MaybeUninit<u8>, u8, u8);
+    #[repr(C)] struct TwoCasesB(V1, MaybeUninit<u8>, u8, u8, MaybeUninit<u8>, MaybeUninit<u8>);
+
+    assert::is_transmutable::<TwoCasesA, TwoCases>();
+    assert::is_transmutable::<TwoCasesB, TwoCases>();
+
+    assert::is_maybe_transmutable::<TwoCases, TwoCasesA>();
+    assert::is_maybe_transmutable::<TwoCases, TwoCasesB>();
+}
diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/enums/repr/should_handle_all.rs
index 630e662b926..a8ec86fa40d 100644
--- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.rs
+++ b/tests/ui/transmutability/enums/repr/should_handle_all.rs
@@ -1,5 +1,4 @@
-//! An enum must have a well-defined layout to participate in a transmutation.
-
+//@ check-pass
 #![crate_type = "lib"]
 #![feature(repr128)]
 #![feature(transmutability)]
@@ -21,23 +20,17 @@ mod assert {
     {}
 }
 
-fn should_reject_repr_rust() {
-    fn void() {
-        enum repr_rust {}
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
-    }
-
+fn should_accept_repr_rust() {
     fn singleton() {
         enum repr_rust { V }
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_rust, ()>();
+        assert::is_maybe_transmutable::<u128, repr_rust>();
     }
 
     fn duplex() {
         enum repr_rust { A, B }
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_rust, ()>();
+        assert::is_maybe_transmutable::<u128, repr_rust>();
     }
 }
 
@@ -116,7 +109,7 @@ fn should_accept_primitive_reprs()
     }
 }
 
-fn should_accept_repr_C() {
+fn should_accept_repr_c() {
     #[repr(C)] enum repr_c { V }
     assert::is_maybe_transmutable::<repr_c, ()>();
     assert::is_maybe_transmutable::<i128, repr_c>();
diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
deleted file mode 100644
index 2a683de6a65..00000000000
--- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
+++ /dev/null
@@ -1,135 +0,0 @@
-error[E0277]: `void::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:27:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `void::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:13:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:28:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `void::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:13:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:33:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:13:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:34:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:13:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:39:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:13:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:40:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:13:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr
index eeed8a62a2a..cabc7bcfef7 100644
--- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr
+++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr
@@ -8,7 +8,7 @@ error[E0277]: `Src` cannot be safely transmuted into `Dst`
   --> $DIR/unknown_src_field.rs:19:36
    |
 LL |     assert::is_transmutable::<Src, Dst>();
-   |                                    ^^^ `Dst` has an unknown layout
+   |                                    ^^^ analyzing the transmutability of `Dst` is not yet supported
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/unknown_src_field.rs:12:14
diff --git a/tests/ui/transmutability/maybeuninit.rs b/tests/ui/transmutability/maybeuninit.rs
new file mode 100644
index 00000000000..77c3381c774
--- /dev/null
+++ b/tests/ui/transmutability/maybeuninit.rs
@@ -0,0 +1,43 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+use std::mem::MaybeUninit;
+
+mod assert {
+    use std::mem::{Assume, BikeshedIntrinsicFrom};
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }>
+    {}
+}
+
+fn validity() {
+    // An initialized byte is a valid uninitialized byte.
+    assert::is_maybe_transmutable::<u8, MaybeUninit<u8>>();
+
+    // An uninitialized byte is never a valid initialized byte.
+    assert::is_maybe_transmutable::<MaybeUninit<u8>, u8>(); //~ ERROR: cannot be safely transmuted
+}
+
+fn padding() {
+    #[repr(align(8))]
+    struct Align8;
+
+    #[repr(u8)]
+    enum ImplicitlyPadded {
+        A(Align8),
+    }
+
+    #[repr(u8)]
+    enum V0 {
+        V0 = 0,
+    }
+
+    #[repr(C)]
+    struct ExplicitlyPadded(V0, MaybeUninit<[u8; 7]>);
+
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+}
diff --git a/tests/ui/transmutability/maybeuninit.stderr b/tests/ui/transmutability/maybeuninit.stderr
new file mode 100644
index 00000000000..be7dcaf35ea
--- /dev/null
+++ b/tests/ui/transmutability/maybeuninit.stderr
@@ -0,0 +1,18 @@
+error[E0277]: `MaybeUninit<u8>` cannot be safely transmuted into `u8`
+  --> $DIR/maybeuninit.rs:21:54
+   |
+LL |     assert::is_maybe_transmutable::<MaybeUninit<u8>, u8>();
+   |                                                      ^^ at least one value of `MaybeUninit<u8>` isn't a bit-valid value of `u8`
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/maybeuninit.rs:12:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this function
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/transmutability/references/unsafecell.rs b/tests/ui/transmutability/references/unsafecell.rs
new file mode 100644
index 00000000000..a8a1f969fb4
--- /dev/null
+++ b/tests/ui/transmutability/references/unsafecell.rs
@@ -0,0 +1,47 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+use std::cell::UnsafeCell;
+
+mod assert {
+    use std::mem::{Assume, BikeshedIntrinsicFrom};
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }>
+    {}
+}
+
+fn value_to_value() {
+    // We accept value-to-value transmutations of `UnsafeCell`-containing types,
+    // because owning a value implies exclusive access.
+    assert::is_maybe_transmutable::<UnsafeCell<u8>, u8>();
+    assert::is_maybe_transmutable::<u8, UnsafeCell<u8>>();
+    assert::is_maybe_transmutable::<UnsafeCell<u8>, UnsafeCell<u8>>();
+}
+
+fn ref_to_ref() {
+    // We forbid `UnsafeCell`-containing ref-to-ref transmutations, because the
+    // two types may use different, incompatible synchronization strategies.
+    assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted
+
+    assert::is_maybe_transmutable::<&'static UnsafeCell<u8>, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted
+}
+
+fn mut_to_mut() {
+    // `UnsafeCell` does't matter for `&mut T` to `&mut U`, since exclusive
+    // borrows can't be used for shared access.
+    assert::is_maybe_transmutable::<&'static mut u8, &'static mut UnsafeCell<u8>>();
+    assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static mut u8>();
+    assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static mut UnsafeCell<u8>>();
+}
+
+fn mut_to_ref() {
+    // We don't care about `UnsafeCell` for transmutations in the form `&mut T
+    // -> &U`, because downgrading a `&mut T` to a `&U` deactivates `&mut T` for
+    // the lifetime of `&U`.
+    assert::is_maybe_transmutable::<&'static mut u8, &'static UnsafeCell<u8>>();
+    assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static u8>();
+    assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static UnsafeCell<u8>>();
+}
diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr
new file mode 100644
index 00000000000..651eb8ceb26
--- /dev/null
+++ b/tests/ui/transmutability/references/unsafecell.stderr
@@ -0,0 +1,33 @@
+error[E0277]: `&u8` cannot be safely transmuted into `&UnsafeCell<u8>`
+  --> $DIR/unsafecell.rs:27:50
+   |
+LL |     assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell<u8>>();
+   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>`
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/unsafecell.rs:12:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this function
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `&UnsafeCell<u8>` cannot be safely transmuted into `&UnsafeCell<u8>`
+  --> $DIR/unsafecell.rs:29:62
+   |
+LL |     assert::is_maybe_transmutable::<&'static UnsafeCell<u8>, &'static UnsafeCell<u8>>();
+   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>`
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/unsafecell.rs:12:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this function
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/structs/repr/should_handle_all.rs
index 2e673601baf..52c24eecf12 100644
--- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.rs
+++ b/tests/ui/transmutability/structs/repr/should_handle_all.rs
@@ -1,3 +1,4 @@
+//@ check-pass
 //! A struct must have a well-defined layout to participate in a transmutation.
 
 #![crate_type = "lib"]
@@ -20,47 +21,47 @@ mod assert {
     {}
 }
 
-fn should_reject_repr_rust()
+fn should_accept_repr_rust()
 {
     fn unit() {
         struct repr_rust;
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_rust, ()>();
+        assert::is_maybe_transmutable::<u128, repr_rust>();
     }
 
     fn tuple() {
         struct repr_rust();
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_rust, ()>();
+        assert::is_maybe_transmutable::<u128, repr_rust>();
     }
 
     fn braces() {
         struct repr_rust{}
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_rust, ()>();
+        assert::is_maybe_transmutable::<u128, repr_rust>();
     }
 
     fn aligned() {
         #[repr(align(1))] struct repr_rust{}
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_rust, ()>();
+        assert::is_maybe_transmutable::<u128, repr_rust>();
     }
 
     fn packed() {
         #[repr(packed)] struct repr_rust{}
-        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_rust, ()>();
+        assert::is_maybe_transmutable::<u128, repr_rust>();
     }
 
     fn nested() {
         struct repr_rust;
         #[repr(C)] struct repr_c(repr_rust);
-        assert::is_maybe_transmutable::<repr_c, ()>(); //~ ERROR cannot be safely transmuted
-        assert::is_maybe_transmutable::<u128, repr_c>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<repr_c, ()>();
+        assert::is_maybe_transmutable::<u128, repr_c>();
     }
 }
 
-fn should_accept_repr_C()
+fn should_accept_repr_c()
 {
     fn unit() {
         #[repr(C)] struct repr_c;
diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
deleted file mode 100644
index 77788f72c21..00000000000
--- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
+++ /dev/null
@@ -1,267 +0,0 @@
-error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:27:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:28:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:33:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:34:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:39:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:40:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:45:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:46:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:51:52
-   |
-LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                    ^^ analyzing the transmutability of `packed::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:52:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                               ^^^^^^^^^ analyzing the transmutability of `packed::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `nested::repr_c` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:58:49
-   |
-LL |         assert::is_maybe_transmutable::<repr_c, ()>();
-   |                                                 ^^ analyzing the transmutability of `nested::repr_c` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c`
-  --> $DIR/should_require_well_defined_layout.rs:59:47
-   |
-LL |         assert::is_maybe_transmutable::<u128, repr_c>();
-   |                                               ^^^^^^ analyzing the transmutability of `nested::repr_c` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error: aborting due to 12 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs
index 4c285a616b3..64110753832 100644
--- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs
+++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs
@@ -22,4 +22,5 @@ fn should_pad_explicitly_packed_field() {
     //~^ ERROR: recursive type
 
     assert::is_maybe_transmutable::<ExplicitlyPadded, ()>();
+    //~^ ERROR: cannot be safely transmuted
 }
diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr
index 7fb051f6625..ebfb5361143 100644
--- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr
+++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr
@@ -15,7 +15,22 @@ error[E0391]: cycle detected when computing layout of `should_pad_explicitly_pac
    = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::BikeshedIntrinsicFrom<should_pad_explicitly_packed_field::ExplicitlyPadded, core::mem::transmutability::Assume { alignment: false, lifetimes: false, safety: false, validity: false }>`
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
-error: aborting due to 2 previous errors
+error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()`
+  --> $DIR/transmute_infinitely_recursive_type.rs:24:55
+   |
+LL |     assert::is_maybe_transmutable::<ExplicitlyPadded, ()>();
+   |                                                       ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/transmute_infinitely_recursive_type.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this function
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src>,
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0072, E0391.
+Some errors have detailed explanations: E0072, E0277, E0391.
 For more information about an error, try `rustc --explain E0072`.
diff --git a/tests/ui/transmutability/transmute-padding-ice.rs b/tests/ui/transmutability/transmute-padding-ice.rs
index 3f3f75bc086..f5935a0009e 100644
--- a/tests/ui/transmutability/transmute-padding-ice.rs
+++ b/tests/ui/transmutability/transmute-padding-ice.rs
@@ -1,7 +1,13 @@
+//@ check-pass
+//! This UI test was introduced as check-fail by a buggy bug-fix for an ICE. In
+//! fact, this transmutation should be valid.
+
 #![crate_type = "lib"]
 #![feature(transmutability)]
 #![allow(dead_code)]
 
+use std::mem::size_of;
+
 mod assert {
     use std::mem::{Assume, BikeshedIntrinsicFrom};
 
@@ -22,6 +28,7 @@ fn test() {
     #[repr(C)]
     struct B(u8, u8);
 
+    assert_eq!(size_of::<A>(), size_of::<B>());
+
     assert::is_maybe_transmutable::<B, A>();
-    //~^ ERROR cannot be safely transmuted
 }
diff --git a/tests/ui/transmutability/transmute-padding-ice.stderr b/tests/ui/transmutability/transmute-padding-ice.stderr
deleted file mode 100644
index 4c121d463c6..00000000000
--- a/tests/ui/transmutability/transmute-padding-ice.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: `B` cannot be safely transmuted into `A`
-  --> $DIR/transmute-padding-ice.rs:25:40
-   |
-LL |     assert::is_maybe_transmutable::<B, A>();
-   |                                        ^ the size of `B` is smaller than the size of `A`
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/transmute-padding-ice.rs:10:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<
-   |  ______________^
-LL | |             Src,
-LL | |             { Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
-LL | |         >,
-   | |_________^ required by this bound in `is_maybe_transmutable`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/transmutability/uninhabited.rs b/tests/ui/transmutability/uninhabited.rs
new file mode 100644
index 00000000000..b61b110f6a1
--- /dev/null
+++ b/tests/ui/transmutability/uninhabited.rs
@@ -0,0 +1,71 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::{Assume, BikeshedIntrinsicFrom};
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, {
+            Assume {
+                alignment: true,
+                lifetimes: true,
+                safety: true,
+                validity: true,
+            }
+        }>
+    {}
+}
+
+fn void() {
+    enum Void {}
+
+    // This transmutation is vacuously acceptable; since one cannot construct a
+    // `Void`, unsoundness cannot directly arise from transmuting a void into
+    // anything else.
+    assert::is_maybe_transmutable::<Void, u128>();
+
+    assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted
+}
+
+// Non-ZST uninhabited types are, nonetheless, uninhabited.
+fn yawning_void() {
+    enum Void {}
+
+    struct YawningVoid(Void, u128);
+
+    const _: () = {
+        assert!(std::mem::size_of::<YawningVoid>() == std::mem::size_of::<u128>());
+        // Just to be sure the above constant actually evaluated:
+        assert!(false); //~ ERROR: evaluation of constant value failed
+    };
+
+    // This transmutation is vacuously acceptable; since one cannot construct a
+    // `Void`, unsoundness cannot directly arise from transmuting a void into
+    // anything else.
+    assert::is_maybe_transmutable::<YawningVoid, u128>();
+
+    assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted
+}
+
+// References to uninhabited types are, logically, uninhabited, but for layout
+// purposes are not ZSTs, and aren't treated as uninhabited when they appear in
+// enum variants.
+fn distant_void() {
+    enum Void {}
+
+    enum DistantVoid {
+        A(&'static Void)
+    }
+
+    const _: () = {
+        assert!(std::mem::size_of::<DistantVoid>() == std::mem::size_of::<usize>());
+        // Just to be sure the above constant actually evaluated:
+        assert!(false); //~ ERROR: evaluation of constant value failed
+    };
+
+    assert::is_maybe_transmutable::<DistantVoid, ()>();
+    assert::is_maybe_transmutable::<DistantVoid, &'static Void>();
+    assert::is_maybe_transmutable::<u128, DistantVoid>(); //~ ERROR: cannot be safely transmuted
+}
diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr
new file mode 100644
index 00000000000..60219b0f263
--- /dev/null
+++ b/tests/ui/transmutability/uninhabited.stderr
@@ -0,0 +1,86 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/uninhabited.rs:41:9
+   |
+LL |         assert!(false);
+   |         ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:41:9
+   |
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/uninhabited.rs:65:9
+   |
+LL |         assert!(false);
+   |         ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:65:9
+   |
+   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `()` cannot be safely transmuted into `void::Void`
+  --> $DIR/uninhabited.rs:29:41
+   |
+LL |     assert::is_maybe_transmutable::<(), Void>();
+   |                                         ^^^^ `void::Void` is uninhabited
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/uninhabited.rs:10:14
+   |
+LL |       pub fn is_maybe_transmutable<Src, Dst>()
+   |              --------------------- required by a bound in this function
+LL |       where
+LL |           Dst: BikeshedIntrinsicFrom<Src, {
+   |  ______________^
+LL | |             Assume {
+LL | |                 alignment: true,
+LL | |                 lifetimes: true,
+...  |
+LL | |             }
+LL | |         }>
+   | |__________^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `()` cannot be safely transmuted into `yawning_void::Void`
+  --> $DIR/uninhabited.rs:49:41
+   |
+LL |     assert::is_maybe_transmutable::<(), Void>();
+   |                                         ^^^^ `yawning_void::Void` is uninhabited
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/uninhabited.rs:10:14
+   |
+LL |       pub fn is_maybe_transmutable<Src, Dst>()
+   |              --------------------- required by a bound in this function
+LL |       where
+LL |           Dst: BikeshedIntrinsicFrom<Src, {
+   |  ______________^
+LL | |             Assume {
+LL | |                 alignment: true,
+LL | |                 lifetimes: true,
+...  |
+LL | |             }
+LL | |         }>
+   | |__________^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `DistantVoid`
+  --> $DIR/uninhabited.rs:70:43
+   |
+LL |     assert::is_maybe_transmutable::<u128, DistantVoid>();
+   |                                           ^^^^^^^^^^^ at least one value of `u128` isn't a bit-valid value of `DistantVoid`
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/uninhabited.rs:10:14
+   |
+LL |       pub fn is_maybe_transmutable<Src, Dst>()
+   |              --------------------- required by a bound in this function
+LL |       where
+LL |           Dst: BikeshedIntrinsicFrom<Src, {
+   |  ______________^
+LL | |             Assume {
+LL | |                 alignment: true,
+LL | |                 lifetimes: true,
+...  |
+LL | |             }
+LL | |         }>
+   | |__________^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
diff --git a/tests/ui/transmutability/unions/repr/should_handle_align.rs b/tests/ui/transmutability/unions/repr/should_handle_align.rs
index 8668cca3cb5..ba4e904e161 100644
--- a/tests/ui/transmutability/unions/repr/should_handle_align.rs
+++ b/tests/ui/transmutability/unions/repr/should_handle_align.rs
@@ -25,13 +25,13 @@ fn should_pad_explicitly_aligned_field() {
     #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
     #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
 
-    #[repr(C)]
+    #[repr(align(1))]
     pub union Uninit {
         a: (),
         b: V1u8,
     }
 
-    #[repr(C, align(2))]
+    #[repr(align(2))]
     pub union align_2 {
         a: V0u8,
     }
diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/unions/repr/should_handle_all.rs
index 8495b0ea88f..85d48dd9b7f 100644
--- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.rs
+++ b/tests/ui/transmutability/unions/repr/should_handle_all.rs
@@ -1,7 +1,7 @@
-//! A struct must have a well-defined layout to participate in a transmutation.
+//@ check-pass
 
 #![crate_type = "lib"]
-#![feature(transmutability)]
+#![feature(transmutability, transparent_unions)]
 #![allow(dead_code, incomplete_features, non_camel_case_types)]
 
 mod assert {
@@ -20,17 +20,17 @@ mod assert {
     {}
 }
 
-fn should_reject_repr_rust()
+fn should_accept_repr_rust()
 {
     union repr_rust {
         a: u8
     }
 
-    assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
-    assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    assert::is_maybe_transmutable::<repr_rust, ()>();
+    assert::is_maybe_transmutable::<u128, repr_rust>();
 }
 
-fn should_accept_repr_C()
+fn should_accept_repr_c()
 {
     #[repr(C)]
     union repr_c {
@@ -41,3 +41,15 @@ fn should_accept_repr_C()
     assert::is_maybe_transmutable::<repr_c, ()>();
     assert::is_maybe_transmutable::<u128, repr_c>();
 }
+
+
+fn should_accept_transparent()
+{
+    #[repr(transparent)]
+    union repr_transparent {
+        a: u8
+    }
+
+    assert::is_maybe_transmutable::<repr_transparent, ()>();
+    assert::is_maybe_transmutable::<u128, repr_transparent>();
+}
diff --git a/tests/ui/transmutability/unions/repr/should_handle_packed.rs b/tests/ui/transmutability/unions/repr/should_handle_packed.rs
index 4af6c1d3a61..fc06eba4353 100644
--- a/tests/ui/transmutability/unions/repr/should_handle_packed.rs
+++ b/tests/ui/transmutability/unions/repr/should_handle_packed.rs
@@ -27,7 +27,6 @@ fn should_pad_explicitly_packed_field() {
     #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 }
     #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 }
 
-    #[repr(C)]
     pub union Uninit {
         a: (),
         b: V1u8,
diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
deleted file mode 100644
index bec07f13103..00000000000
--- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
+++ /dev/null
@@ -1,47 +0,0 @@
-error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()`
-  --> $DIR/should_require_well_defined_layout.rs:29:48
-   |
-LL |     assert::is_maybe_transmutable::<repr_rust, ()>();
-   |                                                ^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust`
-  --> $DIR/should_require_well_defined_layout.rs:30:43
-   |
-LL |     assert::is_maybe_transmutable::<u128, repr_rust>();
-   |                                           ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported.
-   |
-note: required by a bound in `is_maybe_transmutable`
-  --> $DIR/should_require_well_defined_layout.rs:12:14
-   |
-LL |       pub fn is_maybe_transmutable<Src, Dst>()
-   |              --------------------- required by a bound in this function
-LL |       where
-LL |           Dst: BikeshedIntrinsicFrom<Src, {
-   |  ______________^
-LL | |             Assume {
-LL | |                 alignment: true,
-LL | |                 lifetimes: true,
-...  |
-LL | |             }
-LL | |         }>
-   | |__________^ required by this bound in `is_maybe_transmutable`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
deleted file mode 100644
index ae463b6ef5b..00000000000
--- a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(type_alias_impl_trait)]
-
-//@ check-pass
-
-type Foo = impl Fn() -> Foo;
-
-fn foo() -> Foo {
-    foo
-}
-
-fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr
deleted file mode 100644
index 1c36fda4ae1..00000000000
--- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-note: no errors encountered even though delayed bugs were created
-
-note: those delayed bugs will now be shown as internal compiler errors
-
-error: internal compiler error: {OpaqueTypeKey { def_id: DefId(get_rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }) } }}
-   |
-   = 
-           
-
-error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(get_rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }))), bound_vars: [] } } }
-  --> $DIR/rpit_tait_equality_in_canonical_query.rs:32:5
-   |
-LL |     query(get_rpit);
-   |     ^^^^^^^^^^^^^^^
-   |
-
-  --> $DIR/rpit_tait_equality_in_canonical_query.rs:32:5
-   |
-LL |     query(get_rpit);
-   |     ^^^^^^^^^^^^^^^
-
-query stack during panic:
-end of query stack
diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
index 7524cebf9e6..6f50703aca2 100644
--- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
+++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs
@@ -8,17 +8,7 @@
 //@ revisions: current next
 //@ ignore-compare-mode-next-solver (explicit revisions)
 //@[next] compile-flags: -Znext-solver
-//@[next] check-pass
-
-//@[current] known-bug: #108498
-//@[current] failure-status: 101
-//@[current] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId("
-//@[current] normalize-stderr-test: "(?m)note: we would appreciate a bug report.*\n\n" -> ""
-//@[current] normalize-stderr-test: "(?m)note: rustc.*running on.*\n\n" -> ""
-//@[current] normalize-stderr-test: "(?m)note: compiler flags.*\n\n" -> ""
-//@[current] normalize-stderr-test: "(?m)note: delayed at.*$" -> ""
-//@[current] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> ""
-//@[current] normalize-stderr-test: "(?m)^ *at .*\n" -> ""
+//@ check-pass
 
 #![feature(type_alias_impl_trait)]
 
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs
index e5e7fb677ed..19986247d40 100644
--- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs
@@ -1,12 +1,10 @@
 #![feature(type_alias_impl_trait)]
+//@ known-bug: #109268
 
 type Foo = impl Fn() -> Foo;
-//~^ ERROR: unconstrained opaque type
 
 fn crash(x: Foo) -> Foo {
     x
 }
 
-fn main() {
-
-}
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr
new file mode 100644
index 00000000000..ee8922b673e
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr
@@ -0,0 +1,9 @@
+error[E0275]: overflow evaluating the requirement `<Foo as FnOnce<()>>::Output == Foo`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-1.rs:6:21
+   |
+LL | fn crash(x: Foo) -> Foo {
+   |                     ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs
index 7c7a1b405bc..761cc83af51 100644
--- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs
@@ -1,11 +1,11 @@
 #![feature(type_alias_impl_trait)]
+//@ known-bug: #109268
 
 pub trait Bar<T> {
     type Item;
 }
 
 type Foo = impl Bar<Foo, Item = Foo>;
-//~^ ERROR: unconstrained opaque type
 
 fn crash(x: Foo) -> Foo {
     x
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr
new file mode 100644
index 00000000000..3d0f1d30ca2
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr
@@ -0,0 +1,9 @@
+error[E0275]: overflow evaluating the requirement `<Foo as Bar<Foo>>::Item == Foo`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-2.rs:10:21
+   |
+LL | fn crash(x: Foo) -> Foo {
+   |                     ^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs
new file mode 100644
index 00000000000..52942afd639
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs
@@ -0,0 +1,10 @@
+#![feature(type_alias_impl_trait)]
+//@ known-bug: #109268
+
+type Foo<'a> = impl Fn() -> Foo<'a>;
+
+fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> {
+    x
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr
new file mode 100644
index 00000000000..675689bac42
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr
@@ -0,0 +1,9 @@
+error[E0275]: overflow evaluating the requirement `<Foo<'_> as FnOnce<()>>::Output == Foo<'a>`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-3.rs:6:40
+   |
+LL | fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> {
+   |                                        ^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs
new file mode 100644
index 00000000000..e866b45a8e6
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs
@@ -0,0 +1,16 @@
+#![feature(type_alias_impl_trait)]
+//@ known-bug: trait-system-refactor-initiative#43
+
+trait Id {
+    type Assoc;
+}
+impl<T> Id for T {
+    type Assoc = T;
+}
+
+type Ty
+where
+    Ty: Id<Assoc = Ty>,
+= impl Sized;
+fn define() -> Ty {}
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr
new file mode 100644
index 00000000000..aedb78bf5e7
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr
@@ -0,0 +1,39 @@
+error[E0275]: overflow evaluating the requirement `Ty: Id`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:11:1
+   |
+LL | type Ty
+   | ^^^^^^^
+   |
+note: required by a bound on the type alias `Ty`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9
+   |
+LL |     Ty: Id<Assoc = Ty>,
+   |         ^^^^^^^^^^^^^^ required by this bound
+
+error[E0275]: overflow evaluating the requirement `Ty: Id`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:19
+   |
+LL | fn define() -> Ty {}
+   |                   ^^
+   |
+note: required by a bound on the type alias `Ty`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9
+   |
+LL |     Ty: Id<Assoc = Ty>,
+   |         ^^^^^^^^^^^^^^ required by this bound
+
+error[E0275]: overflow evaluating the requirement `Ty: Id`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:16
+   |
+LL | fn define() -> Ty {}
+   |                ^^
+   |
+note: required by a bound on the type alias `Ty`
+  --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9
+   |
+LL |     Ty: Id<Assoc = Ty>,
+   |         ^^^^^^^^^^^^^^ required by this bound
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr
deleted file mode 100644
index 3d43fbe0dbc..00000000000
--- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: unconstrained opaque type
-  --> $DIR/type-alias-impl-trait-with-cycle-error.rs:3:12
-   |
-LL | type Foo = impl Fn() -> Foo;
-   |            ^^^^^^^^^^^^^^^^
-   |
-   = note: `Foo` must be used in combination with a concrete type within the same module
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr
deleted file mode 100644
index e2dc887989b..00000000000
--- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: unconstrained opaque type
-  --> $DIR/type-alias-impl-trait-with-cycle-error2.rs:7:12
-   |
-LL | type Foo = impl Bar<Foo, Item = Foo>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `Foo` must be used in combination with a concrete type within the same module
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs
new file mode 100644
index 00000000000..8ad042eeba6
--- /dev/null
+++ b/tests/ui/type/pattern_types/bad_pat.rs
@@ -0,0 +1,14 @@
+#![feature(pattern_types)]
+#![feature(core_pattern_types)]
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+type NonNullU32_2 = pattern_type!(u32 is 1..=);
+//~^ ERROR: inclusive range with no end
+type Positive2 = pattern_type!(i32 is 0..=);
+//~^ ERROR: inclusive range with no end
+type Wild = pattern_type!(() is _);
+//~^ ERROR: wildcard patterns are not permitted for pattern types
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr
new file mode 100644
index 00000000000..4f0f0bc9742
--- /dev/null
+++ b/tests/ui/type/pattern_types/bad_pat.stderr
@@ -0,0 +1,25 @@
+error[E0586]: inclusive range with no end
+  --> $DIR/bad_pat.rs:7:43
+   |
+LL | type NonNullU32_2 = pattern_type!(u32 is 1..=);
+   |                                           ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error[E0586]: inclusive range with no end
+  --> $DIR/bad_pat.rs:9:40
+   |
+LL | type Positive2 = pattern_type!(i32 is 0..=);
+   |                                        ^^^ help: use `..` instead
+   |
+   = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
+
+error: "wildcard patterns are not permitted for pattern types"
+  --> $DIR/bad_pat.rs:11:33
+   |
+LL | type Wild = pattern_type!(() is _);
+   |                                 ^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0586`.
diff --git a/tests/ui/type/pattern_types/derives.noimpl.stderr b/tests/ui/type/pattern_types/derives.noimpl.stderr
new file mode 100644
index 00000000000..9450e575344
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives.noimpl.stderr
@@ -0,0 +1,14 @@
+error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+  --> $DIR/derives.rs:14:20
+   |
+LL | #[derive(Clone, Copy, PartialEq)]
+   |                       --------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+   |                    ^^^^^^^
+   |
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs
new file mode 100644
index 00000000000..b8b53e61102
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives.rs
@@ -0,0 +1,20 @@
+//! Check that pattern types don't implement traits of their base automatically
+
+#![feature(pattern_types)]
+#![feature(core_pattern_types)]
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+#[derive(Clone, Copy, PartialEq)]
+#[repr(transparent)]
+struct Nanoseconds(NanoI32);
+//~^ ERROR: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+
+type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999);
+
+fn main() {
+    let x = Nanoseconds(unsafe { std::mem::transmute(42) });
+    let y = x.clone();
+    if y == x {}
+}
diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr
new file mode 100644
index 00000000000..1d4d3fc55c3
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives.stderr
@@ -0,0 +1,14 @@
+error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+  --> $DIR/derives.rs:11:20
+   |
+LL | #[derive(Clone, Copy, PartialEq)]
+   |                       --------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+   |                    ^^^^^^^
+   |
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs
new file mode 100644
index 00000000000..3c507a9669d
--- /dev/null
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs
@@ -0,0 +1,14 @@
+//@ compile-flags: -Zno-analysis
+
+use std::pat::pattern_type;
+
+type NonNullU32 = pattern_type!(u32 is 1..);
+//~^ use of unstable library feature 'core_pattern_type'
+type Percent = pattern_type!(u32 is 0..=100);
+//~^ use of unstable library feature 'core_pattern_type'
+type Negative = pattern_type!(i32 is ..=0);
+//~^ use of unstable library feature 'core_pattern_type'
+type Positive = pattern_type!(i32 is 0..);
+//~^ use of unstable library feature 'core_pattern_type'
+type Always = pattern_type!(Option<u32> is Some(_));
+//~^ use of unstable library feature 'core_pattern_type'
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
new file mode 100644
index 00000000000..6f74b89d224
--- /dev/null
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr
@@ -0,0 +1,48 @@
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:5:19
+   |
+LL | type NonNullU32 = pattern_type!(u32 is 1..);
+   |                   ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:7:16
+   |
+LL | type Percent = pattern_type!(u32 is 0..=100);
+   |                ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:9:17
+   |
+LL | type Negative = pattern_type!(i32 is ..=0);
+   |                 ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:11:17
+   |
+LL | type Positive = pattern_type!(i32 is 0..);
+   |                 ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'core_pattern_type'
+  --> $DIR/feature-gate-pattern_types.rs:13:15
+   |
+LL | type Always = pattern_type!(Option<u32> is Some(_));
+   |               ^^^^^^^^^^^^
+   |
+   = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs
new file mode 100644
index 00000000000..d7b3ea58e02
--- /dev/null
+++ b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs
@@ -0,0 +1,12 @@
+//@ compile-flags: -Zno-analysis
+//@ check-pass
+
+#![feature(core_pattern_type)]
+
+use std::pat::pattern_type;
+
+type NonNullU32 = pattern_type!(u32 is 1..);
+type Percent = pattern_type!(u32 is 0..=100);
+type Negative = pattern_type!(i32 is ..=0);
+type Positive = pattern_type!(i32 is 0..);
+type Always = pattern_type!(Option<u32> is Some(_));
diff --git a/tests/ui/type/pattern_types/macros.active.stderr b/tests/ui/type/pattern_types/macros.active.stderr
new file mode 100644
index 00000000000..002e944fe2e
--- /dev/null
+++ b/tests/ui/type/pattern_types/macros.active.stderr
@@ -0,0 +1,10 @@
+error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments
+  --> $DIR/macros.rs:10:12
+   |
+LL |     ($t:ty is $p:pat) => {};
+   |            ^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/type/pattern_types/macros.gated.stderr b/tests/ui/type/pattern_types/macros.gated.stderr
new file mode 100644
index 00000000000..002e944fe2e
--- /dev/null
+++ b/tests/ui/type/pattern_types/macros.gated.stderr
@@ -0,0 +1,10 @@
+error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments
+  --> $DIR/macros.rs:10:12
+   |
+LL |     ($t:ty is $p:pat) => {};
+   |            ^^ not allowed after `ty` fragments
+   |
+   = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/type/pattern_types/macros.rs b/tests/ui/type/pattern_types/macros.rs
new file mode 100644
index 00000000000..fd5fe257e8e
--- /dev/null
+++ b/tests/ui/type/pattern_types/macros.rs
@@ -0,0 +1,15 @@
+//@ revisions: gated active
+
+#![cfg_attr(active, feature(pattern_types))]
+#![allow(incomplete_features)]
+
+// Check that pattern types do not affect existing macros.
+// They don't, because pattern types don't have surface syntax.
+
+macro_rules! foo {
+    ($t:ty is $p:pat) => {}; //~ ERROR `$t:ty` is followed by `is`, which is not allowed for `ty` fragments
+}
+
+fn main() {
+    foo!(u32 is 1..)
+}
diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs
new file mode 100644
index 00000000000..d1fd055dbab
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns.rs
@@ -0,0 +1,23 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN"
+
+use std::pat::pattern_type;
+
+#[rustc_layout(debug)]
+type X = std::num::NonZeroU32; //~ ERROR layout_of
+#[rustc_layout(debug)]
+type Y = pattern_type!(u32 is 1..); //~ ERROR layout_of
+#[rustc_layout(debug)]
+type Z = Option<pattern_type!(u32 is 1..)>; //~ ERROR layout_of
+#[rustc_layout(debug)]
+type A = Option<std::num::NonZeroU32>; //~ ERROR layout_of
+#[rustc_layout(debug)]
+struct NonZeroU32New(pattern_type!(u32 is 1..)); //~ ERROR layout_of
+
+fn main() {
+    let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(42_u32) };
+}
diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr
new file mode 100644
index 00000000000..8465e1b7ff2
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns.stderr
@@ -0,0 +1,343 @@
+error: layout_of(NonZero<u32>) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:11:1
+   |
+LL | type X = std::num::NonZeroU32;
+   | ^^^^^^
+
+error: layout_of((u32) is 1..=) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           fields: Primitive,
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:13:1
+   |
+LL | type Y = pattern_type!(u32 is 1..);
+   | ^^^^^^
+
+error: layout_of(Option<(u32) is 1..=>) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: None,
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+               tag_encoding: Niche {
+                   untagged_variant: 1,
+                   niche_variants: 0..=0,
+                   niche_start: 0,
+               },
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Scalar(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(0 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: Some(
+                           Niche {
+                               offset: Size(0 bytes),
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:15:1
+   |
+LL | type Z = Option<pattern_type!(u32 is 1..)>;
+   | ^^^^^^
+
+error: layout_of(Option<NonZero<u32>>) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: None,
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: (..=0) | (1..),
+               },
+               tag_encoding: Niche {
+                   untagged_variant: 1,
+                   niche_variants: 0..=0,
+                   niche_start: 0,
+               },
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       size: Size(0 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       largest_niche: None,
+                       variants: Single {
+                           index: 0,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(1 bytes),
+                   },
+                   Layout {
+                       size: Size(4 bytes),
+                       align: AbiAndPrefAlign {
+                           abi: Align(4 bytes),
+                           pref: $SOME_ALIGN,
+                       },
+                       abi: Scalar(
+                           Initialized {
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       fields: Arbitrary {
+                           offsets: [
+                               Size(0 bytes),
+                           ],
+                           memory_index: [
+                               0,
+                           ],
+                       },
+                       largest_niche: Some(
+                           Niche {
+                               offset: Size(0 bytes),
+                               value: Int(
+                                   I32,
+                                   false,
+                               ),
+                               valid_range: 1..=4294967295,
+                           },
+                       ),
+                       variants: Single {
+                           index: 1,
+                       },
+                       max_repr_align: None,
+                       unadjusted_abi_align: Align(4 bytes),
+                   },
+               ],
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:17:1
+   |
+LL | type A = Option<std::num::NonZeroU32>;
+   | ^^^^^^
+
+error: layout_of(NonZeroU32New) = Layout {
+           size: Size(4 bytes),
+           align: AbiAndPrefAlign {
+               abi: Align(4 bytes),
+               pref: $SOME_ALIGN,
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I32,
+                       false,
+                   ),
+                   valid_range: 1..=4294967295,
+               },
+           ),
+           variants: Single {
+               index: 0,
+           },
+           max_repr_align: None,
+           unadjusted_abi_align: Align(4 bytes),
+       }
+  --> $DIR/range_patterns.rs:19:1
+   |
+LL | struct NonZeroU32New(pattern_type!(u32 is 1..));
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs
new file mode 100644
index 00000000000..9653a744c41
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs
@@ -0,0 +1,30 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types can have traits implemented for them if
+//! their base type is a local type.
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+
+impl Y {
+    //~^ ERROR cannot define inherent `impl`
+    fn foo() {}
+}
+
+struct MyStruct<T>(T);
+
+impl MyStruct<Y> {
+    fn foo() {}
+}
+
+struct Wrapper(Y);
+
+impl Wrapper {
+    fn foo() {}
+}
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr
new file mode 100644
index 00000000000..784ebb0c9f0
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr
@@ -0,0 +1,16 @@
+error[E0390]: cannot define inherent `impl` for primitive types outside of `core`
+  --> $DIR/range_patterns_inherent_impls.rs:13:1
+   |
+LL | impl Y {
+   | ^^^^^^
+   |
+   = help: consider moving this inherent impl into `core` if possible
+help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
+  --> $DIR/range_patterns_inherent_impls.rs:15:5
+   |
+LL |     fn foo() {}
+   |     ^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0390`.
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs
new file mode 100644
index 00000000000..f8c9af86281
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs
@@ -0,0 +1,19 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types can have local traits
+//! implemented for them.
+
+//@ check-pass
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+
+trait Trait {}
+
+impl Trait for Y {}
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs
new file mode 100644
index 00000000000..acde4580c1b
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs
@@ -0,0 +1,16 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types can have local traits
+//! implemented for them.
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+
+impl Eq for Y {}
+//~^ ERROR: only traits defined in the current crate can be implemented for arbitrary types
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr
new file mode 100644
index 00000000000..41f42455bde
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr
@@ -0,0 +1,14 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+  --> $DIR/range_patterns_trait_impls2.rs:13:1
+   |
+LL | impl Eq for Y {}
+   | ^^^^^^^^^^^^-
+   | |           |
+   | |           `(u32) is 1..=` is not defined in the current crate
+   | impl doesn't use only types from inside the current crate
+   |
+   = note: define and implement a trait or new type instead
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.rs b/tests/ui/type/pattern_types/range_patterns_unusable.rs
new file mode 100644
index 00000000000..7cde44f4133
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable.rs
@@ -0,0 +1,15 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! Some practical niche checks.
+
+use std::pat::pattern_type;
+
+type Z = Option<pattern_type!(u32 is 1..)>;
+
+fn main() {
+    let z: Z = Some(unsafe { std::mem::transmute(42_u32) });
+    let _: Option<u32> = unsafe { std::mem::transmute(z) }; //~ ERROR: different sizes
+}
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.stderr b/tests/ui/type/pattern_types/range_patterns_unusable.stderr
new file mode 100644
index 00000000000..aa0e592684b
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/range_patterns_unusable.rs:14:35
+   |
+LL |     let _: Option<u32> = unsafe { std::mem::transmute(z) };
+   |                                   ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<(u32) is 1..=>` (32 bits)
+   = note: target type: `Option<u32>` (64 bits)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.rs b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs
new file mode 100644
index 00000000000..bc1ab75429d
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs
@@ -0,0 +1,16 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+
+//! check that pattern types don't have an `Add` impl.
+
+use std::pat::pattern_type;
+
+type Y = pattern_type!(u32 is 1..);
+type Z = Option<pattern_type!(u32 is 1..)>;
+
+fn main() {
+    let x: Y = unsafe { std::mem::transmute(42_u32) };
+    let x = x + 1_u32; //~ ERROR cannot add `u32` to `(u32) is 1..=`
+}
diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr
new file mode 100644
index 00000000000..e52d899a703
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr
@@ -0,0 +1,11 @@
+error[E0369]: cannot add `u32` to `(u32) is 1..=`
+  --> $DIR/range_patterns_unusable_math.rs:15:15
+   |
+LL |     let x = x + 1_u32;
+   |             - ^ ----- u32
+   |             |
+   |             (u32) is 1..=
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0369`.
diff --git a/tests/ui/type/pattern_types/range_patterns_usage.rs b/tests/ui/type/pattern_types/range_patterns_usage.rs
new file mode 100644
index 00000000000..7fe50423c51
--- /dev/null
+++ b/tests/ui/type/pattern_types/range_patterns_usage.rs
@@ -0,0 +1,26 @@
+#![feature(pattern_types, rustc_attrs)]
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+#![allow(incomplete_features)]
+//@ check-pass
+
+//! check that pattern types can actually be part of code that compiles successfully.
+
+use std::pat::pattern_type;
+
+type X = std::num::NonZeroU32;
+type Y = pattern_type!(u32 is 1..);
+type Z = Option<pattern_type!(u32 is 1..)>;
+struct NonZeroU32New(pattern_type!(u32 is 1..));
+
+fn main() {
+    let x: Y = unsafe { std::mem::transmute(42_u32) };
+    let z: Z = Some(unsafe { std::mem::transmute(42_u32) });
+    match z {
+        Some(y) => {
+            let _: Y = y;
+        }
+        None => {}
+    }
+    let x: X = unsafe { std::mem::transmute(x) };
+}
diff --git a/tests/ui/type/pattern_types/unimplemented_pat.rs b/tests/ui/type/pattern_types/unimplemented_pat.rs
new file mode 100644
index 00000000000..c02160ff58a
--- /dev/null
+++ b/tests/ui/type/pattern_types/unimplemented_pat.rs
@@ -0,0 +1,15 @@
+//! This test ensures we do not ICE for unimplemented
+//! patterns unless the feature gate is enabled.
+
+#![feature(core_pattern_type)]
+#![feature(core_pattern_types)]
+
+use std::pat::pattern_type;
+
+type Always = pattern_type!(Option<u32> is Some(_));
+//~^ ERROR: pattern types are unstable
+
+type Binding = pattern_type!(Option<u32> is x);
+//~^ ERROR: pattern types are unstable
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/unimplemented_pat.stderr b/tests/ui/type/pattern_types/unimplemented_pat.stderr
new file mode 100644
index 00000000000..481c6017dcc
--- /dev/null
+++ b/tests/ui/type/pattern_types/unimplemented_pat.stderr
@@ -0,0 +1,23 @@
+error[E0658]: pattern types are unstable
+  --> $DIR/unimplemented_pat.rs:9:15
+   |
+LL | type Always = pattern_type!(Option<u32> is Some(_));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
+   = help: add `#![feature(pattern_types)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pattern types are unstable
+  --> $DIR/unimplemented_pat.rs:12:16
+   |
+LL | type Binding = pattern_type!(Option<u32> is x);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information
+   = help: add `#![feature(pattern_types)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/issues/issue-23649-1.rs b/tests/ui/unsized/issue-23649-1.rs
index 1c4252b40c6..1c4252b40c6 100644
--- a/tests/ui/issues/issue-23649-1.rs
+++ b/tests/ui/unsized/issue-23649-1.rs
diff --git a/tests/ui/issues/issue-23649-2.rs b/tests/ui/unsized/issue-23649-2.rs
index 4a953de1768..4a953de1768 100644
--- a/tests/ui/issues/issue-23649-2.rs
+++ b/tests/ui/unsized/issue-23649-2.rs
diff --git a/tests/ui/issues/issue-23649-3.rs b/tests/ui/unsized/issue-23649-3.rs
index 524055d99b4..524055d99b4 100644
--- a/tests/ui/issues/issue-23649-3.rs
+++ b/tests/ui/unsized/issue-23649-3.rs