about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-26 06:59:26 +0000
committerbors <bors@rust-lang.org>2024-01-26 06:59:26 +0000
commitfae15df5c60ccf0f9eaa96651c869d2c2001fddb (patch)
treeb452546913281a644984fff0862defd7ec76890e
parent9f4d1a41a6dccf00caace1e9fd20011d586d8b69 (diff)
parent2318b0825cc2892a388b307d38389658f09ac3b6 (diff)
downloadrust-fae15df5c60ccf0f9eaa96651c869d2c2001fddb.tar.gz
rust-fae15df5c60ccf0f9eaa96651c869d2c2001fddb.zip
Auto merge of #3280 - rust-lang:rustup-2024-01-26, r=RalfJung
Automatic Rustup
-rw-r--r--Cargo.lock21
-rw-r--r--compiler/rustc_ast/src/visit.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs6
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs6
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/static.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs64
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs489
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs2
-rw-r--r--compiler/rustc_const_eval/src/errors.rs7
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs16
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs22
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs19
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs49
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs4
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs2
-rw-r--r--compiler/rustc_data_structures/src/sso/map.rs2
-rw-r--r--compiler/rustc_hir/src/lang_items.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs150
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs55
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs11
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs69
-rw-r--r--compiler/rustc_macros/src/query.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs9
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs19
-rw-r--r--compiler/rustc_middle/src/query/erase.rs5
-rw-r--r--compiler/rustc_middle/src/query/mod.rs12
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs42
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs32
-rw-r--r--compiler/rustc_middle/src/ty/util.rs11
-rw-r--r--compiler/rustc_mir_build/messages.ftl8
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs167
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs512
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs7
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs311
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs119
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs6
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs7
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs42
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs8
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs5
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs16
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs14
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs73
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs136
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs8
-rw-r--r--compiler/rustc_privacy/src/lib.rs90
-rw-r--r--compiler/rustc_session/src/session.rs37
-rw-r--r--compiler/rustc_span/src/symbol.rs10
-rw-r--r--compiler/rustc_target/src/spec/base/wasm.rs3
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1_threads.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasi_preview2.rs64
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs242
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs2
-rw-r--r--compiler/rustc_ty_utils/src/structural_match.rs16
-rw-r--r--library/alloc/src/collections/btree/map.rs777
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs135
-rw-r--r--library/alloc/src/collections/btree/node.rs29
-rw-r--r--library/core/src/intrinsics.rs60
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/marker.rs23
-rw-r--r--library/core/src/num/int_macros.rs284
-rw-r--r--library/core/src/num/nonzero.rs37
-rw-r--r--library/core/src/num/uint_macros.rs249
-rw-r--r--library/core/src/ops/async_function.rs108
-rw-r--r--library/core/src/ops/mod.rs4
-rw-r--r--library/core/src/ptr/const_ptr.rs4
-rw-r--r--library/core/src/ptr/mod.rs8
-rw-r--r--library/core/src/ptr/mut_ptr.rs4
-rw-r--r--library/core/src/tuple.rs5
-rw-r--r--library/std/src/os/mod.rs3
-rw-r--r--library/std/src/os/wasi/mod.rs3
-rw-r--r--library/std/src/os/wasi_preview2/mod.rs5
-rw-r--r--library/std/src/sys/pal/mod.rs3
-rw-r--r--library/std/src/sys/pal/unsupported/net.rs3
-rw-r--r--library/std/src/sys/pal/wasi/helpers.rs123
-rw-r--r--library/std/src/sys/pal/wasi/mod.rs132
-rw-r--r--library/std/src/sys/pal/wasi_preview2/mod.rs78
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs7
-rw-r--r--src/bootstrap/src/lib.rs2
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/wasm32-wasi-preview2.md30
-rw-r--r--src/doc/style-guide/src/editions.md4
-rw-r--r--src/doc/style-guide/src/expressions.md55
-rw-r--r--src/librustdoc/html/templates/item_union.html14
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6254.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6254.stderr15
-rw-r--r--src/tools/clippy/tests/ui/modulo_one.rs3
-rw-r--r--src/tools/clippy/tests/ui/modulo_one.stderr8
-rw-r--r--src/tools/compiletest/src/header.rs3
-rw-r--r--src/tools/compiletest/src/header/tests.rs21
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/machine.rs54
-rw-r--r--src/tools/miri/src/shims/intrinsics/mod.rs13
-rw-r--r--src/tools/miri/tests/pass/const-addrs.rs38
-rw-r--r--src/tools/miri/tests/pass/intrinsics.rs15
-rw-r--r--tests/assembly/targets/targets-elf.rs3
-rw-r--r--tests/codegen/alloc-optimisation.rs2
-rw-r--r--tests/codegen/array-map.rs3
-rw-r--r--tests/codegen/dealloc-no-unwind.rs1
-rw-r--r--tests/codegen/fewer-names.rs1
-rw-r--r--tests/codegen/integer-overflow.rs1
-rw-r--r--tests/codegen/is_val_statically_known.rs48
-rw-r--r--tests/codegen/issues/issue-116878.rs1
-rw-r--r--tests/codegen/issues/issue-44056-macos-tls-align.rs1
-rw-r--r--tests/codegen/issues/issue-69101-bounds-check.rs1
-rw-r--r--tests/codegen/match-optimizes-away.rs1
-rw-r--r--tests/codegen/pow_of_two.rs55
-rw-r--r--tests/codegen/ptr-read-metadata.rs1
-rw-r--r--tests/codegen/slice-as_chunks.rs1
-rw-r--r--tests/codegen/slice-iter-len-eq-zero.rs1
-rw-r--r--tests/codegen/slice-iter-nonnull.rs1
-rw-r--r--tests/codegen/slice-position-bounds-check.rs1
-rw-r--r--tests/codegen/vec-iter-collect-len.rs1
-rw-r--r--tests/codegen/vec-optimizes-away.rs1
-rw-r--r--tests/coverage-run-rustdoc/doctest.coverage5
-rw-r--r--tests/coverage/bad_counter_ids.cov-map16
-rw-r--r--tests/coverage/bad_counter_ids.coverage2
-rw-r--r--tests/coverage/issue-83601.cov-map16
-rw-r--r--tests/coverage/issue-83601.coverage3
-rw-r--r--tests/coverage/issue-84561.cov-map8
-rw-r--r--tests/coverage/issue-84561.coverage2
-rw-r--r--tests/coverage/partial_eq.cov-map48
-rw-r--r--tests/coverage/partial_eq.coverage3
-rw-r--r--tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir21
-rw-r--r--tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir21
-rw-r--r--tests/rustdoc/doc-cfg-target-feature.rs1
-rw-r--r--tests/ui/array-slice-vec/repeat_empty_ok.stderr4
-rw-r--r--tests/ui/associated-consts/issue-105330.rs1
-rw-r--r--tests/ui/associated-consts/issue-105330.stderr12
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-1.stderr7
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-2.stderr8
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-3.rs13
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-3.stderr27
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-4.rs15
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-4.stderr25
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-5.fixed31
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-5.rs32
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-5.stderr31
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-6.fixed30
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-6.rs31
-rw-r--r--tests/ui/associated-types/impl-wf-cycle-6.stderr29
-rw-r--r--tests/ui/associated-types/issue-38821.rs15
-rw-r--r--tests/ui/associated-types/issue-38821.stderr268
-rw-r--r--tests/ui/async-await/async-fn/simple.rs16
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr4
-rw-r--r--tests/ui/coercion/issue-53475.rs2
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs6
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr25
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs4
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr4
-rw-r--r--tests/ui/const-generics/bad-generic-in-copy-impl.rs1
-rw-r--r--tests/ui/const-generics/bad-generic-in-copy-impl.stderr10
-rw-r--r--tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-61336-2.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-61336.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-74950.min.stderr20
-rw-r--r--tests/ui/const-generics/issues/issue-74950.rs2
-rw-r--r--tests/ui/consts/const-blocks/migrate-fail.stderr4
-rw-r--r--tests/ui/consts/const-blocks/nll-fail.stderr4
-rw-r--r--tests/ui/consts/const-err-late.stderr8
-rw-r--r--tests/ui/consts/const_in_pattern/cross-crate-fail.rs4
-rw-r--r--tests/ui/consts/const_in_pattern/cross-crate-fail.stderr8
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs4
-rw-r--r--tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr4
-rw-r--r--tests/ui/consts/const_in_pattern/incomplete-slice.rs4
-rw-r--r--tests/ui/consts/const_in_pattern/incomplete-slice.stderr22
-rw-r--r--tests/ui/consts/const_in_pattern/issue-78057.rs16
-rw-r--r--tests/ui/consts/const_in_pattern/issue-78057.stderr11
-rw-r--r--tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs2
-rw-r--r--tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr4
-rw-r--r--tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs4
-rw-r--r--tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.stderr14
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs2
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr4
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.rs40
-rw-r--r--tests/ui/consts/const_in_pattern/reject_non_structural.stderr40
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.rs6
-rw-r--r--tests/ui/consts/const_in_pattern/warn_corner_cases.stderr12
-rw-r--r--tests/ui/consts/is_val_statically_known.rs15
-rw-r--r--tests/ui/consts/issue-65348.rs7
-rw-r--r--tests/ui/consts/match_ice.rs2
-rw-r--r--tests/ui/consts/match_ice.stderr4
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stdout28
-rw-r--r--tests/ui/did_you_mean/bad-assoc-ty.stderr9
-rw-r--r--tests/ui/dst/dst-bad-assign-3.stderr1
-rw-r--r--tests/ui/dst/dst-bad-assign.stderr1
-rw-r--r--tests/ui/dyn-star/no-implicit-dyn-star.stderr1
-rw-r--r--tests/ui/enum-discriminant/issue-72554.rs1
-rw-r--r--tests/ui/enum-discriminant/issue-72554.stderr21
-rw-r--r--tests/ui/for-loop-while/issue-69841.rs1
-rw-r--r--tests/ui/generic-associated-types/issue-79422.extended.stderr1
-rw-r--r--tests/ui/impl-trait/dyn-impl-type-mismatch.rs18
-rw-r--r--tests/ui/impl-trait/dyn-impl-type-mismatch.stderr43
-rw-r--r--tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr2
-rw-r--r--tests/ui/issue-76387-llvm-miscompile.rs1
-rw-r--r--tests/ui/methods/issues/issue-61525.stderr1
-rw-r--r--tests/ui/pattern/issue-115599.rs2
-rw-r--r--tests/ui/pattern/issue-115599.stderr4
-rw-r--r--tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs2
-rw-r--r--tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr4
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.rs28
-rw-r--r--tests/ui/pattern/usefulness/consts-opaque.stderr190
-rw-r--r--tests/ui/privacy/private-type-in-interface.rs3
-rw-r--r--tests/ui/privacy/private-type-in-interface.stderr16
-rw-r--r--tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr12
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs4
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr8
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs23
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr21
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs19
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr11
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs2
-rw-r--r--tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr14
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs1
-rw-r--r--tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr22
-rw-r--r--tests/ui/symbol-names/const-generics-structural-demangling.stderr2
-rw-r--r--tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr2
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.rs1
-rw-r--r--tests/ui/typeck/typeck_type_placeholder_item.stderr37
-rw-r--r--triagebot.toml136
255 files changed, 4545 insertions, 2917 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 537571ee6b5..74f96983b31 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -212,9 +212,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 
 [[package]]
 name = "askama"
-version = "0.12.0"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"
+checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
 dependencies = [
  "askama_derive",
  "askama_escape",
@@ -222,14 +222,14 @@ dependencies = [
 
 [[package]]
 name = "askama_derive"
-version = "0.12.1"
+version = "0.12.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94"
+checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
 dependencies = [
+ "askama_parser",
  "basic-toml",
  "mime",
  "mime_guess",
- "nom",
  "proc-macro2",
  "quote",
  "serde",
@@ -243,6 +243,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
 
 [[package]]
+name = "askama_parser"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
+dependencies = [
+ "nom",
+]
+
+[[package]]
 name = "autocfg"
 version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3654,10 +3663,10 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "bitflags 2.4.1",
+ "either",
  "elsa",
  "ena",
  "indexmap",
- "itertools",
  "jobserver",
  "libc",
  "measureme",
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 89f50d3a0a7..8d084ee29a7 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -375,11 +375,11 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         }
         ItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
         ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id),
-        ItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
+        ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
             if let Some(qself) = qself {
                 visitor.visit_ty(&qself.ty);
             }
-            walk_path(visitor, path);
+            visitor.visit_path(path, *id);
             if let Some(body) = body {
                 visitor.visit_block(body);
             }
@@ -502,7 +502,7 @@ where
         }
         GenericArgs::Parenthesized(data) => {
             walk_list!(visitor, visit_ty, &data.inputs);
-            walk_fn_ret_ty(visitor, &data.output);
+            visitor.visit_fn_ret_ty(&data.output);
         }
     }
 }
@@ -713,11 +713,11 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
         AssocItemKind::MacCall(mac) => {
             visitor.visit_mac_call(mac);
         }
-        AssocItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
+        AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
             if let Some(qself) = qself {
                 visitor.visit_ty(&qself.ty);
             }
-            walk_path(visitor, path);
+            visitor.visit_path(path, *id);
             if let Some(body) = body {
                 visitor.visit_block(body);
             }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 14ae999427d..ce3fa1ab32c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -19,19 +19,6 @@ pub fn expand_deriving_eq(
 ) {
     let span = cx.with_def_site_ctxt(span);
 
-    let structural_trait_def = TraitDef {
-        span,
-        path: path_std!(marker::StructuralEq),
-        skip_path_as_bound: true, // crucial!
-        needs_copy_as_bound_if_packed: false,
-        additional_bounds: Vec::new(),
-        supports_unions: true,
-        methods: Vec::new(),
-        associated_types: Vec::new(),
-        is_const: false,
-    };
-    structural_trait_def.expand(cx, mitem, item, push);
-
     let trait_def = TraitDef {
         span,
         path: path_std!(cmp::Eq),
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 3607b7cd944..a79909ce0c8 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -104,9 +104,6 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
 #[lang = "structural_peq"]
 pub trait StructuralPartialEq {}
 
-#[lang = "structural_teq"]
-pub trait StructuralEq {}
-
 #[lang = "not"]
 pub trait Not {
     type Output;
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index a27853fa0a8..819cb5ef137 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -443,6 +443,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
             ret.write_cvalue(fx, a);
         }
+        sym::is_val_statically_known => {
+            intrinsic_args!(fx, args => (_a); intrinsic);
+
+            let res = fx.bcx.ins().iconst(types::I8, 0);
+            ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
+        }
         sym::breakpoint => {
             intrinsic_args!(fx, args => (); intrinsic);
 
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index db94bc1c86a..230009741dc 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -100,9 +100,6 @@ unsafe impl<T: ?Sized> Freeze for &mut T {}
 #[lang = "structural_peq"]
 pub trait StructuralPartialEq {}
 
-#[lang = "structural_teq"]
-pub trait StructuralEq {}
-
 #[lang = "not"]
 pub trait Not {
     type Output;
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 053f759329f..5760d96165d 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -196,15 +196,16 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
 
         let mut functions = FxHashMap::default();
         let builtins = [
-            "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow",
-            "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
+            "__builtin_unreachable", "abort", "__builtin_expect", /*"__builtin_expect_with_probability",*/
+            "__builtin_constant_p", "__builtin_add_overflow", "__builtin_mul_overflow", "__builtin_saddll_overflow",
+            /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
             "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow",
             "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow",
             "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos",
             "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf",
             "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf",
             "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round",
-            "__builtin_expect_with_probability",
+           
         ];
 
         for builtin in builtins.iter() {
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 85b891fce3e..eac8cb43779 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -123,6 +123,12 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                 sym::unlikely => {
                     self.expect(args[0].immediate(), false)
                 }
+                sym::is_val_statically_known => {
+                    let a = args[0].immediate();
+                    let builtin = self.context.get_builtin_function("__builtin_constant_p");
+                    let res = self.context.new_call(None, builtin, &[a]);
+                    self.icmp(IntPredicate::IntEQ, res, self.const_i32(0))
+                }
                 kw::Try => {
                     try_intrinsic(
                         self,
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
index 0b933754c29..e7c46ae3fcc 100644
--- a/compiler/rustc_codegen_gcc/tests/run/static.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -61,9 +61,6 @@ mod libc {
 #[lang = "structural_peq"]
 pub trait StructuralPartialEq {}
 
-#[lang = "structural_teq"]
-pub trait StructuralEq {}
-
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
 pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index f3b2caf9b80..5ef05dfbe4c 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -916,6 +916,20 @@ impl<'ll> CodegenCx<'ll, '_> {
         ifn!("llvm.lifetime.start.p0i8", fn(t_i64, ptr) -> void);
         ifn!("llvm.lifetime.end.p0i8", fn(t_i64, ptr) -> void);
 
+        // FIXME: This is an infinitesimally small portion of the types you can
+        // pass to this intrinsic, if we can ever lazily register intrinsics we
+        // should register these when they're used, that way any type can be
+        // passed.
+        ifn!("llvm.is.constant.i1", fn(i1) -> i1);
+        ifn!("llvm.is.constant.i8", fn(t_i8) -> i1);
+        ifn!("llvm.is.constant.i16", fn(t_i16) -> i1);
+        ifn!("llvm.is.constant.i32", fn(t_i32) -> i1);
+        ifn!("llvm.is.constant.i64", fn(t_i64) -> i1);
+        ifn!("llvm.is.constant.i128", fn(t_i128) -> i1);
+        ifn!("llvm.is.constant.isize", fn(t_isize) -> i1);
+        ifn!("llvm.is.constant.f32", fn(t_f32) -> i1);
+        ifn!("llvm.is.constant.f64", fn(t_f64) -> i1);
+
         ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
         ifn!("llvm.eh.typeid.for", fn(ptr) -> t_i32);
         ifn!("llvm.localescape", fn(...) -> void);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a0f9d5cf7cd..f1a6f7bd8e6 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -119,6 +119,10 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
             sym::likely => {
                 self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)])
             }
+            sym::is_val_statically_known => self.call_intrinsic(
+                &format!("llvm.is.constant.{:?}", args[0].layout.immediate_llvm_type(self.cx)),
+                &[args[0].immediate()],
+            ),
             sym::unlikely => self
                 .call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
             kw::Try => {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 959653c9326..f098fc9cb59 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -52,6 +52,15 @@ use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
 use std::{env, fmt, fs, io, mem, str};
 
+#[derive(Default)]
+pub struct SearchPaths(OnceCell<Vec<PathBuf>>);
+
+impl SearchPaths {
+    pub(super) fn get(&self, sess: &Session) -> &[PathBuf] {
+        self.0.get_or_init(|| archive_search_paths(sess))
+    }
+}
+
 pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) {
     if let Err(e) = fs::remove_file(path) {
         if e.kind() != io::ErrorKind::NotFound {
@@ -1265,7 +1274,7 @@ fn link_sanitizer_runtime(
         let path = find_sanitizer_runtime(sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
         linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
-        linker.link_dylib(&filename, false, true);
+        linker.link_dylib_by_name(&filename, false, true);
     } else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
         // MSVC provides the `/INFERASANLIBS` argument to automatically find the
         // compatible ASAN library.
@@ -1273,7 +1282,7 @@ fn link_sanitizer_runtime(
     } else {
         let filename = format!("librustc{channel}_rt.{name}.a");
         let path = find_sanitizer_runtime(sess, &filename).join(&filename);
-        linker.link_whole_rlib(&path);
+        linker.link_staticlib_by_path(&path, true);
     }
 }
 
@@ -2445,7 +2454,7 @@ fn add_native_libs_from_crate(
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: &CodegenResults,
     tmpdir: &Path,
-    search_paths: &OnceCell<Vec<PathBuf>>,
+    search_paths: &SearchPaths,
     bundled_libs: &FxHashSet<Symbol>,
     cnum: CrateNum,
     link_static: bool,
@@ -2505,28 +2514,16 @@ fn add_native_libs_from_crate(
                         if let Some(filename) = lib.filename {
                             // If rlib contains native libs as archives, they are unpacked to tmpdir.
                             let path = tmpdir.join(filename.as_str());
-                            if whole_archive {
-                                cmd.link_whole_rlib(&path);
-                            } else {
-                                cmd.link_rlib(&path);
-                            }
+                            cmd.link_staticlib_by_path(&path, whole_archive);
                         }
                     } else {
-                        if whole_archive {
-                            cmd.link_whole_staticlib(
-                                name,
-                                verbatim,
-                                search_paths.get_or_init(|| archive_search_paths(sess)),
-                            );
-                        } else {
-                            cmd.link_staticlib(name, verbatim)
-                        }
+                        cmd.link_staticlib_by_name(name, verbatim, whole_archive, search_paths);
                     }
                 }
             }
             NativeLibKind::Dylib { as_needed } => {
                 if link_dynamic {
-                    cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
+                    cmd.link_dylib_by_name(name, verbatim, as_needed.unwrap_or(true))
                 }
             }
             NativeLibKind::Unspecified => {
@@ -2534,17 +2531,17 @@ fn add_native_libs_from_crate(
                 // link kind is unspecified.
                 if !link_output_kind.can_link_dylib() && !sess.target.crt_static_allows_dylibs {
                     if link_static {
-                        cmd.link_staticlib(name, verbatim)
+                        cmd.link_staticlib_by_name(name, verbatim, false, search_paths);
                     }
                 } else {
                     if link_dynamic {
-                        cmd.link_dylib(name, verbatim, true);
+                        cmd.link_dylib_by_name(name, verbatim, true);
                     }
                 }
             }
             NativeLibKind::Framework { as_needed } => {
                 if link_dynamic {
-                    cmd.link_framework(name, as_needed.unwrap_or(true))
+                    cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true))
                 }
             }
             NativeLibKind::RawDylib => {
@@ -2581,7 +2578,7 @@ fn add_local_native_libraries(
         }
     }
 
-    let search_paths = OnceCell::new();
+    let search_paths = SearchPaths::default();
     // All static and dynamic native library dependencies are linked to the local crate.
     let link_static = true;
     let link_dynamic = true;
@@ -2623,7 +2620,7 @@ fn add_upstream_rust_crates<'a>(
         .find(|(ty, _)| *ty == crate_type)
         .expect("failed to find crate type in dependency format list");
 
-    let search_paths = OnceCell::new();
+    let search_paths = SearchPaths::default();
     for &cnum in &codegen_results.crate_info.used_crates {
         // We may not pass all crates through to the linker. Some crates may appear statically in
         // an existing dylib, meaning we'll pick up all the symbols from the dylib.
@@ -2698,7 +2695,7 @@ fn add_upstream_native_libraries(
     tmpdir: &Path,
     link_output_kind: LinkOutputKind,
 ) {
-    let search_path = OnceCell::new();
+    let search_paths = SearchPaths::default();
     for &cnum in &codegen_results.crate_info.used_crates {
         // Static libraries are not linked here, they are linked in `add_upstream_rust_crates`.
         // FIXME: Merge this function to `add_upstream_rust_crates` so that all native libraries
@@ -2720,7 +2717,7 @@ fn add_upstream_native_libraries(
             archive_builder_builder,
             codegen_results,
             tmpdir,
-            &search_path,
+            &search_paths,
             &Default::default(),
             cnum,
             link_static,
@@ -2791,7 +2788,7 @@ fn add_static_crate<'a>(
         } else {
             fix_windows_verbatim_for_gcc(path)
         };
-        cmd.link_rlib(&rlib_path);
+        cmd.link_staticlib_by_path(&rlib_path, false);
     };
 
     if !are_upstream_rust_objects_already_included(sess)
@@ -2859,13 +2856,24 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
     // Just need to tell the linker about where the library lives and
     // what its name is
     let parent = cratepath.parent();
+    // When producing a dll, the MSVC linker may not actually emit a
+    // `foo.lib` file if the dll doesn't actually export any symbols, so we
+    // check to see if the file is there and just omit linking to it if it's
+    // not present.
+    if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() {
+        return;
+    }
     if let Some(dir) = parent {
         cmd.include_path(&rehome_sysroot_lib_dir(sess, dir));
     }
-    let stem = cratepath.file_stem().unwrap().to_str().unwrap();
+    // "<dir>/name.dll -> name.dll" on windows-msvc
+    // "<dir>/name.dll -> name" on windows-gnu
+    // "<dir>/libname.<ext> -> name" elsewhere
+    let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() };
+    let stem = stem.unwrap().to_str().unwrap();
     // Convert library file-stem into a cc -l argument.
     let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 };
-    cmd.link_rust_dylib(&stem[prefix..], parent.unwrap_or_else(|| Path::new("")));
+    cmd.link_dylib_by_name(&stem[prefix..], false, true);
 }
 
 fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 90f5027c264..9f06f398288 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -1,5 +1,6 @@
 use super::command::Command;
 use super::symbol_export;
+use crate::back::link::SearchPaths;
 use crate::errors;
 use rustc_span::symbol::sym;
 
@@ -166,13 +167,18 @@ pub fn get_linker<'a>(
 pub trait Linker {
     fn cmd(&mut self) -> &mut Command;
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
-    fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool);
-    fn link_rust_dylib(&mut self, lib: &str, path: &Path);
-    fn link_framework(&mut self, framework: &str, as_needed: bool);
-    fn link_staticlib(&mut self, lib: &str, verbatim: bool);
-    fn link_rlib(&mut self, lib: &Path);
-    fn link_whole_rlib(&mut self, lib: &Path);
-    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]);
+    fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool);
+    fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
+        bug!("framework linked with unsupported linker")
+    }
+    fn link_staticlib_by_name(
+        &mut self,
+        name: &str,
+        verbatim: bool,
+        whole_archive: bool,
+        search_paths: &SearchPaths,
+    );
+    fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
     fn include_path(&mut self, path: &Path);
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
@@ -432,8 +438,8 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool) {
-        if self.sess.target.os == "illumos" && lib == "c" {
+    fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
+        if self.sess.target.os == "illumos" && name == "c" {
             // libc will be added via late_link_args on illumos so that it will
             // appear last in the library search order.
             // FIXME: This should be replaced by a more complete and generic
@@ -454,7 +460,7 @@ impl<'a> Linker for GccLinker<'a> {
             }
         }
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
+        self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },));
         if !as_needed {
             if self.sess.target.is_like_osx {
                 // See above FIXME comment
@@ -463,14 +469,56 @@ impl<'a> Linker for GccLinker<'a> {
             }
         }
     }
-    fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
+
+    fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
+        self.hint_dynamic();
+        if !as_needed {
+            // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
+            // flag but we have no way to detect that here.
+            // self.cmd.arg("-needed_framework").arg(name);
+            self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
+        }
+        self.cmd.arg("-framework").arg(name);
+    }
+
+    fn link_staticlib_by_name(
+        &mut self,
+        name: &str,
+        verbatim: bool,
+        whole_archive: bool,
+        search_paths: &SearchPaths,
+    ) {
         self.hint_static();
-        self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
+        let colon = if verbatim && self.is_gnu { ":" } else { "" };
+        if !whole_archive {
+            self.cmd.arg(format!("-l{colon}{name}"));
+        } else if self.sess.target.is_like_osx {
+            // -force_load is the macOS equivalent of --whole-archive, but it
+            // involves passing the full path to the library to link.
+            self.linker_arg("-force_load");
+            let search_paths = search_paths.get(self.sess);
+            self.linker_arg(find_native_static_library(name, verbatim, search_paths, self.sess));
+        } else {
+            self.linker_arg("--whole-archive");
+            self.cmd.arg(format!("-l{colon}{name}"));
+            self.linker_arg("--no-whole-archive");
+        }
     }
-    fn link_rlib(&mut self, lib: &Path) {
+
+    fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         self.hint_static();
-        self.cmd.arg(lib);
+        if !whole_archive {
+            self.cmd.arg(path);
+        } else if self.sess.target.is_like_osx {
+            self.linker_arg("-force_load");
+            self.linker_arg(path);
+        } else {
+            self.linker_arg("--whole-archive");
+            self.linker_arg(path);
+            self.linker_arg("--no-whole-archive");
+        }
     }
+
     fn include_path(&mut self, path: &Path) {
         self.cmd.arg("-L").arg(path);
     }
@@ -493,55 +541,6 @@ impl<'a> Linker for GccLinker<'a> {
         self.linker_args(&["-z", "norelro"]);
     }
 
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
-        self.hint_dynamic();
-        self.cmd.arg(format!("-l{lib}"));
-    }
-
-    fn link_framework(&mut self, framework: &str, as_needed: bool) {
-        self.hint_dynamic();
-        if !as_needed {
-            // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
-            // flag but we have no way to detect that here.
-            // self.cmd.arg("-needed_framework").arg(framework);
-            self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
-        }
-        self.cmd.arg("-framework").arg(framework);
-    }
-
-    // Here we explicitly ask that the entire archive is included into the
-    // result artifact. For more details see #15460, but the gist is that
-    // the linker will strip away any unused objects in the archive if we
-    // don't otherwise explicitly reference them. This can occur for
-    // libraries which are just providing bindings, libraries with generic
-    // functions, etc.
-    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) {
-        self.hint_static();
-        let target = &self.sess.target;
-        if !target.is_like_osx {
-            self.linker_arg("--whole-archive");
-            self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
-            self.linker_arg("--no-whole-archive");
-        } else {
-            // -force_load is the macOS equivalent of --whole-archive, but it
-            // involves passing the full path to the library to link.
-            self.linker_arg("-force_load");
-            let lib = find_native_static_library(lib, verbatim, search_path, self.sess);
-            self.linker_arg(&lib);
-        }
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        self.hint_static();
-        if self.sess.target.is_like_osx {
-            self.linker_arg("-force_load");
-            self.linker_arg(&lib);
-        } else {
-            self.linker_args(&[OsString::from("--whole-archive"), lib.into()]);
-            self.linker_arg("--no-whole-archive");
-        }
-    }
-
     fn gc_sections(&mut self, keep_metadata: bool) {
         // The dead_strip option to the linker specifies that functions and data
         // unreachable by the entry point will be removed. This is quite useful
@@ -821,9 +820,32 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    fn link_rlib(&mut self, lib: &Path) {
-        self.cmd.arg(lib);
+    fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
+        self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
+    }
+
+    fn link_staticlib_by_name(
+        &mut self,
+        name: &str,
+        verbatim: bool,
+        whole_archive: bool,
+        _search_paths: &SearchPaths,
+    ) {
+        let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
+        let suffix = if verbatim { "" } else { ".lib" };
+        self.cmd.arg(format!("{prefix}{name}{suffix}"));
+    }
+
+    fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
+        if !whole_archive {
+            self.cmd.arg(path);
+        } else {
+            let mut arg = OsString::from("/WHOLEARCHIVE:");
+            arg.push(path);
+            self.cmd.arg(arg);
+        }
     }
+
     fn add_object(&mut self, path: &Path) {
         self.cmd.arg(path);
     }
@@ -845,25 +867,6 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg("/OPT:NOREF,NOICF");
     }
 
-    fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) {
-        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
-    }
-
-    fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
-        // When producing a dll, the MSVC linker may not actually emit a
-        // `foo.lib` file if the dll doesn't actually export any symbols, so we
-        // check to see if the file is there and just omit linking to it if it's
-        // not present.
-        let name = format!("{lib}.dll.lib");
-        if path.join(&name).exists() {
-            self.cmd.arg(name);
-        }
-    }
-
-    fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
-        self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
-    }
-
     fn full_relro(&mut self) {
         // noop
     }
@@ -899,18 +902,7 @@ impl<'a> Linker for MsvcLinker<'a> {
     fn framework_path(&mut self, _path: &Path) {
         bug!("frameworks are not supported on windows")
     }
-    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
-        bug!("frameworks are not supported on windows")
-    }
 
-    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) {
-        self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
-    }
-    fn link_whole_rlib(&mut self, path: &Path) {
-        let mut arg = OsString::from("/WHOLEARCHIVE:");
-        arg.push(path);
-        self.cmd.arg(arg);
-    }
     fn optimize(&mut self) {
         // Needs more investigation of `/OPT` arguments
     }
@@ -1057,43 +1049,35 @@ impl<'a> Linker for EmLinker<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn include_path(&mut self, path: &Path) {
-        self.cmd.arg("-L").arg(path);
-    }
-
-    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
+        // Emscripten always links statically
+        self.cmd.arg("-l").arg(name);
     }
 
-    fn output_filename(&mut self, path: &Path) {
-        self.cmd.arg("-o").arg(path);
+    fn link_staticlib_by_name(
+        &mut self,
+        name: &str,
+        _verbatim: bool,
+        _whole_archive: bool,
+        _search_paths: &SearchPaths,
+    ) {
+        self.cmd.arg("-l").arg(name);
     }
 
-    fn add_object(&mut self, path: &Path) {
+    fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
         self.cmd.arg(path);
     }
 
-    fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) {
-        // Emscripten always links statically
-        self.link_staticlib(lib, verbatim);
-    }
-
-    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) {
-        // not supported?
-        self.link_staticlib(lib, verbatim);
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        // not supported?
-        self.link_rlib(lib);
+    fn include_path(&mut self, path: &Path) {
+        self.cmd.arg("-L").arg(path);
     }
 
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
-        self.link_dylib(lib, false, true);
+    fn output_filename(&mut self, path: &Path) {
+        self.cmd.arg("-o").arg(path);
     }
 
-    fn link_rlib(&mut self, lib: &Path) {
-        self.add_object(lib);
+    fn add_object(&mut self, path: &Path) {
+        self.cmd.arg(path);
     }
 
     fn full_relro(&mut self) {
@@ -1112,10 +1096,6 @@ impl<'a> Linker for EmLinker<'a> {
         bug!("frameworks are not supported on Emscripten")
     }
 
-    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
-        bug!("frameworks are not supported on Emscripten")
-    }
-
     fn gc_sections(&mut self, _keep_metadata: bool) {
         // noop
     }
@@ -1249,16 +1229,30 @@ impl<'a> Linker for WasmLd<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
+        self.cmd.arg("-l").arg(name);
     }
 
-    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
-        self.cmd.arg("-l").arg(lib);
+    fn link_staticlib_by_name(
+        &mut self,
+        name: &str,
+        _verbatim: bool,
+        whole_archive: bool,
+        _search_paths: &SearchPaths,
+    ) {
+        if !whole_archive {
+            self.cmd.arg("-l").arg(name);
+        } else {
+            self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive");
+        }
     }
 
-    fn link_rlib(&mut self, lib: &Path) {
-        self.cmd.arg(lib);
+    fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
+        if !whole_archive {
+            self.cmd.arg(path);
+        } else {
+            self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive");
+        }
     }
 
     fn include_path(&mut self, path: &Path) {
@@ -1283,22 +1277,6 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn no_relro(&mut self) {}
 
-    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
-        self.cmd.arg("-l").arg(lib);
-    }
-
-    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
-        panic!("frameworks not supported")
-    }
-
-    fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
-        self.cmd.arg("--whole-archive").arg("-l").arg(lib).arg("--no-whole-archive");
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
-    }
-
     fn gc_sections(&mut self, _keep_metadata: bool) {
         self.cmd.arg("--gc-sections");
     }
@@ -1398,17 +1376,40 @@ pub struct L4Bender<'a> {
 }
 
 impl<'a> Linker for L4Bender<'a> {
-    fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
+    fn cmd(&mut self) -> &mut Command {
+        &mut self.cmd
+    }
+
+    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
+    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
         bug!("dylibs are not supported on L4Re");
     }
-    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
+
+    fn link_staticlib_by_name(
+        &mut self,
+        name: &str,
+        _verbatim: bool,
+        whole_archive: bool,
+        _search_paths: &SearchPaths,
+    ) {
         self.hint_static();
-        self.cmd.arg(format!("-PC{lib}"));
+        if !whole_archive {
+            self.cmd.arg(format!("-PC{name}"));
+        } else {
+            self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive");
+        }
     }
-    fn link_rlib(&mut self, lib: &Path) {
+
+    fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         self.hint_static();
-        self.cmd.arg(lib);
+        if !whole_archive {
+            self.cmd.arg(path);
+        } else {
+            self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive");
+        }
     }
+
     fn include_path(&mut self, path: &Path) {
         self.cmd.arg("-L").arg(path);
     }
@@ -1436,31 +1437,6 @@ impl<'a> Linker for L4Bender<'a> {
         self.cmd.arg("-z").arg("norelro");
     }
 
-    fn cmd(&mut self) -> &mut Command {
-        &mut self.cmd
-    }
-
-    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
-
-    fn link_rust_dylib(&mut self, _: &str, _: &Path) {
-        panic!("Rust dylibs not supported");
-    }
-
-    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
-        bug!("frameworks not supported on L4Re");
-    }
-
-    fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
-        self.hint_static();
-        self.cmd.arg("--whole-archive").arg(format!("-l{lib}"));
-        self.cmd.arg("--no-whole-archive");
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        self.hint_static();
-        self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
-    }
-
     fn gc_sections(&mut self, keep_metadata: bool) {
         if !keep_metadata {
             self.cmd.arg("--gc-sections");
@@ -1571,19 +1547,56 @@ impl<'a> AixLinker<'a> {
 }
 
 impl<'a> Linker for AixLinker<'a> {
-    fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
+    fn cmd(&mut self) -> &mut Command {
+        &mut self.cmd
+    }
+
+    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
+        match output_kind {
+            LinkOutputKind::DynamicDylib => {
+                self.hint_dynamic();
+                self.build_dylib(out_filename);
+            }
+            LinkOutputKind::StaticDylib => {
+                self.hint_static();
+                self.build_dylib(out_filename);
+            }
+            _ => {}
+        }
+    }
+
+    fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
         self.hint_dynamic();
-        self.cmd.arg(format!("-l{lib}"));
+        self.cmd.arg(format!("-l{name}"));
     }
 
-    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
+    fn link_staticlib_by_name(
+        &mut self,
+        name: &str,
+        verbatim: bool,
+        whole_archive: bool,
+        search_paths: &SearchPaths,
+    ) {
         self.hint_static();
-        self.cmd.arg(format!("-l{lib}"));
+        if !whole_archive {
+            self.cmd.arg(format!("-l{name}"));
+        } else {
+            let mut arg = OsString::from("-bkeepfile:");
+            let search_path = search_paths.get(self.sess);
+            arg.push(find_native_static_library(name, verbatim, search_path, self.sess));
+            self.cmd.arg(arg);
+        }
     }
 
-    fn link_rlib(&mut self, lib: &Path) {
+    fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
         self.hint_static();
-        self.cmd.arg(lib);
+        if !whole_archive {
+            self.cmd.arg(path);
+        } else {
+            let mut arg = OsString::from("-bkeepfile:");
+            arg.push(path);
+            self.cmd.arg(arg);
+        }
     }
 
     fn include_path(&mut self, path: &Path) {
@@ -1608,44 +1621,6 @@ impl<'a> Linker for AixLinker<'a> {
 
     fn no_relro(&mut self) {}
 
-    fn cmd(&mut self) -> &mut Command {
-        &mut self.cmd
-    }
-
-    fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
-        match output_kind {
-            LinkOutputKind::DynamicDylib => {
-                self.hint_dynamic();
-                self.build_dylib(out_filename);
-            }
-            LinkOutputKind::StaticDylib => {
-                self.hint_static();
-                self.build_dylib(out_filename);
-            }
-            _ => {}
-        }
-    }
-
-    fn link_rust_dylib(&mut self, lib: &str, _: &Path) {
-        self.hint_dynamic();
-        self.cmd.arg(format!("-l{lib}"));
-    }
-
-    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
-        bug!("frameworks not supported on AIX");
-    }
-
-    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) {
-        self.hint_static();
-        let lib = find_native_static_library(lib, verbatim, search_path, self.sess);
-        self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
-    }
-
-    fn link_whole_rlib(&mut self, lib: &Path) {
-        self.hint_static();
-        self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
-    }
-
     fn gc_sections(&mut self, _keep_metadata: bool) {
         self.cmd.arg("-bgc");
     }
@@ -1810,11 +1785,21 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn link_rlib(&mut self, path: &Path) {
-        self.cmd.arg("--rlib").arg(path);
+    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
+        panic!("external dylibs not supported")
+    }
+
+    fn link_staticlib_by_name(
+        &mut self,
+        _name: &str,
+        _verbatim: bool,
+        _whole_archive: bool,
+        _search_paths: &SearchPaths,
+    ) {
+        panic!("staticlibs not supported")
     }
 
-    fn link_whole_rlib(&mut self, path: &Path) {
+    fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
         self.cmd.arg("--rlib").arg(path);
     }
 
@@ -1844,30 +1829,10 @@ impl<'a> Linker for PtxLinker<'a> {
         self.cmd.arg("-o").arg(path);
     }
 
-    fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
-        panic!("external dylibs not supported")
-    }
-
-    fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
-        panic!("external dylibs not supported")
-    }
-
-    fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) {
-        panic!("staticlibs not supported")
-    }
-
-    fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
-        panic!("staticlibs not supported")
-    }
-
     fn framework_path(&mut self, _path: &Path) {
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
-        panic!("frameworks not supported")
-    }
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
@@ -1907,11 +1872,21 @@ impl<'a> Linker for BpfLinker<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn link_rlib(&mut self, path: &Path) {
-        self.cmd.arg(path);
+    fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
+        panic!("external dylibs not supported")
     }
 
-    fn link_whole_rlib(&mut self, path: &Path) {
+    fn link_staticlib_by_name(
+        &mut self,
+        _name: &str,
+        _verbatim: bool,
+        _whole_archive: bool,
+        _search_paths: &SearchPaths,
+    ) {
+        panic!("staticlibs not supported")
+    }
+
+    fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
         self.cmd.arg(path);
     }
 
@@ -1942,30 +1917,10 @@ impl<'a> Linker for BpfLinker<'a> {
         self.cmd.arg("-o").arg(path);
     }
 
-    fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
-        panic!("external dylibs not supported")
-    }
-
-    fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
-        panic!("external dylibs not supported")
-    }
-
-    fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) {
-        panic!("staticlibs not supported")
-    }
-
-    fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
-        panic!("staticlibs not supported")
-    }
-
     fn framework_path(&mut self, _path: &Path) {
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
-        panic!("frameworks not supported")
-    }
-
     fn full_relro(&mut self) {}
 
     fn partial_relro(&mut self) {}
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index d5a33b6f01e..274ff25fb9b 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -531,6 +531,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                     )?;
                 }
             }
+            // The intrinsic represents whether the value is known to the optimizer (LLVM).
+            // We're not doing any optimizations here, so there is no optimizer that could know the value.
+            // (We know the value here in the machine of course, but this is the runtime of that code,
+            // not the optimization stage.)
+            sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?,
             _ => {
                 throw_unsup_format!(
                     "intrinsic `{intrinsic_name}` is not supported at compile-time"
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 707bb8d8933..12544f5b029 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -138,7 +138,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
         }
         // Trait objects are not allowed in type level constants, as we have no concept for
         // resolving their backing type, even if we can do that at const eval time. We may
-        // hypothetically be able to allow `dyn StructuralEq` trait objects in the future,
+        // hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future,
         // but it is unclear if this is useful.
         ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
 
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 4a654480ef5..064d97a49d7 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -864,9 +864,6 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
             InvalidProgramInfo::FnAbiAdjustForForeignAbi(_) => {
                 rustc_middle::error::middle_adjust_for_foreign_abi_error
             }
-            InvalidProgramInfo::ConstPropNonsense => {
-                panic!("We had const-prop nonsense, this should never be printed")
-            }
         }
     }
     fn add_args<G: EmissionGuarantee>(
@@ -875,9 +872,7 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
         builder: &mut DiagnosticBuilder<'_, G>,
     ) {
         match self {
-            InvalidProgramInfo::TooGeneric
-            | InvalidProgramInfo::AlreadyReported(_)
-            | InvalidProgramInfo::ConstPropNonsense => {}
+            InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
             InvalidProgramInfo::Layout(e) => {
                 // The level doesn't matter, `diag` is consumed without it being used.
                 let dummy_level = Level::Bug;
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index e6370adb983..c14bd142efa 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -1131,13 +1131,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         span: Option<Span>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        let const_val = val.eval(*self.tcx, self.param_env, span).map_err(|err| {
-            // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on.
-            // Are we not always populating `required_consts`?
-            err.emit_note(*self.tcx);
-            err
-        })?;
-        self.const_val_to_op(const_val, val.ty(), layout)
+        M::eval_mir_constant(self, *val, span, layout, |ecx, val, span, layout| {
+            let const_val = val.eval(*ecx.tcx, ecx.param_env, span).map_err(|err| {
+                // FIXME: somehow this is reachable even when POST_MONO_CHECKS is on.
+                // Are we not always populating `required_consts`?
+                err.emit_note(*ecx.tcx);
+                err
+            })?;
+            ecx.const_val_to_op(const_val, val.ty(), layout)
+        })
     }
 
     #[must_use]
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 5e69965512b..b981a1ee2ca 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -13,6 +13,7 @@ use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::def_id::DefId;
+use rustc_span::Span;
 use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi as CallAbi;
 
@@ -510,6 +511,27 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
     ) -> InterpResult<'tcx> {
         Ok(())
     }
+
+    /// Evaluate the given constant. The `eval` function will do all the required evaluation,
+    /// but this hook has the chance to do some pre/postprocessing.
+    #[inline(always)]
+    fn eval_mir_constant<F>(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        val: mir::Const<'tcx>,
+        span: Option<Span>,
+        layout: Option<TyAndLayout<'tcx>>,
+        eval: F,
+    ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>
+    where
+        F: Fn(
+            &InterpCx<'mir, 'tcx, Self>,
+            mir::Const<'tcx>,
+            Option<Span>,
+            Option<TyAndLayout<'tcx>>,
+        ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>,
+    {
+        eval(ecx, val, span, layout)
+    }
 }
 
 /// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index b39b219b46a..80d4bda4827 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -643,11 +643,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let layout = self.layout_of_local(frame, local, layout)?;
         let op = *frame.locals[local].access()?;
         if matches!(op, Operand::Immediate(_)) {
-            if layout.is_unsized() {
-                // ConstProp marks *all* locals as `Immediate::Uninit` since it cannot
-                // efficiently check whether they are sized. We have to catch that case here.
-                throw_inval!(ConstPropNonsense);
-            }
+            assert!(!layout.is_unsized());
         }
         Ok(OpTy { op, layout })
     }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index b39efad61bb..772445f4f62 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -519,11 +519,7 @@ where
         } else {
             // Unsized `Local` isn't okay (we cannot store the metadata).
             match frame_ref.locals[local].access()? {
-                Operand::Immediate(_) => {
-                    // ConstProp marks *all* locals as `Immediate::Uninit` since it cannot
-                    // efficiently check whether they are sized. We have to catch that case here.
-                    throw_inval!(ConstPropNonsense);
-                }
+                Operand::Immediate(_) => bug!(),
                 Operand::Indirect(mplace) => Place::Ptr(*mplace),
             }
         };
@@ -816,17 +812,8 @@ where
         // avoid force_allocation.
         let src = match self.read_immediate_raw(src)? {
             Right(src_val) => {
-                // FIXME(const_prop): Const-prop can possibly evaluate an
-                // unsized copy operation when it thinks that the type is
-                // actually sized, due to a trivially false where-clause
-                // predicate like `where Self: Sized` with `Self = dyn Trait`.
-                // See #102553 for an example of such a predicate.
-                if src.layout().is_unsized() {
-                    throw_inval!(ConstPropNonsense);
-                }
-                if dest.layout().is_unsized() {
-                    throw_inval!(ConstPropNonsense);
-                }
+                assert!(!src.layout().is_unsized());
+                assert!(!dest.layout().is_unsized());
                 assert_eq!(src.layout().size, dest.layout().size);
                 // Yay, we got a value that we can write directly.
                 return if layout_compat {
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 9a034ba22b9..bd60e066f72 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -153,11 +153,7 @@ where
 
         // Offset may need adjustment for unsized fields.
         let (meta, offset) = if field_layout.is_unsized() {
-            if base.layout().is_sized() {
-                // An unsized field of a sized type? Sure...
-                // But const-prop actually feeds us such nonsense MIR! (see test `const_prop/issue-86351.rs`)
-                throw_inval!(ConstPropNonsense);
-            }
+            assert!(!base.layout().is_sized());
             let base_meta = base.meta();
             // Re-use parent metadata to determine dynamic field layout.
             // With custom DSTS, this *will* execute user-defined code, but the same
@@ -205,29 +201,26 @@ where
         // see https://github.com/rust-lang/rust/issues/93688#issuecomment-1032929496.)
         // So we just "offset" by 0.
         let layout = base.layout().for_variant(self, variant);
-        if layout.abi.is_uninhabited() {
-            // `read_discriminant` should have excluded uninhabited variants... but ConstProp calls
-            // us on dead code.
-            // In the future we might want to allow this to permit code like this:
-            // (this is a Rust/MIR pseudocode mix)
-            // ```
-            // enum Option2 {
-            //   Some(i32, !),
-            //   None,
-            // }
-            //
-            // fn panic() -> ! { panic!() }
-            //
-            // let x: Option2;
-            // x.Some.0 = 42;
-            // x.Some.1 = panic();
-            // SetDiscriminant(x, Some);
-            // ```
-            // However, for now we don't generate such MIR, and this check here *has* found real
-            // bugs (see https://github.com/rust-lang/rust/issues/115145), so we will keep rejecting
-            // it.
-            throw_inval!(ConstPropNonsense)
-        }
+        // In the future we might want to allow this to permit code like this:
+        // (this is a Rust/MIR pseudocode mix)
+        // ```
+        // enum Option2 {
+        //   Some(i32, !),
+        //   None,
+        // }
+        //
+        // fn panic() -> ! { panic!() }
+        //
+        // let x: Option2;
+        // x.Some.0 = 42;
+        // x.Some.1 = panic();
+        // SetDiscriminant(x, Some);
+        // ```
+        // However, for now we don't generate such MIR, and this check here *has* found real
+        // bugs (see https://github.com/rust-lang/rust/issues/115145), so we will keep rejecting
+        // it.
+        assert!(!layout.abi.is_uninhabited());
+
         // This cannot be `transmute` as variants *can* have a smaller size than the entire enum.
         base.offset(Size::ZERO, layout, self)
     }
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 1e58bd645cd..a8060463b69 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -14,7 +14,7 @@ pub use self::type_name::type_name;
 /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
 /// same type as the result.
 #[inline]
-pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool {
+pub fn binop_left_homogeneous(op: mir::BinOp) -> bool {
     use rustc_middle::mir::BinOp::*;
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
@@ -26,7 +26,7 @@ pub(crate) fn binop_left_homogeneous(op: mir::BinOp) -> bool {
 /// Classify whether an operator is "right-homogeneous", i.e., the RHS has the
 /// same type as the LHS.
 #[inline]
-pub(crate) fn binop_right_homogeneous(op: mir::BinOp) -> bool {
+pub fn binop_right_homogeneous(op: mir::BinOp) -> bool {
     use rustc_middle::mir::BinOp::*;
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 9d598c32e6f..08aa68ca54a 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -7,10 +7,10 @@ edition = "2021"
 # tidy-alphabetical-start
 arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
+either = "1.0"
 elsa = "=1.7.1"
 ena = "0.14.2"
 indexmap = { version = "2.0.0" }
-itertools = "0.11"
 jobserver_crate = { version = "0.1.27", package = "jobserver" }
 libc = "0.2"
 measureme = "11"
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 162dbd234d6..4b02b183460 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -3,7 +3,7 @@ use crate::fx::{FxHashMap, FxHasher};
 use crate::sync::{is_dyn_thread_safe, CacheAligned};
 use crate::sync::{Lock, LockGuard, Mode};
 #[cfg(parallel_compiler)]
-use itertools::Either;
+use either::Either;
 use std::borrow::Borrow;
 use std::collections::hash_map::RawEntryMut;
 use std::hash::{Hash, Hasher};
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
index 04e359a5470..2ef4a2ccd84 100644
--- a/compiler/rustc_data_structures/src/sso/map.rs
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -1,6 +1,6 @@
 use crate::fx::FxHashMap;
 use arrayvec::ArrayVec;
-use itertools::Either;
+use either::Either;
 use std::fmt;
 use std::hash::Hash;
 use std::ops::Index;
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 85d10872b3d..8e327c029df 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -143,8 +143,6 @@ language_item_table! {
     Unsize,                  sym::unsize,              unsize_trait,               Target::Trait,          GenericRequirement::Minimum(1);
     /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
     StructuralPeq,           sym::structural_peq,      structural_peq_trait,       Target::Trait,          GenericRequirement::None;
-    /// Trait injected by `#[derive(Eq)]`, (i.e. "Total EQ"; no, I will not apologize).
-    StructuralTeq,           sym::structural_teq,      structural_teq_trait,       Target::Trait,          GenericRequirement::None;
     Copy,                    sym::copy,                copy_trait,                 Target::Trait,          GenericRequirement::Exact(0);
     Clone,                   sym::clone,               clone_trait,                Target::Trait,          GenericRequirement::None;
     Sync,                    sym::sync,                sync_trait,                 Target::Trait,          GenericRequirement::Exact(0);
@@ -208,6 +206,10 @@ language_item_table! {
     FnMut,                   sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
     FnOnce,                  sym::fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
 
+    AsyncFn,                 sym::async_fn,            async_fn_trait,             Target::Trait,          GenericRequirement::Exact(1);
+    AsyncFnMut,              sym::async_fn_mut,        async_fn_mut_trait,         Target::Trait,          GenericRequirement::Exact(1);
+    AsyncFnOnce,             sym::async_fn_once,       async_fn_once_trait,        Target::Trait,          GenericRequirement::Exact(1);
+
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
     Iterator,                sym::iterator,            iterator_trait,             Target::Trait,          GenericRequirement::Exact(0);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 7c3e296dfce..60e4403c1c7 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -453,6 +453,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
 
             sym::black_box => (1, vec![param(0)], param(0)),
 
+            sym::is_val_statically_known => (1, vec![param(0)], tcx.types.bool),
+
             sym::const_eval_select => (4, vec![param(0), param(1), param(2)], param(3)),
 
             sym::vtable_size | sym::vtable_align => {
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 8d362f74b0a..5a387844593 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -25,14 +25,21 @@ use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCause};
 use std::collections::BTreeMap;
 
-pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
+pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
     let lang_items = tcx.lang_items();
-    Checker { tcx, trait_def_id }
-        .check(lang_items.drop_trait(), visit_implementation_of_drop)
-        .check(lang_items.copy_trait(), visit_implementation_of_copy)
-        .check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
-        .check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
-        .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
+    let checker = Checker { tcx, trait_def_id };
+    let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
+    res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
+    res = res.and(
+        checker.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty),
+    );
+    res = res.and(
+        checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
+    );
+    res.and(
+        checker
+            .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
+    )
 }
 
 struct Checker<'tcx> {
@@ -41,33 +48,40 @@ struct Checker<'tcx> {
 }
 
 impl<'tcx> Checker<'tcx> {
-    fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
+    fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> Result<(), ErrorGuaranteed>
     where
-        F: FnMut(TyCtxt<'tcx>, LocalDefId),
+        F: FnMut(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
     {
+        let mut res = Ok(());
         if Some(self.trait_def_id) == trait_def_id {
             for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
-                f(self.tcx, impl_def_id);
+                res = res.and(f(self.tcx, impl_def_id));
             }
         }
-        self
+        res
     }
 }
 
-fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+fn visit_implementation_of_drop(
+    tcx: TyCtxt<'_>,
+    impl_did: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     // Destructors only work on local ADT types.
     match tcx.type_of(impl_did).instantiate_identity().kind() {
-        ty::Adt(def, _) if def.did().is_local() => return,
-        ty::Error(_) => return,
+        ty::Adt(def, _) if def.did().is_local() => return Ok(()),
+        ty::Error(_) => return Ok(()),
         _ => {}
     }
 
     let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
 
-    tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span });
+    Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }))
 }
 
-fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+fn visit_implementation_of_copy(
+    tcx: TyCtxt<'_>,
+    impl_did: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
 
     let self_type = tcx.type_of(impl_did).instantiate_identity();
@@ -79,59 +93,68 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
     let span = match tcx.hir().expect_item(impl_did).expect_impl() {
-        hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
+        hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
         hir::Impl { self_ty, .. } => self_ty.span,
     };
 
     let cause = traits::ObligationCause::misc(span, impl_did);
     match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
-        Ok(()) => {}
+        Ok(()) => Ok(()),
         Err(CopyImplementationError::InfringingFields(fields)) => {
-            infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
+            Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span))
         }
         Err(CopyImplementationError::NotAnAdt) => {
-            tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span });
+            Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
         }
         Err(CopyImplementationError::HasDestructor) => {
-            tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span });
+            Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
         }
     }
 }
 
-fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+fn visit_implementation_of_const_param_ty(
+    tcx: TyCtxt<'_>,
+    impl_did: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     let self_type = tcx.type_of(impl_did).instantiate_identity();
     assert!(!self_type.has_escaping_bound_vars());
 
     let param_env = tcx.param_env(impl_did);
 
     let span = match tcx.hir().expect_item(impl_did).expect_impl() {
-        hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
+        hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
         impl_ => impl_.self_ty.span,
     };
 
     let cause = traits::ObligationCause::misc(span, impl_did);
     match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
-        Ok(()) => {}
+        Ok(()) => Ok(()),
         Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
-            infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
+            Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span))
         }
         Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
-            tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span });
+            Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
         }
     }
 }
 
-fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+fn visit_implementation_of_coerce_unsized(
+    tcx: TyCtxt<'_>,
+    impl_did: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
 
     // Just compute this for the side-effects, in particular reporting
     // errors; other parts of the code may demand it for the info of
     // course.
     let span = tcx.def_span(impl_did);
-    tcx.at(span).coerce_unsized_info(impl_did);
+    tcx.at(span).ensure().coerce_unsized_info(impl_did)
 }
 
-fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+fn visit_implementation_of_dispatch_from_dyn(
+    tcx: TyCtxt<'_>,
+    impl_did: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
 
     let span = tcx.def_span(impl_did);
@@ -166,26 +189,28 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
     match (source.kind(), target.kind()) {
         (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
             if infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, r_a, *r_b).is_ok()
-                && mutbl_a == *mutbl_b => {}
-        (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
+                && mutbl_a == *mutbl_b =>
+        {
+            Ok(())
+        }
+        (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => Ok(()),
         (&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => {
             if def_a != def_b {
                 let source_path = tcx.def_path_str(def_a.did());
                 let target_path = tcx.def_path_str(def_b.did());
 
-                tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
+                return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
                     span,
                     trait_name: "DispatchFromDyn",
                     note: true,
                     source_path,
                     target_path,
-                });
-
-                return;
+                }));
             }
 
+            let mut res = Ok(());
             if def_a.repr().c() || def_a.repr().packed() {
-                tcx.dcx().emit_err(errors::DispatchFromDynRepr { span });
+                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
             }
 
             let fields = &def_a.non_enum_variant().fields;
@@ -207,11 +232,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                         infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
                     {
                         if ok.obligations.is_empty() {
-                            tcx.dcx().emit_err(errors::DispatchFromDynZST {
+                            res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
                                 span,
                                 name: field.name,
                                 ty: ty_a,
-                            });
+                            }));
 
                             return false;
                         }
@@ -222,13 +247,13 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                 .collect::<Vec<_>>();
 
             if coerced_fields.is_empty() {
-                tcx.dcx().emit_err(errors::DispatchFromDynSingle {
+                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
                     span,
                     trait_name: "DispatchFromDyn",
                     note: true,
-                });
+                }));
             } else if coerced_fields.len() > 1 {
-                tcx.dcx().emit_err(errors::DispatchFromDynMulti {
+                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
                     span,
                     coercions_note: true,
                     number: coerced_fields.len(),
@@ -244,7 +269,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                         })
                         .collect::<Vec<_>>()
                         .join(", "),
-                });
+                }));
             } else {
                 let ocx = ObligationCtxt::new(&infcx);
                 for field in coerced_fields {
@@ -261,21 +286,25 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                 }
                 let errors = ocx.select_all_or_error();
                 if !errors.is_empty() {
-                    infcx.err_ctxt().report_fulfillment_errors(errors);
+                    res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
                 }
 
                 // Finally, resolve all regions.
                 let outlives_env = OutlivesEnvironment::new(param_env);
-                let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
+                res = res.and(ocx.resolve_regions_and_report_errors(impl_did, &outlives_env));
             }
+            res
         }
-        _ => {
-            tcx.dcx().emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" });
-        }
+        _ => Err(tcx
+            .dcx()
+            .emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })),
     }
 }
 
-pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> CoerceUnsizedInfo {
+pub fn coerce_unsized_info<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_did: LocalDefId,
+) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
     debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
     let span = tcx.def_span(impl_did);
 
@@ -292,8 +321,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
     let param_env = tcx.param_env(impl_did);
     assert!(!source.has_escaping_bound_vars());
 
-    let err_info = CoerceUnsizedInfo { custom_kind: None };
-
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
 
     let infcx = tcx.infer_ctxt().build();
@@ -337,14 +364,13 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
             if def_a != def_b {
                 let source_path = tcx.def_path_str(def_a.did());
                 let target_path = tcx.def_path_str(def_b.did());
-                tcx.dcx().emit_err(errors::DispatchFromDynSame {
+                return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame {
                     span,
                     trait_name: "CoerceUnsized",
                     note: true,
                     source_path,
                     target_path,
-                });
-                return err_info;
+                }));
             }
 
             // Here we are considering a case of converting
@@ -419,12 +445,11 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
                 .collect::<Vec<_>>();
 
             if diff_fields.is_empty() {
-                tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
+                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
                     span,
                     trait_name: "CoerceUnsized",
                     note: true,
-                });
-                return err_info;
+                }));
             } else if diff_fields.len() > 1 {
                 let item = tcx.hir().expect_item(impl_did);
                 let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
@@ -433,7 +458,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
                     tcx.def_span(impl_did)
                 };
 
-                tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
+                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
                     span,
                     coercions_note: true,
                     number: diff_fields.len(),
@@ -442,9 +467,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
                         .map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
                         .collect::<Vec<_>>()
                         .join(", "),
-                });
-
-                return err_info;
+                }));
             }
 
             let (i, a, b) = diff_fields[0];
@@ -453,8 +476,9 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
         }
 
         _ => {
-            tcx.dcx().emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" });
-            return err_info;
+            return Err(tcx
+                .dcx()
+                .emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }));
         }
     };
 
@@ -477,7 +501,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
     let outlives_env = OutlivesEnvironment::new(param_env);
     let _ = ocx.resolve_regions_and_report_errors(impl_did, &outlives_env);
 
-    CoerceUnsizedInfo { custom_kind: kind }
+    Ok(CoerceUnsizedInfo { custom_kind: kind })
 }
 
 fn infringing_fields_error(
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 561a254e89e..dafa899ef24 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -10,6 +10,7 @@ use rustc_errors::{error_code, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
+use rustc_span::ErrorGuaranteed;
 use rustc_trait_selection::traits;
 
 mod builtin;
@@ -18,7 +19,11 @@ mod inherent_impls_overlap;
 mod orphan;
 mod unsafety;
 
-fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<'_>) {
+fn check_impl(
+    tcx: TyCtxt<'_>,
+    impl_def_id: LocalDefId,
+    trait_ref: ty::TraitRef<'_>,
+) -> Result<(), ErrorGuaranteed> {
     debug!(
         "(checking implementation) adding impl for trait '{:?}', item '{}'",
         trait_ref,
@@ -28,18 +33,18 @@ fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<
     // Skip impls where one of the self type is an error type.
     // This occurs with e.g., resolve failures (#30589).
     if trait_ref.references_error() {
-        return;
+        return Ok(());
     }
 
-    enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
-    enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id);
+    enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id)
+        .and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id))
 }
 
 fn enforce_trait_manually_implementable(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
     trait_def_id: DefId,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let impl_header_span = tcx.def_span(impl_def_id);
 
     // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
@@ -59,18 +64,17 @@ fn enforce_trait_manually_implementable(
             err.code(error_code!(E0328));
         }
 
-        err.emit();
-        return;
+        return Err(err.emit());
     }
 
     if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable =
         tcx.trait_def(trait_def_id).specialization_kind
     {
         if !tcx.features().specialization && !tcx.features().min_specialization {
-            tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span });
-            return;
+            return Err(tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span }));
         }
     }
+    Ok(())
 }
 
 /// We allow impls of marker traits to overlap, so they can't override impls
@@ -79,22 +83,22 @@ fn enforce_empty_impls_for_marker_traits(
     tcx: TyCtxt<'_>,
     impl_def_id: LocalDefId,
     trait_def_id: DefId,
-) {
+) -> Result<(), ErrorGuaranteed> {
     if !tcx.trait_def(trait_def_id).is_marker {
-        return;
+        return Ok(());
     }
 
     if tcx.associated_item_def_ids(trait_def_id).is_empty() {
-        return;
+        return Ok(());
     }
 
-    struct_span_code_err!(
+    Err(struct_span_code_err!(
         tcx.dcx(),
         tcx.def_span(impl_def_id),
         E0715,
         "impls for marker traits cannot contain items"
     )
-    .emit();
+    .emit())
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -115,23 +119,23 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
-fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
+fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
     // Trigger building the specialization graph for the trait. This will detect and report any
     // overlap errors.
-    tcx.ensure().specialization_graph_of(def_id);
+    let mut res = tcx.ensure().specialization_graph_of(def_id);
 
     let impls = tcx.hir().trait_impls(def_id);
     for &impl_def_id in impls {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
 
-        check_impl(tcx, impl_def_id, trait_ref);
-        check_object_overlap(tcx, impl_def_id, trait_ref);
+        res = res.and(check_impl(tcx, impl_def_id, trait_ref));
+        res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
 
-        unsafety::check_item(tcx, impl_def_id);
-        tcx.ensure().orphan_check_impl(impl_def_id);
+        res = res.and(unsafety::check_item(tcx, impl_def_id));
+        res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
     }
 
-    builtin::check_trait(tcx, def_id);
+    res.and(builtin::check_trait(tcx, def_id))
 }
 
 /// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.
@@ -139,12 +143,12 @@ fn check_object_overlap<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_def_id: LocalDefId,
     trait_ref: ty::TraitRef<'tcx>,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let trait_def_id = trait_ref.def_id;
 
     if trait_ref.references_error() {
         debug!("coherence: skipping impl {:?} with error {:?}", impl_def_id, trait_ref);
-        return;
+        return Ok(());
     }
 
     // check for overlap with the automatic `impl Trait for dyn Trait`
@@ -173,7 +177,7 @@ fn check_object_overlap<'tcx>(
                 let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id);
                 if supertrait_def_ids.any(|d| d == trait_def_id) {
                     let span = tcx.def_span(impl_def_id);
-                    struct_span_code_err!(
+                    return Err(struct_span_code_err!(
                         tcx.dcx(),
                         span,
                         E0371,
@@ -189,9 +193,10 @@ fn check_object_overlap<'tcx>(
                             tcx.def_path_str(trait_def_id)
                         ),
                     )
-                    .emit();
+                    .emit());
                 }
             }
         }
     }
+    Ok(())
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index 7b146573a1b..e4c407af53f 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -6,8 +6,9 @@ use rustc_hir as hir;
 use rustc_hir::Unsafety;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::ErrorGuaranteed;
 
-pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
+pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
     let item = tcx.hir().expect_item(def_id);
     let impl_ = item.expect_impl();
 
@@ -18,7 +19,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
         match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
             (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
-                struct_span_code_err!(
+                return Err(struct_span_code_err!(
                     tcx.dcx(),
                     tcx.def_span(def_id),
                     E0199,
@@ -31,11 +32,11 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     "",
                     rustc_errors::Applicability::MachineApplicable,
                 )
-                .emit();
+                .emit());
             }
 
             (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
-                struct_span_code_err!(
+                return Err(struct_span_code_err!(
                     tcx.dcx(),
                     tcx.def_span(def_id),
                     E0200,
@@ -54,11 +55,11 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     "unsafe ",
                     rustc_errors::Applicability::MaybeIncorrect,
                 )
-                .emit();
+                .emit());
             }
 
             (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
-                struct_span_code_err!(
+                return Err(struct_span_code_err!(
                     tcx.dcx(),
                     tcx.def_span(def_id),
                     E0569,
@@ -77,7 +78,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     "unsafe ",
                     rustc_errors::Applicability::MaybeIncorrect,
                 )
-                .emit();
+                .emit());
             }
 
             (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
@@ -92,4 +93,5 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             }
         }
     }
+    Ok(())
 }
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 0a3a71ba1a2..ad5b6664677 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -172,19 +172,15 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
 
     tcx.sess.time("coherence_checking", || {
         // Check impls constrain their parameters
-        let res =
+        let mut res =
             tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_impl_wf(module));
 
-        // FIXME(matthewjasper) We shouldn't need to use `track_errors` anywhere in this function
-        // or the compiler in general.
-        res.and(tcx.sess.track_errors(|| {
-            for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
-                tcx.ensure().coherent_trait(trait_def_id);
-            }
-        }))
+        for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
+            res = res.and(tcx.ensure().coherent_trait(trait_def_id));
+        }
         // these queries are executed for side-effects (error reporting):
-        .and(tcx.ensure().crate_inherent_impls(()))
-        .and(tcx.ensure().crate_inherent_impls_overlap_check(()))
+        res.and(tcx.ensure().crate_inherent_impls(()))
+            .and(tcx.ensure().crate_inherent_impls_overlap_check(()))
     })?;
 
     if tcx.features().rustc_attrs {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index d486f069989..9dc365526d4 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -220,6 +220,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true),
             (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true),
             (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false),
+            (self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true),
+            (
+                self.tcx.lang_items().async_fn_mut_trait(),
+                Ident::with_dummy_span(sym::async_call_mut),
+                true,
+            ),
+            (
+                self.tcx.lang_items().async_fn_once_trait(),
+                Ident::with_dummy_span(sym::async_call_once),
+                false,
+            ),
         ] {
             let Some(trait_def_id) = opt_trait_def_id else { continue };
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 01cd3c57925..21ea48c6c83 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -294,6 +294,75 @@ impl<T> Trait<T> for X {
                             );
                         }
                     }
+                    (ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias))
+                        if let Some(def_id) = t.principal_def_id()
+                            && tcx.explicit_item_bounds(alias.def_id).skip_binder().iter().any(
+                                |(pred, _span)| match pred.kind().skip_binder() {
+                                    ty::ClauseKind::Trait(trait_predicate)
+                                        if trait_predicate.polarity
+                                            == ty::ImplPolarity::Positive =>
+                                    {
+                                        trait_predicate.def_id() == def_id
+                                    }
+                                    _ => false,
+                                },
+                            ) =>
+                    {
+                        diag.help(format!(
+                            "you can box the `{}` to coerce it to `Box<{}>`, but you'll have to \
+                             change the expected type as well",
+                            values.found, values.expected,
+                        ));
+                    }
+                    (ty::Dynamic(t, _, ty::DynKind::Dyn), _)
+                        if let Some(def_id) = t.principal_def_id() =>
+                    {
+                        let mut impl_def_ids = vec![];
+                        tcx.for_each_relevant_impl(def_id, values.found, |did| {
+                            impl_def_ids.push(did)
+                        });
+                        if let [_] = &impl_def_ids[..] {
+                            let trait_name = tcx.item_name(def_id);
+                            diag.help(format!(
+                                "`{}` implements `{trait_name}` so you could box the found value \
+                                 and coerce it to the trait object `Box<dyn {trait_name}>`, you \
+                                 will have to change the expected type as well",
+                                values.found,
+                            ));
+                        }
+                    }
+                    (_, ty::Dynamic(t, _, ty::DynKind::Dyn))
+                        if let Some(def_id) = t.principal_def_id() =>
+                    {
+                        let mut impl_def_ids = vec![];
+                        tcx.for_each_relevant_impl(def_id, values.expected, |did| {
+                            impl_def_ids.push(did)
+                        });
+                        if let [_] = &impl_def_ids[..] {
+                            let trait_name = tcx.item_name(def_id);
+                            diag.help(format!(
+                                "`{}` implements `{trait_name}` so you could change the expected \
+                                 type to `Box<dyn {trait_name}>`",
+                                values.expected,
+                            ));
+                        }
+                    }
+                    (ty::Dynamic(t, _, ty::DynKind::DynStar), _)
+                        if let Some(def_id) = t.principal_def_id() =>
+                    {
+                        let mut impl_def_ids = vec![];
+                        tcx.for_each_relevant_impl(def_id, values.found, |did| {
+                            impl_def_ids.push(did)
+                        });
+                        if let [_] = &impl_def_ids[..] {
+                            let trait_name = tcx.item_name(def_id);
+                            diag.help(format!(
+                                "`{}` implements `{trait_name}`, `#[feature(dyn_star)]` is likely \
+                                 not enabled; that feature it is currently incomplete",
+                                values.found,
+                            ));
+                        }
+                    }
                     (_, ty::Alias(ty::Opaque, opaque_ty))
                     | (ty::Alias(ty::Opaque, opaque_ty), _) => {
                         if opaque_ty.def_id.is_local()
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index ad1980136f3..25675e06e38 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -120,7 +120,8 @@ struct QueryModifiers {
 
     /// Forward the result on ensure if the query gets recomputed, and
     /// return `Ok(())` otherwise. Only applicable to queries returning
-    /// `Result<(), ErrorGuaranteed>`
+    /// `Result<T, ErrorGuaranteed>`. The `T` is not returned from `ensure`
+    /// invocations.
     ensure_forwards_result_if_red: Option<Ident>,
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index c3d6c21c402..0b352a02b64 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -236,7 +236,14 @@ provide! { tcx, def_id, other, cdata,
     impl_polarity => { table_direct }
     defaultness => { table_direct }
     constness => { table_direct }
-    coerce_unsized_info => { table }
+    coerce_unsized_info => {
+        Ok(cdata
+            .root
+            .tables
+            .coerce_unsized_info
+            .get(cdata, def_id.index)
+            .map(|lazy| lazy.decode((cdata, tcx)))
+            .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) }
     mir_const_qualif => { table }
     rendered_const => { table }
     asyncness => { table_direct }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 2d4e49e27d9..542caf86223 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1994,7 +1994,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 // if this is an impl of `CoerceUnsized`, create its
                 // "unsized info", else just store None
                 if Some(trait_ref.def_id) == tcx.lang_items().coerce_unsized_trait() {
-                    let coerce_unsized_info = tcx.coerce_unsized_info(def_id);
+                    let coerce_unsized_info = tcx.coerce_unsized_info(def_id).unwrap();
                     record!(self.tables.coerce_unsized_info[def_id] <- coerce_unsized_info);
                 }
             }
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 1c9b4e558f0..7a1df495451 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -200,8 +200,6 @@ pub enum InvalidProgramInfo<'tcx> {
     /// (which unfortunately typeck does not reject).
     /// Not using `FnAbiError` as that contains a nested `LayoutError`.
     FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
-    /// We are runnning into a nonsense situation due to ConstProp violating our invariants.
-    ConstPropNonsense,
 }
 
 /// Details of why a pointer had to be in-bounds.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 36f5ba161d5..37c5bba46a7 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -244,18 +244,23 @@ impl<'tcx> MirSource<'tcx> {
     }
 }
 
+/// Additional information carried by a MIR body when it is lowered from a coroutine.
+/// This information is modified as it is lowered during the `StateTransform` MIR pass,
+/// so not all fields will be active at a given time. For example, the `yield_ty` is
+/// taken out of the field after yields are turned into returns, and the `coroutine_drop`
+/// body is only populated after the state transform pass.
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct CoroutineInfo<'tcx> {
-    /// The yield type of the function, if it is a coroutine.
+    /// The yield type of the function. This field is removed after the state transform pass.
     pub yield_ty: Option<Ty<'tcx>>,
 
-    /// The resume type of the function, if it is a coroutine.
+    /// The resume type of the function. This field is removed after the state transform pass.
     pub resume_ty: Option<Ty<'tcx>>,
 
-    /// Coroutine drop glue.
+    /// Coroutine drop glue. This field is populated after the state transform pass.
     pub coroutine_drop: Option<Body<'tcx>>,
 
-    /// The layout of a coroutine. Produced by the state transformation.
+    /// The layout of a coroutine. This field is populated after the state transform pass.
     pub coroutine_layout: Option<CoroutineLayout<'tcx>>,
 
     /// If this is a coroutine then record the type of source expression that caused this coroutine
@@ -303,6 +308,12 @@ pub struct Body<'tcx> {
     /// and used for debuginfo. Indexed by a `SourceScope`.
     pub source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
 
+    /// Additional information carried by a MIR body when it is lowered from a coroutine.
+    ///
+    /// Note that the coroutine drop shim, any promoted consts, and other synthetic MIR
+    /// bodies that come from processing a coroutine body are not typically coroutines
+    /// themselves, and should probably set this to `None` to avoid carrying redundant
+    /// information.
     pub coroutine: Option<Box<CoroutineInfo<'tcx>>>,
 
     /// Declarations of locals.
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 778b4308d2e..1b01df6a187 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -1,6 +1,7 @@
 use crate::mir;
 use crate::query::CyclePlaceholder;
 use crate::traits;
+use crate::ty::adjustment::CoerceUnsizedInfo;
 use crate::ty::{self, Ty};
 use std::intrinsics::transmute_unchecked;
 use std::mem::{size_of, MaybeUninit};
@@ -105,6 +106,10 @@ impl EraseType for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuarantee
         [u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
 }
 
+impl EraseType for Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed> {
+    type Result = [u8; size_of::<Result<CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>>()];
+}
+
 impl EraseType for Result<Option<ty::EarlyBinder<ty::Const<'_>>>, rustc_errors::ErrorGuaranteed> {
     type Result = [u8; size_of::<
         Result<Option<ty::EarlyBinder<ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 23daefd5a65..1122f571fff 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -977,10 +977,11 @@ rustc_queries! {
     }
 
     /// Caches `CoerceUnsized` kinds for impls on custom types.
-    query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
+    query coerce_unsized_info(key: DefId) -> Result<ty::adjustment::CoerceUnsizedInfo, ErrorGuaranteed> {
         desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
+        ensure_forwards_result_if_red
     }
 
     query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
@@ -1000,8 +1001,9 @@ rustc_queries! {
         desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) }
     }
 
-    query coherent_trait(def_id: DefId) -> () {
+    query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> {
         desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
+        ensure_forwards_result_if_red
     }
 
     /// Borrow-checks the function body. If this is a closure, returns
@@ -1032,6 +1034,7 @@ rustc_queries! {
             "checking whether impl `{}` follows the orphan rules",
             tcx.def_path_str(key),
         }
+        ensure_forwards_result_if_red
     }
 
     /// Check whether the function has any recursion that could cause the inliner to trigger
@@ -1300,6 +1303,7 @@ rustc_queries! {
     query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> {
         desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
         cache_on_disk_if { true }
+        ensure_forwards_result_if_red
     }
     query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] {
         desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
@@ -1356,9 +1360,9 @@ rustc_queries! {
     ///
     /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types
     /// correctly.
-    query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
+    query has_structural_eq_impl(ty: Ty<'tcx>) -> bool {
         desc {
-            "computing whether `{}` implements `PartialStructuralEq` and `StructuralEq`",
+            "computing whether `{}` implements `StructuralPartialEq`",
             ty
         }
     }
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 63f4bab7914..5a4b86eeffd 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -20,6 +20,7 @@ use std::marker::PhantomData;
 use std::mem;
 use std::num::NonZeroUsize;
 use std::ops::{ControlFlow, Deref};
+use std::ptr::NonNull;
 
 /// An entity in the Rust type system, which can be one of
 /// several kinds (types, lifetimes, and consts).
@@ -31,10 +32,29 @@ use std::ops::{ControlFlow, Deref};
 /// `Region` and `Const` are all interned.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct GenericArg<'tcx> {
-    ptr: NonZeroUsize,
+    ptr: NonNull<()>,
     marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
 }
 
+#[cfg(parallel_compiler)]
+unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where
+    &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend
+{
+}
+#[cfg(parallel_compiler)]
+unsafe impl<'tcx> rustc_data_structures::sync::DynSync for GenericArg<'tcx> where
+    &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSync
+{
+}
+unsafe impl<'tcx> Send for GenericArg<'tcx> where
+    &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): Send
+{
+}
+unsafe impl<'tcx> Sync for GenericArg<'tcx> where
+    &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): Sync
+{
+}
+
 impl<'tcx> IntoDiagnosticArg for GenericArg<'tcx> {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         self.to_string().into_diagnostic_arg()
@@ -60,21 +80,21 @@ impl<'tcx> GenericArgKind<'tcx> {
             GenericArgKind::Lifetime(lt) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0);
-                (REGION_TAG, lt.0.0 as *const ty::RegionKind<'tcx> as usize)
+                (REGION_TAG, NonNull::from(lt.0.0).cast())
             }
             GenericArgKind::Type(ty) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
-                (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize)
+                (TYPE_TAG, NonNull::from(ty.0.0).cast())
             }
             GenericArgKind::Const(ct) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
-                (CONST_TAG, ct.0.0 as *const WithCachedTypeInfo<ty::ConstData<'tcx>> as usize)
+                (CONST_TAG, NonNull::from(ct.0.0).cast())
             }
         };
 
-        GenericArg { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData }
+        GenericArg { ptr: ptr.map_addr(|addr| addr | tag), marker: PhantomData }
     }
 }
 
@@ -123,20 +143,22 @@ impl<'tcx> From<ty::Term<'tcx>> for GenericArg<'tcx> {
 impl<'tcx> GenericArg<'tcx> {
     #[inline]
     pub fn unpack(self) -> GenericArgKind<'tcx> {
-        let ptr = self.ptr.get();
+        let ptr = unsafe {
+            self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK))
+        };
         // SAFETY: use of `Interned::new_unchecked` here is ok because these
         // pointers were originally created from `Interned` types in `pack()`,
         // and this is just going in the other direction.
         unsafe {
-            match ptr & TAG_MASK {
+            match self.ptr.addr().get() & TAG_MASK {
                 REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const ty::RegionKind<'tcx>),
+                    ptr.cast::<ty::RegionKind<'tcx>>().as_ref(),
                 ))),
                 TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
+                    ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(),
                 ))),
                 CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::ConstData<'tcx>>),
+                    ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(),
                 ))),
                 _ => intrinsics::unreachable(),
             }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a5d9e0fcf44..dac60ae58a0 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -63,6 +63,7 @@ use std::marker::PhantomData;
 use std::mem;
 use std::num::NonZeroUsize;
 use std::ops::ControlFlow;
+use std::ptr::NonNull;
 use std::{fmt, str};
 
 pub use crate::ty::diagnostics::*;
@@ -848,10 +849,23 @@ pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Term<'tcx> {
-    ptr: NonZeroUsize,
+    ptr: NonNull<()>,
     marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
 }
 
+#[cfg(parallel_compiler)]
+unsafe impl<'tcx> rustc_data_structures::sync::DynSend for Term<'tcx> where
+    &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSend
+{
+}
+#[cfg(parallel_compiler)]
+unsafe impl<'tcx> rustc_data_structures::sync::DynSync for Term<'tcx> where
+    &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSync
+{
+}
+unsafe impl<'tcx> Send for Term<'tcx> where &'tcx (Ty<'tcx>, Const<'tcx>): Send {}
+unsafe impl<'tcx> Sync for Term<'tcx> where &'tcx (Ty<'tcx>, Const<'tcx>): Sync {}
+
 impl Debug for Term<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let data = if let Some(ty) = self.ty() {
@@ -914,17 +928,19 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> {
 impl<'tcx> Term<'tcx> {
     #[inline]
     pub fn unpack(self) -> TermKind<'tcx> {
-        let ptr = self.ptr.get();
+        let ptr = unsafe {
+            self.ptr.map_addr(|addr| NonZeroUsize::new_unchecked(addr.get() & !TAG_MASK))
+        };
         // SAFETY: use of `Interned::new_unchecked` here is ok because these
         // pointers were originally created from `Interned` types in `pack()`,
         // and this is just going in the other direction.
         unsafe {
-            match ptr & TAG_MASK {
+            match self.ptr.addr().get() & TAG_MASK {
                 TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
+                    ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(),
                 ))),
                 CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
-                    &*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::ConstData<'tcx>>),
+                    ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(),
                 ))),
                 _ => core::intrinsics::unreachable(),
             }
@@ -986,16 +1002,16 @@ impl<'tcx> TermKind<'tcx> {
             TermKind::Ty(ty) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
-                (TYPE_TAG, ty.0.0 as *const WithCachedTypeInfo<ty::TyKind<'tcx>> as usize)
+                (TYPE_TAG, NonNull::from(ty.0.0).cast())
             }
             TermKind::Const(ct) => {
                 // Ensure we can use the tag bits.
                 assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
-                (CONST_TAG, ct.0.0 as *const WithCachedTypeInfo<ty::ConstData<'tcx>> as usize)
+                (CONST_TAG, NonNull::from(ct.0.0).cast())
             }
         };
 
-        Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData }
+        Term { ptr: ptr.map_addr(|addr| addr | tag), marker: PhantomData }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index ef621f29bfd..8cc8abbe718 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -350,7 +350,7 @@ impl<'tcx> TyCtxt<'tcx> {
         validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>,
     ) -> Option<ty::Destructor> {
         let drop_trait = self.lang_items().drop_trait()?;
-        self.ensure().coherent_trait(drop_trait);
+        self.ensure().coherent_trait(drop_trait).ok()?;
 
         let ty = self.type_of(adt_did).instantiate_identity();
         let mut dtor_candidate = None;
@@ -1249,19 +1249,18 @@ impl<'tcx> Ty<'tcx> {
     /// Primitive types (`u32`, `str`) have structural equality by definition. For composite data
     /// types, equality for the type as a whole is structural when it is the same as equality
     /// between all components (fields, array elements, etc.) of that type. For ADTs, structural
-    /// equality is indicated by an implementation of `PartialStructuralEq` and `StructuralEq` for
-    /// that type.
+    /// equality is indicated by an implementation of `StructuralPartialEq` for that type.
     ///
     /// This function is "shallow" because it may return `true` for a composite type whose fields
-    /// are not `StructuralEq`. For example, `[T; 4]` has structural equality regardless of `T`
+    /// are not `StructuralPartialEq`. For example, `[T; 4]` has structural equality regardless of `T`
     /// because equality for arrays is determined by the equality of each array element. If you
     /// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way
     /// down, you will need to use a type visitor.
     #[inline]
     pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind() {
-            // Look for an impl of both `PartialStructuralEq` and `StructuralEq`.
-            ty::Adt(..) => tcx.has_structural_eq_impls(self),
+            // Look for an impl of `StructuralPartialEq`.
+            ty::Adt(..) => tcx.has_structural_eq_impl(self),
 
             // Primitive types that satisfy `Eq`.
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => true,
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 2f11cb123ee..9631b72f20c 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -110,7 +110,7 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
 mir_build_float_pattern = floating-point types cannot be used in patterns
 
 mir_build_indirect_structural_match =
-    to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+    to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]`
 
 mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
 
@@ -254,7 +254,7 @@ mir_build_non_partial_eq_match =
     to use a constant of type `{$non_peq_ty}` in a pattern, the type must implement `PartialEq`
 
 mir_build_nontrivial_structural_match =
-    to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+    to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]`
 
 mir_build_pattern_not_covered = refutable pattern in {$origin}
     .pattern_ty = the matched value is of type `{$pattern_ty}`
@@ -297,9 +297,9 @@ mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
     } into the body
 
 mir_build_type_not_structural =
-     to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+     to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]`
 
-mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
 
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index c5824c30770..8b9e507c8c7 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -1,21 +1,12 @@
 //! Propagates constants for early reporting of statically known
 //! assertion failures
 
-use rustc_const_eval::interpret::{
-    self, compile_time_machine, AllocId, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
-    InterpResult, OpTy, PlaceTy, Pointer,
-};
-use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::query::TyCtxtAt;
-use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{self, ParamEnv, TyCtxt};
-use rustc_span::def_id::DefId;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
 use rustc_target::abi::Size;
-use rustc_target::spec::abi::Abi as CallAbi;
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
 /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
@@ -49,162 +40,6 @@ pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{
     throw_machine_stop!(Zst)
 }}
 
-pub(crate) struct ConstPropMachine<'mir, 'tcx> {
-    /// The virtual call stack.
-    stack: Vec<Frame<'mir, 'tcx>>,
-    pub written_only_inside_own_block_locals: FxHashSet<Local>,
-    pub can_const_prop: IndexVec<Local, ConstPropMode>,
-}
-
-impl ConstPropMachine<'_, '_> {
-    pub fn new(can_const_prop: IndexVec<Local, ConstPropMode>) -> Self {
-        Self {
-            stack: Vec::new(),
-            written_only_inside_own_block_locals: Default::default(),
-            can_const_prop,
-        }
-    }
-}
-
-impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> {
-    compile_time_machine!(<'mir, 'tcx>);
-
-    const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`)
-
-    const POST_MONO_CHECKS: bool = false; // this MIR is still generic!
-
-    type MemoryKind = !;
-
-    #[inline(always)]
-    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
-        false // no reason to enforce alignment
-    }
-
-    #[inline(always)]
-    fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
-        false // for now, we don't enforce validity
-    }
-
-    fn load_mir(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::InstanceDef<'tcx>,
-    ) -> InterpResult<'tcx, &'tcx Body<'tcx>> {
-        throw_machine_stop_str!("calling functions isn't supported in ConstProp")
-    }
-
-    fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _msg: &str) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("panicking isn't supported in ConstProp")
-    }
-
-    fn find_mir_or_eval_fn(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _abi: CallAbi,
-        _args: &[FnArg<'tcx>],
-        _destination: &PlaceTy<'tcx>,
-        _target: Option<BasicBlock>,
-        _unwind: UnwindAction,
-    ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> {
-        Ok(None)
-    }
-
-    fn call_intrinsic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _args: &[OpTy<'tcx>],
-        _destination: &PlaceTy<'tcx>,
-        _target: Option<BasicBlock>,
-        _unwind: UnwindAction,
-    ) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
-    }
-
-    fn assert_panic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _msg: &rustc_middle::mir::AssertMessage<'tcx>,
-        _unwind: rustc_middle::mir::UnwindAction,
-    ) -> InterpResult<'tcx> {
-        bug!("panics terminators are not evaluated in ConstProp")
-    }
-
-    fn binary_ptr_op(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        _bin_op: BinOp,
-        _left: &ImmTy<'tcx>,
-        _right: &ImmTy<'tcx>,
-    ) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> {
-        // We can't do this because aliasing of memory can differ between const eval and llvm
-        throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
-    }
-
-    fn before_access_local_mut<'a>(
-        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-        frame: usize,
-        local: Local,
-    ) -> InterpResult<'tcx> {
-        assert_eq!(frame, 0);
-        match ecx.machine.can_const_prop[local] {
-            ConstPropMode::NoPropagation => {
-                throw_machine_stop_str!(
-                    "tried to write to a local that is marked as not propagatable"
-                )
-            }
-            ConstPropMode::OnlyInsideOwnBlock => {
-                ecx.machine.written_only_inside_own_block_locals.insert(local);
-            }
-            ConstPropMode::FullConstProp => {}
-        }
-        Ok(())
-    }
-
-    fn before_access_global(
-        _tcx: TyCtxtAt<'tcx>,
-        _machine: &Self,
-        _alloc_id: AllocId,
-        alloc: ConstAllocation<'tcx>,
-        _static_def_id: Option<DefId>,
-        is_write: bool,
-    ) -> InterpResult<'tcx> {
-        if is_write {
-            throw_machine_stop_str!("can't write to global");
-        }
-        // If the static allocation is mutable, then we can't const prop it as its content
-        // might be different at runtime.
-        if alloc.inner().mutability.is_mut() {
-            throw_machine_stop_str!("can't access mutable globals in ConstProp");
-        }
-
-        Ok(())
-    }
-
-    #[inline(always)]
-    fn expose_ptr(_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("exposing pointers isn't supported in ConstProp")
-    }
-
-    #[inline(always)]
-    fn init_frame_extra(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        frame: Frame<'mir, 'tcx>,
-    ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
-        Ok(frame)
-    }
-
-    #[inline(always)]
-    fn stack<'a>(
-        ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] {
-        &ecx.machine.stack
-    }
-
-    #[inline(always)]
-    fn stack_mut<'a>(
-        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>> {
-        &mut ecx.machine.stack
-    }
-}
-
 /// The mode that `ConstProp` is allowed to run in for a given `Local`.
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum ConstPropMode {
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index b8fecaf635a..aa22b8c7c58 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -3,37 +3,26 @@
 
 use std::fmt::Debug;
 
-use either::Left;
-
-use rustc_const_eval::interpret::Immediate;
-use rustc_const_eval::interpret::{
-    InterpCx, InterpResult, MemoryKind, OpTy, Scalar, StackPopCleanup,
-};
-use rustc_const_eval::ReportErrorExt;
+use rustc_const_eval::interpret::{ImmTy, Projectable};
+use rustc_const_eval::interpret::{InterpCx, InterpResult, Scalar};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
 use rustc_index::bit_set::BitSet;
+use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{
-    self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
-};
+use rustc_middle::ty::{self, ConstInt, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::Span;
-use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
+use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, VariantIdx};
 
 use crate::const_prop::CanConstProp;
-use crate::const_prop::ConstPropMachine;
 use crate::const_prop::ConstPropMode;
-use crate::errors::AssertLint;
+use crate::dataflow_const_prop::DummyMachine;
+use crate::errors::{AssertLint, AssertLintKind};
 use crate::MirLint;
 
-/// The maximum number of bytes that we'll allocate space for a local or the return value.
-/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
-/// Severely regress performance.
-const MAX_ALLOC_LIMIT: u64 = 1024;
-
 pub struct ConstPropLint;
 
 impl<'tcx> MirLint<'tcx> for ConstPropLint {
@@ -81,11 +70,85 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint {
 
 /// Finds optimization opportunities on the MIR.
 struct ConstPropagator<'mir, 'tcx> {
-    ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
+    ecx: InterpCx<'mir, 'tcx, DummyMachine>,
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
     worklist: Vec<BasicBlock>,
     visited_blocks: BitSet<BasicBlock>,
+    locals: IndexVec<Local, Value<'tcx>>,
+    body: &'mir Body<'tcx>,
+    written_only_inside_own_block_locals: FxHashSet<Local>,
+    can_const_prop: IndexVec<Local, ConstPropMode>,
+}
+
+#[derive(Debug, Clone)]
+enum Value<'tcx> {
+    Immediate(ImmTy<'tcx>),
+    Aggregate { variant: VariantIdx, fields: IndexVec<FieldIdx, Value<'tcx>> },
+    Uninit,
+}
+
+impl<'tcx> From<ImmTy<'tcx>> for Value<'tcx> {
+    fn from(v: ImmTy<'tcx>) -> Self {
+        Self::Immediate(v)
+    }
+}
+
+impl<'tcx> Value<'tcx> {
+    fn project(
+        &self,
+        proj: &[PlaceElem<'tcx>],
+        prop: &ConstPropagator<'_, 'tcx>,
+    ) -> Option<&Value<'tcx>> {
+        let mut this = self;
+        for proj in proj {
+            this = match (*proj, this) {
+                (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => {
+                    fields.get(idx).unwrap_or(&Value::Uninit)
+                }
+                (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => {
+                    let idx = prop.get_const(idx.into())?.immediate()?;
+                    let idx = prop.ecx.read_target_usize(idx).ok()?;
+                    fields.get(FieldIdx::from_u32(idx.try_into().ok()?)).unwrap_or(&Value::Uninit)
+                }
+                (
+                    PlaceElem::ConstantIndex { offset, min_length: _, from_end: false },
+                    Value::Aggregate { fields, .. },
+                ) => fields
+                    .get(FieldIdx::from_u32(offset.try_into().ok()?))
+                    .unwrap_or(&Value::Uninit),
+                _ => return None,
+            };
+        }
+        Some(this)
+    }
+
+    fn project_mut(&mut self, proj: &[PlaceElem<'_>]) -> Option<&mut Value<'tcx>> {
+        let mut this = self;
+        for proj in proj {
+            this = match (proj, this) {
+                (PlaceElem::Field(idx, _), Value::Aggregate { fields, .. }) => {
+                    fields.ensure_contains_elem(*idx, || Value::Uninit)
+                }
+                (PlaceElem::Field(..), val @ Value::Uninit) => {
+                    *val = Value::Aggregate {
+                        variant: VariantIdx::new(0),
+                        fields: Default::default(),
+                    };
+                    val.project_mut(&[*proj])?
+                }
+                _ => return None,
+            };
+        }
+        Some(this)
+    }
+
+    fn immediate(&self) -> Option<&ImmTy<'tcx>> {
+        match self {
+            Value::Immediate(op) => Some(op),
+            _ => None,
+        }
+    }
 }
 
 impl<'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'_, 'tcx> {
@@ -121,49 +184,10 @@ impl<'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'_, 'tcx> {
 impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     fn new(body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>) -> ConstPropagator<'mir, 'tcx> {
         let def_id = body.source.def_id();
-        let args = &GenericArgs::identity_for_item(tcx, def_id);
         let param_env = tcx.param_env_reveal_all_normalized(def_id);
 
         let can_const_prop = CanConstProp::check(tcx, param_env, body);
-        let mut ecx = InterpCx::new(
-            tcx,
-            tcx.def_span(def_id),
-            param_env,
-            ConstPropMachine::new(can_const_prop),
-        );
-
-        let ret_layout = ecx
-            .layout_of(body.bound_return_ty().instantiate(tcx, args))
-            .ok()
-            // Don't bother allocating memory for large values.
-            // I don't know how return types can seem to be unsized but this happens in the
-            // `type/type-unsatisfiable.rs` test.
-            .filter(|ret_layout| {
-                ret_layout.is_sized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
-            })
-            .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
-
-        let ret = ecx
-            .allocate(ret_layout, MemoryKind::Stack)
-            .expect("couldn't perform small allocation")
-            .into();
-
-        ecx.push_stack_frame(
-            Instance::new(def_id, args),
-            body,
-            &ret,
-            StackPopCleanup::Root { cleanup: false },
-        )
-        .expect("failed to push initial stack frame");
-
-        for local in body.local_decls.indices() {
-            // Mark everything initially live.
-            // This is somewhat dicey since some of them might be unsized and it is incoherent to
-            // mark those as live... We rely on `local_to_place`/`local_to_op` in the interpreter
-            // stopping us before those unsized immediates can cause issues deeper in the
-            // interpreter.
-            ecx.frame_mut().locals[local].make_live_uninit();
-        }
+        let ecx = InterpCx::new(tcx, tcx.def_span(def_id), param_env, DummyMachine);
 
         ConstPropagator {
             ecx,
@@ -171,61 +195,47 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             param_env,
             worklist: vec![START_BLOCK],
             visited_blocks: BitSet::new_empty(body.basic_blocks.len()),
+            locals: IndexVec::from_elem_n(Value::Uninit, body.local_decls.len()),
+            body,
+            can_const_prop,
+            written_only_inside_own_block_locals: Default::default(),
         }
     }
 
-    fn body(&self) -> &'mir Body<'tcx> {
-        self.ecx.frame().body
-    }
-
     fn local_decls(&self) -> &'mir LocalDecls<'tcx> {
-        &self.body().local_decls
+        &self.body.local_decls
     }
 
-    fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
-        let op = match self.ecx.eval_place_to_op(place, None) {
-            Ok(op) => {
-                if op
-                    .as_mplace_or_imm()
-                    .right()
-                    .is_some_and(|imm| matches!(*imm, Immediate::Uninit))
-                {
-                    // Make sure nobody accidentally uses this value.
-                    return None;
-                }
-                op
-            }
-            Err(e) => {
-                trace!("get_const failed: {:?}", e.into_kind().debug());
-                return None;
-            }
-        };
-
-        // Try to read the local as an immediate so that if it is representable as a scalar, we can
-        // handle it as such, but otherwise, just return the value as is.
-        Some(match self.ecx.read_immediate_raw(&op) {
-            Ok(Left(imm)) => imm.into(),
-            _ => op,
-        })
+    fn get_const(&self, place: Place<'tcx>) -> Option<&Value<'tcx>> {
+        self.locals[place.local].project(&place.projection, self)
     }
 
     /// Remove `local` from the pool of `Locals`. Allows writing to them,
     /// but not reading from them anymore.
-    fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
-        ecx.frame_mut().locals[local].make_live_uninit();
-        ecx.machine.written_only_inside_own_block_locals.remove(&local);
+    fn remove_const(&mut self, local: Local) {
+        self.locals[local] = Value::Uninit;
+        self.written_only_inside_own_block_locals.remove(&local);
+    }
+
+    fn access_mut(&mut self, place: &Place<'_>) -> Option<&mut Value<'tcx>> {
+        match self.can_const_prop[place.local] {
+            ConstPropMode::NoPropagation => return None,
+            ConstPropMode::OnlyInsideOwnBlock => {
+                self.written_only_inside_own_block_locals.insert(place.local);
+            }
+            ConstPropMode::FullConstProp => {}
+        }
+        self.locals[place.local].project_mut(place.projection)
     }
 
     fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
-        source_info.scope.lint_root(&self.body().source_scopes)
+        source_info.scope.lint_root(&self.body.source_scopes)
     }
 
-    fn use_ecx<F, T>(&mut self, location: Location, f: F) -> Option<T>
+    fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
     where
         F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
     {
-        // Overwrite the PC -- whatever the interpreter does to it does not make any sense anyway.
-        self.ecx.frame_mut().loc = Left(location);
         match f(self) {
             Ok(val) => Some(val),
             Err(error) => {
@@ -244,7 +254,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     }
 
     /// Returns the value, if any, of evaluating `c`.
-    fn eval_constant(&mut self, c: &ConstOperand<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
+    fn eval_constant(&mut self, c: &ConstOperand<'tcx>) -> Option<ImmTy<'tcx>> {
         // FIXME we need to revisit this for #67176
         if c.has_param() {
             return None;
@@ -258,46 +268,62 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         // manually normalized.
         let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?;
 
-        self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None))
+        self.use_ecx(|this| this.ecx.eval_mir_constant(&val, Some(c.span), None))?
+            .as_mplace_or_imm()
+            .right()
     }
 
     /// Returns the value, if any, of evaluating `place`.
-    fn eval_place(&mut self, place: Place<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
-        trace!("eval_place(place={:?})", place);
-        self.use_ecx(location, |this| this.ecx.eval_place_to_op(place, None))
+    #[instrument(level = "trace", skip(self), ret)]
+    fn eval_place(&mut self, place: Place<'tcx>) -> Option<ImmTy<'tcx>> {
+        match self.get_const(place)? {
+            Value::Immediate(imm) => Some(imm.clone()),
+            Value::Aggregate { .. } => None,
+            Value::Uninit => None,
+        }
     }
 
     /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
     /// or `eval_place`, depending on the variant of `Operand` used.
-    fn eval_operand(&mut self, op: &Operand<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
+    fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option<ImmTy<'tcx>> {
         match *op {
-            Operand::Constant(ref c) => self.eval_constant(c, location),
-            Operand::Move(place) | Operand::Copy(place) => self.eval_place(place, location),
+            Operand::Constant(ref c) => self.eval_constant(c),
+            Operand::Move(place) | Operand::Copy(place) => self.eval_place(place),
         }
     }
 
-    fn report_assert_as_lint(&self, source_info: &SourceInfo, lint: AssertLint<impl Debug>) {
+    fn report_assert_as_lint(
+        &self,
+        location: Location,
+        lint_kind: AssertLintKind,
+        assert_kind: AssertKind<impl Debug>,
+    ) {
+        let source_info = self.body.source_info(location);
         if let Some(lint_root) = self.lint_root(*source_info) {
-            self.tcx.emit_node_span_lint(lint.lint(), lint_root, source_info.span, lint);
+            let span = source_info.span;
+            self.tcx.emit_node_span_lint(
+                lint_kind.lint(),
+                lint_root,
+                span,
+                AssertLint { span, assert_kind, lint_kind },
+            );
         }
     }
 
     fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>, location: Location) -> Option<()> {
-        if let (val, true) = self.use_ecx(location, |this| {
-            let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
+        let arg = self.eval_operand(arg)?;
+        if let (val, true) = self.use_ecx(|this| {
+            let val = this.ecx.read_immediate(&arg)?;
             let (_res, overflow) = this.ecx.overflowing_unary_op(op, &val)?;
             Ok((val, overflow))
         })? {
             // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
             // appropriate to use.
             assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
-            let source_info = self.body().source_info(location);
             self.report_assert_as_lint(
-                source_info,
-                AssertLint::ArithmeticOverflow(
-                    source_info.span,
-                    AssertKind::OverflowNeg(val.to_const_int()),
-                ),
+                location,
+                AssertLintKind::ArithmeticOverflow,
+                AssertKind::OverflowNeg(val.to_const_int()),
             );
             return None;
         }
@@ -312,11 +338,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         right: &Operand<'tcx>,
         location: Location,
     ) -> Option<()> {
-        let r = self.use_ecx(location, |this| {
-            this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?)
-        });
-        let l = self
-            .use_ecx(location, |this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
+        let r =
+            self.eval_operand(right).and_then(|r| self.use_ecx(|this| this.ecx.read_immediate(&r)));
+        let l =
+            self.eval_operand(left).and_then(|l| self.use_ecx(|this| this.ecx.read_immediate(&l)));
         // Check for exceeding shifts *even if* we cannot evaluate the LHS.
         if matches!(op, BinOp::Shr | BinOp::Shl) {
             let r = r.clone()?;
@@ -328,7 +353,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             let r_bits = r.to_scalar().to_bits(right_size).ok();
             if r_bits.is_some_and(|b| b >= left_size.bits() as u128) {
                 debug!("check_binary_op: reporting assert for {:?}", location);
-                let source_info = self.body().source_info(location);
                 let panic = AssertKind::Overflow(
                     op,
                     match l {
@@ -342,27 +366,21 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     },
                     r.to_const_int(),
                 );
-                self.report_assert_as_lint(
-                    source_info,
-                    AssertLint::ArithmeticOverflow(source_info.span, panic),
-                );
+                self.report_assert_as_lint(location, AssertLintKind::ArithmeticOverflow, panic);
                 return None;
             }
         }
 
         if let (Some(l), Some(r)) = (l, r) {
             // The remaining operators are handled through `overflowing_binary_op`.
-            if self.use_ecx(location, |this| {
+            if self.use_ecx(|this| {
                 let (_res, overflow) = this.ecx.overflowing_binary_op(op, &l, &r)?;
                 Ok(overflow)
             })? {
-                let source_info = self.body().source_info(location);
                 self.report_assert_as_lint(
-                    source_info,
-                    AssertLint::ArithmeticOverflow(
-                        source_info.span,
-                        AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
-                    ),
+                    location,
+                    AssertLintKind::ArithmeticOverflow,
+                    AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
                 );
                 return None;
             }
@@ -411,7 +429,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 // value the local has right now.
                 // Thus, all locals that have their reference taken
                 // must not take part in propagation.
-                Self::remove_const(&mut self.ecx, place.local);
+                self.remove_const(place.local);
 
                 return None;
             }
@@ -453,17 +471,17 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         cond: &Operand<'tcx>,
         location: Location,
     ) -> Option<!> {
-        let value = &self.eval_operand(cond, location)?;
+        let value = &self.eval_operand(cond)?;
         trace!("assertion on {:?} should be {:?}", value, expected);
 
         let expected = Scalar::from_bool(expected);
-        let value_const = self.use_ecx(location, |this| this.ecx.read_scalar(value))?;
+        let value_const = self.use_ecx(|this| this.ecx.read_scalar(value))?;
 
         if expected != value_const {
             // Poison all places this operand references so that further code
             // doesn't use the invalid value
             if let Some(place) = cond.place() {
-                Self::remove_const(&mut self.ecx, place.local);
+                self.remove_const(place.local);
             }
 
             enum DbgVal<T> {
@@ -481,7 +499,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             let mut eval_to_int = |op| {
                 // This can be `None` if the lhs wasn't const propagated and we just
                 // triggered the assert on the value of the rhs.
-                self.eval_operand(op, location)
+                self.eval_operand(op)
                     .and_then(|op| self.ecx.read_immediate(&op).ok())
                     .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int()))
             };
@@ -503,11 +521,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 // Need proper const propagator for these.
                 _ => return None,
             };
-            let source_info = self.body().source_info(location);
-            self.report_assert_as_lint(
-                source_info,
-                AssertLint::UnconditionalPanic(source_info.span, msg),
-            );
+            self.report_assert_as_lint(location, AssertLintKind::UnconditionalPanic, msg);
         }
 
         None
@@ -515,16 +529,176 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
     fn ensure_not_propagated(&self, local: Local) {
         if cfg!(debug_assertions) {
+            let val = self.get_const(local.into());
             assert!(
-                self.get_const(local.into()).is_none()
+                matches!(val, Some(Value::Uninit))
                     || self
                         .layout_of(self.local_decls()[local].ty)
                         .map_or(true, |layout| layout.is_zst()),
-                "failed to remove values for `{local:?}`, value={:?}",
-                self.get_const(local.into()),
+                "failed to remove values for `{local:?}`, value={val:?}",
             )
         }
     }
+
+    #[instrument(level = "trace", skip(self), ret)]
+    fn eval_rvalue(
+        &mut self,
+        rvalue: &Rvalue<'tcx>,
+        location: Location,
+        dest: &Place<'tcx>,
+    ) -> Option<()> {
+        if !dest.projection.is_empty() {
+            return None;
+        }
+        use rustc_middle::mir::Rvalue::*;
+        let layout = self.ecx.layout_of(dest.ty(self.body, self.tcx).ty).ok()?;
+        trace!(?layout);
+
+        let val: Value<'_> = match *rvalue {
+            ThreadLocalRef(_) => return None,
+
+            Use(ref operand) => self.eval_operand(operand)?.into(),
+
+            CopyForDeref(place) => self.eval_place(place)?.into(),
+
+            BinaryOp(bin_op, box (ref left, ref right)) => {
+                let left = self.eval_operand(left)?;
+                let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?;
+
+                let right = self.eval_operand(right)?;
+                let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?;
+
+                let val =
+                    self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?;
+                val.into()
+            }
+
+            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
+                let left = self.eval_operand(left)?;
+                let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?;
+
+                let right = self.eval_operand(right)?;
+                let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?;
+
+                let (val, overflowed) =
+                    self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?;
+                let overflowed = ImmTy::from_bool(overflowed, self.tcx);
+                Value::Aggregate {
+                    variant: VariantIdx::new(0),
+                    fields: [Value::from(val), overflowed.into()].into_iter().collect(),
+                }
+            }
+
+            UnaryOp(un_op, ref operand) => {
+                let operand = self.eval_operand(operand)?;
+                let val = self.use_ecx(|this| this.ecx.read_immediate(&operand))?;
+
+                let val = self.use_ecx(|this| this.ecx.wrapping_unary_op(un_op, &val))?;
+                val.into()
+            }
+
+            Aggregate(ref kind, ref fields) => Value::Aggregate {
+                fields: fields
+                    .iter()
+                    .map(|field| self.eval_operand(field).map_or(Value::Uninit, Value::Immediate))
+                    .collect(),
+                variant: match **kind {
+                    AggregateKind::Adt(_, variant, _, _, _) => variant,
+                    AggregateKind::Array(_)
+                    | AggregateKind::Tuple
+                    | AggregateKind::Closure(_, _)
+                    | AggregateKind::Coroutine(_, _) => VariantIdx::new(0),
+                },
+            },
+
+            Repeat(ref op, n) => {
+                trace!(?op, ?n);
+                return None;
+            }
+
+            Len(place) => {
+                let len = match self.get_const(place)? {
+                    Value::Immediate(src) => src.len(&self.ecx).ok()?,
+                    Value::Aggregate { fields, .. } => fields.len() as u64,
+                    Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() {
+                        ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?,
+                        _ => return None,
+                    },
+                };
+                ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into()
+            }
+
+            Ref(..) | AddressOf(..) => return None,
+
+            NullaryOp(ref null_op, ty) => {
+                let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?;
+                let val = match null_op {
+                    NullOp::SizeOf => op_layout.size.bytes(),
+                    NullOp::AlignOf => op_layout.align.abi.bytes(),
+                    NullOp::OffsetOf(fields) => {
+                        op_layout.offset_of_subfield(self, fields.iter()).bytes()
+                    }
+                };
+                ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into()
+            }
+
+            ShallowInitBox(..) => return None,
+
+            Cast(ref kind, ref value, to) => match kind {
+                CastKind::IntToInt | CastKind::IntToFloat => {
+                    let value = self.eval_operand(value)?;
+                    let value = self.ecx.read_immediate(&value).ok()?;
+                    let to = self.ecx.layout_of(to).ok()?;
+                    let res = self.ecx.int_to_int_or_float(&value, to).ok()?;
+                    res.into()
+                }
+                CastKind::FloatToFloat | CastKind::FloatToInt => {
+                    let value = self.eval_operand(value)?;
+                    let value = self.ecx.read_immediate(&value).ok()?;
+                    let to = self.ecx.layout_of(to).ok()?;
+                    let res = self.ecx.float_to_float_or_int(&value, to).ok()?;
+                    res.into()
+                }
+                CastKind::Transmute => {
+                    let value = self.eval_operand(value)?;
+                    let to = self.ecx.layout_of(to).ok()?;
+                    // `offset` for immediates only supports scalar/scalar-pair ABIs,
+                    // so bail out if the target is not one.
+                    match (value.layout.abi, to.abi) {
+                        (Abi::Scalar(..), Abi::Scalar(..)) => {}
+                        (Abi::ScalarPair(..), Abi::ScalarPair(..)) => {}
+                        _ => return None,
+                    }
+
+                    value.offset(Size::ZERO, to, &self.ecx).ok()?.into()
+                }
+                _ => return None,
+            },
+
+            Discriminant(place) => {
+                let variant = match self.get_const(place)? {
+                    Value::Immediate(op) => {
+                        let op = op.clone();
+                        self.use_ecx(|this| this.ecx.read_discriminant(&op))?
+                    }
+                    Value::Aggregate { variant, .. } => *variant,
+                    Value::Uninit => return None,
+                };
+                let imm = self.use_ecx(|this| {
+                    this.ecx.discriminant_for_variant(
+                        place.ty(this.local_decls(), this.tcx).ty,
+                        variant,
+                    )
+                })?;
+                imm.into()
+            }
+        };
+        trace!(?val);
+
+        *self.access_mut(dest)? = val;
+
+        Some(())
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
@@ -546,7 +720,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
     fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
         trace!("visit_constant: {:?}", constant);
         self.super_constant(constant, location);
-        self.eval_constant(constant, location);
+        self.eval_constant(constant);
     }
 
     fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
@@ -554,15 +728,12 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
 
         let Some(()) = self.check_rvalue(rvalue, location) else { return };
 
-        match self.ecx.machine.can_const_prop[place.local] {
+        match self.can_const_prop[place.local] {
             // Do nothing if the place is indirect.
             _ if place.is_indirect() => {}
             ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
             ConstPropMode::OnlyInsideOwnBlock | ConstPropMode::FullConstProp => {
-                if self
-                    .use_ecx(location, |this| this.ecx.eval_rvalue_into_place(rvalue, *place))
-                    .is_none()
-                {
+                if self.eval_rvalue(rvalue, location, place).is_none() {
                     // Const prop failed, so erase the destination, ensuring that whatever happens
                     // from here on, does not know about the previous value.
                     // This is important in case we have
@@ -578,7 +749,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
                         Nuking the entire site from orbit, it's the only way to be sure",
                         place,
                     );
-                    Self::remove_const(&mut self.ecx, place.local);
+                    self.remove_const(place.local);
                 }
             }
         }
@@ -592,28 +763,24 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
         self.super_statement(statement, location);
 
         match statement.kind {
-            StatementKind::SetDiscriminant { ref place, .. } => {
-                match self.ecx.machine.can_const_prop[place.local] {
+            StatementKind::SetDiscriminant { ref place, variant_index } => {
+                match self.can_const_prop[place.local] {
                     // Do nothing if the place is indirect.
                     _ if place.is_indirect() => {}
                     ConstPropMode::NoPropagation => self.ensure_not_propagated(place.local),
                     ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => {
-                        if self.use_ecx(location, |this| this.ecx.statement(statement)).is_some() {
-                            trace!("propped discriminant into {:?}", place);
-                        } else {
-                            Self::remove_const(&mut self.ecx, place.local);
+                        match self.access_mut(place) {
+                            Some(Value::Aggregate { variant, .. }) => *variant = variant_index,
+                            _ => self.remove_const(place.local),
                         }
                     }
                 }
             }
             StatementKind::StorageLive(local) => {
-                let frame = self.ecx.frame_mut();
-                frame.locals[local].make_live_uninit();
+                self.remove_const(local);
             }
             StatementKind::StorageDead(local) => {
-                let frame = self.ecx.frame_mut();
-                // We don't actually track liveness, so the local remains live. But forget its value.
-                frame.locals[local].make_live_uninit();
+                self.remove_const(local);
             }
             _ => {}
         }
@@ -626,9 +793,8 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
                 self.check_assertion(*expected, msg, cond, location);
             }
             TerminatorKind::SwitchInt { ref discr, ref targets } => {
-                if let Some(ref value) = self.eval_operand(discr, location)
-                    && let Some(value_const) =
-                        self.use_ecx(location, |this| this.ecx.read_scalar(value))
+                if let Some(ref value) = self.eval_operand(discr)
+                    && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value))
                     && let Ok(constant) = value_const.try_to_int()
                     && let Ok(constant) = constant.to_bits(constant.size())
                 {
@@ -665,7 +831,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
         // which were modified in the current block.
         // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
         let mut written_only_inside_own_block_locals =
-            std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
+            std::mem::take(&mut self.written_only_inside_own_block_locals);
 
         // This loop can get very hot for some bodies: it check each local in each bb.
         // To avoid this quadratic behaviour, we only clear the locals that were modified inside
@@ -673,17 +839,13 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
         // The order in which we remove consts does not matter.
         #[allow(rustc::potential_query_instability)]
         for local in written_only_inside_own_block_locals.drain() {
-            debug_assert_eq!(
-                self.ecx.machine.can_const_prop[local],
-                ConstPropMode::OnlyInsideOwnBlock
-            );
-            Self::remove_const(&mut self.ecx, local);
+            debug_assert_eq!(self.can_const_prop[local], ConstPropMode::OnlyInsideOwnBlock);
+            self.remove_const(local);
         }
-        self.ecx.machine.written_only_inside_own_block_locals =
-            written_only_inside_own_block_locals;
+        self.written_only_inside_own_block_locals = written_only_inside_own_block_locals;
 
         if cfg!(debug_assertions) {
-            for (local, &mode) in self.ecx.machine.can_const_prop.iter_enumerated() {
+            for (local, &mode) in self.can_const_prop.iter_enumerated() {
                 match mode {
                     ConstPropMode::FullConstProp => {}
                     ConstPropMode::NoPropagation | ConstPropMode::OnlyInsideOwnBlock => {
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 347f9b49efe..bde879f6067 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1231,7 +1231,12 @@ fn create_coroutine_drop_shim<'tcx>(
     drop_clean: BasicBlock,
 ) -> Body<'tcx> {
     let mut body = body.clone();
-    body.arg_count = 1; // make sure the resume argument is not included here
+    // Take the coroutine info out of the body, since the drop shim is
+    // not a coroutine body itself; it just has its drop built out of it.
+    let _ = body.coroutine.take();
+    // Make sure the resume argument is not included here, since we're
+    // building a body for `drop_in_place`.
+    body.arg_count = 1;
 
     let source_info = SourceInfo::outermost(body.span);
 
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index a11d224e8f1..ad5fcc3acf1 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -59,167 +59,154 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
             _ => {}
         }
 
-        trace!("InstrumentCoverage starting for {def_id:?}");
-        Instrumentor::new(tcx, mir_body).inject_counters();
-        trace!("InstrumentCoverage done for {def_id:?}");
+        instrument_function_for_coverage(tcx, mir_body);
     }
 }
 
-struct Instrumentor<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    mir_body: &'a mut mir::Body<'tcx>,
-    hir_info: ExtractedHirInfo,
-    basic_coverage_blocks: CoverageGraph,
-}
-
-impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
-        let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local());
+fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
+    let def_id = mir_body.source.def_id();
+    let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered();
 
-        debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id());
+    let hir_info = extract_hir_info(tcx, def_id.expect_local());
+    let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
 
-        let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
+    ////////////////////////////////////////////////////
+    // Compute coverage spans from the `CoverageGraph`.
+    let Some(coverage_spans) =
+        spans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
+    else {
+        // No relevant spans were found in MIR, so skip instrumenting this function.
+        return;
+    };
 
-        Self { tcx, mir_body, hir_info, basic_coverage_blocks }
+    ////////////////////////////////////////////////////
+    // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
+    // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
+    // and all `Expression` dependencies (operands) are also generated, for any other
+    // `BasicCoverageBlock`s not already associated with a coverage span.
+    let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
+    let coverage_counters =
+        CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
+
+    let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters);
+    if mappings.is_empty() {
+        // No spans could be converted into valid mappings, so skip this function.
+        debug!("no spans could be converted into valid mappings; skipping");
+        return;
     }
 
-    fn inject_counters(&'a mut self) {
-        ////////////////////////////////////////////////////
-        // Compute coverage spans from the `CoverageGraph`.
-        let Some(coverage_spans) = CoverageSpans::generate_coverage_spans(
-            self.mir_body,
-            &self.hir_info,
-            &self.basic_coverage_blocks,
-        ) else {
-            // No relevant spans were found in MIR, so skip instrumenting this function.
-            return;
-        };
-
-        ////////////////////////////////////////////////////
-        // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
-        // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
-        // and all `Expression` dependencies (operands) are also generated, for any other
-        // `BasicCoverageBlock`s not already associated with a coverage span.
-        let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
-        let coverage_counters = CoverageCounters::make_bcb_counters(
-            &self.basic_coverage_blocks,
-            bcb_has_coverage_spans,
-        );
+    inject_coverage_statements(
+        mir_body,
+        &basic_coverage_blocks,
+        bcb_has_coverage_spans,
+        &coverage_counters,
+    );
 
-        let mappings = self.create_mappings(&coverage_spans, &coverage_counters);
-        if mappings.is_empty() {
-            // No spans could be converted into valid mappings, so skip this function.
-            debug!("no spans could be converted into valid mappings; skipping");
-            return;
-        }
+    mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
+        function_source_hash: hir_info.function_source_hash,
+        num_counters: coverage_counters.num_counters(),
+        expressions: coverage_counters.into_expressions(),
+        mappings,
+    }));
+}
 
-        self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters);
+/// For each coverage span extracted from MIR, create a corresponding
+/// mapping.
+///
+/// Precondition: All BCBs corresponding to those spans have been given
+/// coverage counters.
+fn create_mappings<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hir_info: &ExtractedHirInfo,
+    coverage_spans: &CoverageSpans,
+    coverage_counters: &CoverageCounters,
+) -> Vec<Mapping> {
+    let source_map = tcx.sess.source_map();
+    let body_span = hir_info.body_span;
+
+    let source_file = source_map.lookup_source_file(body_span.lo());
+    use rustc_session::RemapFileNameExt;
+    let file_name = Symbol::intern(&source_file.name.for_codegen(tcx.sess).to_string_lossy());
+
+    let term_for_bcb = |bcb| {
+        coverage_counters
+            .bcb_counter(bcb)
+            .expect("all BCBs with spans were given counters")
+            .as_term()
+    };
 
-        self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
-            function_source_hash: self.hir_info.function_source_hash,
-            num_counters: coverage_counters.num_counters(),
-            expressions: coverage_counters.into_expressions(),
-            mappings,
-        }));
-    }
+    coverage_spans
+        .all_bcb_mappings()
+        .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| {
+            let kind = match bcb_mapping_kind {
+                BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
+            };
+            let code_region = make_code_region(source_map, file_name, span, body_span)?;
+            Some(Mapping { kind, code_region })
+        })
+        .collect::<Vec<_>>()
+}
 
-    /// For each coverage span extracted from MIR, create a corresponding
-    /// mapping.
-    ///
-    /// Precondition: All BCBs corresponding to those spans have been given
-    /// coverage counters.
-    fn create_mappings(
-        &self,
-        coverage_spans: &CoverageSpans,
-        coverage_counters: &CoverageCounters,
-    ) -> Vec<Mapping> {
-        let source_map = self.tcx.sess.source_map();
-        let body_span = self.hir_info.body_span;
-
-        let source_file = source_map.lookup_source_file(body_span.lo());
-        use rustc_session::RemapFileNameExt;
-        let file_name =
-            Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy());
-
-        let term_for_bcb = |bcb| {
-            coverage_counters
-                .bcb_counter(bcb)
-                .expect("all BCBs with spans were given counters")
-                .as_term()
+/// For each BCB node or BCB edge that has an associated coverage counter,
+/// inject any necessary coverage statements into MIR.
+fn inject_coverage_statements<'tcx>(
+    mir_body: &mut mir::Body<'tcx>,
+    basic_coverage_blocks: &CoverageGraph,
+    bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
+    coverage_counters: &CoverageCounters,
+) {
+    // Process the counters associated with BCB nodes.
+    for (bcb, counter_kind) in coverage_counters.bcb_node_counters() {
+        let do_inject = match counter_kind {
+            // Counter-increment statements always need to be injected.
+            BcbCounter::Counter { .. } => true,
+            // The only purpose of expression-used statements is to detect
+            // when a mapping is unreachable, so we only inject them for
+            // expressions with one or more mappings.
+            BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb),
         };
-
-        coverage_spans
-            .all_bcb_mappings()
-            .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| {
-                let kind = match bcb_mapping_kind {
-                    BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)),
-                };
-                let code_region = make_code_region(source_map, file_name, span, body_span)?;
-                Some(Mapping { kind, code_region })
-            })
-            .collect::<Vec<_>>()
+        if do_inject {
+            inject_statement(
+                mir_body,
+                make_mir_coverage_kind(counter_kind),
+                basic_coverage_blocks[bcb].leader_bb(),
+            );
+        }
     }
 
-    /// For each BCB node or BCB edge that has an associated coverage counter,
-    /// inject any necessary coverage statements into MIR.
-    fn inject_coverage_statements(
-        &mut self,
-        bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool,
-        coverage_counters: &CoverageCounters,
-    ) {
-        // Process the counters associated with BCB nodes.
-        for (bcb, counter_kind) in coverage_counters.bcb_node_counters() {
-            let do_inject = match counter_kind {
-                // Counter-increment statements always need to be injected.
-                BcbCounter::Counter { .. } => true,
-                // The only purpose of expression-used statements is to detect
-                // when a mapping is unreachable, so we only inject them for
-                // expressions with one or more mappings.
-                BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb),
-            };
-            if do_inject {
-                inject_statement(
-                    self.mir_body,
-                    self.make_mir_coverage_kind(counter_kind),
-                    self.basic_coverage_blocks[bcb].leader_bb(),
-                );
-            }
+    // Process the counters associated with BCB edges.
+    for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() {
+        let do_inject = match counter_kind {
+            // Counter-increment statements always need to be injected.
+            BcbCounter::Counter { .. } => true,
+            // BCB-edge expressions never have mappings, so they never need
+            // a corresponding statement.
+            BcbCounter::Expression { .. } => false,
+        };
+        if !do_inject {
+            continue;
         }
 
-        // Process the counters associated with BCB edges.
-        for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() {
-            let do_inject = match counter_kind {
-                // Counter-increment statements always need to be injected.
-                BcbCounter::Counter { .. } => true,
-                // BCB-edge expressions never have mappings, so they never need
-                // a corresponding statement.
-                BcbCounter::Expression { .. } => false,
-            };
-            if !do_inject {
-                continue;
-            }
-
-            // We need to inject a coverage statement into a new BB between the
-            // last BB of `from_bcb` and the first BB of `to_bcb`.
-            let from_bb = self.basic_coverage_blocks[from_bcb].last_bb();
-            let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb();
+        // We need to inject a coverage statement into a new BB between the
+        // last BB of `from_bcb` and the first BB of `to_bcb`.
+        let from_bb = basic_coverage_blocks[from_bcb].last_bb();
+        let to_bb = basic_coverage_blocks[to_bcb].leader_bb();
 
-            let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
-            debug!(
-                "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
+        let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb);
+        debug!(
+            "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \
                 requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}",
-            );
+        );
 
-            // Inject a counter into the newly-created BB.
-            inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb);
-        }
+        // Inject a counter into the newly-created BB.
+        inject_statement(mir_body, make_mir_coverage_kind(counter_kind), new_bb);
     }
+}
 
-    fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind {
-        match *counter_kind {
-            BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id },
-            BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id },
-        }
+fn make_mir_coverage_kind(counter_kind: &BcbCounter) -> CoverageKind {
+    match *counter_kind {
+        BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id },
+        BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id },
     }
 }
 
@@ -329,7 +316,7 @@ fn make_code_region(
     start_line = source_map.doctest_offset_line(&file.name, start_line);
     end_line = source_map.doctest_offset_line(&file.name, end_line);
 
-    Some(CodeRegion {
+    check_code_region(CodeRegion {
         file_name,
         start_line: start_line as u32,
         start_col: start_col as u32,
@@ -338,6 +325,39 @@ fn make_code_region(
     })
 }
 
+/// If `llvm-cov` sees a code region that is improperly ordered (end < start),
+/// it will immediately exit with a fatal error. To prevent that from happening,
+/// discard regions that are improperly ordered, or might be interpreted in a
+/// way that makes them improperly ordered.
+fn check_code_region(code_region: CodeRegion) -> Option<CodeRegion> {
+    let CodeRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
+
+    // Line/column coordinates are supposed to be 1-based. If we ever emit
+    // coordinates of 0, `llvm-cov` might misinterpret them.
+    let all_nonzero = [start_line, start_col, end_line, end_col].into_iter().all(|x| x != 0);
+    // Coverage mappings use the high bit of `end_col` to indicate that a
+    // region is actually a "gap" region, so make sure it's unset.
+    let end_col_has_high_bit_unset = (end_col & (1 << 31)) == 0;
+    // If a region is improperly ordered (end < start), `llvm-cov` will exit
+    // with a fatal error, which is inconvenient for users and hard to debug.
+    let is_ordered = (start_line, start_col) <= (end_line, end_col);
+
+    if all_nonzero && end_col_has_high_bit_unset && is_ordered {
+        Some(code_region)
+    } else {
+        debug!(
+            ?code_region,
+            ?all_nonzero,
+            ?end_col_has_high_bit_unset,
+            ?is_ordered,
+            "Skipping code region that would be misinterpreted or rejected by LLVM"
+        );
+        // If this happens in a debug build, ICE to make it easier to notice.
+        debug_assert!(false, "Improper code region: {code_region:?}");
+        None
+    }
+}
+
 fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     // Only instrument functions, methods, and closures (not constants since they are evaluated
     // at compile time by Miri).
@@ -351,7 +371,18 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
         return false;
     }
 
+    // Don't instrument functions with `#[automatically_derived]` on their
+    // enclosing impl block, on the assumption that most users won't care about
+    // coverage for derived impls.
+    if let Some(impl_of) = tcx.impl_of_method(def_id.to_def_id())
+        && tcx.is_automatically_derived(impl_of)
+    {
+        trace!("InstrumentCoverage skipped for {def_id:?} (automatically derived)");
+        return false;
+    }
+
     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+        trace!("InstrumentCoverage skipped for {def_id:?} (`#[coverage(off)]`)");
         return false;
     }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 81f6c831206..dee6a3b7143 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -26,45 +26,6 @@ pub(super) struct CoverageSpans {
 }
 
 impl CoverageSpans {
-    /// Extracts coverage-relevant spans from MIR, and associates them with
-    /// their corresponding BCBs.
-    ///
-    /// Returns `None` if no coverage-relevant spans could be extracted.
-    pub(super) fn generate_coverage_spans(
-        mir_body: &mir::Body<'_>,
-        hir_info: &ExtractedHirInfo,
-        basic_coverage_blocks: &CoverageGraph,
-    ) -> Option<Self> {
-        let mut mappings = vec![];
-
-        let coverage_spans = CoverageSpansGenerator::generate_coverage_spans(
-            mir_body,
-            hir_info,
-            basic_coverage_blocks,
-        );
-        mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
-            // Each span produced by the generator represents an ordinary code region.
-            BcbMapping { kind: BcbMappingKind::Code(bcb), span }
-        }));
-
-        if mappings.is_empty() {
-            return None;
-        }
-
-        // Identify which BCBs have one or more mappings.
-        let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-        let mut insert = |bcb| {
-            bcb_has_mappings.insert(bcb);
-        };
-        for &BcbMapping { kind, span: _ } in &mappings {
-            match kind {
-                BcbMappingKind::Code(bcb) => insert(bcb),
-            }
-        }
-
-        Some(Self { bcb_has_mappings, mappings })
-    }
-
     pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
         self.bcb_has_mappings.contains(bcb)
     }
@@ -74,6 +35,43 @@ impl CoverageSpans {
     }
 }
 
+/// Extracts coverage-relevant spans from MIR, and associates them with
+/// their corresponding BCBs.
+///
+/// Returns `None` if no coverage-relevant spans could be extracted.
+pub(super) fn generate_coverage_spans(
+    mir_body: &mir::Body<'_>,
+    hir_info: &ExtractedHirInfo,
+    basic_coverage_blocks: &CoverageGraph,
+) -> Option<CoverageSpans> {
+    let mut mappings = vec![];
+
+    let sorted_spans =
+        from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks);
+    let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans);
+    mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| {
+        // Each span produced by the generator represents an ordinary code region.
+        BcbMapping { kind: BcbMappingKind::Code(bcb), span }
+    }));
+
+    if mappings.is_empty() {
+        return None;
+    }
+
+    // Identify which BCBs have one or more mappings.
+    let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
+    let mut insert = |bcb| {
+        bcb_has_mappings.insert(bcb);
+    };
+    for &BcbMapping { kind, span: _ } in &mappings {
+        match kind {
+            BcbMappingKind::Code(bcb) => insert(bcb),
+        }
+    }
+
+    Some(CoverageSpans { bcb_has_mappings, mappings })
+}
+
 /// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
 /// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s.
 /// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent
@@ -130,7 +128,7 @@ impl CoverageSpan {
 ///  * Merge spans that represent continuous (both in source code and control flow), non-branching
 ///    execution
 ///  * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
-struct CoverageSpansGenerator<'a> {
+struct SpansRefiner<'a> {
     /// The BasicCoverageBlock Control Flow Graph (BCB CFG).
     basic_coverage_blocks: &'a CoverageGraph,
 
@@ -173,40 +171,15 @@ struct CoverageSpansGenerator<'a> {
     refined_spans: Vec<CoverageSpan>,
 }
 
-impl<'a> CoverageSpansGenerator<'a> {
-    /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
-    /// counted.
-    ///
-    /// The basic steps are:
-    ///
-    /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
-    ///    `BasicCoverageBlockData`.
-    /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
-    ///    are sorted with longer spans before shorter spans; and equal spans are sorted
-    ///    (deterministically) based on "dominator" relationship (if any).
-    /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
-    ///    if another span or spans are already counting the same code region), or should be merged
-    ///    into a broader combined span (because it represents a contiguous, non-branching, and
-    ///    uninterrupted region of source code).
-    ///
-    ///    Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
-    ///    closures have their own MIR, their `Span` in their enclosing function should be left
-    ///    "uncovered".
-    ///
-    /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
-    /// to be).
-    pub(super) fn generate_coverage_spans(
-        mir_body: &mir::Body<'_>,
-        hir_info: &ExtractedHirInfo,
+impl<'a> SpansRefiner<'a> {
+    /// Takes the initial list of (sorted) spans extracted from MIR, and "refines"
+    /// them by merging compatible adjacent spans, removing redundant spans,
+    /// and carving holes in spans when they overlap in unwanted ways.
+    fn refine_sorted_spans(
         basic_coverage_blocks: &'a CoverageGraph,
+        sorted_spans: Vec<CoverageSpan>,
     ) -> Vec<CoverageSpan> {
-        let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
-            mir_body,
-            hir_info,
-            basic_coverage_blocks,
-        );
-
-        let coverage_spans = Self {
+        let this = Self {
             basic_coverage_blocks,
             sorted_spans_iter: sorted_spans.into_iter(),
             some_curr: None,
@@ -217,7 +190,7 @@ impl<'a> CoverageSpansGenerator<'a> {
             refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
         };
 
-        coverage_spans.to_refined_spans()
+        this.to_refined_spans()
     }
 
     /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 1b6dfccd574..8d8e8e61327 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -12,6 +12,12 @@ use crate::coverage::graph::{
 use crate::coverage::spans::CoverageSpan;
 use crate::coverage::ExtractedHirInfo;
 
+/// Traverses the MIR body to produce an initial collection of coverage-relevant
+/// spans, each associated with a node in the coverage graph (BCB) and possibly
+/// other metadata.
+///
+/// The returned spans are sorted in a specific order that is expected by the
+/// subsequent span-refinement step.
 pub(super) fn mir_to_initial_sorted_coverage_spans(
     mir_body: &mir::Body<'_>,
     hir_info: &ExtractedHirInfo,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index ad12bce9b02..d5f22b2cdbc 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -403,7 +403,12 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             operand,
             &mut |elem, op| match elem {
                 TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(),
-                TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(),
+                TrackElem::Variant(idx) => {
+                    if op.layout.for_variant(&self.ecx, idx).abi.is_uninhabited() {
+                        return None;
+                    }
+                    self.ecx.project_downcast(op, idx).ok()
+                }
                 TrackElem::Discriminant => {
                     let variant = self.ecx.read_discriminant(op).ok()?;
                     let discr_value =
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 2ee660ddc9b..4574cb4d28d 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -201,45 +201,39 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
     }
 }
 
-pub(crate) enum AssertLint<P> {
-    ArithmeticOverflow(Span, AssertKind<P>),
-    UnconditionalPanic(Span, AssertKind<P>),
+pub(crate) struct AssertLint<P> {
+    pub span: Span,
+    pub assert_kind: AssertKind<P>,
+    pub lint_kind: AssertLintKind,
+}
+
+pub(crate) enum AssertLintKind {
+    ArithmeticOverflow,
+    UnconditionalPanic,
 }
 
 impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> {
     fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
-        let span = self.span();
-        let assert_kind = self.panic();
-        let message = assert_kind.diagnostic_message();
-        assert_kind.add_args(&mut |name, value| {
+        let message = self.assert_kind.diagnostic_message();
+        self.assert_kind.add_args(&mut |name, value| {
             diag.arg(name, value);
         });
-        diag.span_label(span, message);
+        diag.span_label(self.span, message);
     }
 
     fn msg(&self) -> DiagnosticMessage {
-        match self {
-            AssertLint::ArithmeticOverflow(..) => fluent::mir_transform_arithmetic_overflow,
-            AssertLint::UnconditionalPanic(..) => fluent::mir_transform_operation_will_panic,
+        match self.lint_kind {
+            AssertLintKind::ArithmeticOverflow => fluent::mir_transform_arithmetic_overflow,
+            AssertLintKind::UnconditionalPanic => fluent::mir_transform_operation_will_panic,
         }
     }
 }
 
-impl<P> AssertLint<P> {
+impl AssertLintKind {
     pub fn lint(&self) -> &'static Lint {
         match self {
-            AssertLint::ArithmeticOverflow(..) => lint::builtin::ARITHMETIC_OVERFLOW,
-            AssertLint::UnconditionalPanic(..) => lint::builtin::UNCONDITIONAL_PANIC,
-        }
-    }
-    pub fn span(&self) -> Span {
-        match self {
-            AssertLint::ArithmeticOverflow(sp, _) | AssertLint::UnconditionalPanic(sp, _) => *sp,
-        }
-    }
-    pub fn panic(self) -> AssertKind<P> {
-        match self {
-            AssertLint::ArithmeticOverflow(_, p) | AssertLint::UnconditionalPanic(_, p) => p,
+            AssertLintKind::ArithmeticOverflow => lint::builtin::ARITHMETIC_OVERFLOW,
+            AssertLintKind::UnconditionalPanic => lint::builtin::UNCONDITIONAL_PANIC,
         }
     }
 }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 8b991268819..b86244e5a4b 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1113,7 +1113,13 @@ fn find_vtable_types_for_unsizing<'tcx>(
             assert_eq!(source_adt_def, target_adt_def);
 
             let CustomCoerceUnsized::Struct(coerce_index) =
-                crate::custom_coerce_unsize_info(tcx, source_ty, target_ty);
+                match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) {
+                    Ok(ccu) => ccu,
+                    Err(e) => {
+                        let e = Ty::new_error(tcx.tcx, e);
+                        return (e, e);
+                    }
+                };
 
             let source_fields = &source_adt_def.non_enum_variant().fields;
             let target_fields = &target_adt_def.non_enum_variant().fields;
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 2f5f2d15cd4..3fa40db3c80 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -15,6 +15,7 @@ use rustc_middle::query::{Providers, TyCtxtAt};
 use rustc_middle::traits;
 use rustc_middle::ty::adjustment::CustomCoerceUnsized;
 use rustc_middle::ty::{self, Ty};
+use rustc_span::ErrorGuaranteed;
 
 mod collector;
 mod errors;
@@ -28,7 +29,7 @@ fn custom_coerce_unsize_info<'tcx>(
     tcx: TyCtxtAt<'tcx>,
     source_ty: Ty<'tcx>,
     target_ty: Ty<'tcx>,
-) -> CustomCoerceUnsized {
+) -> Result<CustomCoerceUnsized, ErrorGuaranteed> {
     let trait_ref = ty::TraitRef::from_lang_item(
         tcx.tcx,
         LangItem::CoerceUnsized,
@@ -40,7 +41,7 @@ fn custom_coerce_unsize_info<'tcx>(
         Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData {
             impl_def_id,
             ..
-        })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(),
+        })) => Ok(tcx.coerce_unsized_info(impl_def_id)?.custom_kind.unwrap()),
         impl_source => {
             bug!("invalid `CoerceUnsized` impl_source: {:?}", impl_source);
         }
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index eba71a23435..e94a0373c79 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -391,12 +391,18 @@ impl IntRange {
 /// first.
 impl fmt::Debug for IntRange {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let Finite(lo) = self.lo {
+        if self.is_singleton() {
+            // Only finite ranges can be singletons.
+            let Finite(lo) = self.lo else { unreachable!() };
             write!(f, "{lo}")?;
-        }
-        write!(f, "{}", RangeEnd::Excluded)?;
-        if let Finite(hi) = self.hi {
-            write!(f, "{hi}")?;
+        } else {
+            if let Finite(lo) = self.lo {
+                write!(f, "{lo}")?;
+            }
+            write!(f, "{}", RangeEnd::Excluded)?;
+            if let Finite(hi) = self.hi {
+                write!(f, "{hi}")?;
+            }
         }
         Ok(())
     }
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 4fd01b5e638..a55d53dfdac 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -101,15 +101,23 @@ pub trait TypeCx: Sized + fmt::Debug {
 
     /// The types of the fields for this constructor. The result must have a length of
     /// `ctor_arity()`.
-    fn ctor_sub_tys(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> &[Self::Ty];
+    fn ctor_sub_tys<'a>(
+        &'a self,
+        ctor: &'a Constructor<Self>,
+        ty: &'a Self::Ty,
+    ) -> impl Iterator<Item = Self::Ty> + ExactSizeIterator + Captures<'a>;
 
     /// The set of all the constructors for `ty`.
     ///
     /// This must follow the invariants of `ConstructorSet`
     fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
 
-    /// Best-effort `Debug` implementation.
-    fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
+    /// Write the name of the variant represented by `pat`. Used for the best-effort `Debug` impl of
+    /// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`.
+    fn write_variant_name(
+        f: &mut fmt::Formatter<'_>,
+        pat: &crate::pat::DeconstructedPat<'_, Self>,
+    ) -> fmt::Result;
 
     /// Raise a bug.
     fn bug(&self, fmt: fmt::Arguments<'_>) -> !;
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index 8cd0ecb073c..1cc31074556 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -142,7 +142,75 @@ impl<'p, Cx: TypeCx> DeconstructedPat<'p, Cx> {
 /// This is best effort and not good enough for a `Display` impl.
 impl<'p, Cx: TypeCx> fmt::Debug for DeconstructedPat<'p, Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Cx::debug_pat(f, self)
+        let pat = self;
+        let mut first = true;
+        let mut start_or_continue = |s| {
+            if first {
+                first = false;
+                ""
+            } else {
+                s
+            }
+        };
+        let mut start_or_comma = || start_or_continue(", ");
+
+        match pat.ctor() {
+            Struct | Variant(_) | UnionField => {
+                Cx::write_variant_name(f, pat)?;
+                // Without `cx`, we can't know which field corresponds to which, so we can't
+                // get the names of the fields. Instead we just display everything as a tuple
+                // struct, which should be good enough.
+                write!(f, "(")?;
+                for p in pat.iter_fields() {
+                    write!(f, "{}", start_or_comma())?;
+                    write!(f, "{p:?}")?;
+                }
+                write!(f, ")")
+            }
+            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
+            // be careful to detect strings here. However a string literal pattern will never
+            // be reported as a non-exhaustiveness witness, so we can ignore this issue.
+            Ref => {
+                let subpattern = pat.iter_fields().next().unwrap();
+                write!(f, "&{:?}", subpattern)
+            }
+            Slice(slice) => {
+                let mut subpatterns = pat.iter_fields();
+                write!(f, "[")?;
+                match slice.kind {
+                    SliceKind::FixedLen(_) => {
+                        for p in subpatterns {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                    SliceKind::VarLen(prefix_len, _) => {
+                        for p in subpatterns.by_ref().take(prefix_len) {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                        write!(f, "{}", start_or_comma())?;
+                        write!(f, "..")?;
+                        for p in subpatterns {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                }
+                write!(f, "]")
+            }
+            Bool(b) => write!(f, "{b}"),
+            // Best-effort, will render signed ranges incorrectly
+            IntRange(range) => write!(f, "{range:?}"),
+            F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
+            F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
+            Str(value) => write!(f, "{value:?}"),
+            Opaque(..) => write!(f, "<constant pattern>"),
+            Or => {
+                for pat in pat.iter_fields() {
+                    write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
+                }
+                Ok(())
+            }
+            Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()),
+        }
     }
 }
 
@@ -241,8 +309,7 @@ impl<Cx: TypeCx> WitnessPat<Cx> {
     /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
     /// `Some(_)`.
     pub(crate) fn wild_from_ctor(pcx: &PlaceCtxt<'_, Cx>, ctor: Constructor<Cx>) -> Self {
-        let field_tys = pcx.ctor_sub_tys(&ctor);
-        let fields = field_tys.iter().cloned().map(|ty| Self::wildcard(ty)).collect();
+        let fields = pcx.ctor_sub_tys(&ctor).map(|ty| Self::wildcard(ty)).collect();
         Self::new(ctor, fields, pcx.ty.clone())
     }
 
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d8c3c010a2a..23cab5f43ab 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -3,7 +3,6 @@ use std::fmt;
 use std::iter::once;
 
 use rustc_arena::{DroplessArena, TypedArena};
-use rustc_data_structures::captures::Captures;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
 use rustc_index::{Idx, IndexVec};
@@ -20,7 +19,7 @@ use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
 use crate::constructor::{
     IntRange, MaybeInfiniteInt, OpaqueId, RangeEnd, Slice, SliceKind, VariantVisibility,
 };
-use crate::{errors, TypeCx};
+use crate::{errors, Captures, TypeCx};
 
 use crate::constructor::Constructor::*;
 
@@ -210,11 +209,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
     /// Returns the types of the fields for a given constructor. The result must have a length of
     /// `ctor.arity()`.
     #[instrument(level = "trace", skip(self))]
-    pub(crate) fn ctor_sub_tys(
-        &self,
-        ctor: &Constructor<'p, 'tcx>,
+    pub(crate) fn ctor_sub_tys<'a>(
+        &'a self,
+        ctor: &'a Constructor<'p, 'tcx>,
         ty: RevealedTy<'tcx>,
-    ) -> &[RevealedTy<'tcx>] {
+    ) -> impl Iterator<Item = RevealedTy<'tcx>> + ExactSizeIterator + Captures<'a> {
         fn reveal_and_alloc<'a, 'tcx>(
             cx: &'a RustcMatchCheckCtxt<'_, 'tcx>,
             iter: impl Iterator<Item = Ty<'tcx>>,
@@ -222,7 +221,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
             cx.dropless_arena.alloc_from_iter(iter.map(|ty| cx.reveal_opaque_ty(ty)))
         }
         let cx = self;
-        match ctor {
+        let slice = match ctor {
             Struct | Variant(_) | UnionField => match ty.kind() {
                 ty::Tuple(fs) => reveal_and_alloc(cx, fs.iter()),
                 ty::Adt(adt, args) => {
@@ -263,7 +262,8 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
             Or => {
                 bug!("called `Fields::wildcards` on an `Or` ctor")
             }
-        }
+        };
+        slice.iter().copied()
     }
 
     /// The number of fields for this constructor.
@@ -850,103 +850,6 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
 
         Pat { ty: pat.ty().inner(), span: DUMMY_SP, kind }
     }
-
-    /// Best-effort `Debug` implementation.
-    pub(crate) fn debug_pat(
-        f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<'_, Self>,
-    ) -> fmt::Result {
-        let mut first = true;
-        let mut start_or_continue = |s| {
-            if first {
-                first = false;
-                ""
-            } else {
-                s
-            }
-        };
-        let mut start_or_comma = || start_or_continue(", ");
-
-        match pat.ctor() {
-            Struct | Variant(_) | UnionField => match pat.ty().kind() {
-                ty::Adt(def, _) if def.is_box() => {
-                    // Without `box_patterns`, the only legal pattern of type `Box` is `_` (outside
-                    // of `std`). So this branch is only reachable when the feature is enabled and
-                    // the pattern is a box pattern.
-                    let subpattern = pat.iter_fields().next().unwrap();
-                    write!(f, "box {subpattern:?}")
-                }
-                ty::Adt(..) | ty::Tuple(..) => {
-                    let variant =
-                        match pat.ty().kind() {
-                            ty::Adt(adt, _) => Some(adt.variant(
-                                RustcMatchCheckCtxt::variant_index_for_adt(pat.ctor(), *adt),
-                            )),
-                            ty::Tuple(_) => None,
-                            _ => unreachable!(),
-                        };
-
-                    if let Some(variant) = variant {
-                        write!(f, "{}", variant.name)?;
-                    }
-
-                    // Without `cx`, we can't know which field corresponds to which, so we can't
-                    // get the names of the fields. Instead we just display everything as a tuple
-                    // struct, which should be good enough.
-                    write!(f, "(")?;
-                    for p in pat.iter_fields() {
-                        write!(f, "{}", start_or_comma())?;
-                        write!(f, "{p:?}")?;
-                    }
-                    write!(f, ")")
-                }
-                _ => write!(f, "_"),
-            },
-            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
-            // be careful to detect strings here. However a string literal pattern will never
-            // be reported as a non-exhaustiveness witness, so we can ignore this issue.
-            Ref => {
-                let subpattern = pat.iter_fields().next().unwrap();
-                write!(f, "&{:?}", subpattern)
-            }
-            Slice(slice) => {
-                let mut subpatterns = pat.iter_fields();
-                write!(f, "[")?;
-                match slice.kind {
-                    SliceKind::FixedLen(_) => {
-                        for p in subpatterns {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                    }
-                    SliceKind::VarLen(prefix_len, _) => {
-                        for p in subpatterns.by_ref().take(prefix_len) {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                        write!(f, "{}", start_or_comma())?;
-                        write!(f, "..")?;
-                        for p in subpatterns {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                    }
-                }
-                write!(f, "]")
-            }
-            Bool(b) => write!(f, "{b}"),
-            // Best-effort, will render signed ranges incorrectly
-            IntRange(range) => write!(f, "{range:?}"),
-            F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
-            F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
-            Str(value) => write!(f, "{value}"),
-            Opaque(..) => write!(f, "<constant pattern>"),
-            Or => {
-                for pat in pat.iter_fields() {
-                    write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
-                }
-                Ok(())
-            }
-            Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", pat.ty()),
-        }
-    }
 }
 
 impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
@@ -964,11 +867,11 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
     fn ctor_arity(&self, ctor: &crate::constructor::Constructor<Self>, ty: &Self::Ty) -> usize {
         self.ctor_arity(ctor, *ty)
     }
-    fn ctor_sub_tys(
-        &self,
-        ctor: &crate::constructor::Constructor<Self>,
-        ty: &Self::Ty,
-    ) -> &[Self::Ty] {
+    fn ctor_sub_tys<'a>(
+        &'a self,
+        ctor: &'a crate::constructor::Constructor<Self>,
+        ty: &'a Self::Ty,
+    ) -> impl Iterator<Item = Self::Ty> + ExactSizeIterator + Captures<'a> {
         self.ctor_sub_tys(ctor, *ty)
     }
     fn ctors_for_ty(
@@ -978,12 +881,21 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
         self.ctors_for_ty(*ty)
     }
 
-    fn debug_pat(
+    fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
         pat: &crate::pat::DeconstructedPat<'_, Self>,
     ) -> fmt::Result {
-        Self::debug_pat(f, pat)
+        if let ty::Adt(adt, _) = pat.ty().kind() {
+            if adt.is_box() {
+                write!(f, "Box")?
+            } else {
+                let variant = adt.variant(Self::variant_index_for_adt(pat.ctor(), *adt));
+                write!(f, "{}", variant.name)?;
+            }
+        }
+        Ok(())
     }
+
     fn bug(&self, fmt: fmt::Arguments<'_>) -> ! {
         span_bug!(self.scrut_span, "{}", fmt)
     }
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index d7852a2b2cb..0de48c9f3c0 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -750,7 +750,10 @@ impl<'a, Cx: TypeCx> PlaceCtxt<'a, Cx> {
     pub(crate) fn ctor_arity(&self, ctor: &Constructor<Cx>) -> usize {
         self.mcx.tycx.ctor_arity(ctor, self.ty)
     }
-    pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] {
+    pub(crate) fn ctor_sub_tys(
+        &'a self,
+        ctor: &'a Constructor<Cx>,
+    ) -> impl Iterator<Item = Cx::Ty> + ExactSizeIterator + Captures<'a> {
         self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
     }
     pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
@@ -1058,8 +1061,7 @@ impl<'p, Cx: TypeCx> Matrix<'p, Cx> {
     ) -> Matrix<'p, Cx> {
         let ctor_sub_tys = pcx.ctor_sub_tys(ctor);
         let arity = ctor_sub_tys.len();
-        let specialized_place_ty =
-            ctor_sub_tys.iter().chain(self.place_ty[1..].iter()).cloned().collect();
+        let specialized_place_ty = ctor_sub_tys.chain(self.place_ty[1..].iter().cloned()).collect();
         let ctor_sub_validity = self.place_validity[0].specialize(ctor);
         let specialized_place_validity = std::iter::repeat(ctor_sub_validity)
             .take(arity)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 0d4ee1e8dca..ae10695fae4 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -24,13 +24,13 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, PatKind};
-use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, Const, GenericParamDefKind};
 use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, sym, Ident};
@@ -1064,29 +1064,22 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
 
 struct TypePrivacyVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
+    module_def_id: LocalModDefId,
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
-    current_item: LocalDefId,
     span: Span,
 }
 
 impl<'tcx> TypePrivacyVisitor<'tcx> {
-    /// Gets the type-checking results for the current body.
-    /// As this will ICE if called outside bodies, only call when working with
-    /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
-    #[track_caller]
-    fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
-        self.maybe_typeck_results
-            .expect("`TypePrivacyVisitor::typeck_results` called outside of body")
-    }
-
     fn item_is_accessible(&self, did: DefId) -> bool {
-        self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx)
+        self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
     }
 
     // Take node-id of an expression or pattern and check its type for privacy.
     fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
         self.span = span;
-        let typeck_results = self.typeck_results();
+        let typeck_results = self
+            .maybe_typeck_results
+            .unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body"));
         let result: ControlFlow<()> = try {
             self.visit(typeck_results.node_type(id))?;
             self.visit(typeck_results.node_args(id))?;
@@ -1107,35 +1100,13 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
-    type NestedFilter = nested_filter::All;
-
-    /// We want to visit items in the context of their containing
-    /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
-    }
-
-    fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
-        // Don't visit nested modules, since we run a separate visitor walk
-        // for each module in `effective_visibilities`
-    }
-
-    fn visit_nested_body(&mut self, body: hir::BodyId) {
+    fn visit_nested_body(&mut self, body_id: hir::BodyId) {
         let old_maybe_typeck_results =
-            self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
-        let body = self.tcx.hir().body(body);
-        self.visit_body(body);
+            self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
+        self.visit_body(self.tcx.hir().body(body_id));
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
-    fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) {
-        match generic_arg {
-            hir::GenericArg::Type(t) => self.visit_ty(t),
-            hir::GenericArg::Infer(inf) => self.visit_infer(inf),
-            hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {}
-        }
-    }
-
     fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
         self.span = hir_ty.span;
         if let Some(typeck_results) = self.maybe_typeck_results {
@@ -1163,19 +1134,19 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                     return;
                 }
             } else {
-                // We don't do anything for const infers here.
+                // FIXME: check types of const infers here.
             }
         } else {
-            bug!("visit_infer without typeck_results");
+            span_bug!(self.span, "`hir::InferArg` outside of a body");
         }
         intravisit::walk_inf(self, inf);
     }
 
     fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
         self.span = trait_ref.path.span;
-        if self.maybe_typeck_results.is_none() {
-            // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
-            // The traits' privacy in bodies is already checked as a part of trait object types.
+        if self.maybe_typeck_results.is_some() {
+            // Privacy of traits in bodies is checked as a part of trait object types.
+        } else {
             let bounds = rustc_hir_analysis::hir_trait_to_predicates(
                 self.tcx,
                 trait_ref,
@@ -1223,7 +1194,10 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
             hir::ExprKind::MethodCall(segment, ..) => {
                 // Method calls have to be checked specially.
                 self.span = segment.ident.span;
-                if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) {
+                let typeck_results = self
+                    .maybe_typeck_results
+                    .unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body"));
+                if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
                     if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() {
                         return;
                     }
@@ -1251,9 +1225,13 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                 Res::Def(kind, def_id) => Some((kind, def_id)),
                 _ => None,
             },
-            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
-                .maybe_typeck_results
-                .and_then(|typeck_results| typeck_results.type_dependent_def(id)),
+            hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
+                match self.maybe_typeck_results {
+                    Some(typeck_results) => typeck_results.type_dependent_def(id),
+                    // FIXME: Check type-relative associated types in signatures.
+                    None => None,
+                }
+            }
         };
         let def = def.filter(|(kind, _)| {
             matches!(
@@ -1307,15 +1285,6 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
 
         intravisit::walk_local(self, local);
     }
-
-    // Check types in item interfaces.
-    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
-        let old_maybe_typeck_results = self.maybe_typeck_results.take();
-        intravisit::walk_item(self, item);
-        self.maybe_typeck_results = old_maybe_typeck_results;
-        self.current_item = orig_current_item;
-    }
 }
 
 impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
@@ -1785,13 +1754,8 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
 
     // Check privacy of explicitly written types and traits as well as
     // inferred types of expressions and patterns.
-    let mut visitor = TypePrivacyVisitor {
-        tcx,
-        maybe_typeck_results: None,
-        current_item: module_def_id.to_local_def_id(),
-        span,
-    };
-    intravisit::walk_mod(&mut visitor, module, hir_id);
+    let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span };
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor);
 }
 
 fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 24aa336c68f..891a83ce80c 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -332,20 +332,6 @@ impl Session {
         }
     }
 
-    // FIXME(matthewjasper) Remove this method, it should never be needed.
-    pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorGuaranteed>
-    where
-        F: FnOnce() -> T,
-    {
-        let old_count = self.dcx().err_count();
-        let result = f();
-        if self.dcx().err_count() == old_count {
-            Ok(result)
-        } else {
-            Err(self.dcx().delayed_bug("`self.err_count()` changed but an error was not emitted"))
-        }
-    }
-
     /// Used for code paths of expensive computations that should only take place when
     /// warnings or errors are emitted. If no messages are emitted ("good path"), then
     /// it's likely a bug.
@@ -1524,16 +1510,25 @@ pub trait RemapFileNameExt {
     where
         Self: 'a;
 
-    fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_>;
+    /// Returns a possibly remapped filename based on the passed scope and remap cli options.
+    ///
+    /// One and only one scope should be passed to this method. For anything related to
+    /// "codegen" see the [`RemapFileNameExt::for_codegen`] method.
+    fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_>;
 
+    /// Return a possibly remapped filename, to be used in "codegen" related parts.
     fn for_codegen(&self, sess: &Session) -> Self::Output<'_>;
 }
 
 impl RemapFileNameExt for rustc_span::FileName {
     type Output<'a> = rustc_span::FileNameDisplay<'a>;
 
-    fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> {
-        if sess.opts.unstable_opts.remap_path_scope.contains(scopes) {
+    fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> {
+        assert!(
+            scope.bits().count_ones() == 1,
+            "one and only one scope should be passed to for_scope"
+        );
+        if sess.opts.unstable_opts.remap_path_scope.contains(scope) {
             self.prefer_remapped_unconditionaly()
         } else {
             self.prefer_local()
@@ -1552,8 +1547,12 @@ impl RemapFileNameExt for rustc_span::FileName {
 impl RemapFileNameExt for rustc_span::RealFileName {
     type Output<'a> = &'a Path;
 
-    fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> {
-        if sess.opts.unstable_opts.remap_path_scope.contains(scopes) {
+    fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> {
+        assert!(
+            scope.bits().count_ones() == 1,
+            "one and only one scope should be passed to for_scope"
+        );
+        if sess.opts.unstable_opts.remap_path_scope.contains(scope) {
             self.remapped_path_if_available()
         } else {
             self.local_path_if_available()
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 90a38b26f73..4a1c222a528 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -310,7 +310,6 @@ symbols! {
         Some,
         SpanCtxt,
         String,
-        StructuralEq,
         StructuralPartialEq,
         SubdiagnosticMessage,
         Sync,
@@ -425,8 +424,14 @@ symbols! {
         assume,
         assume_init,
         async_await,
+        async_call,
+        async_call_mut,
+        async_call_once,
         async_closure,
+        async_fn,
         async_fn_in_trait,
+        async_fn_mut,
+        async_fn_once,
         async_fn_track_caller,
         async_for_loop,
         async_iterator,
@@ -910,6 +915,7 @@ symbols! {
         io_stderr,
         io_stdout,
         irrefutable_let_patterns,
+        is_val_statically_known,
         isa_attribute,
         isize,
         issue,
@@ -1618,7 +1624,6 @@ symbols! {
         struct_variant,
         structural_match,
         structural_peq,
-        structural_teq,
         sub,
         sub_assign,
         sub_with_overflow,
@@ -1793,6 +1798,7 @@ symbols! {
         warn,
         wasm_abi,
         wasm_import_module,
+        wasm_preview2,
         wasm_target_feature,
         while_let,
         windows,
diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs
index 87ade9e58cf..4b4d2aca26e 100644
--- a/compiler/rustc_target/src/spec/base/wasm.rs
+++ b/compiler/rustc_target/src/spec/base/wasm.rs
@@ -38,9 +38,6 @@ pub fn options() -> TargetOptions {
                 // supposed to be imported and have all other symbols generate errors if
                 // they remain undefined.
                 concat!($prefix, "--allow-undefined"),
-                // Rust code should never have warnings, and warnings are often
-                // indicative of bugs, let's prevent them.
-                concat!($prefix, "--fatal-warnings"),
                 // LLD only implements C++-like demangling, which doesn't match our own
                 // mangling scheme. Tell LLD to not demangle anything and leave it up to
                 // us to demangle these symbols later. Currently rustc does not perform
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 884bd23e8cc..ead3be7fd52 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1574,6 +1574,7 @@ supported_targets! {
     ("wasm32-unknown-emscripten", wasm32_unknown_emscripten),
     ("wasm32-unknown-unknown", wasm32_unknown_unknown),
     ("wasm32-wasi", wasm32_wasi),
+    ("wasm32-wasi-preview2", wasm32_wasi_preview2),
     ("wasm32-wasi-preview1-threads", wasm32_wasi_preview1_threads),
     ("wasm64-unknown-unknown", wasm64_unknown_unknown),
 
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
index 394f02ecac4..e9e874297d3 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs
@@ -5,10 +5,7 @@ use crate::spec::{
 pub fn target() -> Target {
     // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests.
     let pre_link_args = LinkArgs::new();
-    let post_link_args = TargetOptions::link_args(
-        LinkerFlavor::EmCc,
-        &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"],
-    );
+    let post_link_args = TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0"]);
 
     let opts = TargetOptions {
         os: "emscripten".into(),
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1_threads.rs
index 28ea4cc9ece..389c67f8ae9 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1_threads.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview1_threads.rs
@@ -72,11 +72,12 @@
 //! best we can with this target. Don't start relying on too much here unless
 //! you know what you're getting in to!
 
-use crate::spec::{base, crt_objects, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};
+use crate::spec::{base, crt_objects, cvs, Cc, LinkSelfContainedDefault, LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut options = base::wasm::options();
 
+    options.families = cvs!["wasm", "wasi"];
     options.os = "wasi".into();
 
     options.add_pre_link_args(
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview2.rs
new file mode 100644
index 00000000000..fc44e5d4cbc
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasi_preview2.rs
@@ -0,0 +1,64 @@
+//! The `wasm32-wasi-preview2` target is the next evolution of the
+//! wasm32-wasi target. While the wasi specification is still under
+//! active development, the {review 2 iteration is considered an "island
+//! of stability" that should allow users to rely on it indefinitely.
+//!
+//! The `wasi` target is a proposal to define a standardized set of WebAssembly
+//! component imports that allow it to interoperate with the host system in a
+//! standardized way. This set of imports is intended to empower WebAssembly
+//! binaries with host capabilities such as filesystem access, network access, etc.
+//!
+//! Wasi Preview 2 relies on the WebAssembly component model which is an extension of
+//! the core WebAssembly specification which allows interoperability between WebAssembly
+//! modules (known as "components") through high-level, shared-nothing APIs instead of the
+//! low-level, shared-everything linear memory model of the core WebAssembly specification.
+//!
+//! You can see more about wasi at <https://wasi.dev> and the component model at
+//! <https://github.com/WebAssembly/component-model>.
+
+use crate::spec::crt_objects;
+use crate::spec::LinkSelfContainedDefault;
+use crate::spec::{base, Target};
+
+pub fn target() -> Target {
+    let mut options = base::wasm::options();
+
+    options.os = "wasi".into();
+    options.env = "preview2".into();
+    options.linker = Some("wasm-component-ld".into());
+
+    options.pre_link_objects_self_contained = crt_objects::pre_wasi_self_contained();
+    options.post_link_objects_self_contained = crt_objects::post_wasi_self_contained();
+
+    // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
+    options.link_self_contained = LinkSelfContainedDefault::True;
+
+    // Right now this is a bit of a workaround but we're currently saying that
+    // the target by default has a static crt which we're taking as a signal
+    // for "use the bundled crt". If that's turned off then the system's crt
+    // will be used, but this means that default usage of this target doesn't
+    // need an external compiler but it's still interoperable with an external
+    // compiler if configured correctly.
+    options.crt_static_default = true;
+    options.crt_static_respected = true;
+
+    // Allow `+crt-static` to create a "cdylib" output which is just a wasm file
+    // without a main function.
+    options.crt_static_allows_dylibs = true;
+
+    // WASI's `sys::args::init` function ignores its arguments; instead,
+    // `args::args()` makes the WASI API calls itself.
+    options.main_needs_argc_argv = false;
+
+    // And, WASI mangles the name of "main" to distinguish between different
+    // signatures.
+    options.entry_name = "__main_void".into();
+
+    Target {
+        llvm_target: "wasm32-unknown-unknown".into(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(),
+        arch: "wasm32".into(),
+        options,
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index e31aaaa1969..6a40ffebdad 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -7,7 +7,7 @@ use super::{
 
 use crate::errors;
 use crate::infer::InferCtxt;
-use crate::traits::{NormalizeExt, ObligationCtxt};
+use crate::traits::{ImplDerivedObligationCause, NormalizeExt, ObligationCtxt};
 
 use hir::def::CtorOf;
 use rustc_data_structures::fx::FxHashSet;
@@ -2973,7 +2973,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             | ObligationCauseCode::ObjectTypeBound(..) => {}
             ObligationCauseCode::RustCall => {
                 if let Some(pred) = predicate.to_opt_poly_trait_pred()
-                    && Some(pred.def_id()) == self.tcx.lang_items().sized_trait()
+                    && Some(pred.def_id()) == tcx.lang_items().sized_trait()
                 {
                     err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
                 }
@@ -3022,15 +3022,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         let def_id = trait_pred.def_id();
                         let visible_item = if let Some(local) = def_id.as_local() {
                             // Check for local traits being reachable.
-                            let vis = &self.tcx.resolutions(()).effective_visibilities;
+                            let vis = &tcx.resolutions(()).effective_visibilities;
                             // Account for non-`pub` traits in the root of the local crate.
-                            let is_locally_reachable = self.tcx.parent(def_id).is_crate_root();
+                            let is_locally_reachable = tcx.parent(def_id).is_crate_root();
                             vis.is_reachable(local) || is_locally_reachable
                         } else {
                             // Check for foreign traits being reachable.
-                            self.tcx.visible_parent_map(()).get(&def_id).is_some()
+                            tcx.visible_parent_map(()).get(&def_id).is_some()
                         };
-                        if Some(def_id) == self.tcx.lang_items().sized_trait()
+                        if Some(def_id) == tcx.lang_items().sized_trait()
                             && let Some(hir::Node::TraitItem(hir::TraitItem {
                                 ident,
                                 kind: hir::TraitItemKind::Type(bounds, None),
@@ -3039,7 +3039,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             // Do not suggest relaxing if there is an explicit `Sized` obligation.
                             && !bounds.iter()
                                 .filter_map(|bound| bound.trait_ref())
-                                .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait())
+                                .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
                         {
                             let (span, separator) = if let [.., last] = bounds {
                                 (last.span().shrink_to_hi(), " +")
@@ -3102,10 +3102,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             ObligationCauseCode::Coercion { source, target } => {
                 let mut file = None;
-                let source =
-                    self.tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file);
-                let target =
-                    self.tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file);
+                let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file);
+                let target = tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file);
                 err.note(with_forced_trimmed_paths!(format!(
                     "required for the cast from `{source}` to `{target}`",
                 )));
@@ -3155,10 +3153,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 } else {
                     // FIXME: we may suggest array::repeat instead
                     err.help("consider using `core::array::from_fn` to initialize the array");
-                    err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information");
+                    err.help("see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information");
                 }
 
-                if self.tcx.sess.is_nightly_build()
+                if tcx.sess.is_nightly_build()
                     && matches!(is_constable, IsConstable::Fn | IsConstable::Ctor)
                 {
                     err.help(
@@ -3168,8 +3166,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
             ObligationCauseCode::VariableType(hir_id) => {
-                let parent_node = self.tcx.hir().parent_id(hir_id);
-                match self.tcx.opt_hir_node(parent_node) {
+                let parent_node = tcx.hir().parent_id(hir_id);
+                match tcx.opt_hir_node(parent_node) {
                     Some(Node::Local(hir::Local { ty: Some(ty), .. })) => {
                         err.span_suggestion_verbose(
                             ty.span.shrink_to_lo(),
@@ -3207,7 +3205,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         err.note("all local variables must have a statically known size");
                     }
                 }
-                if !self.tcx.features().unsized_locals {
+                if !tcx.features().unsized_locals {
                     err.help("unsized locals are gated as an unstable feature");
                 }
             }
@@ -3289,7 +3287,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     err.note("all function arguments must have a statically known size");
                 }
                 if tcx.sess.opts.unstable_features.is_nightly_build()
-                    && !self.tcx.features().unsized_fn_params
+                    && !tcx.features().unsized_fn_params
                 {
                     err.help("unsized fn params are gated as an unstable feature");
                 }
@@ -3358,7 +3356,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     "all values captured by value by a closure must have a statically known size",
                 );
                 let hir::ExprKind::Closure(closure) =
-                    self.tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
+                    tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind
                 else {
                     bug!("expected closure in SizedClosureCapture obligation");
                 };
@@ -3369,7 +3367,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
             ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => {
-                let what = match self.tcx.coroutine_kind(coroutine_def_id) {
+                let what = match tcx.coroutine_kind(coroutine_def_id) {
                     None
                     | Some(hir::CoroutineKind::Coroutine(_))
                     | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => {
@@ -3420,10 +3418,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 'print: {
                     if !is_upvar_tys_infer_tuple {
                         let mut file = None;
-                        let ty_str = self.tcx.short_ty_string(ty, &mut file);
+                        let ty_str = tcx.short_ty_string(ty, &mut file);
                         let msg = format!("required because it appears within the type `{ty_str}`");
                         match ty.kind() {
-                            ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
+                            ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
                                 Some(ident) => err.span_note(ident.span, msg),
                                 None => err.note(msg),
                             },
@@ -3446,7 +3444,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 {
                                     break 'print;
                                 }
-                                err.span_note(self.tcx.def_span(def_id), msg)
+                                err.span_note(tcx.def_span(def_id), msg)
                             }
                             ty::CoroutineWitness(def_id, args) => {
                                 use std::fmt::Write;
@@ -3463,7 +3461,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 err.note(msg.trim_end_matches(", ").to_string())
                             }
                             ty::Coroutine(def_id, _) => {
-                                let sp = self.tcx.def_span(def_id);
+                                let sp = tcx.def_span(def_id);
 
                                 // Special-case this to say "async block" instead of `[static coroutine]`.
                                 let kind = tcx.coroutine_kind(def_id).unwrap();
@@ -3475,7 +3473,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 )
                             }
                             ty::Closure(def_id, _) => err.span_note(
-                                self.tcx.def_span(def_id),
+                                tcx.def_span(def_id),
                                 "required because it's used within this closure",
                             ),
                             ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
@@ -3519,14 +3517,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     self.resolve_vars_if_possible(data.derived.parent_trait_pred);
                 let parent_def_id = parent_trait_pred.def_id();
                 let mut file = None;
-                let self_ty =
-                    self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
-                let msg = format!(
-                    "required for `{self_ty}` to implement `{}`",
-                    parent_trait_pred.print_modifiers_and_trait_path()
-                );
+                let self_ty_str =
+                    tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
+                let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
+                let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
                 let mut is_auto_trait = false;
-                match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) {
+                match tcx.hir().get_if_local(data.impl_or_alias_def_id) {
                     Some(Node::Item(hir::Item {
                         kind: hir::ItemKind::Trait(is_auto, ..),
                         ident,
@@ -3538,7 +3534,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         err.span_note(ident.span, msg);
                     }
                     Some(Node::Item(hir::Item {
-                        kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+                        kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }),
                         ..
                     })) => {
                         let mut spans = Vec::with_capacity(2);
@@ -3565,6 +3561,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             );
                         }
                         err.span_note(spans, msg);
+                        point_at_assoc_type_restriction(
+                            tcx,
+                            err,
+                            &self_ty_str,
+                            &trait_name,
+                            predicate,
+                            &generics,
+                            &data,
+                        );
                     }
                     _ => {
                         err.note(msg);
@@ -3618,9 +3623,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         pluralize!(count)
                     ));
                     let mut file = None;
-                    let self_ty = self
-                        .tcx
-                        .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
+                    let self_ty =
+                        tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file);
                     err.note(format!(
                         "required for `{self_ty}` to implement `{}`",
                         parent_trait_pred.print_modifiers_and_trait_path()
@@ -3678,10 +3682,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 multispan.push_span_label(span, "required by this bound");
                 err.span_note(
                     multispan,
-                    format!(
-                        "required by a bound on the type alias `{}`",
-                        self.infcx.tcx.item_name(def_id)
-                    ),
+                    format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)),
                 );
             }
             ObligationCauseCode::FunctionArgumentObligation {
@@ -3712,25 +3713,23 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 });
             }
             ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
-                let item_name = self.tcx.item_name(trait_item_def_id);
+                let item_name = tcx.item_name(trait_item_def_id);
                 let msg = format!(
                     "the requirement `{predicate}` appears on the `impl`'s {kind} \
                      `{item_name}` but not on the corresponding trait's {kind}",
                 );
-                let sp = self
-                    .tcx
+                let sp = tcx
                     .opt_item_ident(trait_item_def_id)
                     .map(|i| i.span)
-                    .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id));
+                    .unwrap_or_else(|| tcx.def_span(trait_item_def_id));
                 let mut assoc_span: MultiSpan = sp.into();
                 assoc_span.push_span_label(
                     sp,
                     format!("this trait's {kind} doesn't have the requirement `{predicate}`"),
                 );
-                if let Some(ident) = self
-                    .tcx
+                if let Some(ident) = tcx
                     .opt_associated_item(trait_item_def_id)
-                    .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx)))
+                    .and_then(|i| tcx.opt_item_ident(i.container_id(tcx)))
                 {
                     assoc_span.push_span_label(ident.span, "in this trait");
                 }
@@ -4820,6 +4819,29 @@ fn hint_missing_borrow<'tcx>(
     }
 }
 
+/// Collect all the paths that reference `Self`.
+/// Used to suggest replacing associated types with an explicit type in `where` clauses.
+#[derive(Debug)]
+pub struct SelfVisitor<'v> {
+    pub paths: Vec<&'v hir::Ty<'v>>,
+    pub name: Option<Symbol>,
+}
+
+impl<'v> Visitor<'v> for SelfVisitor<'v> {
+    fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+        if let hir::TyKind::Path(path) = ty.kind
+            && let hir::QPath::TypeRelative(inner_ty, segment) = path
+            && (Some(segment.ident.name) == self.name || self.name.is_none())
+            && let hir::TyKind::Path(inner_path) = inner_ty.kind
+            && let hir::QPath::Resolved(None, inner_path) = inner_path
+            && let Res::SelfTyAlias { .. } = inner_path.res
+        {
+            self.paths.push(ty);
+        }
+        hir::intravisit::walk_ty(self, ty);
+    }
+}
+
 /// Collect all the returned expressions within the input expression.
 /// Used to point at the return spans when we want to suggest some change to them.
 #[derive(Default)]
@@ -5064,6 +5086,134 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
     Some(sugg)
 }
 
+/// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain
+/// they are not allowed and if possible suggest alternatives.
+fn point_at_assoc_type_restriction(
+    tcx: TyCtxt<'_>,
+    err: &mut Diagnostic,
+    self_ty_str: &str,
+    trait_name: &str,
+    predicate: ty::Predicate<'_>,
+    generics: &hir::Generics<'_>,
+    data: &ImplDerivedObligationCause<'_>,
+) {
+    let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else {
+        return;
+    };
+    let ty::ClauseKind::Projection(proj) = clause else {
+        return;
+    };
+    let name = tcx.item_name(proj.projection_ty.def_id);
+    let mut predicates = generics.predicates.iter().peekable();
+    let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None;
+    while let Some(pred) = predicates.next() {
+        let hir::WherePredicate::BoundPredicate(pred) = pred else {
+            continue;
+        };
+        let mut bounds = pred.bounds.iter().peekable();
+        while let Some(bound) = bounds.next() {
+            let Some(trait_ref) = bound.trait_ref() else {
+                continue;
+            };
+            if bound.span() != data.span {
+                continue;
+            }
+            if let hir::TyKind::Path(path) = pred.bounded_ty.kind
+                && let hir::QPath::TypeRelative(ty, segment) = path
+                && segment.ident.name == name
+                && let hir::TyKind::Path(inner_path) = ty.kind
+                && let hir::QPath::Resolved(None, inner_path) = inner_path
+                && let Res::SelfTyAlias { .. } = inner_path.res
+            {
+                // The following block is to determine the right span to delete for this bound
+                // that will leave valid code after the suggestion is applied.
+                let span = if pred.origin == hir::PredicateOrigin::WhereClause
+                    && generics
+                        .predicates
+                        .iter()
+                        .filter(|p| {
+                            matches!(
+                                p,
+                                hir::WherePredicate::BoundPredicate(p)
+                                if hir::PredicateOrigin::WhereClause == p.origin
+                            )
+                        })
+                        .count()
+                        == 1
+                {
+                    // There's only one `where` bound, that needs to be removed. Remove the whole
+                    // `where` clause.
+                    generics.where_clause_span
+                } else if let Some(hir::WherePredicate::BoundPredicate(next)) = predicates.peek()
+                    && pred.origin == next.origin
+                {
+                    // There's another bound, include the comma for the current one.
+                    pred.span.until(next.span)
+                } else if let Some(prev) = prev
+                    && pred.origin == prev.origin
+                {
+                    // Last bound, try to remove the previous comma.
+                    prev.span.shrink_to_hi().to(pred.span)
+                } else if pred.origin == hir::PredicateOrigin::WhereClause {
+                    pred.span.with_hi(generics.where_clause_span.hi())
+                } else {
+                    pred.span
+                };
+
+                err.span_suggestion_verbose(
+                    span,
+                    "associated type for the current `impl` cannot be restricted in `where` \
+                     clauses, remove this bound",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            if let Some(new) =
+                tcx.associated_items(data.impl_or_alias_def_id).find_by_name_and_kind(
+                    tcx,
+                    Ident::with_dummy_span(name),
+                    ty::AssocKind::Type,
+                    data.impl_or_alias_def_id,
+                )
+            {
+                // The associated type is specified in the `impl` we're
+                // looking at. Point at it.
+                let span = tcx.def_span(new.def_id);
+                err.span_label(
+                    span,
+                    format!(
+                        "associated type `<{self_ty_str} as {trait_name}>::{name}` is specified \
+                         here",
+                    ),
+                );
+                // Search for the associated type `Self::{name}`, get
+                // its type and suggest replacing the bound with it.
+                let mut visitor = SelfVisitor { paths: vec![], name: Some(name) };
+                visitor.visit_trait_ref(trait_ref);
+                for path in visitor.paths {
+                    err.span_suggestion_verbose(
+                        path.span,
+                        "replace the associated type with the type specified in this `impl`",
+                        tcx.type_of(new.def_id).skip_binder().to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            } else {
+                let mut visitor = SelfVisitor { paths: vec![], name: None };
+                visitor.visit_trait_ref(trait_ref);
+                let span: MultiSpan =
+                    visitor.paths.iter().map(|p| p.span).collect::<Vec<Span>>().into();
+                err.span_note(
+                    span,
+                    "associated types for the current `impl` cannot be restricted in `where` \
+                     clauses",
+                );
+            }
+        }
+        prev = Some(pred);
+    }
+}
+
 fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
     let mut refs = vec![];
 
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 868a8a3e8b8..d5a37e63d87 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -39,7 +39,7 @@ pub fn search_for_structural_match_violation<'tcx>(
 
 /// This implements the traversal over the structure of a given type to try to
 /// find instances of ADTs (specifically structs or enums) that do not implement
-/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
+/// `StructuralPartialEq`.
 struct Search<'tcx> {
     span: Span,
 
diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs
index 6e7a9887774..241aff9c30a 100644
--- a/compiler/rustc_ty_utils/src/structural_match.rs
+++ b/compiler/rustc_ty_utils/src/structural_match.rs
@@ -6,13 +6,12 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 
 /// This method returns true if and only if `adt_ty` itself has been marked as
-/// eligible for structural-match: namely, if it implements both
-/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
-/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
+/// eligible for structural-match: namely, if it implements
+/// `StructuralPartialEq` (which is injected by `#[derive(PartialEq)]`).
 ///
 /// Note that this does *not* recursively check if the substructure of `adt_ty`
-/// implements the traits.
-fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
+/// implements the trait.
+fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
     let infcx = &tcx.infer_ctxt().build();
     let cause = ObligationCause::dummy();
 
@@ -21,11 +20,6 @@ fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
     let structural_peq_def_id =
         infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
     ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id);
-    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
-    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
-    let structural_teq_def_id =
-        infcx.tcx.require_lang_item(LangItem::StructuralTeq, Some(cause.span));
-    ocx.register_bound(cause, ty::ParamEnv::empty(), adt_ty, structural_teq_def_id);
 
     // We deliberately skip *reporting* fulfillment errors (via
     // `report_fulfillment_errors`), for two reasons:
@@ -40,5 +34,5 @@ fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
-    providers.has_structural_eq_impls = has_structural_eq_impls;
+    providers.has_structural_eq_impl = has_structural_eq_impl;
 }
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 4bdd9639557..b585e2082f1 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -1,6 +1,7 @@
 use crate::vec::Vec;
 use core::borrow::Borrow;
 use core::cmp::Ordering;
+use core::error::Error;
 use core::fmt::{self, Debug};
 use core::hash::{Hash, Hasher};
 use core::iter::FusedIterator;
@@ -2521,14 +2522,10 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         self.len() == 0
     }
 
-    /// Returns a [`Cursor`] pointing at the first element that is above the
-    /// given bound.
+    /// Returns a [`Cursor`] pointing to the first gap above the given bound.
     ///
-    /// If no such element exists then a cursor pointing at the "ghost"
-    /// non-element is returned.
-    ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
-    /// element of the map.
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start
+    /// of the map.
     ///
     /// # Examples
     ///
@@ -2542,14 +2539,16 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(1, "a");
     /// a.insert(2, "b");
     /// a.insert(3, "c");
-    /// a.insert(4, "c");
+    /// a.insert(4, "d");
     /// let cursor = a.lower_bound(Bound::Included(&2));
-    /// assert_eq!(cursor.key(), Some(&2));
+    /// assert_eq!(cursor.peek_prev(), Some((&1, &"a")));
+    /// assert_eq!(cursor.peek_next(), Some((&2, &"b")));
     /// let cursor = a.lower_bound(Bound::Excluded(&2));
-    /// assert_eq!(cursor.key(), Some(&3));
+    /// assert_eq!(cursor.peek_prev(), Some((&2, &"b")));
+    /// assert_eq!(cursor.peek_next(), Some((&3, &"c")));
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn lower_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+    pub fn lower_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
     where
         K: Borrow<Q> + Ord,
         Q: Ord,
@@ -2559,17 +2558,14 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
             Some(root) => root.reborrow(),
         };
         let edge = root_node.lower_bound(SearchBound::from_range(bound));
-        Cursor { current: edge.next_kv().ok(), root: self.root.as_ref() }
+        Cursor { current: Some(edge), root: self.root.as_ref() }
     }
 
-    /// Returns a [`CursorMut`] pointing at the first element that is above the
-    /// given bound.
+    /// Returns a [`CursorMut`] pointing to the first gap above the given bound.
     ///
-    /// If no such element exists then a cursor pointing at the "ghost"
-    /// non-element is returned.
     ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the first
-    /// element of the map.
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start
+    /// of the map.
     ///
     /// # Examples
     ///
@@ -2583,14 +2579,16 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(1, "a");
     /// a.insert(2, "b");
     /// a.insert(3, "c");
-    /// a.insert(4, "c");
-    /// let cursor = a.lower_bound_mut(Bound::Included(&2));
-    /// assert_eq!(cursor.key(), Some(&2));
-    /// let cursor = a.lower_bound_mut(Bound::Excluded(&2));
-    /// assert_eq!(cursor.key(), Some(&3));
+    /// a.insert(4, "d");
+    /// let mut cursor = a.lower_bound_mut(Bound::Included(&2));
+    /// assert_eq!(cursor.peek_prev(), Some((&1, &mut "a")));
+    /// assert_eq!(cursor.peek_next(), Some((&2, &mut "b")));
+    /// let mut cursor = a.lower_bound_mut(Bound::Excluded(&2));
+    /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b")));
+    /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c")));
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn lower_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+    pub fn lower_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
     where
         K: Borrow<Q> + Ord,
         Q: Ord,
@@ -2599,31 +2597,31 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         let root_node = match root.as_mut() {
             None => {
                 return CursorMut {
-                    current: None,
-                    root: dormant_root,
-                    length: &mut self.length,
-                    alloc: &mut *self.alloc,
+                    inner: CursorMutKey {
+                        current: None,
+                        root: dormant_root,
+                        length: &mut self.length,
+                        alloc: &mut *self.alloc,
+                    },
                 };
             }
             Some(root) => root.borrow_mut(),
         };
         let edge = root_node.lower_bound(SearchBound::from_range(bound));
         CursorMut {
-            current: edge.next_kv().ok(),
-            root: dormant_root,
-            length: &mut self.length,
-            alloc: &mut *self.alloc,
+            inner: CursorMutKey {
+                current: Some(edge),
+                root: dormant_root,
+                length: &mut self.length,
+                alloc: &mut *self.alloc,
+            },
         }
     }
 
-    /// Returns a [`Cursor`] pointing at the last element that is below the
-    /// given bound.
-    ///
-    /// If no such element exists then a cursor pointing at the "ghost"
-    /// non-element is returned.
+    /// Returns a [`Cursor`] pointing at the last gap below the given bound.
     ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
-    /// element of the map.
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end
+    /// of the map.
     ///
     /// # Examples
     ///
@@ -2637,14 +2635,16 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(1, "a");
     /// a.insert(2, "b");
     /// a.insert(3, "c");
-    /// a.insert(4, "c");
+    /// a.insert(4, "d");
     /// let cursor = a.upper_bound(Bound::Included(&3));
-    /// assert_eq!(cursor.key(), Some(&3));
+    /// assert_eq!(cursor.peek_prev(), Some((&3, &"c")));
+    /// assert_eq!(cursor.peek_next(), Some((&4, &"d")));
     /// let cursor = a.upper_bound(Bound::Excluded(&3));
-    /// assert_eq!(cursor.key(), Some(&2));
+    /// assert_eq!(cursor.peek_prev(), Some((&2, &"b")));
+    /// assert_eq!(cursor.peek_next(), Some((&3, &"c")));
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn upper_bound<Q>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
+    pub fn upper_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
     where
         K: Borrow<Q> + Ord,
         Q: Ord,
@@ -2654,17 +2654,13 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
             Some(root) => root.reborrow(),
         };
         let edge = root_node.upper_bound(SearchBound::from_range(bound));
-        Cursor { current: edge.next_back_kv().ok(), root: self.root.as_ref() }
+        Cursor { current: Some(edge), root: self.root.as_ref() }
     }
 
-    /// Returns a [`CursorMut`] pointing at the last element that is below the
-    /// given bound.
-    ///
-    /// If no such element exists then a cursor pointing at the "ghost"
-    /// non-element is returned.
+    /// Returns a [`CursorMut`] pointing at the last gap below the given bound.
     ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing at the last
-    /// element of the map.
+    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end
+    /// of the map.
     ///
     /// # Examples
     ///
@@ -2678,14 +2674,16 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// a.insert(1, "a");
     /// a.insert(2, "b");
     /// a.insert(3, "c");
-    /// a.insert(4, "c");
-    /// let cursor = a.upper_bound_mut(Bound::Included(&3));
-    /// assert_eq!(cursor.key(), Some(&3));
-    /// let cursor = a.upper_bound_mut(Bound::Excluded(&3));
-    /// assert_eq!(cursor.key(), Some(&2));
+    /// a.insert(4, "d");
+    /// let mut cursor = a.upper_bound_mut(Bound::Included(&3));
+    /// assert_eq!(cursor.peek_prev(), Some((&3, &mut "c")));
+    /// assert_eq!(cursor.peek_next(), Some((&4, &mut "d")));
+    /// let mut cursor = a.upper_bound_mut(Bound::Excluded(&3));
+    /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b")));
+    /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c")));
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn upper_bound_mut<Q>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
+    pub fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
     where
         K: Borrow<Q> + Ord,
         Q: Ord,
@@ -2694,20 +2692,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         let root_node = match root.as_mut() {
             None => {
                 return CursorMut {
-                    current: None,
-                    root: dormant_root,
-                    length: &mut self.length,
-                    alloc: &mut *self.alloc,
+                    inner: CursorMutKey {
+                        current: None,
+                        root: dormant_root,
+                        length: &mut self.length,
+                        alloc: &mut *self.alloc,
+                    },
                 };
             }
             Some(root) => root.borrow_mut(),
         };
         let edge = root_node.upper_bound(SearchBound::from_range(bound));
         CursorMut {
-            current: edge.next_back_kv().ok(),
-            root: dormant_root,
-            length: &mut self.length,
-            alloc: &mut *self.alloc,
+            inner: CursorMutKey {
+                current: Some(edge),
+                root: dormant_root,
+                length: &mut self.length,
+                alloc: &mut *self.alloc,
+            },
         }
     }
 }
@@ -2716,14 +2718,14 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
 ///
 /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth.
 ///
-/// Cursors always point to an element in the tree, and index in a logically circular way.
-/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
-/// first elements of the tree.
+/// Cursors always point to a gap between two elements in the map, and can
+/// operate on the two immediately adjacent elements.
 ///
 /// A `Cursor` is created with the [`BTreeMap::lower_bound`] and [`BTreeMap::upper_bound`] methods.
 #[unstable(feature = "btree_cursors", issue = "107540")]
 pub struct Cursor<'a, K: 'a, V: 'a> {
-    current: Option<Handle<NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+    // If current is None then it means the tree has not been allocated yet.
+    current: Option<Handle<NodeRef<marker::Immut<'a>, K, V, marker::Leaf>, marker::Edge>>,
     root: Option<&'a node::Root<K, V>>,
 }
 
@@ -2738,22 +2740,21 @@ impl<K, V> Clone for Cursor<'_, K, V> {
 #[unstable(feature = "btree_cursors", issue = "107540")]
 impl<K: Debug, V: Debug> Debug for Cursor<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("Cursor").field(&self.key_value()).finish()
+        f.write_str("Cursor")
     }
 }
 
 /// A cursor over a `BTreeMap` with editing operations.
 ///
 /// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can
-/// safely mutate the tree during iteration. This is because the lifetime of its yielded
-/// references is tied to its own lifetime, instead of just the underlying tree. This means
+/// safely mutate the map during iteration. This is because the lifetime of its yielded
+/// references is tied to its own lifetime, instead of just the underlying map. This means
 /// cursors cannot yield multiple elements at once.
 ///
-/// Cursors always point to an element in the tree, and index in a logically circular way.
-/// To accommodate this, there is a "ghost" non-element that yields `None` between the last and
-/// first elements of the tree.
+/// Cursors always point to a gap between two elements in the map, and can
+/// operate on the two immediately adjacent elements.
 ///
-/// A `Cursor` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`]
+/// A `CursorMut` is created with the [`BTreeMap::lower_bound_mut`] and [`BTreeMap::upper_bound_mut`]
 /// methods.
 #[unstable(feature = "btree_cursors", issue = "107540")]
 pub struct CursorMut<
@@ -2762,287 +2763,271 @@ pub struct CursorMut<
     V: 'a,
     #[unstable(feature = "allocator_api", issue = "32838")] A = Global,
 > {
-    current: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>>,
+    inner: CursorMutKey<'a, K, V, A>,
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl<K: Debug, V: Debug, A> Debug for CursorMut<'_, K, V, A> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("CursorMut")
+    }
+}
+
+/// A cursor over a `BTreeMap` with editing operations, and which allows
+/// mutating the key of elements.
+///
+/// A `Cursor` is like an iterator, except that it can freely seek back-and-forth, and can
+/// safely mutate the map during iteration. This is because the lifetime of its yielded
+/// references is tied to its own lifetime, instead of just the underlying map. This means
+/// cursors cannot yield multiple elements at once.
+///
+/// Cursors always point to a gap between two elements in the map, and can
+/// operate on the two immediately adjacent elements.
+///
+/// A `CursorMutKey` is created from a [`CursorMut`] with the
+/// [`CursorMut::with_mutable_key`] method.
+///
+/// # Safety
+///
+/// Since this cursor allows mutating keys, you must ensure that the `BTreeMap`
+/// invariants are maintained. Specifically:
+///
+/// * The key of the newly inserted element must be unique in the tree.
+/// * All keys in the tree must remain in sorted order.
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct CursorMutKey<
+    'a,
+    K: 'a,
+    V: 'a,
+    #[unstable(feature = "allocator_api", issue = "32838")] A = Global,
+> {
+    // If current is None then it means the tree has not been allocated yet.
+    current: Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>>,
     root: DormantMutRef<'a, Option<node::Root<K, V>>>,
     length: &'a mut usize,
     alloc: &'a mut A,
 }
 
 #[unstable(feature = "btree_cursors", issue = "107540")]
-impl<K: Debug, V: Debug, A> Debug for CursorMut<'_, K, V, A> {
+impl<K: Debug, V: Debug, A> Debug for CursorMutKey<'_, K, V, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("CursorMut").field(&self.key_value()).finish()
+        f.write_str("CursorMutKey")
     }
 }
 
 impl<'a, K, V> Cursor<'a, K, V> {
-    /// Moves the cursor to the next element of the `BTreeMap`.
+    /// Advances the cursor to the next gap, returning the key and value of the
+    /// element that it moved over.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this will move it to
-    /// the first element of the `BTreeMap`. If it is pointing to the last
-    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    /// If the cursor is already at the end of the map then `None` is returned
+    /// and the cursor is not moved.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn move_next(&mut self) {
-        match self.current.take() {
-            None => {
-                self.current = self.root.and_then(|root| {
-                    root.reborrow().first_leaf_edge().forget_node_type().right_kv().ok()
-                });
+    pub fn next(&mut self) -> Option<(&'a K, &'a V)> {
+        let current = self.current.take()?;
+        match current.next_kv() {
+            Ok(kv) => {
+                let result = kv.into_kv();
+                self.current = Some(kv.next_leaf_edge());
+                Some(result)
             }
-            Some(current) => {
-                self.current = current.next_leaf_edge().next_kv().ok();
+            Err(root) => {
+                self.current = Some(root.last_leaf_edge());
+                None
             }
         }
     }
 
-    /// Moves the cursor to the previous element of the `BTreeMap`.
+    /// Advances the cursor to the previous gap, returning the key and value of
+    /// the element that it moved over.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this will move it to
-    /// the last element of the `BTreeMap`. If it is pointing to the first
-    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    /// If the cursor is already at the start of the map then `None` is returned
+    /// and the cursor is not moved.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn move_prev(&mut self) {
-        match self.current.take() {
-            None => {
-                self.current = self.root.and_then(|root| {
-                    root.reborrow().last_leaf_edge().forget_node_type().left_kv().ok()
-                });
+    pub fn prev(&mut self) -> Option<(&'a K, &'a V)> {
+        let current = self.current.take()?;
+        match current.next_back_kv() {
+            Ok(kv) => {
+                let result = kv.into_kv();
+                self.current = Some(kv.next_back_leaf_edge());
+                Some(result)
             }
-            Some(current) => {
-                self.current = current.next_back_leaf_edge().next_back_kv().ok();
+            Err(root) => {
+                self.current = Some(root.first_leaf_edge());
+                None
             }
         }
     }
 
-    /// Returns a reference to the key of the element that the cursor is
-    /// currently pointing to.
-    ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
-    #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn key(&self) -> Option<&'a K> {
-        self.current.as_ref().map(|current| current.into_kv().0)
-    }
-
-    /// Returns a reference to the value of the element that the cursor is
-    /// currently pointing to.
-    ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
-    #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn value(&self) -> Option<&'a V> {
-        self.current.as_ref().map(|current| current.into_kv().1)
-    }
-
-    /// Returns a reference to the key and value of the element that the cursor
-    /// is currently pointing to.
-    ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
-    #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn key_value(&self) -> Option<(&'a K, &'a V)> {
-        self.current.as_ref().map(|current| current.into_kv())
-    }
-
-    /// Returns a reference to the next element.
+    /// Returns a reference to the the key and value of the next element without
+    /// moving the cursor.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this returns
-    /// the first element of the `BTreeMap`. If it is pointing to the last
-    /// element of the `BTreeMap` then this returns `None`.
+    /// If the cursor is at the end of the map then `None` is returned
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn peek_next(&self) -> Option<(&'a K, &'a V)> {
-        let mut next = self.clone();
-        next.move_next();
-        next.current.as_ref().map(|current| current.into_kv())
+        self.clone().next()
     }
 
-    /// Returns a reference to the previous element.
+    /// Returns a reference to the the key and value of the previous element
+    /// without moving the cursor.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this returns
-    /// the last element of the `BTreeMap`. If it is pointing to the first
-    /// element of the `BTreeMap` then this returns `None`.
+    /// If the cursor is at the start of the map then `None` is returned.
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn peek_prev(&self) -> Option<(&'a K, &'a V)> {
-        let mut prev = self.clone();
-        prev.move_prev();
-        prev.current.as_ref().map(|current| current.into_kv())
+        self.clone().prev()
     }
 }
 
 impl<'a, K, V, A> CursorMut<'a, K, V, A> {
-    /// Moves the cursor to the next element of the `BTreeMap`.
+    /// Advances the cursor to the next gap, returning the key and value of the
+    /// element that it moved over.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this will move it to
-    /// the first element of the `BTreeMap`. If it is pointing to the last
-    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    /// If the cursor is already at the end of the map then `None` is returned
+    /// and the cursor is not moved.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn move_next(&mut self) {
-        match self.current.take() {
-            None => {
-                // SAFETY: The previous borrow of root has ended.
-                self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
-                    root.borrow_mut().first_leaf_edge().forget_node_type().right_kv().ok()
-                });
-            }
-            Some(current) => {
-                self.current = current.next_leaf_edge().next_kv().ok();
-            }
-        }
+    pub fn next(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = self.inner.next()?;
+        Some((&*k, v))
     }
 
-    /// Moves the cursor to the previous element of the `BTreeMap`.
+    /// Advances the cursor to the previous gap, returning the key and value of
+    /// the element that it moved over.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this will move it to
-    /// the last element of the `BTreeMap`. If it is pointing to the first
-    /// element of the `BTreeMap` then this will move it to the "ghost" non-element.
+    /// If the cursor is already at the start of the map then `None` is returned
+    /// and the cursor is not moved.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn move_prev(&mut self) {
-        match self.current.take() {
-            None => {
-                // SAFETY: The previous borrow of root has ended.
-                self.current = unsafe { self.root.reborrow() }.as_mut().and_then(|root| {
-                    root.borrow_mut().last_leaf_edge().forget_node_type().left_kv().ok()
-                });
-            }
-            Some(current) => {
-                self.current = current.next_back_leaf_edge().next_back_kv().ok();
-            }
-        }
+    pub fn prev(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = self.inner.prev()?;
+        Some((&*k, v))
     }
 
-    /// Returns a reference to the key of the element that the cursor is
-    /// currently pointing to.
+    /// Returns a reference to the the key and value of the next element without
+    /// moving the cursor.
     ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
+    /// If the cursor is at the end of the map then `None` is returned
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn key(&self) -> Option<&K> {
-        self.current.as_ref().map(|current| current.reborrow().into_kv().0)
+    pub fn peek_next(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = self.inner.peek_next()?;
+        Some((&*k, v))
     }
 
-    /// Returns a reference to the value of the element that the cursor is
-    /// currently pointing to.
+    /// Returns a reference to the the key and value of the previous element
+    /// without moving the cursor.
     ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
+    /// If the cursor is at the start of the map then `None` is returned.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn value(&self) -> Option<&V> {
-        self.current.as_ref().map(|current| current.reborrow().into_kv().1)
+    pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> {
+        let (k, v) = self.inner.peek_prev()?;
+        Some((&*k, v))
     }
 
-    /// Returns a reference to the key and value of the element that the cursor
-    /// is currently pointing to.
+    /// Returns a read-only cursor pointing to the same location as the
+    /// `CursorMut`.
     ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
+    /// The lifetime of the returned `Cursor` is bound to that of the
+    /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
+    /// `CursorMut` is frozen for the lifetime of the `Cursor`.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn key_value(&self) -> Option<(&K, &V)> {
-        self.current.as_ref().map(|current| current.reborrow().into_kv())
+    pub fn as_cursor(&self) -> Cursor<'_, K, V> {
+        self.inner.as_cursor()
     }
 
-    /// Returns a mutable reference to the value of the element that the cursor
-    /// is currently pointing to.
+    /// Converts the cursor into a [`CursorMutKey`], which allows mutating
+    /// the key of elements in the tree.
+    ///
+    /// # Safety
+    ///
+    /// Since this cursor allows mutating keys, you must ensure that the `BTreeMap`
+    /// invariants are maintained. Specifically:
     ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All keys in the tree must remain in sorted order.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn value_mut(&mut self) -> Option<&mut V> {
-        self.current.as_mut().map(|current| current.kv_mut().1)
+    pub unsafe fn with_mutable_key(self) -> CursorMutKey<'a, K, V, A> {
+        self.inner
     }
+}
 
-    /// Returns a reference to the key and mutable reference to the value of the
-    /// element that the cursor is currently pointing to.
+impl<'a, K, V, A> CursorMutKey<'a, K, V, A> {
+    /// Advances the cursor to the next gap, returning the key and value of the
+    /// element that it moved over.
     ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
+    /// If the cursor is already at the end of the map then `None` is returned
+    /// and the cursor is not moved.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn key_value_mut(&mut self) -> Option<(&K, &mut V)> {
-        self.current.as_mut().map(|current| {
-            let (k, v) = current.kv_mut();
-            (&*k, v)
-        })
+    pub fn next(&mut self) -> Option<(&mut K, &mut V)> {
+        let current = self.current.take()?;
+        match current.next_kv() {
+            Ok(mut kv) => {
+                // SAFETY: The key/value pointers remain valid even after the
+                // cursor is moved forward. The lifetimes then prevent any
+                // further access to the cursor.
+                let (k, v) = unsafe { kv.reborrow_mut().into_kv_mut() };
+                let (k, v) = (k as *mut _, v as *mut _);
+                self.current = Some(kv.next_leaf_edge());
+                Some(unsafe { (&mut *k, &mut *v) })
+            }
+            Err(root) => {
+                self.current = Some(root.last_leaf_edge());
+                None
+            }
+        }
     }
 
-    /// Returns a mutable reference to the key of the element that the cursor is
-    /// currently pointing to.
-    ///
-    /// This returns `None` if the cursor is currently pointing to the
-    /// "ghost" non-element.
+    /// Advances the cursor to the previous gap, returning the key and value of
+    /// the element that it moved over.
     ///
-    /// # Safety
-    ///
-    /// This can be used to modify the key, but you must ensure that the
-    /// `BTreeMap` invariants are maintained. Specifically:
-    ///
-    /// * The key must remain unique within the tree.
-    /// * The key must remain in sorted order with regards to other elements in
-    ///   the tree.
+    /// If the cursor is already at the start of the map then `None` is returned
+    /// and the cursor is not moved.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub unsafe fn key_mut_unchecked(&mut self) -> Option<&mut K> {
-        self.current.as_mut().map(|current| current.kv_mut().0)
+    pub fn prev(&mut self) -> Option<(&mut K, &mut V)> {
+        let current = self.current.take()?;
+        match current.next_back_kv() {
+            Ok(mut kv) => {
+                // SAFETY: The key/value pointers remain valid even after the
+                // cursor is moved forward. The lifetimes then prevent any
+                // further access to the cursor.
+                let (k, v) = unsafe { kv.reborrow_mut().into_kv_mut() };
+                let (k, v) = (k as *mut _, v as *mut _);
+                self.current = Some(kv.next_back_leaf_edge());
+                Some(unsafe { (&mut *k, &mut *v) })
+            }
+            Err(root) => {
+                self.current = Some(root.first_leaf_edge());
+                None
+            }
+        }
     }
 
-    /// Returns a reference to the key and value of the next element.
+    /// Returns a reference to the the key and value of the next element without
+    /// moving the cursor.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this returns
-    /// the first element of the `BTreeMap`. If it is pointing to the last
-    /// element of the `BTreeMap` then this returns `None`.
+    /// If the cursor is at the end of the map then `None` is returned
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn peek_next(&mut self) -> Option<(&K, &mut V)> {
-        let (k, v) = match self.current {
-            None => {
-                // SAFETY: The previous borrow of root has ended.
-                unsafe { self.root.reborrow() }
-                    .as_mut()?
-                    .borrow_mut()
-                    .first_leaf_edge()
-                    .next_kv()
-                    .ok()?
-                    .into_kv_valmut()
-            }
-            // SAFETY: We're not using this to mutate the tree.
-            Some(ref mut current) => {
-                unsafe { current.reborrow_mut() }.next_leaf_edge().next_kv().ok()?.into_kv_valmut()
-            }
-        };
-        Some((k, v))
+    pub fn peek_next(&mut self) -> Option<(&mut K, &mut V)> {
+        let current = self.current.as_mut()?;
+        // SAFETY: We're not using this to mutate the tree.
+        let kv = unsafe { current.reborrow_mut() }.next_kv().ok()?.into_kv_mut();
+        Some(kv)
     }
 
-    /// Returns a reference to the key and value of the previous element.
+    /// Returns a reference to the the key and value of the previous element
+    /// without moving the cursor.
     ///
-    /// If the cursor is pointing to the "ghost" non-element then this returns
-    /// the last element of the `BTreeMap`. If it is pointing to the first
-    /// element of the `BTreeMap` then this returns `None`.
+    /// If the cursor is at the start of the map then `None` is returned.
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn peek_prev(&mut self) -> Option<(&K, &mut V)> {
-        let (k, v) = match self.current.as_mut() {
-            None => {
-                // SAFETY: The previous borrow of root has ended.
-                unsafe { self.root.reborrow() }
-                    .as_mut()?
-                    .borrow_mut()
-                    .last_leaf_edge()
-                    .next_back_kv()
-                    .ok()?
-                    .into_kv_valmut()
-            }
-            Some(current) => {
-                // SAFETY: We're not using this to mutate the tree.
-                unsafe { current.reborrow_mut() }
-                    .next_back_leaf_edge()
-                    .next_back_kv()
-                    .ok()?
-                    .into_kv_valmut()
-            }
-        };
-        Some((k, v))
+    pub fn peek_prev(&mut self) -> Option<(&mut K, &mut V)> {
+        let current = self.current.as_mut()?;
+        // SAFETY: We're not using this to mutate the tree.
+        let kv = unsafe { current.reborrow_mut() }.next_back_kv().ok()?.into_kv_mut();
+        Some(kv)
     }
 
-    /// Returns a read-only cursor pointing to the current element.
+    /// Returns a read-only cursor pointing to the same location as the
+    /// `CursorMutKey`.
     ///
     /// The lifetime of the returned `Cursor` is bound to that of the
-    /// `CursorMut`, which means it cannot outlive the `CursorMut` and that the
-    /// `CursorMut` is frozen for the lifetime of the `Cursor`.
+    /// `CursorMutKey`, which means it cannot outlive the `CursorMutKey` and that the
+    /// `CursorMutKey` is frozen for the lifetime of the `Cursor`.
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn as_cursor(&self) -> Cursor<'_, K, V> {
         Cursor {
@@ -3054,11 +3039,12 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> {
 }
 
 // Now the tree editing operations
-impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
-    /// Inserts a new element into the `BTreeMap` after the current one.
+impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMutKey` is currently pointing to.
     ///
-    /// If the cursor is pointing at the "ghost" non-element then the new element is
-    /// inserted at the front of the `BTreeMap`.
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
     ///
     /// # Safety
     ///
@@ -3071,20 +3057,19 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
     pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) {
         let edge = match self.current.take() {
             None => {
+                // Tree is empty, allocate a new root.
                 // SAFETY: We have no other reference to the tree.
-                match unsafe { self.root.reborrow() } {
-                    root @ None => {
-                        // Tree is empty, allocate a new root.
-                        let mut node = NodeRef::new_leaf(self.alloc.clone());
-                        node.borrow_mut().push(key, value);
-                        *root = Some(node.forget_type());
-                        *self.length += 1;
-                        return;
-                    }
-                    Some(root) => root.borrow_mut().first_leaf_edge(),
-                }
+                let root = unsafe { self.root.reborrow() };
+                debug_assert!(root.is_none());
+                let mut node = NodeRef::new_leaf(self.alloc.clone());
+                // SAFETY: We don't touch the root while the handle is alive.
+                let handle = unsafe { node.borrow_mut().push_with_handle(key, value) };
+                *root = Some(node.forget_type());
+                *self.length += 1;
+                self.current = Some(handle.left_edge());
+                return;
             }
-            Some(current) => current.next_leaf_edge(),
+            Some(current) => current,
         };
 
         let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
@@ -3094,14 +3079,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
             let root = unsafe { self.root.reborrow().as_mut().unwrap() };
             root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
         });
-        self.current = handle.left_edge().next_back_kv().ok();
+        self.current = Some(handle.left_edge());
         *self.length += 1;
     }
 
-    /// Inserts a new element into the `BTreeMap` before the current one.
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMutKey` is currently pointing to.
     ///
-    /// If the cursor is pointing at the "ghost" non-element then the new element is
-    /// inserted at the end of the `BTreeMap`.
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
     ///
     /// # Safety
     ///
@@ -3119,15 +3105,17 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
                     root @ None => {
                         // Tree is empty, allocate a new root.
                         let mut node = NodeRef::new_leaf(self.alloc.clone());
-                        node.borrow_mut().push(key, value);
+                        // SAFETY: We don't touch the root while the handle is alive.
+                        let handle = unsafe { node.borrow_mut().push_with_handle(key, value) };
                         *root = Some(node.forget_type());
                         *self.length += 1;
+                        self.current = Some(handle.right_edge());
                         return;
                     }
                     Some(root) => root.borrow_mut().last_leaf_edge(),
                 }
             }
-            Some(current) => current.next_back_leaf_edge(),
+            Some(current) => current,
         };
 
         let handle = edge.insert_recursing(key, value, self.alloc.clone(), |ins| {
@@ -3137,14 +3125,15 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
             let root = unsafe { self.root.reborrow().as_mut().unwrap() };
             root.push_internal_level(self.alloc.clone()).push(ins.kv.0, ins.kv.1, ins.right)
         });
-        self.current = handle.right_edge().next_kv().ok();
+        self.current = Some(handle.right_edge());
         *self.length += 1;
     }
 
-    /// Inserts a new element into the `BTreeMap` after the current one.
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMutKey` is currently pointing to.
     ///
-    /// If the cursor is pointing at the "ghost" non-element then the new element is
-    /// inserted at the front of the `BTreeMap`.
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
     ///
     /// # Panics
     ///
@@ -3154,26 +3143,28 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
     /// - the given key compares greater than or equal to the next element (if
     ///   any).
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn insert_after(&mut self, key: K, value: V) {
-        if let Some(current) = self.key() {
-            if &key <= current {
-                panic!("key must be ordered above the current element");
+    pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
+        if let Some((prev, _)) = self.peek_prev() {
+            if &key <= prev {
+                return Err(UnorderedKeyError {});
             }
         }
         if let Some((next, _)) = self.peek_next() {
             if &key >= next {
-                panic!("key must be ordered below the next element");
+                return Err(UnorderedKeyError {});
             }
         }
         unsafe {
             self.insert_after_unchecked(key, value);
         }
+        Ok(())
     }
 
-    /// Inserts a new element into the `BTreeMap` before the current one.
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMutKey` is currently pointing to.
     ///
-    /// If the cursor is pointing at the "ghost" non-element then the new element is
-    /// inserted at the end of the `BTreeMap`.
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
     ///
     /// # Panics
     ///
@@ -3183,36 +3174,36 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
     /// - the given key compares less than or equal to the previous element (if
     ///   any).
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn insert_before(&mut self, key: K, value: V) {
-        if let Some(current) = self.key() {
-            if &key >= current {
-                panic!("key must be ordered below the current element");
-            }
-        }
+    pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
         if let Some((prev, _)) = self.peek_prev() {
             if &key <= prev {
-                panic!("key must be ordered above the previous element");
+                return Err(UnorderedKeyError {});
+            }
+        }
+        if let Some((next, _)) = self.peek_next() {
+            if &key >= next {
+                return Err(UnorderedKeyError {});
             }
         }
         unsafe {
             self.insert_before_unchecked(key, value);
         }
+        Ok(())
     }
 
-    /// Removes the current element from the `BTreeMap`.
-    ///
-    /// The element that was removed is returned, and the cursor is
-    /// moved to point to the next element in the `BTreeMap`.
+    /// Removes the next element from the `BTreeMap`.
     ///
-    /// If the cursor is currently pointing to the "ghost" non-element then no element
-    /// is removed and `None` is returned. The cursor is not moved in this case.
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (before the removed element).
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn remove_current(&mut self) -> Option<(K, V)> {
+    pub fn remove_next(&mut self) -> Option<(K, V)> {
         let current = self.current.take()?;
         let mut emptied_internal_root = false;
-        let (kv, pos) =
-            current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
-        self.current = pos.next_kv().ok();
+        let (kv, pos) = current
+            .next_kv()
+            .ok()?
+            .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+        self.current = Some(pos);
         *self.length -= 1;
         if emptied_internal_root {
             // SAFETY: This is safe since current does not point within the now
@@ -3223,20 +3214,19 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
         Some(kv)
     }
 
-    /// Removes the current element from the `BTreeMap`.
+    /// Removes the precending element from the `BTreeMap`.
     ///
-    /// The element that was removed is returned, and the cursor is
-    /// moved to point to the previous element in the `BTreeMap`.
-    ///
-    /// If the cursor is currently pointing to the "ghost" non-element then no element
-    /// is removed and `None` is returned. The cursor is not moved in this case.
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (after the removed element).
     #[unstable(feature = "btree_cursors", issue = "107540")]
-    pub fn remove_current_and_move_back(&mut self) -> Option<(K, V)> {
+    pub fn remove_prev(&mut self) -> Option<(K, V)> {
         let current = self.current.take()?;
         let mut emptied_internal_root = false;
-        let (kv, pos) =
-            current.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
-        self.current = pos.next_back_kv().ok();
+        let (kv, pos) = current
+            .next_back_kv()
+            .ok()?
+            .remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
+        self.current = Some(pos);
         *self.length -= 1;
         if emptied_internal_root {
             // SAFETY: This is safe since current does not point within the now
@@ -3248,5 +3238,114 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
     }
 }
 
+impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMut` is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeMap` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All keys in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_after_unchecked(&mut self, key: K, value: V) {
+        unsafe { self.inner.insert_after_unchecked(key, value) }
+    }
+
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMut` is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
+    ///
+    /// # Safety
+    ///
+    /// You must ensure that the `BTreeMap` invariants are maintained.
+    /// Specifically:
+    ///
+    /// * The key of the newly inserted element must be unique in the tree.
+    /// * All keys in the tree must remain in sorted order.
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub unsafe fn insert_before_unchecked(&mut self, key: K, value: V) {
+        unsafe { self.inner.insert_before_unchecked(key, value) }
+    }
+
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMut` is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap before the
+    /// newly inserted element.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if:
+    /// - the given key compares less than or equal to the current element (if
+    ///   any).
+    /// - the given key compares greater than or equal to the next element (if
+    ///   any).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
+        self.inner.insert_after(key, value)
+    }
+
+    /// Inserts a new element into the `BTreeMap` in the gap that the
+    /// `CursorMut` is currently pointing to.
+    ///
+    /// After the insertion the cursor will be pointing at the gap after the
+    /// newly inserted element.
+    ///
+    /// # Panics
+    ///
+    /// This function panics if:
+    /// - the given key compares greater than or equal to the current element
+    ///   (if any).
+    /// - the given key compares less than or equal to the previous element (if
+    ///   any).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
+        self.inner.insert_before(key, value)
+    }
+
+    /// Removes the next element from the `BTreeMap`.
+    ///
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (before the removed element).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_next(&mut self) -> Option<(K, V)> {
+        self.inner.remove_next()
+    }
+
+    /// Removes the precending element from the `BTreeMap`.
+    ///
+    /// The element that was removed is returned. The cursor position is
+    /// unchanged (after the removed element).
+    #[unstable(feature = "btree_cursors", issue = "107540")]
+    pub fn remove_prev(&mut self) -> Option<(K, V)> {
+        self.inner.remove_prev()
+    }
+}
+
+/// Error type returned by [`CursorMut::insert_before`] and
+/// [`CursorMut::insert_after`] if the key being inserted is not properly
+/// ordered with regards to adjacent keys.
+#[derive(Clone, PartialEq, Eq, Debug)]
+#[unstable(feature = "btree_cursors", issue = "107540")]
+pub struct UnorderedKeyError {}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl fmt::Display for UnorderedKeyError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "key is not properly ordered relative to neighbors")
+    }
+}
+
+#[unstable(feature = "btree_cursors", issue = "107540")]
+impl Error for UnorderedKeyError {}
+
 #[cfg(test)]
 mod tests;
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index a1b7cfe6b17..56620cf890d 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -2349,112 +2349,151 @@ fn test_cursor() {
     let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
 
     let mut cur = map.lower_bound(Bound::Unbounded);
-    assert_eq!(cur.key(), Some(&1));
-    cur.move_next();
-    assert_eq!(cur.key(), Some(&2));
-    assert_eq!(cur.peek_next(), Some((&3, &'c')));
-    cur.move_prev();
-    assert_eq!(cur.key(), Some(&1));
+    assert_eq!(cur.peek_next(), Some((&1, &'a')));
     assert_eq!(cur.peek_prev(), None);
+    assert_eq!(cur.prev(), None);
+    assert_eq!(cur.next(), Some((&1, &'a')));
+
+    assert_eq!(cur.next(), Some((&2, &'b')));
+
+    assert_eq!(cur.peek_next(), Some((&3, &'c')));
+    assert_eq!(cur.prev(), Some((&2, &'b')));
+    assert_eq!(cur.peek_prev(), Some((&1, &'a')));
 
     let mut cur = map.upper_bound(Bound::Excluded(&1));
-    assert_eq!(cur.key(), None);
-    cur.move_next();
-    assert_eq!(cur.key(), Some(&1));
-    cur.move_prev();
-    assert_eq!(cur.key(), None);
-    assert_eq!(cur.peek_prev(), Some((&3, &'c')));
+    assert_eq!(cur.peek_prev(), None);
+    assert_eq!(cur.next(), Some((&1, &'a')));
+    assert_eq!(cur.prev(), Some((&1, &'a')));
 }
 
 #[test]
 fn test_cursor_mut() {
     let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]);
     let mut cur = map.lower_bound_mut(Bound::Excluded(&3));
-    assert_eq!(cur.key(), Some(&5));
-    cur.insert_before(4, 'd');
-    assert_eq!(cur.key(), Some(&5));
+    assert_eq!(cur.peek_next(), Some((&5, &mut 'e')));
+    assert_eq!(cur.peek_prev(), Some((&3, &mut 'c')));
+
+    cur.insert_before(4, 'd').unwrap();
+    assert_eq!(cur.peek_next(), Some((&5, &mut 'e')));
     assert_eq!(cur.peek_prev(), Some((&4, &mut 'd')));
-    cur.move_next();
-    assert_eq!(cur.key(), None);
-    cur.insert_before(6, 'f');
-    assert_eq!(cur.key(), None);
-    assert_eq!(cur.remove_current(), None);
-    assert_eq!(cur.key(), None);
-    cur.insert_after(0, '?');
-    assert_eq!(cur.key(), None);
-    assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')]));
+
+    assert_eq!(cur.next(), Some((&5, &mut 'e')));
+    assert_eq!(cur.peek_next(), None);
+    assert_eq!(cur.peek_prev(), Some((&5, &mut 'e')));
+    cur.insert_before(6, 'f').unwrap();
+    assert_eq!(cur.peek_next(), None);
+    assert_eq!(cur.peek_prev(), Some((&6, &mut 'f')));
+    assert_eq!(cur.remove_prev(), Some((6, 'f')));
+    assert_eq!(cur.remove_prev(), Some((5, 'e')));
+    assert_eq!(cur.remove_next(), None);
+    assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')]));
 
     let mut cur = map.upper_bound_mut(Bound::Included(&5));
-    assert_eq!(cur.key(), Some(&5));
-    assert_eq!(cur.remove_current(), Some((5, 'e')));
-    assert_eq!(cur.key(), Some(&6));
-    assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f')));
-    assert_eq!(cur.key(), Some(&4));
-    assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')]));
+    assert_eq!(cur.peek_next(), None);
+    assert_eq!(cur.prev(), Some((&4, &mut 'd')));
+    assert_eq!(cur.peek_next(), Some((&4, &mut 'd')));
+    assert_eq!(cur.peek_prev(), Some((&3, &mut 'c')));
+    assert_eq!(cur.remove_next(), Some((4, 'd')));
+    assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')]));
+}
+
+#[test]
+fn test_cursor_mut_key() {
+    let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]);
+    let mut cur = unsafe { map.lower_bound_mut(Bound::Excluded(&3)).with_mutable_key() };
+    assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e')));
+    assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c')));
+
+    cur.insert_before(4, 'd').unwrap();
+    assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e')));
+    assert_eq!(cur.peek_prev(), Some((&mut 4, &mut 'd')));
+
+    assert_eq!(cur.next(), Some((&mut 5, &mut 'e')));
+    assert_eq!(cur.peek_next(), None);
+    assert_eq!(cur.peek_prev(), Some((&mut 5, &mut 'e')));
+    cur.insert_before(6, 'f').unwrap();
+    assert_eq!(cur.peek_next(), None);
+    assert_eq!(cur.peek_prev(), Some((&mut 6, &mut 'f')));
+    assert_eq!(cur.remove_prev(), Some((6, 'f')));
+    assert_eq!(cur.remove_prev(), Some((5, 'e')));
+    assert_eq!(cur.remove_next(), None);
+    assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')]));
+
+    let mut cur = unsafe { map.upper_bound_mut(Bound::Included(&5)).with_mutable_key() };
+    assert_eq!(cur.peek_next(), None);
+    assert_eq!(cur.prev(), Some((&mut 4, &mut 'd')));
+    assert_eq!(cur.peek_next(), Some((&mut 4, &mut 'd')));
+    assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c')));
+    assert_eq!(cur.remove_next(), Some((4, 'd')));
+    assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')]));
+}
+
+#[test]
+fn test_cursor_empty() {
+    let mut map = BTreeMap::new();
+    let mut cur = map.lower_bound_mut(Bound::Excluded(&3));
+    assert_eq!(cur.peek_next(), None);
+    assert_eq!(cur.peek_prev(), None);
+    cur.insert_after(0, 0).unwrap();
+    assert_eq!(cur.peek_next(), Some((&0, &mut 0)));
+    assert_eq!(cur.peek_prev(), None);
+    assert_eq!(map, BTreeMap::from([(0, 0)]));
 }
 
-#[should_panic(expected = "key must be ordered above the previous element")]
 #[test]
 fn test_cursor_mut_insert_before_1() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_before(0, 'd');
+    cur.insert_before(0, 'd').unwrap_err();
 }
 
-#[should_panic(expected = "key must be ordered above the previous element")]
 #[test]
 fn test_cursor_mut_insert_before_2() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_before(1, 'd');
+    cur.insert_before(1, 'd').unwrap_err();
 }
 
-#[should_panic(expected = "key must be ordered below the current element")]
 #[test]
 fn test_cursor_mut_insert_before_3() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_before(2, 'd');
+    cur.insert_before(2, 'd').unwrap_err();
 }
 
-#[should_panic(expected = "key must be ordered below the current element")]
 #[test]
 fn test_cursor_mut_insert_before_4() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_before(3, 'd');
+    cur.insert_before(3, 'd').unwrap_err();
 }
 
-#[should_panic(expected = "key must be ordered above the current element")]
 #[test]
 fn test_cursor_mut_insert_after_1() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_after(1, 'd');
+    cur.insert_after(1, 'd').unwrap_err();
 }
 
-#[should_panic(expected = "key must be ordered above the current element")]
 #[test]
 fn test_cursor_mut_insert_after_2() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_after(2, 'd');
+    cur.insert_after(2, 'd').unwrap_err();
 }
 
-#[should_panic(expected = "key must be ordered below the next element")]
 #[test]
 fn test_cursor_mut_insert_after_3() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_after(3, 'd');
+    cur.insert_after(3, 'd').unwrap_err();
 }
 
-#[should_panic(expected = "key must be ordered below the next element")]
 #[test]
 fn test_cursor_mut_insert_after_4() {
     let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
     let mut cur = map.upper_bound_mut(Bound::Included(&2));
-    cur.insert_after(4, 'd');
+    cur.insert_after(4, 'd').unwrap_err();
 }
 
 #[test]
@@ -2462,14 +2501,14 @@ fn cursor_peek_prev_agrees_with_cursor_mut() {
     let mut map = BTreeMap::from([(1, 1), (2, 2), (3, 3)]);
 
     let cursor = map.lower_bound(Bound::Excluded(&3));
-    assert!(cursor.key().is_none());
+    assert!(cursor.peek_next().is_none());
 
     let prev = cursor.peek_prev();
     assert_matches!(prev, Some((&3, _)));
 
     // Shadow names so the two parts of this test match.
     let mut cursor = map.lower_bound_mut(Bound::Excluded(&3));
-    assert!(cursor.key().is_none());
+    assert!(cursor.peek_next().is_none());
 
     let prev = cursor.peek_prev();
     assert_matches!(prev, Some((&3, _)));
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 3233a575ecf..78ccb3af66d 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -648,17 +648,36 @@ impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
     /// Adds a key-value pair to the end of the node, and returns
-    /// the mutable reference of the inserted value.
-    pub fn push(&mut self, key: K, val: V) -> &mut V {
+    /// a handle to the inserted value.
+    ///
+    /// # Safety
+    ///
+    /// The returned handle has an unbound lifetime.
+    pub unsafe fn push_with_handle<'b>(
+        &mut self,
+        key: K,
+        val: V,
+    ) -> Handle<NodeRef<marker::Mut<'b>, K, V, marker::Leaf>, marker::KV> {
         let len = self.len_mut();
         let idx = usize::from(*len);
         assert!(idx < CAPACITY);
         *len += 1;
         unsafe {
             self.key_area_mut(idx).write(key);
-            self.val_area_mut(idx).write(val)
+            self.val_area_mut(idx).write(val);
+            Handle::new_kv(
+                NodeRef { height: self.height, node: self.node, _marker: PhantomData },
+                idx,
+            )
         }
     }
+
+    /// Adds a key-value pair to the end of the node, and returns
+    /// the mutable reference of the inserted value.
+    pub fn push(&mut self, key: K, val: V) -> *mut V {
+        // SAFETY: The unbound handle is no longer accessible.
+        unsafe { self.push_with_handle(key, val).into_val_mut() }
+    }
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
@@ -1100,10 +1119,10 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
         unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
     }
 
-    pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
+    pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
         debug_assert!(self.idx < self.node.len());
         let leaf = self.node.into_leaf_mut();
-        let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() };
+        let k = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() };
         let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() };
         (k, v)
     }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 5d917dc6fbb..76a53a9366a 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2517,6 +2517,66 @@ extern "rust-intrinsic" {
     where
         G: FnOnce<ARG, Output = RET>,
         F: FnOnce<ARG, Output = RET>;
+
+    /// Returns whether the argument's value is statically known at
+    /// compile-time.
+    ///
+    /// This is useful when there is a way of writing the code that will
+    /// be *faster* when some variables have known values, but *slower*
+    /// in the general case: an `if is_val_statically_known(var)` can be used
+    /// to select between these two variants. The `if` will be optimized away
+    /// and only the desired branch remains.
+    ///
+    /// Formally speaking, this function non-deterministically returns `true`
+    /// or `false`, and the caller has to ensure sound behavior for both cases.
+    /// In other words, the following code has *Undefined Behavior*:
+    ///
+    /// ```
+    /// #![feature(is_val_statically_known)]
+    /// #![feature(core_intrinsics)]
+    /// # #![allow(internal_features)]
+    /// use std::hint::unreachable_unchecked;
+    /// use std::intrinsics::is_val_statically_known;
+    ///
+    /// unsafe {
+    ///    if !is_val_statically_known(0) { unreachable_unchecked(); }
+    /// }
+    /// ```
+    ///
+    /// This also means that the following code's behavior is unspecified; it
+    /// may panic, or it may not:
+    ///
+    /// ```no_run
+    /// #![feature(is_val_statically_known)]
+    /// #![feature(core_intrinsics)]
+    /// # #![allow(internal_features)]
+    /// use std::intrinsics::is_val_statically_known;
+    ///
+    /// unsafe {
+    ///     assert_eq!(is_val_statically_known(0), is_val_statically_known(0));
+    /// }
+    /// ```
+    ///
+    /// Unsafe code may not rely on `is_val_statically_known` returning any
+    /// particular value, ever. However, the compiler will generally make it
+    /// return `true` only if the value of the argument is actually known.
+    ///
+    /// When calling this in a `const fn`, both paths must be semantically
+    /// equivalent, that is, the result of the `true` branch and the `false`
+    /// branch must return the same value and have the same side-effects *no
+    /// matter what*.
+    #[rustc_const_unstable(feature = "is_val_statically_known", issue = "none")]
+    #[rustc_nounwind]
+    #[cfg(not(bootstrap))]
+    pub fn is_val_statically_known<T: Copy>(arg: T) -> bool;
+}
+
+// FIXME: Seems using `unstable` here completely ignores `rustc_allow_const_fn_unstable`
+// and thus compiling stage0 core doesn't work.
+#[rustc_const_stable(feature = "is_val_statically_known", since = "0.0.0")]
+#[cfg(bootstrap)]
+pub const unsafe fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
+    false
 }
 
 // Some functions are defined here because they accidentally got made
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index ead8cbe0e2f..2af242d4b50 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -200,6 +200,7 @@
 //
 // Language features:
 // tidy-alphabetical-start
+#![cfg_attr(not(bootstrap), feature(is_val_statically_known))]
 #![feature(abi_unadjusted)]
 #![feature(adt_const_params)]
 #![feature(allow_internal_unsafe)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 561f8ef36ff..d6e0e1895cd 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -187,7 +187,7 @@ pub trait Unsize<T: ?Sized> {
 /// Required trait for constants used in pattern matches.
 ///
 /// Any type that derives `PartialEq` automatically implements this trait,
-/// *regardless* of whether its type-parameters implement `Eq`.
+/// *regardless* of whether its type-parameters implement `PartialEq`.
 ///
 /// If a `const` item contains some type that does not implement this trait,
 /// then that type either (1.) does not implement `PartialEq` (which means the
@@ -200,7 +200,7 @@ pub trait Unsize<T: ?Sized> {
 /// a pattern match.
 ///
 /// See also the [structural match RFC][RFC1445], and [issue 63438] which
-/// motivated migrating from attribute-based design to this trait.
+/// motivated migrating from an attribute-based design to this trait.
 ///
 /// [RFC1445]: https://github.com/rust-lang/rfcs/blob/master/text/1445-restrict-constants-in-patterns.md
 /// [issue 63438]: https://github.com/rust-lang/rust/issues/63438
@@ -218,7 +218,7 @@ marker_impls! {
         isize, i8, i16, i32, i64, i128,
         bool,
         char,
-        str /* Technically requires `[u8]: StructuralEq` */,
+        str /* Technically requires `[u8]: StructuralPartialEq` */,
         (),
         {T, const N: usize} [T; N],
         {T} [T],
@@ -275,6 +275,7 @@ marker_impls! {
 #[unstable(feature = "structural_match", issue = "31434")]
 #[diagnostic::on_unimplemented(message = "the type `{Self}` does not `#[derive(Eq)]`")]
 #[lang = "structural_teq"]
+#[cfg(bootstrap)]
 pub trait StructuralEq {
     // Empty.
 }
@@ -282,6 +283,7 @@ pub trait StructuralEq {
 // FIXME: Remove special cases of these types from the compiler pattern checking code and always check `T: StructuralEq` instead
 marker_impls! {
     #[unstable(feature = "structural_match", issue = "31434")]
+    #[cfg(bootstrap)]
     StructuralEq for
         usize, u8, u16, u32, u64, u128,
         isize, i8, i16, i32, i64, i128,
@@ -859,6 +861,7 @@ impl<T: ?Sized> Default for PhantomData<T> {
 impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
 
 #[unstable(feature = "structural_match", issue = "31434")]
+#[cfg(bootstrap)]
 impl<T: ?Sized> StructuralEq for PhantomData<T> {}
 
 /// Compiler-internal trait used to indicate the type of enum discriminants.
@@ -1038,6 +1041,20 @@ pub trait PointerLike {}
 #[unstable(feature = "adt_const_params", issue = "95174")]
 #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
 #[allow(multiple_supertrait_upcastable)]
+#[cfg(not(bootstrap))]
+pub trait ConstParamTy: StructuralPartialEq + Eq {}
+
+/// A marker for types which can be used as types of `const` generic parameters.
+///
+/// These types must have a proper equivalence relation (`Eq`) and it must be automatically
+/// derived (`StructuralPartialEq`). There's a hard-coded check in the compiler ensuring
+/// that all fields are also `ConstParamTy`, which implies that recursively, all fields
+/// are `StructuralPartialEq`.
+#[lang = "const_param_ty"]
+#[unstable(feature = "adt_const_params", issue = "95174")]
+#[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")]
+#[allow(multiple_supertrait_upcastable)]
+#[cfg(bootstrap)]
 pub trait ConstParamTy: StructuralEq + StructuralPartialEq + Eq {}
 
 /// Derive macro generating an impl of the trait `ConstParamTy`.
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index d052dcc3e6e..bb35b6128ea 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1374,26 +1374,59 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
-            if exp == 0 {
-                return Some(1);
-            }
-            let mut base = self;
-            let mut acc: Self = 1;
-
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    acc = try_opt!(acc.checked_mul(base));
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.unsigned_abs().is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return Some(1);
                 }
-                exp /= 2;
-                base = try_opt!(base.checked_mul(base));
+                if self == -1 { // Avoid divide by zero
+                    return Some(if exp & 1 != 0 { -1 } else { 1 });
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
+                if exp > Self::BITS / power_used { return None; } // Division of constants is free
+
+                // SAFETY: exp <= Self::BITS / power_used
+                let res = unsafe { intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                )};
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+
+                let sign = self.is_negative() && exp & 1 != 0;
+                if !sign && res == Self::MIN  {
+                    None
+                } else if sign {
+                    Some(res.wrapping_neg())
+                } else {
+                    Some(res)
+                }
+            } else {
+                if exp == 0 {
+                    return Some(1);
+                }
+                let mut base = self;
+                let mut acc: Self = 1;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        acc = try_opt!(acc.checked_mul(base));
+                    }
+                    exp /= 2;
+                    base = try_opt!(base.checked_mul(base));
+                }
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
+                acc.checked_mul(base)
             }
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
-            acc.checked_mul(base)
         }
 
         /// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@@ -2058,27 +2091,58 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn wrapping_pow(self, mut exp: u32) -> Self {
-            if exp == 0 {
-                return 1;
-            }
-            let mut base = self;
-            let mut acc: Self = 1;
-
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    acc = acc.wrapping_mul(base);
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.unsigned_abs().is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return 1;
+                }
+                if self == -1 { // Avoid divide by zero
+                    return if exp & 1 != 0 { -1 } else { 1 };
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
+                if exp > Self::BITS / power_used { return 0; } // Division of constants is free
+
+                // SAFETY: exp <= Self::BITS / power_used
+                let res = unsafe { intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                )};
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+
+                let sign = self.is_negative() && exp & 1 != 0;
+                if sign {
+                    res.wrapping_neg()
+                } else {
+                    res
+                }
+            } else {
+                if exp == 0 {
+                    return 1;
+                }
+                let mut base = self;
+                let mut acc: Self = 1;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        acc = acc.wrapping_mul(base);
+                    }
+                    exp /= 2;
+                    base = base.wrapping_mul(base);
                 }
-                exp /= 2;
-                base = base.wrapping_mul(base);
-            }
 
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
-            acc.wrapping_mul(base)
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
+                acc.wrapping_mul(base)
+            }
         }
 
         /// Calculates `self` + `rhs`
@@ -2561,36 +2625,68 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
-            if exp == 0 {
-                return (1,false);
-            }
-            let mut base = self;
-            let mut acc: Self = 1;
-            let mut overflown = false;
-            // Scratch space for storing results of overflowing_mul.
-            let mut r;
-
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    r = acc.overflowing_mul(base);
-                    acc = r.0;
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.unsigned_abs().is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return (1, false);
+                }
+                if self == -1 { // Avoid divide by zero
+                    return (if exp & 1 != 0 { -1 } else { 1 }, false);
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
+                if exp > Self::BITS / power_used { return (0, true); } // Division of constants is free
+
+                // SAFETY: exp <= Self::BITS / power_used
+                let res = unsafe { intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                )};
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+
+                let sign = self.is_negative() && exp & 1 != 0;
+                let overflow = res == Self::MIN;
+                if sign {
+                    (res.wrapping_neg(), overflow)
+                } else {
+                    (res, overflow)
+                }
+            } else {
+                if exp == 0 {
+                    return (1,false);
+                }
+                let mut base = self;
+                let mut acc: Self = 1;
+                let mut overflown = false;
+                // Scratch space for storing results of overflowing_mul.
+                let mut r;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        r = acc.overflowing_mul(base);
+                        acc = r.0;
+                        overflown |= r.1;
+                    }
+                    exp /= 2;
+                    r = base.overflowing_mul(base);
+                    base = r.0;
                     overflown |= r.1;
                 }
-                exp /= 2;
-                r = base.overflowing_mul(base);
-                base = r.0;
-                overflown |= r.1;
-            }
 
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
-            r = acc.overflowing_mul(base);
-            r.1 |= overflown;
-            r
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
+                r = acc.overflowing_mul(base);
+                r.1 |= overflown;
+                r
+            }
         }
 
         /// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2608,28 +2704,68 @@ macro_rules! int_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         #[rustc_inherit_overflow_checks]
+        #[track_caller] // Hides the hackish overflow check for powers of two.
         pub const fn pow(self, mut exp: u32) -> Self {
-            if exp == 0 {
-                return 1;
-            }
-            let mut base = self;
-            let mut acc = 1;
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.unsigned_abs().is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return 1;
+                }
+                if self == -1 { // Avoid divide by zero
+                    return if exp & 1 != 0 { -1 } else { 1 };
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 };
+                if exp > Self::BITS / power_used { // Division of constants is free
+                    #[allow(arithmetic_overflow)]
+                    return Self::MAX * Self::MAX * 0;
+                }
 
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    acc = acc * base;
+                // SAFETY: exp <= Self::BITS / power_used
+                let res = unsafe { intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                )};
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+
+                let sign = self.is_negative() && exp & 1 != 0;
+                #[allow(arithmetic_overflow)]
+                if !sign && res == Self::MIN  {
+                    // So it panics.
+                    _ = Self::MAX * Self::MAX;
+                }
+                if sign {
+                    res.wrapping_neg()
+                } else {
+                    res
+                }
+            } else {
+                if exp == 0 {
+                    return 1;
+                }
+                let mut base = self;
+                let mut acc = 1;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        acc = acc * base;
+                    }
+                    exp /= 2;
+                    base = base * base;
                 }
-                exp /= 2;
-                base = base * base;
-            }
 
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
-            acc * base
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
+                acc * base
+            }
         }
 
         /// Returns the square root of the number, rounded down.
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 640f1e3fa85..45ac544ceaa 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -288,6 +288,43 @@ macro_rules! nonzero_integer {
                 unsafe { intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) as u32 }
             }
 
+            /// Returns the number of ones in the binary representation of `self`.
+            ///
+            /// # Examples
+            ///
+            /// Basic usage:
+            ///
+            /// ```
+            /// #![feature(non_zero_count_ones)]
+            /// # fn main() { test().unwrap(); }
+            /// # fn test() -> Option<()> {
+            #[doc = concat!("# use std::num::{self, ", stringify!($Ty), "};")]
+            ///
+            /// let one = num::NonZeroU32::new(1)?;
+            /// let three = num::NonZeroU32::new(3)?;
+            #[doc = concat!("let a = ", stringify!($Ty), "::new(0b100_0000)?;")]
+            #[doc = concat!("let b = ", stringify!($Ty), "::new(0b100_0011)?;")]
+            ///
+            /// assert_eq!(a.count_ones(), one);
+            /// assert_eq!(b.count_ones(), three);
+            /// # Some(())
+            /// # }
+            /// ```
+            ///
+            #[unstable(feature = "non_zero_count_ones", issue = "120287")]
+            #[rustc_const_unstable(feature = "non_zero_count_ones", issue = "120287")]
+            #[doc(alias = "popcount")]
+            #[doc(alias = "popcnt")]
+            #[must_use = "this returns the result of the operation, \
+                        without modifying the original"]
+            #[inline(always)]
+            pub const fn count_ones(self) -> NonZeroU32 {
+                // SAFETY:
+                // `self` is non-zero, which means it has at least one bit set, which means
+                // that the result of `count_ones` is non-zero.
+                unsafe { NonZeroU32::new_unchecked(self.get().count_ones()) }
+            }
+
             nonzero_integer_signedness_dependent_methods! {
                 Self = $Ty,
                 Primitive = $signedness $Int,
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index a217c2e259d..d450c68a5b2 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1364,28 +1364,49 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
-            if exp == 0 {
-                return Some(1);
-            }
-            let mut base = self;
-            let mut acc: Self = 1;
-
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    acc = try_opt!(acc.checked_mul(base));
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return Some(1);
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
+                if exp > Self::BITS / power_used { return None; } // Division of constants is free
+
+                // SAFETY: exp <= Self::BITS / power_used
+                unsafe { Some(intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                )) }
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+            } else {
+                if exp == 0 {
+                    return Some(1);
+                }
+                let mut base = self;
+                let mut acc: Self = 1;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        acc = try_opt!(acc.checked_mul(base));
+                    }
+                    exp /= 2;
+                    base = try_opt!(base.checked_mul(base));
                 }
-                exp /= 2;
-                base = try_opt!(base.checked_mul(base));
-            }
 
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
 
-            acc.checked_mul(base)
+                acc.checked_mul(base)
+            }
         }
 
         /// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@@ -1887,27 +1908,48 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn wrapping_pow(self, mut exp: u32) -> Self {
-            if exp == 0 {
-                return 1;
-            }
-            let mut base = self;
-            let mut acc: Self = 1;
-
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    acc = acc.wrapping_mul(base);
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return 1;
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
+                if exp > Self::BITS / power_used {  return 0; } // Division of constants is free
+
+                // SAFETY: exp <= Self::BITS / power_used
+                unsafe { intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                )}
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+            } else {
+                if exp == 0 {
+                    return 1;
+                }
+                let mut base = self;
+                let mut acc: Self = 1;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        acc = acc.wrapping_mul(base);
+                    }
+                    exp /= 2;
+                    base = base.wrapping_mul(base);
                 }
-                exp /= 2;
-                base = base.wrapping_mul(base);
-            }
 
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
-            acc.wrapping_mul(base)
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
+                acc.wrapping_mul(base)
+            }
         }
 
         /// Calculates `self` + `rhs`
@@ -2341,37 +2383,58 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
-            if exp == 0{
-                return (1,false);
-            }
-            let mut base = self;
-            let mut acc: Self = 1;
-            let mut overflown = false;
-            // Scratch space for storing results of overflowing_mul.
-            let mut r;
-
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    r = acc.overflowing_mul(base);
-                    acc = r.0;
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return (1, false);
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
+                if exp > Self::BITS / power_used {  return (0, true); } // Division of constants is free
+
+                // SAFETY: exp <= Self::BITS / power_used
+                unsafe { (intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                ), false) }
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+            } else {
+                if exp == 0{
+                    return (1,false);
+                }
+                let mut base = self;
+                let mut acc: Self = 1;
+                let mut overflown = false;
+                // Scratch space for storing results of overflowing_mul.
+                let mut r;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        r = acc.overflowing_mul(base);
+                        acc = r.0;
+                        overflown |= r.1;
+                    }
+                    exp /= 2;
+                    r = base.overflowing_mul(base);
+                    base = r.0;
                     overflown |= r.1;
                 }
-                exp /= 2;
-                r = base.overflowing_mul(base);
-                base = r.0;
-                overflown |= r.1;
-            }
 
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
-            r = acc.overflowing_mul(base);
-            r.1 |= overflown;
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
+                r = acc.overflowing_mul(base);
+                r.1 |= overflown;
 
-            r
+                r
+            }
         }
 
         /// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2387,28 +2450,64 @@ macro_rules! uint_impl {
         #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
+        #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)]
         #[inline]
         #[rustc_inherit_overflow_checks]
+        #[track_caller] // Hides the hackish overflow check for powers of two.
         pub const fn pow(self, mut exp: u32) -> Self {
-            if exp == 0 {
-                return 1;
-            }
-            let mut base = self;
-            let mut acc = 1;
+            // LLVM now knows that `self` is a constant value, but not a
+            // constant in Rust. This allows us to compute the power used at
+            // compile-time.
+            //
+            // This will likely add a branch in debug builds, but this should
+            // be ok.
+            //
+            // This is a massive performance boost in release builds as you can
+            // get the power of a power of two and the exponent through a `shl`
+            // instruction, but we must add a couple more checks for parity with
+            // our own `pow`.
+            // SAFETY: This path has the same behavior as the other.
+            if unsafe { intrinsics::is_val_statically_known(self) }
+                && self.is_power_of_two()
+            {
+                if self == 1 { // Avoid divide by zero
+                    return 1;
+                }
+                // SAFETY: We just checked this is a power of two. and above zero.
+                let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 };
+                if exp > Self::BITS / power_used { // Division of constants is free
+                    #[allow(arithmetic_overflow)]
+                    return Self::MAX * Self::MAX * 0;
+                }
 
-            while exp > 1 {
-                if (exp & 1) == 1 {
-                    acc = acc * base;
+                // SAFETY: exp <= Self::BITS / power_used
+                unsafe { intrinsics::unchecked_shl(
+                    1 as Self,
+                    intrinsics::unchecked_mul(power_used, exp) as Self
+                )}
+                // LLVM doesn't always optimize out the checks
+                // at the ir level.
+            } else {
+                if exp == 0 {
+                    return 1;
+                }
+                let mut base = self;
+                let mut acc = 1;
+
+                while exp > 1 {
+                    if (exp & 1) == 1 {
+                        acc = acc * base;
+                    }
+                    exp /= 2;
+                    base = base * base;
                 }
-                exp /= 2;
-                base = base * base;
-            }
 
-            // since exp!=0, finally the exp must be 1.
-            // Deal with the final bit of the exponent separately, since
-            // squaring the base afterwards is not necessary and may cause a
-            // needless overflow.
-            acc * base
+                // since exp!=0, finally the exp must be 1.
+                // Deal with the final bit of the exponent separately, since
+                // squaring the base afterwards is not necessary and may cause a
+                // needless overflow.
+                acc * base
+            }
         }
 
         /// Returns the square root of the number, rounded down.
diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs
new file mode 100644
index 00000000000..965873f163e
--- /dev/null
+++ b/library/core/src/ops/async_function.rs
@@ -0,0 +1,108 @@
+use crate::future::Future;
+use crate::marker::Tuple;
+
+/// An async-aware version of the [`Fn`](crate::ops::Fn) trait.
+///
+/// All `async fn` and functions returning futures implement this trait.
+#[unstable(feature = "async_fn_traits", issue = "none")]
+#[rustc_paren_sugar]
+#[fundamental]
+#[must_use = "async closures are lazy and do nothing unless called"]
+#[cfg_attr(not(bootstrap), lang = "async_fn")]
+pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
+    /// Future returned by [`AsyncFn::async_call`].
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    type CallFuture<'a>: Future<Output = Self::Output>
+    where
+        Self: 'a;
+
+    /// Call the [`AsyncFn`], returning a future which may borrow from the called closure.
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>;
+}
+
+/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait.
+///
+/// All `async fn` and functions returning futures implement this trait.
+#[unstable(feature = "async_fn_traits", issue = "none")]
+#[rustc_paren_sugar]
+#[fundamental]
+#[must_use = "async closures are lazy and do nothing unless called"]
+#[cfg_attr(not(bootstrap), lang = "async_fn_mut")]
+pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> {
+    /// Future returned by [`AsyncFnMut::async_call_mut`].
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    type CallMutFuture<'a>: Future<Output = Self::Output>
+    where
+        Self: 'a;
+
+    /// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure.
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>;
+}
+
+/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait.
+///
+/// All `async fn` and functions returning futures implement this trait.
+#[unstable(feature = "async_fn_traits", issue = "none")]
+#[rustc_paren_sugar]
+#[fundamental]
+#[must_use = "async closures are lazy and do nothing unless called"]
+#[cfg_attr(not(bootstrap), lang = "async_fn_once")]
+pub trait AsyncFnOnce<Args: Tuple> {
+    /// Future returned by [`AsyncFnOnce::async_call_once`].
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    type CallOnceFuture: Future<Output = Self::Output>;
+
+    /// Output type of the called closure's future.
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    type Output;
+
+    /// Call the [`AsyncFnOnce`], returning a future which may move out of the called closure.
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture;
+}
+
+mod impls {
+    use super::{AsyncFn, AsyncFnMut, AsyncFnOnce};
+    use crate::future::Future;
+    use crate::marker::Tuple;
+
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    impl<F: Fn<A>, A: Tuple> AsyncFn<A> for F
+    where
+        <F as FnOnce<A>>::Output: Future,
+    {
+        type CallFuture<'a> = <F as FnOnce<A>>::Output where Self: 'a;
+
+        extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> {
+            self.call(args)
+        }
+    }
+
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    impl<F: FnMut<A>, A: Tuple> AsyncFnMut<A> for F
+    where
+        <F as FnOnce<A>>::Output: Future,
+    {
+        type CallMutFuture<'a> = <F as FnOnce<A>>::Output where Self: 'a;
+
+        extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> {
+            self.call_mut(args)
+        }
+    }
+
+    #[unstable(feature = "async_fn_traits", issue = "none")]
+    impl<F: FnOnce<A>, A: Tuple> AsyncFnOnce<A> for F
+    where
+        <F as FnOnce<A>>::Output: Future,
+    {
+        type CallOnceFuture = <F as FnOnce<A>>::Output;
+
+        type Output = <<F as FnOnce<A>>::Output as Future>::Output;
+
+        extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture {
+            self.call_once(args)
+        }
+    }
+}
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 35654d0b853..4289a86f89b 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -139,6 +139,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 mod arith;
+mod async_function;
 mod bit;
 mod control_flow;
 mod coroutine;
@@ -173,6 +174,9 @@ pub use self::drop::Drop;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::function::{Fn, FnMut, FnOnce};
 
+#[unstable(feature = "async_fn_traits", issue = "none")]
+pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce};
+
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::index::{Index, IndexMut};
 
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 12ff64de879..5ce9ddeb676 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -220,7 +220,7 @@ impl<T: ?Sized> *const T {
     /// provenance. (Reconstructing address space information, if required, is your responsibility.)
     ///
     /// Using this method means that code is *not* following [Strict
-    /// Provenance][../index.html#strict-provenance] rules. Supporting
+    /// Provenance][super#strict-provenance] rules. Supporting
     /// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by
     /// tools that help you to stay conformant with the Rust memory model, so it is recommended to
     /// use [`addr`][pointer::addr] wherever possible.
@@ -232,7 +232,7 @@ impl<T: ?Sized> *const T {
     /// available.
     ///
     /// It is unclear whether this method can be given a satisfying unambiguous specification. This
-    /// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
+    /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
     ///
     /// [`from_exposed_addr`]: from_exposed_addr
     #[must_use]
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index a9078854125..dce7e035fc7 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -649,7 +649,7 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
 /// address makes sense in the address space that this pointer will be used with.
 ///
 /// Using this function means that code is *not* following [Strict
-/// Provenance][../index.html#strict-provenance] rules. "Guessing" a
+/// Provenance][self#strict-provenance] rules. "Guessing" a
 /// suitable provenance complicates specification and reasoning and may not be supported by
 /// tools that help you to stay conformant with the Rust memory model, so it is recommended to
 /// use [`with_addr`][pointer::with_addr] wherever possible.
@@ -660,7 +660,7 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
 /// pointer has to pick up.
 ///
 /// It is unclear whether this function can be given a satisfying unambiguous specification. This
-/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
+/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance].
 #[must_use]
 #[inline(always)]
 #[unstable(feature = "exposed_provenance", issue = "95228")]
@@ -689,7 +689,7 @@ where
 /// address makes sense in the address space that this pointer will be used with.
 ///
 /// Using this function means that code is *not* following [Strict
-/// Provenance][../index.html#strict-provenance] rules. "Guessing" a
+/// Provenance][self#strict-provenance] rules. "Guessing" a
 /// suitable provenance complicates specification and reasoning and may not be supported by
 /// tools that help you to stay conformant with the Rust memory model, so it is recommended to
 /// use [`with_addr`][pointer::with_addr] wherever possible.
@@ -700,7 +700,7 @@ where
 /// pointer has to pick up.
 ///
 /// It is unclear whether this function can be given a satisfying unambiguous specification. This
-/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
+/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance].
 #[must_use]
 #[inline(always)]
 #[unstable(feature = "exposed_provenance", issue = "95228")]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 4f5fca4367d..3e5678a7d91 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -227,7 +227,7 @@ impl<T: ?Sized> *mut T {
     /// provenance. (Reconstructing address space information, if required, is your responsibility.)
     ///
     /// Using this method means that code is *not* following [Strict
-    /// Provenance][../index.html#strict-provenance] rules. Supporting
+    /// Provenance][super#strict-provenance] rules. Supporting
     /// [`from_exposed_addr_mut`][] complicates specification and reasoning and may not be supported
     /// by tools that help you to stay conformant with the Rust memory model, so it is recommended
     /// to use [`addr`][pointer::addr] wherever possible.
@@ -239,7 +239,7 @@ impl<T: ?Sized> *mut T {
     /// available.
     ///
     /// It is unclear whether this method can be given a satisfying unambiguous specification. This
-    /// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
+    /// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
     ///
     /// [`from_exposed_addr_mut`]: from_exposed_addr_mut
     #[must_use]
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index e1b77e34f21..47e27bdc735 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -2,7 +2,7 @@
 
 use crate::cmp::Ordering::{self, *};
 use crate::marker::ConstParamTy;
-use crate::marker::{StructuralEq, StructuralPartialEq};
+use crate::marker::StructuralPartialEq;
 
 // Recursive macro for implementing n-ary tuple functions and operations
 //
@@ -64,7 +64,8 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[unstable(feature = "structural_match", issue = "31434")]
-            impl<$($T),+> StructuralEq for ($($T,)+)
+            #[cfg(bootstrap)]
+            impl<$($T),+> crate::marker::StructuralEq for ($($T,)+)
             {}
         }
 
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 6e11b92b618..f03e0790305 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -85,6 +85,9 @@ pub mod linux;
 #[cfg(any(target_os = "wasi", doc))]
 pub mod wasi;
 
+#[cfg(any(all(target_os = "wasi", target_env = "preview2"), doc))]
+pub mod wasi_preview2;
+
 // windows
 #[cfg(not(all(
     doc,
diff --git a/library/std/src/os/wasi/mod.rs b/library/std/src/os/wasi/mod.rs
index bbaf328f457..05c8d30073f 100644
--- a/library/std/src/os/wasi/mod.rs
+++ b/library/std/src/os/wasi/mod.rs
@@ -28,7 +28,8 @@
 //! [`OsStr`]: crate::ffi::OsStr
 //! [`OsString`]: crate::ffi::OsString
 
-#![stable(feature = "rust1", since = "1.0.0")]
+#![cfg_attr(not(target_env = "preview2"), stable(feature = "rust1", since = "1.0.0"))]
+#![cfg_attr(target_env = "preview2", unstable(feature = "wasm_preview2", issue = "none"))]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![doc(cfg(target_os = "wasi"))]
 
diff --git a/library/std/src/os/wasi_preview2/mod.rs b/library/std/src/os/wasi_preview2/mod.rs
new file mode 100644
index 00000000000..1d44dd72814
--- /dev/null
+++ b/library/std/src/os/wasi_preview2/mod.rs
@@ -0,0 +1,5 @@
+//! Platform-specific extensions to `std` for Preview 2 of the WebAssembly System Interface (WASI).
+//!
+//! This module is currently empty, but will be filled over time as wasi-libc support for WASI Preview 2 is stabilized.
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs
index 041b7c35582..f927d88d46c 100644
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
@@ -40,6 +40,9 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "wasi")] {
         mod wasi;
         pub use self::wasi::*;
+    } else if #[cfg(all(target_os = "wasi", target_env = "preview2"))] {
+        mod wasi_preview2;
+        pub use self::wasi_preview2::*;
     } else if #[cfg(target_family = "wasm")] {
         mod wasm;
         pub use self::wasm::*;
diff --git a/library/std/src/sys/pal/unsupported/net.rs b/library/std/src/sys/pal/unsupported/net.rs
index bbc52703f96..931fe9ba246 100644
--- a/library/std/src/sys/pal/unsupported/net.rs
+++ b/library/std/src/sys/pal/unsupported/net.rs
@@ -364,7 +364,4 @@ pub mod netc {
         pub sin6_flowinfo: u32,
         pub sin6_scope_id: u32,
     }
-
-    #[derive(Copy, Clone)]
-    pub struct sockaddr {}
 }
diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs
new file mode 100644
index 00000000000..82149cef8fa
--- /dev/null
+++ b/library/std/src/sys/pal/wasi/helpers.rs
@@ -0,0 +1,123 @@
+use crate::io as std_io;
+use crate::mem;
+
+#[inline]
+pub fn is_interrupted(errno: i32) -> bool {
+    errno == wasi::ERRNO_INTR.raw().into()
+}
+
+pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
+    use std_io::ErrorKind;
+
+    let Ok(errno) = u16::try_from(errno) else {
+        return ErrorKind::Uncategorized;
+    };
+
+    macro_rules! match_errno {
+        ($($($errno:ident)|+ => $errkind:ident),*, _ => $wildcard:ident $(,)?) => {
+            match errno {
+                $(e if $(e == ::wasi::$errno.raw())||+ => ErrorKind::$errkind),*,
+                _ => ErrorKind::$wildcard,
+            }
+        };
+    }
+
+    match_errno! {
+        ERRNO_2BIG           => ArgumentListTooLong,
+        ERRNO_ACCES          => PermissionDenied,
+        ERRNO_ADDRINUSE      => AddrInUse,
+        ERRNO_ADDRNOTAVAIL   => AddrNotAvailable,
+        ERRNO_AFNOSUPPORT    => Unsupported,
+        ERRNO_AGAIN          => WouldBlock,
+        //    ALREADY        => "connection already in progress",
+        //    BADF           => "bad file descriptor",
+        //    BADMSG         => "bad message",
+        ERRNO_BUSY           => ResourceBusy,
+        //    CANCELED       => "operation canceled",
+        //    CHILD          => "no child processes",
+        ERRNO_CONNABORTED    => ConnectionAborted,
+        ERRNO_CONNREFUSED    => ConnectionRefused,
+        ERRNO_CONNRESET      => ConnectionReset,
+        ERRNO_DEADLK         => Deadlock,
+        //    DESTADDRREQ    => "destination address required",
+        ERRNO_DOM            => InvalidInput,
+        //    DQUOT          => /* reserved */,
+        ERRNO_EXIST          => AlreadyExists,
+        //    FAULT          => "bad address",
+        ERRNO_FBIG           => FileTooLarge,
+        ERRNO_HOSTUNREACH    => HostUnreachable,
+        //    IDRM           => "identifier removed",
+        //    ILSEQ          => "illegal byte sequence",
+        //    INPROGRESS     => "operation in progress",
+        ERRNO_INTR           => Interrupted,
+        ERRNO_INVAL          => InvalidInput,
+        ERRNO_IO             => Uncategorized,
+        //    ISCONN         => "socket is connected",
+        ERRNO_ISDIR          => IsADirectory,
+        ERRNO_LOOP           => FilesystemLoop,
+        //    MFILE          => "file descriptor value too large",
+        ERRNO_MLINK          => TooManyLinks,
+        //    MSGSIZE        => "message too large",
+        //    MULTIHOP       => /* reserved */,
+        ERRNO_NAMETOOLONG    => InvalidFilename,
+        ERRNO_NETDOWN        => NetworkDown,
+        //    NETRESET       => "connection aborted by network",
+        ERRNO_NETUNREACH     => NetworkUnreachable,
+        //    NFILE          => "too many files open in system",
+        //    NOBUFS         => "no buffer space available",
+        ERRNO_NODEV          => NotFound,
+        ERRNO_NOENT          => NotFound,
+        //    NOEXEC         => "executable file format error",
+        //    NOLCK          => "no locks available",
+        //    NOLINK         => /* reserved */,
+        ERRNO_NOMEM          => OutOfMemory,
+        //    NOMSG          => "no message of the desired type",
+        //    NOPROTOOPT     => "protocol not available",
+        ERRNO_NOSPC          => StorageFull,
+        ERRNO_NOSYS          => Unsupported,
+        ERRNO_NOTCONN        => NotConnected,
+        ERRNO_NOTDIR         => NotADirectory,
+        ERRNO_NOTEMPTY       => DirectoryNotEmpty,
+        //    NOTRECOVERABLE => "state not recoverable",
+        //    NOTSOCK        => "not a socket",
+        ERRNO_NOTSUP         => Unsupported,
+        //    NOTTY          => "inappropriate I/O control operation",
+        ERRNO_NXIO           => NotFound,
+        //    OVERFLOW       => "value too large to be stored in data type",
+        //    OWNERDEAD      => "previous owner died",
+        ERRNO_PERM           => PermissionDenied,
+        ERRNO_PIPE           => BrokenPipe,
+        //    PROTO          => "protocol error",
+        ERRNO_PROTONOSUPPORT => Unsupported,
+        //    PROTOTYPE      => "protocol wrong type for socket",
+        //    RANGE          => "result too large",
+        ERRNO_ROFS           => ReadOnlyFilesystem,
+        ERRNO_SPIPE          => NotSeekable,
+        ERRNO_SRCH           => NotFound,
+        //    STALE          => /* reserved */,
+        ERRNO_TIMEDOUT       => TimedOut,
+        ERRNO_TXTBSY         => ResourceBusy,
+        ERRNO_XDEV           => CrossesDevices,
+        ERRNO_NOTCAPABLE     => PermissionDenied,
+        _                    => Uncategorized,
+    }
+}
+
+pub fn abort_internal() -> ! {
+    unsafe { libc::abort() }
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    let mut ret = (0u64, 0u64);
+    unsafe {
+        let base = &mut ret as *mut (u64, u64) as *mut u8;
+        let len = mem::size_of_val(&ret);
+        wasi::random_get(base, len).expect("random_get failure");
+    }
+    return ret;
+}
+
+#[inline]
+pub(crate) fn err2io(err: wasi::Errno) -> std_io::Error {
+    std_io::Error::from_raw_os_error(err.raw().into())
+}
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index 4ffc8ecdd67..a4b55093bf4 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -14,9 +14,6 @@
 //! compiling for wasm. That way it's a compile time error for something that's
 //! guaranteed to be a runtime error!
 
-use crate::io as std_io;
-use crate::mem;
-
 #[path = "../unix/alloc.rs"]
 pub mod alloc;
 pub mod args;
@@ -72,123 +69,12 @@ cfg_if::cfg_if! {
 mod common;
 pub use common::*;
 
-#[inline]
-pub fn is_interrupted(errno: i32) -> bool {
-    errno == wasi::ERRNO_INTR.raw().into()
-}
-
-pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
-    use std_io::ErrorKind;
-
-    let Ok(errno) = u16::try_from(errno) else {
-        return ErrorKind::Uncategorized;
-    };
-
-    macro_rules! match_errno {
-        ($($($errno:ident)|+ => $errkind:ident),*, _ => $wildcard:ident $(,)?) => {
-            match errno {
-                $(e if $(e == ::wasi::$errno.raw())||+ => ErrorKind::$errkind),*,
-                _ => ErrorKind::$wildcard,
-            }
-        };
-    }
-
-    match_errno! {
-        ERRNO_2BIG           => ArgumentListTooLong,
-        ERRNO_ACCES          => PermissionDenied,
-        ERRNO_ADDRINUSE      => AddrInUse,
-        ERRNO_ADDRNOTAVAIL   => AddrNotAvailable,
-        ERRNO_AFNOSUPPORT    => Unsupported,
-        ERRNO_AGAIN          => WouldBlock,
-        //    ALREADY        => "connection already in progress",
-        //    BADF           => "bad file descriptor",
-        //    BADMSG         => "bad message",
-        ERRNO_BUSY           => ResourceBusy,
-        //    CANCELED       => "operation canceled",
-        //    CHILD          => "no child processes",
-        ERRNO_CONNABORTED    => ConnectionAborted,
-        ERRNO_CONNREFUSED    => ConnectionRefused,
-        ERRNO_CONNRESET      => ConnectionReset,
-        ERRNO_DEADLK         => Deadlock,
-        //    DESTADDRREQ    => "destination address required",
-        ERRNO_DOM            => InvalidInput,
-        //    DQUOT          => /* reserved */,
-        ERRNO_EXIST          => AlreadyExists,
-        //    FAULT          => "bad address",
-        ERRNO_FBIG           => FileTooLarge,
-        ERRNO_HOSTUNREACH    => HostUnreachable,
-        //    IDRM           => "identifier removed",
-        //    ILSEQ          => "illegal byte sequence",
-        //    INPROGRESS     => "operation in progress",
-        ERRNO_INTR           => Interrupted,
-        ERRNO_INVAL          => InvalidInput,
-        ERRNO_IO             => Uncategorized,
-        //    ISCONN         => "socket is connected",
-        ERRNO_ISDIR          => IsADirectory,
-        ERRNO_LOOP           => FilesystemLoop,
-        //    MFILE          => "file descriptor value too large",
-        ERRNO_MLINK          => TooManyLinks,
-        //    MSGSIZE        => "message too large",
-        //    MULTIHOP       => /* reserved */,
-        ERRNO_NAMETOOLONG    => InvalidFilename,
-        ERRNO_NETDOWN        => NetworkDown,
-        //    NETRESET       => "connection aborted by network",
-        ERRNO_NETUNREACH     => NetworkUnreachable,
-        //    NFILE          => "too many files open in system",
-        //    NOBUFS         => "no buffer space available",
-        ERRNO_NODEV          => NotFound,
-        ERRNO_NOENT          => NotFound,
-        //    NOEXEC         => "executable file format error",
-        //    NOLCK          => "no locks available",
-        //    NOLINK         => /* reserved */,
-        ERRNO_NOMEM          => OutOfMemory,
-        //    NOMSG          => "no message of the desired type",
-        //    NOPROTOOPT     => "protocol not available",
-        ERRNO_NOSPC          => StorageFull,
-        ERRNO_NOSYS          => Unsupported,
-        ERRNO_NOTCONN        => NotConnected,
-        ERRNO_NOTDIR         => NotADirectory,
-        ERRNO_NOTEMPTY       => DirectoryNotEmpty,
-        //    NOTRECOVERABLE => "state not recoverable",
-        //    NOTSOCK        => "not a socket",
-        ERRNO_NOTSUP         => Unsupported,
-        //    NOTTY          => "inappropriate I/O control operation",
-        ERRNO_NXIO           => NotFound,
-        //    OVERFLOW       => "value too large to be stored in data type",
-        //    OWNERDEAD      => "previous owner died",
-        ERRNO_PERM           => PermissionDenied,
-        ERRNO_PIPE           => BrokenPipe,
-        //    PROTO          => "protocol error",
-        ERRNO_PROTONOSUPPORT => Unsupported,
-        //    PROTOTYPE      => "protocol wrong type for socket",
-        //    RANGE          => "result too large",
-        ERRNO_ROFS           => ReadOnlyFilesystem,
-        ERRNO_SPIPE          => NotSeekable,
-        ERRNO_SRCH           => NotFound,
-        //    STALE          => /* reserved */,
-        ERRNO_TIMEDOUT       => TimedOut,
-        ERRNO_TXTBSY         => ResourceBusy,
-        ERRNO_XDEV           => CrossesDevices,
-        ERRNO_NOTCAPABLE     => PermissionDenied,
-        _                    => Uncategorized,
-    }
-}
-
-pub fn abort_internal() -> ! {
-    unsafe { libc::abort() }
-}
-
-pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut ret = (0u64, 0u64);
-    unsafe {
-        let base = &mut ret as *mut (u64, u64) as *mut u8;
-        let len = mem::size_of_val(&ret);
-        wasi::random_get(base, len).expect("random_get failure");
-    }
-    return ret;
-}
-
-#[inline]
-fn err2io(err: wasi::Errno) -> std_io::Error {
-    std_io::Error::from_raw_os_error(err.raw().into())
-}
+mod helpers;
+// These exports are listed individually to work around Rust's glob import
+// conflict rules. If we glob export `helpers` and `common` together, then
+// the compiler complains about conflicts.
+pub use helpers::abort_internal;
+pub use helpers::decode_error_kind;
+use helpers::err2io;
+pub use helpers::hashmap_random_keys;
+pub use helpers::is_interrupted;
diff --git a/library/std/src/sys/pal/wasi_preview2/mod.rs b/library/std/src/sys/pal/wasi_preview2/mod.rs
new file mode 100644
index 00000000000..b61695015bb
--- /dev/null
+++ b/library/std/src/sys/pal/wasi_preview2/mod.rs
@@ -0,0 +1,78 @@
+//! System bindings for the wasi preview 2 target.
+//!
+//! This is the next evolution of the original wasi target, and is intended to
+//! replace that target over time.
+//!
+//! To begin with, this target mirrors the wasi target 1 to 1, but over
+//! time this will change significantly.
+
+#[path = "../unix/alloc.rs"]
+pub mod alloc;
+#[path = "../wasi/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+#[path = "../wasi/env.rs"]
+pub mod env;
+#[path = "../wasi/fd.rs"]
+pub mod fd;
+#[path = "../wasi/fs.rs"]
+pub mod fs;
+#[allow(unused)]
+#[path = "../wasm/atomics/futex.rs"]
+pub mod futex;
+#[path = "../wasi/io.rs"]
+pub mod io;
+
+#[path = "../wasi/net.rs"]
+pub mod net;
+#[path = "../wasi/os.rs"]
+pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
+#[path = "../unix/path.rs"]
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+#[path = "../wasi/stdio.rs"]
+pub mod stdio;
+#[path = "../wasi/thread.rs"]
+pub mod thread;
+#[path = "../unsupported/thread_local_dtor.rs"]
+pub mod thread_local_dtor;
+#[path = "../unsupported/thread_local_key.rs"]
+pub mod thread_local_key;
+#[path = "../wasi/time.rs"]
+pub mod time;
+
+cfg_if::cfg_if! {
+    if #[cfg(target_feature = "atomics")] {
+        compile_error!("The wasm32-wasi-preview2 target does not support atomics");
+    } else {
+        #[path = "../unsupported/locks/mod.rs"]
+        pub mod locks;
+        #[path = "../unsupported/once.rs"]
+        pub mod once;
+        #[path = "../unsupported/thread_parking.rs"]
+        pub mod thread_parking;
+    }
+}
+
+#[path = "../unsupported/common.rs"]
+#[deny(unsafe_op_in_unsafe_fn)]
+#[allow(unused)]
+mod common;
+pub use common::*;
+
+#[path = "../wasi/helpers.rs"]
+mod helpers;
+// These exports are listed individually to work around Rust's glob import
+// conflict rules. If we glob export `helpers` and `common` together, then
+// the compiler complains about conflicts.
+pub use helpers::abort_internal;
+pub use helpers::decode_error_kind;
+use helpers::err2io;
+pub use helpers::hashmap_random_keys;
+pub use helpers::is_interrupted;
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index f954f01fe4e..e06bc3fb09a 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -367,10 +367,13 @@ fn copy_self_contained_objects(
         let srcdir = builder
             .wasi_root(target)
             .unwrap_or_else(|| {
-                panic!("Target {:?} does not have a \"wasi-root\" key", target.triple)
+                panic!(
+                    "Target {:?} does not have a \"wasi-root\" key in Config.toml",
+                    target.triple
+                )
             })
             .join("lib")
-            .join(target.to_string().replace("-preview1", ""));
+            .join(target.to_string().replace("-preview1", "").replace("-preview2", ""));
         for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {
             copy_and_stamp(
                 builder,
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 1336abf6c7a..1726e7aacbc 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -88,7 +88,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     (Some(Mode::Std), "no_sync", None),
     (Some(Mode::Std), "backtrace_in_libstd", None),
     /* Extra values not defined in the built-in targets yet, but used in std */
-    (Some(Mode::Std), "target_env", Some(&["libnx"])),
+    (Some(Mode::Std), "target_env", Some(&["libnx", "preview2"])),
     // (Some(Mode::Std), "target_os", Some(&[])),
     // #[cfg(bootstrap)] zkvm
     (Some(Mode::Std), "target_os", Some(&["zkvm"])),
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 1998b008dc8..990998ea704 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -59,6 +59,7 @@
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [\*-unknown-uefi](platform-support/unknown-uefi.md)
     - [wasm32-wasi-preview1-threads](platform-support/wasm32-wasi-preview1-threads.md)
+    - [wasm32-wasi-preview2](platform-support/wasm32-wasi-preview2.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
     - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index f648a60b6c4..fb751b7229e 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -360,6 +360,7 @@ target | std | host | notes
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode ARMv7-A Linux with NEON, MUSL
+[`wasm32-wasi-preview2`](platform-support/wasm32-wasi-preview2.md) | ✓ |  | WebAssembly
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
 `x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
 [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? |  | x86 64-bit tvOS
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasi-preview2.md b/src/doc/rustc/src/platform-support/wasm32-wasi-preview2.md
new file mode 100644
index 00000000000..837efd13d41
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/wasm32-wasi-preview2.md
@@ -0,0 +1,30 @@
+# `wasm32-wasi-preview2`
+
+**Tier: 3**
+
+The `wasm32-wasi-preview2` target is a new and still (as of January 2024) an
+experimental target. This target is an extension to `wasm32-wasi-preview1` target,
+originally known as `wasm32-wasi`. It is the next evolution in the development of
+wasi (the [WebAssembly System Interface](https://wasi.dev)) that uses the WebAssembly
+[component model] to allow for a standardized set of syscalls that are intended to empower
+WebAssembly binaries with native host capabilities.
+
+[component model]: https://github.com/WebAssembly/component-model
+
+## Target maintainers
+
+- Alex Crichton, https://github.com/alexcrichton
+- Ryan Levick, https://github.com/rylev
+
+## Requirements
+
+This target is cross-compiled. The target supports `std` fully.
+
+## Platform requirements
+
+The WebAssembly runtime should support the wasi preview 2 API set.
+
+This target is not a stable target. This means that there are only a few engines
+which implement wasi preview 2, for example:
+
+* Wasmtime - `-W component-model`
diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md
index 19e62c4867c..b9a89c20cee 100644
--- a/src/doc/style-guide/src/editions.md
+++ b/src/doc/style-guide/src/editions.md
@@ -36,6 +36,10 @@ For a full history of changes in the Rust 2024 style edition, see the git
 history of the style guide. Notable changes in the Rust 2024 style edition
 include:
 
+- [#114764](https://github.com/rust-lang/rust/pull/114764) As the last member
+  of a delimited expression, delimited expressions are generally combinable,
+  regardless of the number of members. Previously only applied with exactly
+  one member (except for closures with explicit blocks).
 - Miscellaneous `rustfmt` bugfixes.
 - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
 - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index 12037b5992e..171a24cd89d 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -818,11 +818,11 @@ E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not.
 
 ## Combinable expressions
 
-Where a function call has a single argument, and that argument is formatted
-across multiple-lines, format the outer call as if it were a single-line call,
+When the last argument in a function call is formatted across
+multiple-lines, format the outer call as if it were a single-line call,
 if the result fits. Apply the same combining behaviour to any similar
 expressions which have multi-line, block-indented lists of sub-expressions
-delimited by parentheses (e.g., macros or tuple struct literals). E.g.,
+delimited by parentheses, brackets, or braces. E.g.,
 
 ```rust
 foo(bar(
@@ -848,20 +848,61 @@ let arr = [combinable(
     an_expr,
     another_expr,
 )];
+
+let x = Thing(an_expr, another_expr, match cond {
+    A => 1,
+    B => 2,
+});
+
+let x = format!("Stuff: {}", [
+    an_expr,
+    another_expr,
+]);
+
+let x = func(an_expr, another_expr, SomeStruct {
+    field: this_is_long,
+    another_field: 123,
+});
 ```
 
 Apply this behavior recursively.
 
-For a function with multiple arguments, if the last argument is a multi-line
-closure with an explicit block, there are no other closure arguments, and all
-the arguments and the first line of the closure fit on the first line, use the
-same combining behavior:
+If the last argument is a multi-line closure with an explicit block,
+only apply the combining behavior if there are no other closure arguments.
 
 ```rust
+// Combinable
 foo(first_arg, x, |param| {
     action();
     foo(param)
 })
+// Not combinable, because the closure is not the last argument
+foo(
+    first_arg,
+    |param| {
+        action();
+        foo(param)
+    },
+    whatever,
+)
+// Not combinable, because the first line of the closure does not fit
+foo(
+    first_arg,
+    x,
+    move |very_long_param_causing_line_to_overflow| -> Bar {
+        action();
+        foo(param)
+    },
+)
+// Not combinable, because there is more than one closure argument
+foo(
+    first_arg,
+    |x| x.bar(),
+    |param| {
+        action();
+        foo(param)
+    },
+)
 ```
 
 ## Ranges
diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html
index 8db7986fa75..b1c1d5a63a0 100644
--- a/src/librustdoc/html/templates/item_union.html
+++ b/src/librustdoc/html/templates/item_union.html
@@ -1,8 +1,8 @@
 <pre class="rust item-decl"><code>
-    {{ self.render_attributes_in_pre() | safe }}
-    {{ self.render_union() | safe }}
+    {{ self.render_attributes_in_pre()|safe }}
+    {{ self.render_union()|safe }}
 </code></pre>
-{{ self.document() | safe }}
+{{ self.document()|safe }}
 {% if self.fields_iter().peek().is_some() %}
     <h2 id="fields" class="fields section-header"> {# #}
         Fields<a href="#fields" class="anchor">§</a> {# #}
@@ -12,13 +12,13 @@
         <span id="structfield.{{ name }}" {#+ #}
             class="{{ ItemType::StructField +}} section-header"> {# #}
             <a href="#structfield.{{ name }}" class="anchor field">§</a> {# #}
-            <code>{{ name }}: {{+ self.print_ty(ty) | safe }}</code> {# #}
+            <code>{{ name }}: {{+ self.print_ty(ty)|safe }}</code> {# #}
         </span>
         {% if let Some(stability_class) = self.stability_field(field) %}
             <span class="stab {{ stability_class }}"></span>
         {% endif %}
-        {{ self.document_field(field) | safe }}
+        {{ self.document_field(field)|safe }}
     {% endfor %}
 {% endif %}
-{{ self.render_assoc_items() | safe }}
-{{ self.document_type_layout() | safe }}
+{{ self.render_assoc_items()|safe }}
+{{ self.document_type_layout()|safe }}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
index 2ae426cf789..8af60890390 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6254.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs
@@ -11,8 +11,6 @@ fn main() {
     // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
     match FOO_REF_REF {
         FOO_REF_REF => {},
-        //~^ ERROR: to use a constant of type `Foo` in a pattern, `Foo` must be annotated
-        //~| NOTE: for more information, see issue #62411 <https://github.com/rust-lang/ru
         Foo(_) => {},
     }
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr b/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
deleted file mode 100644
index 7a34e6cceee..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-6254.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/ice-6254.rs:13:9
-   |
-LL |         FOO_REF_REF => {},
-   |         ^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-   = note: `-D indirect-structural-match` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(indirect_structural_match)]`
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/clippy/tests/ui/modulo_one.rs b/src/tools/clippy/tests/ui/modulo_one.rs
index c1dbe9d9a87..c332a15f157 100644
--- a/src/tools/clippy/tests/ui/modulo_one.rs
+++ b/src/tools/clippy/tests/ui/modulo_one.rs
@@ -33,7 +33,6 @@ fn main() {
     INT_MIN % NEG_ONE;
     //~^ ERROR: this operation will panic at runtime
     //~| ERROR: any number modulo -1 will panic/overflow or result in 0
-    // ONLY caught by rustc
+    // Not caught by lint, we don't look into static items, even if entirely immutable.
     INT_MIN % STATIC_NEG_ONE;
-    //~^ ERROR: this operation will panic at runtime
 }
diff --git a/src/tools/clippy/tests/ui/modulo_one.stderr b/src/tools/clippy/tests/ui/modulo_one.stderr
index cc211ab6cd3..06bbb0f5d9a 100644
--- a/src/tools/clippy/tests/ui/modulo_one.stderr
+++ b/src/tools/clippy/tests/ui/modulo_one.stderr
@@ -12,12 +12,6 @@ error: this operation will panic at runtime
 LL |     INT_MIN % NEG_ONE;
    |     ^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
 
-error: this operation will panic at runtime
-  --> $DIR/modulo_one.rs:37:5
-   |
-LL |     INT_MIN % STATIC_NEG_ONE;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow
-
 error: any number modulo 1 will be 0
   --> $DIR/modulo_one.rs:8:5
    |
@@ -57,5 +51,5 @@ error: any number modulo -1 will panic/overflow or result in 0
 LL |     INT_MIN % NEG_ONE;
    |     ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index e70e01e8757..ff907152ca9 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1109,9 +1109,6 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
 }
 
 fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
-    if config.system_llvm && line.starts_with("no-system-llvm") {
-        return IgnoreDecision::Ignore { reason: "ignored when the system LLVM is used".into() };
-    }
     if let Some(needed_components) =
         config.parse_name_value_directive(line, "needs-llvm-components")
     {
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 8882f1582ac..c859e8acade 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -243,15 +243,6 @@ fn aux_build() {
 }
 
 #[test]
-fn no_system_llvm() {
-    let config: Config = cfg().system_llvm(false).build();
-    assert!(!check_ignore(&config, "// no-system-llvm"));
-
-    let config: Config = cfg().system_llvm(true).build();
-    assert!(check_ignore(&config, "// no-system-llvm"));
-}
-
-#[test]
 fn llvm_version() {
     let config: Config = cfg().llvm_version("8.1.2").build();
     assert!(check_ignore(&config, "// min-llvm-version: 9.0"));
@@ -267,6 +258,18 @@ fn llvm_version() {
 }
 
 #[test]
+fn system_llvm_version() {
+    let config: Config = cfg().system_llvm(true).llvm_version("17.0.0").build();
+    assert!(check_ignore(&config, "// min-system-llvm-version: 18.0"));
+
+    let config: Config = cfg().system_llvm(true).llvm_version("18.0.0").build();
+    assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0"));
+
+    let config: Config = cfg().llvm_version("17.0.0").build();
+    assert!(!check_ignore(&config, "// min-system-llvm-version: 18.0"));
+}
+
+#[test]
 fn ignore_target() {
     let config: Config = cfg().target("x86_64-unknown-linux-gnu").build();
 
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 62bef6d52d9..6624672775f 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-f6ee4bf3847277d6d6e2007ff664f8ea0895b11b
+dd2559e08e1530806740931037d6bb83ef956161
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 567ac6cff67..946887637ff 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -3,12 +3,14 @@
 
 use std::borrow::Cow;
 use std::cell::{Cell, RefCell};
+use std::collections::hash_map::Entry;
 use std::fmt;
 use std::path::Path;
 use std::process;
 
 use either::Either;
 use rand::rngs::StdRng;
+use rand::Rng;
 use rand::SeedableRng;
 
 use rustc_ast::ast::Mutability;
@@ -45,6 +47,11 @@ pub const SIGRTMIN: i32 = 34;
 /// `SIGRTMAX` - `SIGRTMIN` >= 8 (which is the value of `_POSIX_RTSIG_MAX`)
 pub const SIGRTMAX: i32 = 42;
 
+/// Each const has multiple addresses, but only this many. Since const allocations are never
+/// deallocated, choosing a new [`AllocId`] and thus base address for each evaluation would
+/// produce unbounded memory usage.
+const ADDRS_PER_CONST: usize = 16;
+
 /// Extra data stored with each stack frame
 pub struct FrameExtra<'tcx> {
     /// Extra data for the Borrow Tracker.
@@ -65,12 +72,19 @@ pub struct FrameExtra<'tcx> {
     /// optimization.
     /// This is used by `MiriMachine::current_span` and `MiriMachine::caller_span`
     pub is_user_relevant: bool,
+
+    /// We have a cache for the mapping from [`mir::Const`] to resulting [`AllocId`].
+    /// However, we don't want all frames to always get the same result, so we insert
+    /// an additional bit of "salt" into the cache key. This salt is fixed per-frame
+    /// so that within a call, a const will have a stable address.
+    salt: usize,
 }
 
 impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         // Omitting `timing`, it does not support `Debug`.
-        let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _ } = self;
+        let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } =
+            self;
         f.debug_struct("FrameData")
             .field("borrow_tracker", borrow_tracker)
             .field("catch_unwind", catch_unwind)
@@ -80,7 +94,8 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
 
 impl VisitProvenance for FrameExtra<'_> {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-        let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _ } = self;
+        let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } =
+            self;
 
         catch_unwind.visit_provenance(visit);
         borrow_tracker.visit_provenance(visit);
@@ -552,6 +567,11 @@ pub struct MiriMachine<'mir, 'tcx> {
     /// The spans we will use to report where an allocation was created and deallocated in
     /// diagnostics.
     pub(crate) allocation_spans: RefCell<FxHashMap<AllocId, (Span, Option<Span>)>>,
+
+    /// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`)
+    /// that is fixed per stack frame; this lets us have sometimes different results for the
+    /// same const while ensuring consistent results within a single call.
+    const_cache: RefCell<FxHashMap<(mir::Const<'tcx>, usize), OpTy<'tcx, Provenance>>>,
 }
 
 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
@@ -677,6 +697,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
             stack_size,
             collect_leak_backtraces: config.collect_leak_backtraces,
             allocation_spans: RefCell::new(FxHashMap::default()),
+            const_cache: RefCell::new(FxHashMap::default()),
         }
     }
 
@@ -788,6 +809,7 @@ impl VisitProvenance for MiriMachine<'_, '_> {
             stack_size: _,
             collect_leak_backtraces: _,
             allocation_spans: _,
+            const_cache: _,
         } = self;
 
         threads.visit_provenance(visit);
@@ -1345,6 +1367,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
             catch_unwind: None,
             timing,
             is_user_relevant: ecx.machine.is_user_relevant(&frame),
+            salt: ecx.machine.rng.borrow_mut().gen::<usize>() % ADDRS_PER_CONST,
         };
 
         Ok(frame.with_extra(extra))
@@ -1450,4 +1473,31 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
         ecx.machine.allocation_spans.borrow_mut().insert(alloc_id, (span, None));
         Ok(())
     }
+
+    fn eval_mir_constant<F>(
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        val: mir::Const<'tcx>,
+        span: Option<Span>,
+        layout: Option<TyAndLayout<'tcx>>,
+        eval: F,
+    ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>
+    where
+        F: Fn(
+            &InterpCx<'mir, 'tcx, Self>,
+            mir::Const<'tcx>,
+            Option<Span>,
+            Option<TyAndLayout<'tcx>>,
+        ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>,
+    {
+        let frame = ecx.active_thread_stack().last().unwrap();
+        let mut cache = ecx.machine.const_cache.borrow_mut();
+        match cache.entry((val, frame.extra.salt)) {
+            Entry::Vacant(ve) => {
+                let op = eval(ecx, val, span, layout)?;
+                ve.insert(op.clone());
+                Ok(op)
+            }
+            Entry::Occupied(oe) => Ok(oe.get().clone()),
+        }
+    }
 }
diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs
index a1db7bf74f2..e34fb118f72 100644
--- a/src/tools/miri/src/shims/intrinsics/mod.rs
+++ b/src/tools/miri/src/shims/intrinsics/mod.rs
@@ -5,6 +5,7 @@ use std::iter;
 
 use log::trace;
 
+use rand::Rng;
 use rustc_apfloat::{Float, Round};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::{
@@ -141,6 +142,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?;
             }
 
+            // We want to return either `true` or `false` at random, or else something like
+            // ```
+            // if !is_val_statically_known(0) { unreachable_unchecked(); }
+            // ```
+            // Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
+            "is_val_statically_known" => {
+                let [arg] = check_arg_count(args)?;
+                this.validate_operand(arg)?;
+                let branch: bool = this.machine.rng.get_mut().gen();
+                this.write_scalar(Scalar::from_bool(branch), dest)?;
+            }
+
             // Floating-point operations
             "fabsf32" => {
                 let [f] = check_arg_count(args)?;
diff --git a/src/tools/miri/tests/pass/const-addrs.rs b/src/tools/miri/tests/pass/const-addrs.rs
new file mode 100644
index 00000000000..6c14f0b679c
--- /dev/null
+++ b/src/tools/miri/tests/pass/const-addrs.rs
@@ -0,0 +1,38 @@
+// The const fn interpreter creates a new AllocId every time it evaluates any const.
+// If we do that in Miri, repeatedly evaluating a const causes unbounded memory use
+// we need to keep track of the base address for that AllocId, and the allocation is never
+// deallocated.
+// In Miri we explicitly store previously-assigned AllocIds for each const and ensure
+// that we only hand out a finite number of AllocIds per const.
+// MIR inlining will put every evaluation of the const we're repeatedly evaluting into the same
+// stack frame, breaking this test.
+//@compile-flags: -Zinline-mir=no
+#![feature(strict_provenance)]
+
+const EVALS: usize = 256;
+
+use std::collections::HashSet;
+fn main() {
+    let mut addrs = HashSet::new();
+    for _ in 0..EVALS {
+        addrs.insert(const_addr());
+    }
+    // Check that the const allocation has multiple base addresses
+    assert!(addrs.len() > 1);
+    // But also that we get a limited number of unique base addresses
+    assert!(addrs.len() < EVALS);
+
+    // Check that within a call we always produce the same address
+    let mut prev = 0;
+    for iter in 0..EVALS {
+        let addr = "test".as_bytes().as_ptr().addr();
+        if iter > 0 {
+            assert_eq!(prev, addr);
+        }
+        prev = addr;
+    }
+}
+
+fn const_addr() -> usize {
+    "test".as_bytes().as_ptr().addr()
+}
diff --git a/src/tools/miri/tests/pass/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics.rs
index 8c6eeab2219..8e46bd7ad48 100644
--- a/src/tools/miri/tests/pass/intrinsics.rs
+++ b/src/tools/miri/tests/pass/intrinsics.rs
@@ -33,6 +33,21 @@ fn main() {
     assert_eq!(intrinsics::likely(false), false);
     assert_eq!(intrinsics::unlikely(true), true);
 
+    let mut saw_true = false;
+    let mut saw_false = false;
+
+    for _ in 0..50 {
+        if unsafe { intrinsics::is_val_statically_known(0) } {
+            saw_true = true;
+        } else {
+            saw_false = true;
+        }
+    }
+    assert!(
+        saw_true && saw_false,
+        "`is_val_statically_known` failed to return both true and false. Congrats, you won the lottery!"
+    );
+
     intrinsics::forget(Bomb);
 
     let _v = intrinsics::discriminant_value(&Some(()));
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 6eec05e85ac..f6f2f5e88ff 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -534,6 +534,9 @@
 // revisions: wasm64_unknown_unknown
 // [wasm64_unknown_unknown] compile-flags: --target wasm64-unknown-unknown
 // [wasm64_unknown_unknown] needs-llvm-components: webassembly
+// revisions: wasm32_wasi_preview2
+// [wasm32_wasi_preview2] compile-flags: --target wasm32-wasi-preview2
+// [wasm32_wasi_preview2] needs-llvm-components: webassembly
 // revisions: x86_64_apple_darwin
 // [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin
 // [x86_64_apple_darwin] needs-llvm-components: x86
diff --git a/tests/codegen/alloc-optimisation.rs b/tests/codegen/alloc-optimisation.rs
index f88d695d87e..900eb687a45 100644
--- a/tests/codegen/alloc-optimisation.rs
+++ b/tests/codegen/alloc-optimisation.rs
@@ -1,5 +1,3 @@
-//
-// no-system-llvm
 // compile-flags: -O
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/array-map.rs b/tests/codegen/array-map.rs
index 4d218e6a951..9846cc7f5c8 100644
--- a/tests/codegen/array-map.rs
+++ b/tests/codegen/array-map.rs
@@ -1,5 +1,4 @@
 // compile-flags: -C opt-level=3 -C target-cpu=x86-64-v3
-// no-system-llvm
 // only-x86_64
 // ignore-debug (the extra assertions get in the way)
 
@@ -10,7 +9,7 @@
 pub fn short_integer_map(x: [u32; 8]) -> [u32; 8] {
     // CHECK: load <8 x i32>
     // CHECK: shl <8 x i32>
-    // CHECK: or <8 x i32>
+    // CHECK: or{{( disjoint)?}} <8 x i32>
     // CHECK: store <8 x i32>
     x.map(|x| 2 * x + 1)
 }
diff --git a/tests/codegen/dealloc-no-unwind.rs b/tests/codegen/dealloc-no-unwind.rs
index 3812ef44ff2..c2656908f16 100644
--- a/tests/codegen/dealloc-no-unwind.rs
+++ b/tests/codegen/dealloc-no-unwind.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O
 
 #![crate_type="lib"]
diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs
index df1080bff2b..05643fab96a 100644
--- a/tests/codegen/fewer-names.rs
+++ b/tests/codegen/fewer-names.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -Coverflow-checks=no -O
 // revisions: YES NO
 // [YES]compile-flags: -Zfewer-names=yes
diff --git a/tests/codegen/integer-overflow.rs b/tests/codegen/integer-overflow.rs
index 183de56db96..b5c351b5e35 100644
--- a/tests/codegen/integer-overflow.rs
+++ b/tests/codegen/integer-overflow.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O -C overflow-checks=on
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/is_val_statically_known.rs b/tests/codegen/is_val_statically_known.rs
new file mode 100644
index 00000000000..44187d4f667
--- /dev/null
+++ b/tests/codegen/is_val_statically_known.rs
@@ -0,0 +1,48 @@
+// compile-flags: --crate-type=lib -Zmerge-functions=disabled -O
+
+#![feature(core_intrinsics)]
+
+use std::intrinsics::is_val_statically_known;
+
+pub struct A(u32);
+pub enum B {
+    Ye(u32),
+}
+
+#[inline]
+pub fn _u32(a: u32) -> i32 {
+    if unsafe { is_val_statically_known(a) } { 1 } else { 0 }
+}
+
+// CHECK-LABEL: @_u32_true(
+#[no_mangle]
+pub fn _u32_true() -> i32 {
+    // CHECK: ret i32 1
+    _u32(1)
+}
+
+// CHECK-LABEL: @_u32_false(
+#[no_mangle]
+pub fn _u32_false(a: u32) -> i32 {
+    // CHECK: ret i32 0
+    _u32(a)
+}
+
+#[inline]
+pub fn _bool(b: bool) -> i32 {
+    if unsafe { is_val_statically_known(b) } { 3 } else { 2 }
+}
+
+// CHECK-LABEL: @_bool_true(
+#[no_mangle]
+pub fn _bool_true() -> i32 {
+    // CHECK: ret i32 3
+    _bool(true)
+}
+
+// CHECK-LABEL: @_bool_false(
+#[no_mangle]
+pub fn _bool_false(b: bool) -> i32 {
+    // CHECK: ret i32 2
+    _bool(b)
+}
diff --git a/tests/codegen/issues/issue-116878.rs b/tests/codegen/issues/issue-116878.rs
index d5f679459f7..5864f532324 100644
--- a/tests/codegen/issues/issue-116878.rs
+++ b/tests/codegen/issues/issue-116878.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
diff --git a/tests/codegen/issues/issue-44056-macos-tls-align.rs b/tests/codegen/issues/issue-44056-macos-tls-align.rs
index 1a3923f1bb1..44aa9766d3c 100644
--- a/tests/codegen/issues/issue-44056-macos-tls-align.rs
+++ b/tests/codegen/issues/issue-44056-macos-tls-align.rs
@@ -1,6 +1,5 @@
 //
 // only-macos
-// no-system-llvm
 // compile-flags: -O
 
 #![crate_type = "rlib"]
diff --git a/tests/codegen/issues/issue-69101-bounds-check.rs b/tests/codegen/issues/issue-69101-bounds-check.rs
index a3aca3a2912..655de45fd51 100644
--- a/tests/codegen/issues/issue-69101-bounds-check.rs
+++ b/tests/codegen/issues/issue-69101-bounds-check.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O
 // ignore-debug: the debug assertions get in the way
 #![crate_type = "lib"]
diff --git a/tests/codegen/match-optimizes-away.rs b/tests/codegen/match-optimizes-away.rs
index 8f66c518ccf..400606b42d5 100644
--- a/tests/codegen/match-optimizes-away.rs
+++ b/tests/codegen/match-optimizes-away.rs
@@ -1,5 +1,4 @@
 //
-// no-system-llvm
 // compile-flags: -O
 #![crate_type="lib"]
 
diff --git a/tests/codegen/pow_of_two.rs b/tests/codegen/pow_of_two.rs
new file mode 100644
index 00000000000..a8c0550e332
--- /dev/null
+++ b/tests/codegen/pow_of_two.rs
@@ -0,0 +1,55 @@
+// compile-flags: --crate-type=lib -Zmerge-functions=disabled -O -C overflow-checks=false
+
+// CHECK-LABEL: @a(
+#[no_mangle]
+pub fn a(exp: u32) -> u64 {
+    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64
+    // CHECK: %{{[^ ]+}} = zext i32 %exp to i64
+    // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}}
+    // CHECK: ret i64 %{{[^ ]+}}
+    2u64.pow(exp)
+}
+
+// CHECK-LABEL: @b(
+#[no_mangle]
+pub fn b(exp: u32) -> i64 {
+    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64
+    // CHECK: %{{[^ ]+}} = zext i32 %exp to i64
+    // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}}
+    // CHECK: ret i64 %{{[^ ]+}}
+    2i64.pow(exp)
+}
+
+// CHECK-LABEL: @c(
+#[no_mangle]
+pub fn c(exp: u32) -> u32 {
+    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 16
+    // CHECK: %{{[^ ]+}} = shl nuw nsw i32 %exp, 1
+    // CHECK: %{{[^ ]+}} = shl nuw i32 1, %{{[^ ]+}}
+    // CHECK: %{{[^ ]+}} = select i1 %{{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
+    // CHECK: ret i32 %{{[^ ]+}}
+    4u32.pow(exp)
+}
+
+// CHECK-LABEL: @d(
+#[no_mangle]
+pub fn d(exp: u32) -> u32 {
+    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6
+    // CHECK: %{{[^ ]+}} = mul nuw nsw i32 %exp, 5
+    // CHECK: %{{[^ ]+}} = shl nuw nsw i32 1, %{{[^ ]+}}
+    // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
+    // CHECK: ret i32 %{{[^ ]+}}
+    32u32.pow(exp)
+}
+
+// CHECK-LABEL: @e(
+#[no_mangle]
+pub fn e(exp: u32) -> i32 {
+    // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6
+    // CHECK: %{{[^ ]+}} = mul nuw {{(nsw )?}}i32 %exp, 5
+    // CHECK: %{{[^ ]+}} = shl nuw {{(nsw )?}}i32 1, %{{[^ ]+}}
+    // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}}
+    // CHECK: ret i32 %{{[^ ]+}}
+    32i32.pow(exp)
+}
+// note: d and e are expected to yield the same IR
diff --git a/tests/codegen/ptr-read-metadata.rs b/tests/codegen/ptr-read-metadata.rs
index 73d1db6df27..94152ed11ba 100644
--- a/tests/codegen/ptr-read-metadata.rs
+++ b/tests/codegen/ptr-read-metadata.rs
@@ -1,5 +1,4 @@
 // compile-flags: -O -Z merge-functions=disabled
-// no-system-llvm
 // ignore-debug (the extra assertions get in the way)
 
 #![crate_type = "lib"]
diff --git a/tests/codegen/slice-as_chunks.rs b/tests/codegen/slice-as_chunks.rs
index efac9f3d68d..e832f90d07a 100644
--- a/tests/codegen/slice-as_chunks.rs
+++ b/tests/codegen/slice-as_chunks.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O
 // only-64bit (because the LLVM type of i64 for usize shows up)
 // ignore-debug: the debug assertions get in the way
diff --git a/tests/codegen/slice-iter-len-eq-zero.rs b/tests/codegen/slice-iter-len-eq-zero.rs
index c7515ce35a3..77febf5170d 100644
--- a/tests/codegen/slice-iter-len-eq-zero.rs
+++ b/tests/codegen/slice-iter-len-eq-zero.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O
 // ignore-debug: the debug assertions add extra comparisons
 #![crate_type = "lib"]
diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs
index 1e691cc34c9..93c8828ccd3 100644
--- a/tests/codegen/slice-iter-nonnull.rs
+++ b/tests/codegen/slice-iter-nonnull.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O
 // ignore-debug (these add extra checks that make it hard to verify)
 #![crate_type = "lib"]
diff --git a/tests/codegen/slice-position-bounds-check.rs b/tests/codegen/slice-position-bounds-check.rs
index b494f42b296..57904e5e499 100644
--- a/tests/codegen/slice-position-bounds-check.rs
+++ b/tests/codegen/slice-position-bounds-check.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -O -C panic=abort
 #![crate_type = "lib"]
 
diff --git a/tests/codegen/vec-iter-collect-len.rs b/tests/codegen/vec-iter-collect-len.rs
index 73348ddd063..3a0d6c30919 100644
--- a/tests/codegen/vec-iter-collect-len.rs
+++ b/tests/codegen/vec-iter-collect-len.rs
@@ -1,5 +1,4 @@
 // ignore-debug: the debug assertions get in the way
-// no-system-llvm
 // compile-flags: -O
 #![crate_type="lib"]
 
diff --git a/tests/codegen/vec-optimizes-away.rs b/tests/codegen/vec-optimizes-away.rs
index 6f477a796b6..3be342dabeb 100644
--- a/tests/codegen/vec-optimizes-away.rs
+++ b/tests/codegen/vec-optimizes-away.rs
@@ -1,5 +1,4 @@
 // ignore-debug: the debug assertions get in the way
-// no-system-llvm
 // compile-flags: -O
 #![crate_type = "lib"]
 
diff --git a/tests/coverage-run-rustdoc/doctest.coverage b/tests/coverage-run-rustdoc/doctest.coverage
index 5797784f411..5125dc075ee 100644
--- a/tests/coverage-run-rustdoc/doctest.coverage
+++ b/tests/coverage-run-rustdoc/doctest.coverage
@@ -34,8 +34,7 @@ $DIR/doctest.rs:
    LL|       |//!
    LL|       |//! doctest returning a result:
    LL|      1|//! ```
-   LL|      2|//! #[derive(Debug, PartialEq)]
-                       ^1
+   LL|      1|//! #[derive(Debug, PartialEq)]
    LL|      1|//! struct SomeError {
    LL|      1|//!     msg: String,
    LL|      1|//! }
@@ -63,7 +62,7 @@ $DIR/doctest.rs:
    LL|      1|//!     println!("called some_func()");
    LL|      1|//! }
    LL|       |//!
-   LL|      0|//! #[derive(Debug)]
+   LL|       |//! #[derive(Debug)]
    LL|       |//! struct SomeError;
    LL|       |//!
    LL|       |//! extern crate doctest_crate;
diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map
index 0b8081acfa6..3b51e3ef9de 100644
--- a/tests/coverage/bad_counter_ids.cov-map
+++ b/tests/coverage/bad_counter_ids.cov-map
@@ -1,19 +1,3 @@
-Function name: <bad_counter_ids::Foo as core::cmp::PartialEq>::eq
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 11, 00, 1a]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 12, 17) to (start + 0, 26)
-
-Function name: <bad_counter_ids::Foo as core::fmt::Debug>::fmt
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 0a, 00, 0f]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 12, 10) to (start + 0, 15)
-
 Function name: bad_counter_ids::eq_bad
 Raw bytes (14): 0x[01, 01, 00, 02, 01, 23, 01, 02, 1f, 00, 03, 01, 00, 02]
 Number of files: 1
diff --git a/tests/coverage/bad_counter_ids.coverage b/tests/coverage/bad_counter_ids.coverage
index d69ebf160ea..5474ec2f785 100644
--- a/tests/coverage/bad_counter_ids.coverage
+++ b/tests/coverage/bad_counter_ids.coverage
@@ -9,7 +9,7 @@
    LL|       |// a too-large counter ID and silently discard the entire function from its
    LL|       |// coverage reports.
    LL|       |
-   LL|      8|#[derive(Debug, PartialEq, Eq)]
+   LL|       |#[derive(Debug, PartialEq, Eq)]
    LL|       |struct Foo(u32);
    LL|       |
    LL|      1|fn eq_good() {
diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map
index f5db3a89750..f2447e3c92c 100644
--- a/tests/coverage/issue-83601.cov-map
+++ b/tests/coverage/issue-83601.cov-map
@@ -1,19 +1,3 @@
-Function name: <issue_83601::Foo as core::cmp::PartialEq>::eq
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 11, 00, 1a]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 3, 17) to (start + 0, 26)
-
-Function name: <issue_83601::Foo as core::fmt::Debug>::fmt
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 0a, 00, 0f]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 3, 10) to (start + 0, 15)
-
 Function name: issue_83601::main
 Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
 Number of files: 1
diff --git a/tests/coverage/issue-83601.coverage b/tests/coverage/issue-83601.coverage
index 7995332cad3..e050106e6f0 100644
--- a/tests/coverage/issue-83601.coverage
+++ b/tests/coverage/issue-83601.coverage
@@ -1,7 +1,6 @@
    LL|       |// Shows that rust-lang/rust/83601 is resolved
    LL|       |
-   LL|      3|#[derive(Debug, PartialEq, Eq)]
-                              ^2
+   LL|       |#[derive(Debug, PartialEq, Eq)]
    LL|       |struct Foo(u32);
    LL|       |
    LL|      1|fn main() {
diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map
index 6d577b3d485..88436964af0 100644
--- a/tests/coverage/issue-84561.cov-map
+++ b/tests/coverage/issue-84561.cov-map
@@ -1,11 +1,3 @@
-Function name: <issue_84561::Foo as core::cmp::PartialEq>::eq
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 0a, 00, 13]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 4, 10) to (start + 0, 19)
-
 Function name: <issue_84561::Foo as core::fmt::Debug>::fmt
 Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 8a, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06]
 Number of files: 1
diff --git a/tests/coverage/issue-84561.coverage b/tests/coverage/issue-84561.coverage
index 9080d95eff5..90a2d069d39 100644
--- a/tests/coverage/issue-84561.coverage
+++ b/tests/coverage/issue-84561.coverage
@@ -1,7 +1,7 @@
    LL|       |// This demonstrated Issue #84561: function-like macros produce unintuitive coverage results.
    LL|       |
    LL|       |// failure-status: 101
-   LL|     21|#[derive(PartialEq, Eq)]
+   LL|       |#[derive(PartialEq, Eq)]
    LL|       |struct Foo(u32);
    LL|       |
    LL|       |#[rustfmt::skip]
diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map
index 5e4aae0260b..80670fbfa5a 100644
--- a/tests/coverage/partial_eq.cov-map
+++ b/tests/coverage/partial_eq.cov-map
@@ -1,51 +1,3 @@
-Function name: <partial_eq::Version as core::clone::Clone>::clone (unused)
-Raw bytes (9): 0x[01, 01, 00, 01, 00, 04, 0a, 00, 0f]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Zero) at (prev + 4, 10) to (start + 0, 15)
-
-Function name: <partial_eq::Version as core::cmp::Ord>::cmp (unused)
-Raw bytes (14): 0x[01, 01, 00, 02, 00, 04, 33, 00, 34, 00, 00, 35, 00, 36]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Zero) at (prev + 4, 51) to (start + 0, 52)
-- Code(Zero) at (prev + 0, 53) to (start + 0, 54)
-
-Function name: <partial_eq::Version as core::cmp::PartialEq>::eq (unused)
-Raw bytes (14): 0x[01, 01, 00, 02, 00, 04, 18, 00, 19, 00, 00, 20, 00, 21]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 2
-- Code(Zero) at (prev + 4, 24) to (start + 0, 25)
-- Code(Zero) at (prev + 0, 32) to (start + 0, 33)
-
-Function name: <partial_eq::Version as core::cmp::PartialOrd>::partial_cmp
-Raw bytes (22): 0x[01, 01, 04, 07, 0b, 00, 09, 0f, 15, 00, 11, 02, 01, 04, 27, 00, 28, 03, 00, 30, 00, 31]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 4
-- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add)
-- expression 1 operands: lhs = Zero, rhs = Counter(2)
-- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5)
-- expression 3 operands: lhs = Zero, rhs = Counter(4)
-Number of file 0 mappings: 2
-- Code(Counter(0)) at (prev + 4, 39) to (start + 0, 40)
-- Code(Expression(0, Add)) at (prev + 0, 48) to (start + 0, 49)
-    = ((Zero + c2) + ((Zero + c4) + c5))
-
-Function name: <partial_eq::Version as core::fmt::Debug>::fmt
-Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 11, 00, 16]
-Number of files: 1
-- file 0 => global file 1
-Number of expressions: 0
-Number of file 0 mappings: 1
-- Code(Counter(0)) at (prev + 4, 17) to (start + 0, 22)
-
 Function name: <partial_eq::Version>::new
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 06, 06]
 Number of files: 1
diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage
index 6e3696386a7..9de1c933570 100644
--- a/tests/coverage/partial_eq.coverage
+++ b/tests/coverage/partial_eq.coverage
@@ -1,8 +1,7 @@
    LL|       |// This test confirms an earlier problem was resolved, supporting the MIR graph generated by the
    LL|       |// structure of this test.
    LL|       |
-   LL|      2|#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-                       ^0            ^0      ^0     ^1       ^1 ^0^0
+   LL|       |#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
    LL|       |pub struct Version {
    LL|       |    major: usize,
    LL|       |    minor: usize,
diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir
index 25bffbe2488..7214b01c601 100644
--- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir
+++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir
@@ -1,25 +1,4 @@
 // MIR for `main::{closure#0}` 0 coroutine_drop
-/* coroutine_layout = CoroutineLayout {
-    field_tys: {
-        _0: CoroutineSavedTy {
-            ty: std::string::String,
-            source_info: SourceInfo {
-                span: $DIR/coroutine_drop_cleanup.rs:12:13: 12:15 (#0),
-                scope: scope[0],
-            },
-            ignore_for_traits: false,
-        },
-    },
-    variant_fields: {
-        Unresumed(0): [],
-        Returned (1): [],
-        Panicked (2): [],
-        Suspend0 (3): [_0],
-    },
-    storage_conflicts: BitMatrix(1x1) {
-        (_0, _0),
-    },
-} */
 
 fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () {
     let mut _0: ();
diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir
index 2eac754b15c..00769a493b5 100644
--- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir
+++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir
@@ -1,25 +1,4 @@
 // MIR for `main::{closure#0}` 0 coroutine_drop
-/* coroutine_layout = CoroutineLayout {
-    field_tys: {
-        _0: CoroutineSavedTy {
-            ty: std::string::String,
-            source_info: SourceInfo {
-                span: $DIR/coroutine_drop_cleanup.rs:12:13: 12:15 (#0),
-                scope: scope[0],
-            },
-            ignore_for_traits: false,
-        },
-    },
-    variant_fields: {
-        Unresumed(0): [],
-        Returned (1): [],
-        Panicked (2): [],
-        Suspend0 (3): [_0],
-    },
-    storage_conflicts: BitMatrix(1x1) {
-        (_0, _0),
-    },
-} */
 
 fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () {
     let mut _0: ();
diff --git a/tests/rustdoc/doc-cfg-target-feature.rs b/tests/rustdoc/doc-cfg-target-feature.rs
index f1b000dc823..98d230c978b 100644
--- a/tests/rustdoc/doc-cfg-target-feature.rs
+++ b/tests/rustdoc/doc-cfg-target-feature.rs
@@ -1,7 +1,6 @@
 // only-x86_64
 // compile-flags:--test
 // should-fail
-// no-system-llvm
 
 // #49723: rustdoc didn't add target features when extracting or running doctests
 
diff --git a/tests/ui/array-slice-vec/repeat_empty_ok.stderr b/tests/ui/array-slice-vec/repeat_empty_ok.stderr
index bc3a68c905d..c272d47d961 100644
--- a/tests/ui/array-slice-vec/repeat_empty_ok.stderr
+++ b/tests/ui/array-slice-vec/repeat_empty_ok.stderr
@@ -6,7 +6,7 @@ LL |     let headers = [Header{value: &[]}; 128];
    |
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
    |
 LL + #[derive(Copy)]
@@ -21,7 +21,7 @@ LL |     let headers = [Header{value: &[0]}; 128];
    |
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
    |
 LL + #[derive(Copy)]
diff --git a/tests/ui/associated-consts/issue-105330.rs b/tests/ui/associated-consts/issue-105330.rs
index 6c6dae864f3..285e89cce49 100644
--- a/tests/ui/associated-consts/issue-105330.rs
+++ b/tests/ui/associated-consts/issue-105330.rs
@@ -14,6 +14,5 @@ fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
 
 fn main<A: TraitWAssocConst<A=32>>() {
     //~^ ERROR E0658
-    //~| ERROR E0131
     foo::<Demo>();
 }
diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr
index b4c021d0f4f..452367bed12 100644
--- a/tests/ui/associated-consts/issue-105330.stderr
+++ b/tests/ui/associated-consts/issue-105330.stderr
@@ -43,13 +43,7 @@ LL | impl TraitWAssocConst for impl Demo {
    |
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0131]: `main` function is not allowed to have generic parameters
-  --> $DIR/issue-105330.rs:15:8
-   |
-LL | fn main<A: TraitWAssocConst<A=32>>() {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0131, E0404, E0562, E0658.
-For more information about an error, try `rustc --explain E0131`.
+Some errors have detailed explanations: E0404, E0562, E0658.
+For more information about an error, try `rustc --explain E0404`.
diff --git a/tests/ui/associated-types/impl-wf-cycle-1.stderr b/tests/ui/associated-types/impl-wf-cycle-1.stderr
index 5fa36733f66..d642f9f0e36 100644
--- a/tests/ui/associated-types/impl-wf-cycle-1.stderr
+++ b/tests/ui/associated-types/impl-wf-cycle-1.stderr
@@ -7,6 +7,9 @@ LL | | where
 LL | |     Self::A: Baz,
 LL | |     Self::B: Fiz,
    | |_________________^
+LL |   {
+LL |       type A = ();
+   |       ------ associated type `<(T,) as Grault>::A` is specified here
    |
 note: required for `(T,)` to implement `Grault`
   --> $DIR/impl-wf-cycle-1.rs:15:17
@@ -18,6 +21,10 @@ LL |     Self::A: Baz,
    |              --- unsatisfied trait bound introduced here
    = note: 1 redundant requirement hidden
    = note: required for `(T,)` to implement `Grault`
+help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
+   |
+LL -     Self::A: Baz,
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-types/impl-wf-cycle-2.stderr b/tests/ui/associated-types/impl-wf-cycle-2.stderr
index 17a96bbd934..9454d1d6697 100644
--- a/tests/ui/associated-types/impl-wf-cycle-2.stderr
+++ b/tests/ui/associated-types/impl-wf-cycle-2.stderr
@@ -6,6 +6,9 @@ LL | |
 LL | | where
 LL | |     Self::A: Copy,
    | |__________________^
+LL |   {
+LL |       type A = ();
+   |       ------ associated type `<(T,) as Grault>::A` is specified here
    |
 note: required for `(T,)` to implement `Grault`
   --> $DIR/impl-wf-cycle-2.rs:7:17
@@ -15,6 +18,11 @@ LL | impl<T: Grault> Grault for (T,)
 ...
 LL |     Self::A: Copy,
    |              ---- unsatisfied trait bound introduced here
+help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
+   |
+LL - where
+LL -     Self::A: Copy,
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/associated-types/impl-wf-cycle-3.rs b/tests/ui/associated-types/impl-wf-cycle-3.rs
new file mode 100644
index 00000000000..044033c5e8a
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-3.rs
@@ -0,0 +1,13 @@
+trait A<T> {}
+
+trait B {
+    type Type;
+}
+
+impl<T> B for T //~ ERROR overflow evaluating the requirement
+where
+    T: A<Self::Type>,
+{
+    type Type = bool;
+}
+fn main() {}
diff --git a/tests/ui/associated-types/impl-wf-cycle-3.stderr b/tests/ui/associated-types/impl-wf-cycle-3.stderr
new file mode 100644
index 00000000000..d3ca06f890b
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-3.stderr
@@ -0,0 +1,27 @@
+error[E0275]: overflow evaluating the requirement `<T as B>::Type == <T as B>::Type`
+  --> $DIR/impl-wf-cycle-3.rs:7:1
+   |
+LL | / impl<T> B for T
+LL | | where
+LL | |     T: A<Self::Type>,
+   | |_____________________^
+LL |   {
+LL |       type Type = bool;
+   |       --------- associated type `<T as B>::Type` is specified here
+   |
+note: required for `T` to implement `B`
+  --> $DIR/impl-wf-cycle-3.rs:7:9
+   |
+LL | impl<T> B for T
+   |         ^     ^
+LL | where
+LL |     T: A<Self::Type>,
+   |        ------------- unsatisfied trait bound introduced here
+help: replace the associated type with the type specified in this `impl`
+   |
+LL |     T: A<bool>,
+   |          ~~~~
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/associated-types/impl-wf-cycle-4.rs b/tests/ui/associated-types/impl-wf-cycle-4.rs
new file mode 100644
index 00000000000..bfa8adc71a1
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-4.rs
@@ -0,0 +1,15 @@
+trait Filter {
+    type ToMatch;
+}
+
+impl<T> Filter for T //~ ERROR overflow evaluating the requirement
+where
+    T: Fn(Self::ToMatch),
+{
+}
+
+struct JustFilter<F: Filter> {
+    filter: F,
+}
+
+fn main() {}
diff --git a/tests/ui/associated-types/impl-wf-cycle-4.stderr b/tests/ui/associated-types/impl-wf-cycle-4.stderr
new file mode 100644
index 00000000000..cdbac267d34
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-4.stderr
@@ -0,0 +1,25 @@
+error[E0275]: overflow evaluating the requirement `<T as Filter>::ToMatch == <T as Filter>::ToMatch`
+  --> $DIR/impl-wf-cycle-4.rs:5:1
+   |
+LL | / impl<T> Filter for T
+LL | | where
+LL | |     T: Fn(Self::ToMatch),
+   | |_________________________^
+   |
+note: required for `T` to implement `Filter`
+  --> $DIR/impl-wf-cycle-4.rs:5:9
+   |
+LL | impl<T> Filter for T
+   |         ^^^^^^     ^
+LL | where
+LL |     T: Fn(Self::ToMatch),
+   |        ----------------- unsatisfied trait bound introduced here
+note: associated types for the current `impl` cannot be restricted in `where` clauses
+  --> $DIR/impl-wf-cycle-4.rs:7:11
+   |
+LL |     T: Fn(Self::ToMatch),
+   |           ^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/associated-types/impl-wf-cycle-5.fixed b/tests/ui/associated-types/impl-wf-cycle-5.fixed
new file mode 100644
index 00000000000..bff6ca90975
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-5.fixed
@@ -0,0 +1,31 @@
+// run-rustfix
+
+trait Baz {}
+impl Baz for () {}
+impl<T> Baz for (T,) {}
+
+trait Fiz {}
+impl Fiz for bool {}
+
+trait Grault {
+    type A;
+    type B;
+}
+
+impl Grault for () {
+    type A = ();
+    type B = bool;
+}
+
+impl<T> Grault for (T,)
+//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+where
+    T: Grault,
+{
+    type A = ();
+    type B = bool;
+}
+
+fn main() {
+    let _: <((),) as Grault>::A = ();
+}
diff --git a/tests/ui/associated-types/impl-wf-cycle-5.rs b/tests/ui/associated-types/impl-wf-cycle-5.rs
new file mode 100644
index 00000000000..a822e1fb008
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-5.rs
@@ -0,0 +1,32 @@
+// run-rustfix
+
+trait Baz {}
+impl Baz for () {}
+impl<T> Baz for (T,) {}
+
+trait Fiz {}
+impl Fiz for bool {}
+
+trait Grault {
+    type A;
+    type B;
+}
+
+impl Grault for () {
+    type A = ();
+    type B = bool;
+}
+
+impl<T> Grault for (T,)
+//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+where
+    T: Grault,
+    Self::A: Baz,
+{
+    type A = ();
+    type B = bool;
+}
+
+fn main() {
+    let _: <((),) as Grault>::A = ();
+}
diff --git a/tests/ui/associated-types/impl-wf-cycle-5.stderr b/tests/ui/associated-types/impl-wf-cycle-5.stderr
new file mode 100644
index 00000000000..284a50bb9a3
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-5.stderr
@@ -0,0 +1,31 @@
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+  --> $DIR/impl-wf-cycle-5.rs:20:1
+   |
+LL | / impl<T> Grault for (T,)
+LL | |
+LL | | where
+LL | |     T: Grault,
+LL | |     Self::A: Baz,
+   | |_________________^
+LL |   {
+LL |       type A = ();
+   |       ------ associated type `<(T,) as Grault>::A` is specified here
+   |
+note: required for `(T,)` to implement `Grault`
+  --> $DIR/impl-wf-cycle-5.rs:20:9
+   |
+LL | impl<T> Grault for (T,)
+   |         ^^^^^^     ^^^^
+...
+LL |     Self::A: Baz,
+   |              --- unsatisfied trait bound introduced here
+help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
+   |
+LL -     T: Grault,
+LL -     Self::A: Baz,
+LL +     T: Grault,
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/associated-types/impl-wf-cycle-6.fixed b/tests/ui/associated-types/impl-wf-cycle-6.fixed
new file mode 100644
index 00000000000..73ed64f7ce3
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-6.fixed
@@ -0,0 +1,30 @@
+// run-rustfix
+
+trait Baz {}
+impl Baz for () {}
+impl<T> Baz for (T,) {}
+
+trait Fiz {}
+impl Fiz for bool {}
+
+trait Grault {
+    type A;
+    type B;
+}
+
+impl Grault for () {
+    type A = ();
+    type B = bool;
+}
+
+impl<T: Grault> Grault for (T,)
+//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+
+{
+    type A = ();
+    type B = bool;
+}
+
+fn main() {
+    let _: <((),) as Grault>::A = ();
+}
diff --git a/tests/ui/associated-types/impl-wf-cycle-6.rs b/tests/ui/associated-types/impl-wf-cycle-6.rs
new file mode 100644
index 00000000000..20d635cac5d
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-6.rs
@@ -0,0 +1,31 @@
+// run-rustfix
+
+trait Baz {}
+impl Baz for () {}
+impl<T> Baz for (T,) {}
+
+trait Fiz {}
+impl Fiz for bool {}
+
+trait Grault {
+    type A;
+    type B;
+}
+
+impl Grault for () {
+    type A = ();
+    type B = bool;
+}
+
+impl<T: Grault> Grault for (T,)
+//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _`
+where
+    Self::A: Baz,
+{
+    type A = ();
+    type B = bool;
+}
+
+fn main() {
+    let _: <((),) as Grault>::A = ();
+}
diff --git a/tests/ui/associated-types/impl-wf-cycle-6.stderr b/tests/ui/associated-types/impl-wf-cycle-6.stderr
new file mode 100644
index 00000000000..c9b5d8060be
--- /dev/null
+++ b/tests/ui/associated-types/impl-wf-cycle-6.stderr
@@ -0,0 +1,29 @@
+error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
+  --> $DIR/impl-wf-cycle-6.rs:20:1
+   |
+LL | / impl<T: Grault> Grault for (T,)
+LL | |
+LL | | where
+LL | |     Self::A: Baz,
+   | |_________________^
+LL |   {
+LL |       type A = ();
+   |       ------ associated type `<(T,) as Grault>::A` is specified here
+   |
+note: required for `(T,)` to implement `Grault`
+  --> $DIR/impl-wf-cycle-6.rs:20:17
+   |
+LL | impl<T: Grault> Grault for (T,)
+   |                 ^^^^^^     ^^^^
+...
+LL |     Self::A: Baz,
+   |              --- unsatisfied trait bound introduced here
+help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound
+   |
+LL - where
+LL -     Self::A: Baz,
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/associated-types/issue-38821.rs b/tests/ui/associated-types/issue-38821.rs
index 6753860e9ff..34c35d7acf1 100644
--- a/tests/ui/associated-types/issue-38821.rs
+++ b/tests/ui/associated-types/issue-38821.rs
@@ -22,7 +22,22 @@ pub trait Column: Expression {}
 
 #[derive(Debug, Copy, Clone)]
 //~^ ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
 pub enum ColumnInsertValue<Col, Expr> where
+//~^ ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+//~| ERROR the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
     Col: Column,
     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>,
 {
diff --git a/tests/ui/associated-types/issue-38821.stderr b/tests/ui/associated-types/issue-38821.stderr
index 8b628f5ae6d..0e34f541ea3 100644
--- a/tests/ui/associated-types/issue-38821.stderr
+++ b/tests/ui/associated-types/issue-38821.stderr
@@ -17,6 +17,272 @@ help: consider further restricting the associated type
 LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
    |                                                                       +++++++++++++++++++++++++++++++++++++++
 
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:38:1
+   |
+LL | pub enum ColumnInsertValue<Col, Expr> where
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull
+   |                                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:38:1
+   |
+LL | / pub enum ColumnInsertValue<Col, Expr> where
+LL | |
+LL | |
+LL | |     Col: Column,
+...  |
+LL | |     Default(Col),
+LL | | }
+   | |_^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull
+   |                                                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:10
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+   |                                                                       +++++++++++++++++++++++++++++++++++++++
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:10
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+   |                                                                       +++++++++++++++++++++++++++++++++++++++
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:10
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:10
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:17
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                 ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+   |                                                                       +++++++++++++++++++++++++++++++++++++++
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:23
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+   |                                                                       +++++++++++++++++++++++++++++++++++++++
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:23
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider further restricting the associated type
+   |
+LL |     Expr: Expression<SqlType=<Col::SqlType as IntoNullable>::Nullable>, <Col as Expression>::SqlType: NotNull,
+   |                                                                       +++++++++++++++++++++++++++++++++++++++
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:23
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:23
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:10
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:10
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:23
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not satisfied
+  --> $DIR/issue-38821.rs:23:23
+   |
+LL | #[derive(Debug, Copy, Clone)]
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
+   |
+note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
+  --> $DIR/issue-38821.rs:9:18
+   |
+LL | impl<T: NotNull> IntoNullable for T {
+   |         -------  ^^^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs
new file mode 100644
index 00000000000..99a5d56a309
--- /dev/null
+++ b/tests/ui/async-await/async-fn/simple.rs
@@ -0,0 +1,16 @@
+// edition: 2021
+// check-pass
+
+#![feature(async_fn_traits)]
+
+use std::ops::AsyncFn;
+
+async fn foo() {}
+
+async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 {
+    f(1).await
+}
+
+fn main() {
+    let fut = call_asyncly(|x| async move { x + 1 });
+}
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 814d4736197..d7d538c0b9e 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -125,7 +125,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_env = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_env` are: ``, `eabihf`, `gnu`, `gnueabihf`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `psx`, `relibc`, `sgx`, `uclibc`
+   = note: expected values for `target_env` are: ``, `eabihf`, `gnu`, `gnueabihf`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `preview2`, `psx`, `relibc`, `sgx`, `uclibc`
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -134,7 +134,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_family = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_family` are: `unix`, `wasm`, `windows`
+   = note: expected values for `target_family` are: `unix`, `wasi`, `wasm`, `windows`
    = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/coercion/issue-53475.rs b/tests/ui/coercion/issue-53475.rs
index 3770c024fb9..f389169f954 100644
--- a/tests/ui/coercion/issue-53475.rs
+++ b/tests/ui/coercion/issue-53475.rs
@@ -3,7 +3,7 @@
 use std::any::Any;
 use std::ops::CoerceUnsized;
 
-struct Foo<T> {
+struct Foo<T: ?Sized> {
     data: Box<T>,
 }
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs
index 7174d1ec4f2..dfb8a36ec53 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs
@@ -8,13 +8,11 @@ impl std::marker::ConstParamTy for ImplementsConstParamTy {}
 struct CantParam(ImplementsConstParamTy);
 
 impl std::marker::ConstParamTy for CantParam {}
-//~^ error: the type `CantParam` does not `#[derive(Eq)]`
-//~| error: the type `CantParam` does not `#[derive(PartialEq)]`
+//~^ error: the type `CantParam` does not `#[derive(PartialEq)]`
 //~| the trait bound `CantParam: Eq` is not satisfied
 
 #[derive(std::marker::ConstParamTy)]
-//~^ error: the type `CantParamDerive` does not `#[derive(Eq)]`
-//~| error: the type `CantParamDerive` does not `#[derive(PartialEq)]`
+//~^ error: the type `CantParamDerive` does not `#[derive(PartialEq)]`
 //~| the trait bound `CantParamDerive: Eq` is not satisfied
 struct CantParamDerive(ImplementsConstParamTy);
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr
index 2cf7cc07dbe..e213808cf7b 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr
@@ -21,17 +21,8 @@ LL | impl std::marker::ConstParamTy for CantParam {}
 note: required by a bound in `ConstParamTy`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
 
-error[E0277]: the type `CantParam` does not `#[derive(Eq)]`
-  --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36
-   |
-LL | impl std::marker::ConstParamTy for CantParam {}
-   |                                    ^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParam`
-   |
-note: required by a bound in `ConstParamTy`
-  --> $SRC_DIR/core/src/marker.rs:LL:COL
-
 error[E0277]: the trait bound `CantParamDerive: Eq` is not satisfied
-  --> $DIR/const_param_ty_impl_no_structural_eq.rs:15:10
+  --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10
    |
 LL | #[derive(std::marker::ConstParamTy)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive`
@@ -46,7 +37,7 @@ LL | struct CantParamDerive(ImplementsConstParamTy);
    |
 
 error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]`
-  --> $DIR/const_param_ty_impl_no_structural_eq.rs:15:10
+  --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10
    |
 LL | #[derive(std::marker::ConstParamTy)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive`
@@ -55,16 +46,6 @@ note: required by a bound in `ConstParamTy`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
    = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0277]: the type `CantParamDerive` does not `#[derive(Eq)]`
-  --> $DIR/const_param_ty_impl_no_structural_eq.rs:15:10
-   |
-LL | #[derive(std::marker::ConstParamTy)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParamDerive`
-   |
-note: required by a bound in `ConstParamTy`
-  --> $SRC_DIR/core/src/marker.rs:LL:COL
-   = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs
index c04e96c569b..f2986f9cc60 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs
@@ -1,5 +1,5 @@
 #![allow(incomplete_features)]
-#![feature(adt_const_params, structural_match)]
+#![feature(adt_const_params)]
 
 union Union {
     a: u8,
@@ -11,7 +11,6 @@ impl PartialEq for Union {
     }
 }
 impl Eq for Union {}
-impl std::marker::StructuralEq for Union {}
 
 impl std::marker::ConstParamTy for Union {}
 //~^ ERROR the type `Union` does not `#[derive(PartialEq)]`
@@ -28,7 +27,6 @@ impl PartialEq for UnionDerive {
     }
 }
 impl Eq for UnionDerive {}
-impl std::marker::StructuralEq for UnionDerive {}
 
 
 fn main() {}
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr
index 985b933c40c..4c937db6c3a 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr
@@ -1,11 +1,11 @@
 error: this trait cannot be derived for unions
-  --> $DIR/const_param_ty_impl_union.rs:19:10
+  --> $DIR/const_param_ty_impl_union.rs:18:10
    |
 LL | #[derive(std::marker::ConstParamTy)]
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: the type `Union` does not `#[derive(PartialEq)]`
-  --> $DIR/const_param_ty_impl_union.rs:16:36
+  --> $DIR/const_param_ty_impl_union.rs:15:36
    |
 LL | impl std::marker::ConstParamTy for Union {}
    |                                    ^^^^^ the trait `StructuralPartialEq` is not implemented for `Union`
diff --git a/tests/ui/const-generics/bad-generic-in-copy-impl.rs b/tests/ui/const-generics/bad-generic-in-copy-impl.rs
index b5663464cf4..092a7af236b 100644
--- a/tests/ui/const-generics/bad-generic-in-copy-impl.rs
+++ b/tests/ui/const-generics/bad-generic-in-copy-impl.rs
@@ -2,6 +2,7 @@
 pub struct Foo {
     x: [u8; SIZE],
     //~^ ERROR mismatched types
+    //~| ERROR mismatched types
 }
 
 const SIZE: u32 = 1;
diff --git a/tests/ui/const-generics/bad-generic-in-copy-impl.stderr b/tests/ui/const-generics/bad-generic-in-copy-impl.stderr
index d60d8ec0e90..fbd546d42fb 100644
--- a/tests/ui/const-generics/bad-generic-in-copy-impl.stderr
+++ b/tests/ui/const-generics/bad-generic-in-copy-impl.stderr
@@ -4,6 +4,14 @@ error[E0308]: mismatched types
 LL |     x: [u8; SIZE],
    |             ^^^^ expected `usize`, found `u32`
 
-error: aborting due to 1 previous error
+error[E0308]: mismatched types
+  --> $DIR/bad-generic-in-copy-impl.rs:3:13
+   |
+LL |     x: [u8; SIZE],
+   |             ^^^^ expected `usize`, found `u32`
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
index 3bae93ccb83..220fcd38b09 100644
--- a/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/typeid-equality-by-subtyping.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `TypeId` in a pattern, `TypeId` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/typeid-equality-by-subtyping.rs:18:9
    |
 LL |         WHAT_A_TYPE => 0,
    |         ^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/const-generics/issues/issue-61336-2.stderr b/tests/ui/const-generics/issues/issue-61336-2.stderr
index 9064c2d0b94..b0864689f74 100644
--- a/tests/ui/const-generics/issues/issue-61336-2.stderr
+++ b/tests/ui/const-generics/issues/issue-61336-2.stderr
@@ -6,7 +6,7 @@ LL |     [x; { N }]
    |
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider restricting type parameter `T`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
diff --git a/tests/ui/const-generics/issues/issue-61336.stderr b/tests/ui/const-generics/issues/issue-61336.stderr
index 9935d6c1689..111afbda343 100644
--- a/tests/ui/const-generics/issues/issue-61336.stderr
+++ b/tests/ui/const-generics/issues/issue-61336.stderr
@@ -6,7 +6,7 @@ LL |     [x; N]
    |
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider restricting type parameter `T`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
diff --git a/tests/ui/const-generics/issues/issue-74950.min.stderr b/tests/ui/const-generics/issues/issue-74950.min.stderr
index 54ef1ea1e94..a573dac6087 100644
--- a/tests/ui/const-generics/issues/issue-74950.min.stderr
+++ b/tests/ui/const-generics/issues/issue-74950.min.stderr
@@ -1,5 +1,5 @@
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:20:23
+  --> $DIR/issue-74950.rs:19:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -8,7 +8,7 @@ LL | struct Outer<const I: Inner>;
    = help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
 
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:20:23
+  --> $DIR/issue-74950.rs:19:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -18,7 +18,7 @@ LL | struct Outer<const I: Inner>;
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:20:23
+  --> $DIR/issue-74950.rs:19:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -28,7 +28,7 @@ LL | struct Outer<const I: Inner>;
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:20:23
+  --> $DIR/issue-74950.rs:19:23
    |
 LL | struct Outer<const I: Inner>;
    |                       ^^^^^
@@ -37,15 +37,5 @@ LL | struct Outer<const I: Inner>;
    = help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: `Inner` is forbidden as the type of a const generic parameter
-  --> $DIR/issue-74950.rs:20:23
-   |
-LL | struct Outer<const I: Inner>;
-   |                       ^^^^^
-   |
-   = note: the only supported types are integers, `bool` and `char`
-   = help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-74950.rs b/tests/ui/const-generics/issues/issue-74950.rs
index 43bb322656b..f1f9bd16ebe 100644
--- a/tests/ui/const-generics/issues/issue-74950.rs
+++ b/tests/ui/const-generics/issues/issue-74950.rs
@@ -15,13 +15,11 @@ struct Inner;
 // - impl PartialEq
 // - impl Eq
 // - impl StructuralPartialEq
-// - impl StructuralEq
 #[derive(PartialEq, Eq)]
 struct Outer<const I: Inner>;
 //[min]~^ `Inner` is forbidden
 //[min]~| `Inner` is forbidden
 //[min]~| `Inner` is forbidden
 //[min]~| `Inner` is forbidden
-//[min]~| `Inner` is forbidden
 
 fn main() {}
diff --git a/tests/ui/consts/const-blocks/migrate-fail.stderr b/tests/ui/consts/const-blocks/migrate-fail.stderr
index 95fece0ae8a..3c116026e58 100644
--- a/tests/ui/consts/const-blocks/migrate-fail.stderr
+++ b/tests/ui/consts/const-blocks/migrate-fail.stderr
@@ -7,7 +7,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL + #[derive(Copy)]
@@ -23,7 +23,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL + #[derive(Copy)]
diff --git a/tests/ui/consts/const-blocks/nll-fail.stderr b/tests/ui/consts/const-blocks/nll-fail.stderr
index ed1dc78f77d..ff2b62da668 100644
--- a/tests/ui/consts/const-blocks/nll-fail.stderr
+++ b/tests/ui/consts/const-blocks/nll-fail.stderr
@@ -7,7 +7,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL + #[derive(Copy)]
@@ -23,7 +23,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL + #[derive(Copy)]
diff --git a/tests/ui/consts/const-err-late.stderr b/tests/ui/consts/const-err-late.stderr
index 35c3d000117..53badeafa35 100644
--- a/tests/ui/consts/const-err-late.stderr
+++ b/tests/ui/consts/const-err-late.stderr
@@ -30,6 +30,14 @@ LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+note: erroneous constant encountered
+  --> $DIR/const-err-late.rs:19:31
+   |
+LL |     black_box((S::<i32>::FOO, S::<u32>::FOO));
+   |                               ^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
index ab297f54dff..69f5e66f5af 100644
--- a/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
+++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.rs
@@ -11,14 +11,14 @@ fn main() {
     let _ = Defaulted;
     match None {
         consts::SOME => panic!(),
-        //~^ must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ must be annotated with `#[derive(PartialEq)]`
 
         _ => {}
     }
 
     match None {
         <Defaulted as consts::AssocConst>::SOME  => panic!(),
-        //~^ must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ must be annotated with `#[derive(PartialEq)]`
 
         _ => {}
     }
diff --git a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
index 2f6786999ed..067f2b6e674 100644
--- a/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
+++ b/tests/ui/consts/const_in_pattern/cross-crate-fail.stderr
@@ -1,20 +1,20 @@
-error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cross-crate-fail.rs:13:9
    |
 LL |         consts::SOME => panic!(),
    |         ^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cross-crate-fail.rs:20:9
    |
 LL |         <Defaulted as consts::AssocConst>::SOME  => panic!(),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
index 41de5e7b4fe..34b1422dfb3 100644
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
+++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.rs
@@ -27,9 +27,9 @@ const BAR_BAZ: Foo = if 42 == 42 {
 fn main() {
     match Foo::Qux(CustomEq) {
         BAR_BAZ => panic!(),
-        //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ WARN must be annotated with `#[derive(PartialEq)]`
         //~| NOTE the traits must be derived
-        //~| NOTE StructuralEq.html for details
+        //~| NOTE StructuralPartialEq.html for details
         //~| WARN this was previously accepted
         //~| NOTE see issue #73448
         //~| NOTE `#[warn(nontrivial_structural_match)]` on by default
diff --git a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
index 3f19c67d223..c473c00f8db 100644
--- a/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
+++ b/tests/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr
@@ -1,4 +1,4 @@
-warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/custom-eq-branch-warn.rs:29:9
    |
 LL |         BAR_BAZ => panic!(),
@@ -7,7 +7,7 @@ LL |         BAR_BAZ => panic!(),
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
    = note: `#[warn(nontrivial_structural_match)]` on by default
 
 warning: 1 warning emitted
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.rs b/tests/ui/consts/const_in_pattern/incomplete-slice.rs
index e1ccda71d40..4984acaaf79 100644
--- a/tests/ui/consts/const_in_pattern/incomplete-slice.rs
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.rs
@@ -7,9 +7,7 @@ const E_SL: &[E] = &[E::A];
 
 fn main() {
     match &[][..] {
-        //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004]
+        //~^ ERROR non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered [E0004]
         E_SL => {}
-        //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
-        //~| WARN this was previously accepted by the compiler but is being phased out
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
index 4ecfb3f1c5a..bd61f43727b 100644
--- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
+++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr
@@ -1,28 +1,16 @@
-warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/incomplete-slice.rs:11:9
-   |
-LL |         E_SL => {}
-   |         ^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-   = note: `#[warn(indirect_structural_match)]` on by default
-
-error[E0004]: non-exhaustive patterns: `&_` not covered
+error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered
   --> $DIR/incomplete-slice.rs:9:11
    |
 LL |     match &[][..] {
-   |           ^^^^^^^ pattern `&_` not covered
+   |           ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered
    |
    = note: the matched value is of type `&[E]`
-help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
    |
 LL ~         E_SL => {},
-LL +         &_ => todo!()
+LL +         &[] | &[_, _, ..] => todo!()
    |
 
-error: aborting due to 1 previous error; 1 warning emitted
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/consts/const_in_pattern/issue-78057.rs b/tests/ui/consts/const_in_pattern/issue-78057.rs
deleted file mode 100644
index 88b5d68cb60..00000000000
--- a/tests/ui/consts/const_in_pattern/issue-78057.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![deny(unreachable_patterns)]
-
-#[derive(PartialEq)]
-struct Opaque(i32);
-
-impl Eq for Opaque {}
-
-const FOO: Opaque = Opaque(42);
-
-fn main() {
-    match FOO {
-        FOO => {},
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        _ => {}
-    }
-}
diff --git a/tests/ui/consts/const_in_pattern/issue-78057.stderr b/tests/ui/consts/const_in_pattern/issue-78057.stderr
deleted file mode 100644
index 719295c96a5..00000000000
--- a/tests/ui/consts/const_in_pattern/issue-78057.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: to use a constant of type `Opaque` in a pattern, `Opaque` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/issue-78057.rs:12:9
-   |
-LL |         FOO => {},
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
index fc80d51c72d..141d87d9b70 100644
--- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
+++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.rs
@@ -19,7 +19,7 @@ const BAR_BAZ: Foo = if 42 == 42 {
 fn main() {
     match Foo::Qux(NoEq) {
         BAR_BAZ => panic!(),
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
         _ => {}
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
index 1979c297ae4..b29f959de97 100644
--- a/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
+++ b/tests/ui/consts/const_in_pattern/no-eq-branch-fail.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/no-eq-branch-fail.rs:21:9
    |
 LL |         BAR_BAZ => panic!(),
    |         ^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs b/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs
index 436a2d0de74..515c79d9457 100644
--- a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs
+++ b/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.rs
@@ -1,6 +1,4 @@
 // run-pass
-// Eventually this will be rejected (when the future-compat lints are turned into hard errors), and
-// then this test can be removed. But meanwhile we should ensure that this works and does not ICE.
 struct NoDerive(#[allow(dead_code)] i32);
 
 #[derive(PartialEq)]
@@ -11,8 +9,6 @@ const WRAP_UNSAFE_EMBEDDED: &&WrapEmbedded = &&WrapEmbedded(std::ptr::null());
 fn main() {
     let b = match WRAP_UNSAFE_EMBEDDED {
         WRAP_UNSAFE_EMBEDDED => true,
-        //~^ WARN: must be annotated with `#[derive(PartialEq, Eq)]`
-        //~| previously accepted
         _ => false,
     };
     assert!(b);
diff --git a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.stderr b/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.stderr
deleted file mode 100644
index c186d349e72..00000000000
--- a/tests/ui/consts/const_in_pattern/null-raw-ptr-issue-119270.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-warning: to use a constant of type `WrapEmbedded` in a pattern, `WrapEmbedded` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/null-raw-ptr-issue-119270.rs:13:9
-   |
-LL |         WRAP_UNSAFE_EMBEDDED => true,
-   |         ^^^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-   = note: `#[warn(indirect_structural_match)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
index a8216901c02..86d971044fe 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.rs
@@ -26,7 +26,7 @@ fn main() {
 
     match None {
         NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
         _ => panic!("whoops"),
     }
 }
diff --git a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
index d3628a8decb..88b82d5004b 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_partial_eq.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoPartialEq` in a pattern, `NoPartialEq` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_partial_eq.rs:28:9
    |
 LL |         NO_PARTIAL_EQ_NONE => println!("NO_PARTIAL_EQ_NONE"),
    |         ^^^^^^^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
index df772740ab1..196930baed5 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs
@@ -40,65 +40,65 @@ fn main() {
 
     const ENUM: Derive<NoDerive> = Derive::Some(NoDerive);
     match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const FIELD: OND = TrivialEq(Some(NoDerive)).0;
     match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const NO_DERIVE_SOME: OND = Some(NoDerive);
     const INDIRECT: OND = NO_DERIVE_SOME;
     match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const TUPLE: (OND, OND) = (None, Some(NoDerive));
     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const TYPE_ASCRIPTION: OND = type_ascribe!(Some(NoDerive), OND);
     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const ARRAY: [OND; 2] = [None, Some(NoDerive)];
     match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const REPEAT: [OND; 2] = [Some(NoDerive); 2];
     match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     trait Trait: Sized { const ASSOC: Option<Self>; }
     impl Trait for NoDerive { const ASSOC: Option<NoDerive> = Some(NoDerive); }
     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const BLOCK: OND = { NoDerive; Some(NoDerive) };
     match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
 
     const ADDR_OF: &OND = &Some(NoDerive);
     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
-    //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ WARN must be annotated with `#[derive(PartialEq)]`
     //~| NOTE the traits must be derived
-    //~| NOTE StructuralEq.html for details
+    //~| NOTE StructuralPartialEq.html for details
     //~| WARN previously accepted by the compiler but is being phased out
     //~| NOTE for more information, see issue #62411
 }
diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
index 72bb0aeafa4..da32b6d698b 100644
--- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
+++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr
@@ -1,85 +1,85 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:42:36
    |
 LL |     match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), };
    |                                    ^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:48:28
    |
 LL |     match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), };
    |                            ^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:55:27
    |
 LL |     match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), };
    |                           ^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:61:36
    |
 LL |     match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), };
    |                                    ^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:67:28
    |
 LL |     match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), };
    |                            ^^^^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:73:36
    |
 LL |     match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), };
    |                                    ^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:79:33
    |
 LL |     match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), };
    |                                 ^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:86:28
    |
 LL |     match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), };
    |                            ^^^^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:92:28
    |
 LL |     match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), };
    |                            ^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/reject_non_structural.rs:98:29
    |
 LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), };
@@ -88,7 +88,7 @@ LL |     match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops")
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/reject_non_structural.rs:14:9
    |
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
index d23d85335f8..75f1965921c 100644
--- a/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
+++ b/tests/ui/consts/const_in_pattern/warn_corner_cases.rs
@@ -24,18 +24,18 @@ impl Eq for NoDerive { }
 fn main() {
     const INDEX: Option<NoDerive> = [None, Some(NoDerive(10))][0];
     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
-    //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ WARN must be annotated with `#[derive(PartialEq)]`
     //~| WARN this was previously accepted
 
     const fn build() -> Option<NoDerive> { None }
     const CALL: Option<NoDerive> = build();
     match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
-    //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ WARN must be annotated with `#[derive(PartialEq)]`
     //~| WARN this was previously accepted
 
     impl NoDerive { const fn none() -> Option<NoDerive> { None } }
     const METHOD_CALL: Option<NoDerive> = NoDerive::none();
     match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
-    //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ WARN must be annotated with `#[derive(PartialEq)]`
     //~| WARN this was previously accepted
 }
diff --git a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
index 8c01d2f65ec..8ffd035ebec 100644
--- a/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
+++ b/tests/ui/consts/const_in_pattern/warn_corner_cases.stderr
@@ -1,4 +1,4 @@
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/warn_corner_cases.rs:26:47
    |
 LL |     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
@@ -7,10 +7,10 @@ LL |     match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), };
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
    = note: `#[warn(nontrivial_structural_match)]` on by default
 
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/warn_corner_cases.rs:32:47
    |
 LL |     match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
@@ -19,9 +19,9 @@ LL |     match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), };
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
-warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/warn_corner_cases.rs:38:47
    |
 LL |     match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), };
@@ -30,7 +30,7 @@ LL |     match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CA
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 warning: 3 warnings emitted
 
diff --git a/tests/ui/consts/is_val_statically_known.rs b/tests/ui/consts/is_val_statically_known.rs
new file mode 100644
index 00000000000..b0565842eb4
--- /dev/null
+++ b/tests/ui/consts/is_val_statically_known.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+#![feature(core_intrinsics)]
+#![feature(is_val_statically_known)]
+
+use std::intrinsics::is_val_statically_known;
+
+const CONST_TEST: bool = unsafe { is_val_statically_known(0) };
+
+fn main() {
+    if CONST_TEST {
+        unreachable!("currently expected to return false during const eval");
+        // but note that this is not a guarantee!
+    }
+}
diff --git a/tests/ui/consts/issue-65348.rs b/tests/ui/consts/issue-65348.rs
index 5eafa831d63..01bf2a3fa42 100644
--- a/tests/ui/consts/issue-65348.rs
+++ b/tests/ui/consts/issue-65348.rs
@@ -8,15 +8,16 @@ impl<T> Generic<T> {
     const ARRAY_FIELD: Generic<(i32, [T; 0])> = Generic((0, []));
 }
 
-pub const fn array<T>() ->  &'static T {
+pub const fn array<T>() -> &'static T {
+    #[allow(unconditional_panic)]
     &Generic::<T>::ARRAY[0]
 }
 
-pub const fn newtype_array<T>() ->  &'static T {
+pub const fn newtype_array<T>() -> &'static T {
     &Generic::<T>::NEWTYPE_ARRAY.0[0]
 }
 
-pub const fn array_field<T>() ->  &'static T {
+pub const fn array_field<T>() -> &'static T {
     &(Generic::<T>::ARRAY_FIELD.0).1[0]
 }
 
diff --git a/tests/ui/consts/match_ice.rs b/tests/ui/consts/match_ice.rs
index 632335c841e..ed1fd78809b 100644
--- a/tests/ui/consts/match_ice.rs
+++ b/tests/ui/consts/match_ice.rs
@@ -9,7 +9,7 @@ fn main() {
     const C: &S = &S;
     match C {
         C => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
     }
     const K: &T = &T;
     match K {
diff --git a/tests/ui/consts/match_ice.stderr b/tests/ui/consts/match_ice.stderr
index fb5cbe0ed89..472c24a5cbe 100644
--- a/tests/ui/consts/match_ice.stderr
+++ b/tests/ui/consts/match_ice.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/match_ice.rs:11:9
    |
 LL |         C => {}
    |         ^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index 42154c3c3be..9c6f4d3094b 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -56,8 +56,6 @@ impl ::core::cmp::PartialEq for Empty {
     fn eq(&self, other: &Empty) -> bool { true }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Empty { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Empty {
     #[inline]
     #[doc(hidden)]
@@ -132,8 +130,6 @@ impl ::core::cmp::PartialEq for Point {
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Point { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Point {
     #[inline]
     #[doc(hidden)]
@@ -219,8 +215,6 @@ impl ::core::cmp::PartialEq for PackedPoint {
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for PackedPoint { }
-#[automatically_derived]
 impl ::core::cmp::Eq for PackedPoint {
     #[inline]
     #[doc(hidden)]
@@ -333,8 +327,6 @@ impl ::core::cmp::PartialEq for Big {
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Big { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Big {
     #[inline]
     #[doc(hidden)]
@@ -500,8 +492,6 @@ impl ::core::cmp::PartialEq for Unsized {
     fn eq(&self, other: &Unsized) -> bool { self.0 == other.0 }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Unsized { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Unsized {
     #[inline]
     #[doc(hidden)]
@@ -616,8 +606,6 @@ impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
     }
 }
 #[automatically_derived]
-impl<T: Trait, U> ::core::marker::StructuralEq for Generic<T, U> { }
-#[automatically_derived]
 impl<T: ::core::cmp::Eq + Trait, U: ::core::cmp::Eq> ::core::cmp::Eq for
     Generic<T, U> where T::A: ::core::cmp::Eq {
     #[inline]
@@ -739,8 +727,6 @@ impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
     }
 }
 #[automatically_derived]
-impl<T: Trait, U> ::core::marker::StructuralEq for PackedGeneric<T, U> { }
-#[automatically_derived]
 impl<T: ::core::cmp::Eq + ::core::marker::Copy + Trait, U: ::core::cmp::Eq +
     ::core::marker::Copy> ::core::cmp::Eq for PackedGeneric<T, U> where
     T::A: ::core::cmp::Eq + ::core::marker::Copy {
@@ -825,8 +811,6 @@ impl ::core::cmp::PartialEq for Enum0 {
     fn eq(&self, other: &Enum0) -> bool { match *self {} }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Enum0 { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Enum0 {
     #[inline]
     #[doc(hidden)]
@@ -897,8 +881,6 @@ impl ::core::cmp::PartialEq for Enum1 {
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Enum1 { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Enum1 {
     #[inline]
     #[doc(hidden)]
@@ -965,8 +947,6 @@ impl ::core::cmp::PartialEq for Fieldless1 {
     fn eq(&self, other: &Fieldless1) -> bool { true }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Fieldless1 { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Fieldless1 {
     #[inline]
     #[doc(hidden)]
@@ -1041,8 +1021,6 @@ impl ::core::cmp::PartialEq for Fieldless {
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Fieldless { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Fieldless {
     #[inline]
     #[doc(hidden)]
@@ -1150,8 +1128,6 @@ impl ::core::cmp::PartialEq for Mixed {
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Mixed { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Mixed {
     #[inline]
     #[doc(hidden)]
@@ -1279,8 +1255,6 @@ impl ::core::cmp::PartialEq for Fielded {
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for Fielded { }
-#[automatically_derived]
 impl ::core::cmp::Eq for Fielded {
     #[inline]
     #[doc(hidden)]
@@ -1402,8 +1376,6 @@ impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
     }
 }
 #[automatically_derived]
-impl<T, U> ::core::marker::StructuralEq for EnumGeneric<T, U> { }
-#[automatically_derived]
 impl<T: ::core::cmp::Eq, U: ::core::cmp::Eq> ::core::cmp::Eq for
     EnumGeneric<T, U> {
     #[inline]
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr
index 3c474d19d1d..eed01267224 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr
@@ -191,7 +191,14 @@ error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:33:10
    |
 LL | type H = Fn(u8) -> (u8)::Output;
-   |          ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output`
+   |          ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use fully-qualified syntax
+   |
+LL | type H = <(dyn Fn(u8) -> u8 + 'static) as AsyncFnOnce>::Output;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output;
+   |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0223]: ambiguous associated type
   --> $DIR/bad-assoc-ty.rs:39:19
diff --git a/tests/ui/dst/dst-bad-assign-3.stderr b/tests/ui/dst/dst-bad-assign-3.stderr
index 6dd3434fd21..007f6b898be 100644
--- a/tests/ui/dst/dst-bad-assign-3.stderr
+++ b/tests/ui/dst/dst-bad-assign-3.stderr
@@ -8,6 +8,7 @@ LL |     f5.2 = Bar1 {f: 36};
    |
    = note: expected trait object `dyn ToBar`
                     found struct `Bar1`
+   = help: `Bar1` implements `ToBar` so you could box the found value and coerce it to the trait object `Box<dyn ToBar>`, you will have to change the expected type as well
 
 error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time
   --> $DIR/dst-bad-assign-3.rs:33:5
diff --git a/tests/ui/dst/dst-bad-assign.stderr b/tests/ui/dst/dst-bad-assign.stderr
index d8d1057876f..f935d27e96e 100644
--- a/tests/ui/dst/dst-bad-assign.stderr
+++ b/tests/ui/dst/dst-bad-assign.stderr
@@ -8,6 +8,7 @@ LL |     f5.ptr = Bar1 {f: 36};
    |
    = note: expected trait object `dyn ToBar`
                     found struct `Bar1`
+   = help: `Bar1` implements `ToBar` so you could box the found value and coerce it to the trait object `Box<dyn ToBar>`, you will have to change the expected type as well
 
 error[E0277]: the size for values of type `dyn ToBar` cannot be known at compilation time
   --> $DIR/dst-bad-assign.rs:35:5
diff --git a/tests/ui/dyn-star/no-implicit-dyn-star.stderr b/tests/ui/dyn-star/no-implicit-dyn-star.stderr
index 06c7bcc5748..bea334a8a69 100644
--- a/tests/ui/dyn-star/no-implicit-dyn-star.stderr
+++ b/tests/ui/dyn-star/no-implicit-dyn-star.stderr
@@ -8,6 +8,7 @@ LL |     dyn_star_foreign::require_dyn_star_display(1usize);
    |
    = note: expected trait object `(dyn* std::fmt::Display + 'static)`
                       found type `usize`
+   = help: `usize` implements `Display`, `#[feature(dyn_star)]` is likely not enabled; that feature it is currently incomplete
 note: function defined here
   --> $DIR/auxiliary/dyn-star-foreign.rs:6:8
    |
diff --git a/tests/ui/enum-discriminant/issue-72554.rs b/tests/ui/enum-discriminant/issue-72554.rs
index 54f7e9ac592..1fe9a5f4faa 100644
--- a/tests/ui/enum-discriminant/issue-72554.rs
+++ b/tests/ui/enum-discriminant/issue-72554.rs
@@ -3,6 +3,7 @@ use std::collections::BTreeSet;
 #[derive(Hash)]
 pub enum ElemDerived {
     //~^ ERROR recursive type `ElemDerived` has infinite size
+    //~| ERROR cycle detected
     A(ElemDerived)
 }
 
diff --git a/tests/ui/enum-discriminant/issue-72554.stderr b/tests/ui/enum-discriminant/issue-72554.stderr
index 381f24d351e..648680c6031 100644
--- a/tests/ui/enum-discriminant/issue-72554.stderr
+++ b/tests/ui/enum-discriminant/issue-72554.stderr
@@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size
    |
 LL | pub enum ElemDerived {
    | ^^^^^^^^^^^^^^^^^^^^
-LL |
+...
 LL |     A(ElemDerived)
    |       ----------- recursive without indirection
    |
@@ -12,6 +12,21 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
 LL |     A(Box<ElemDerived>)
    |       ++++           +
 
-error: aborting due to 1 previous error
+error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived`
+  --> $DIR/issue-72554.rs:4:1
+   |
+LL | pub enum ElemDerived {
+   | ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again
+note: cycle used when computing drop-check constraints for `Elem`
+  --> $DIR/issue-72554.rs:11:1
+   |
+LL | pub enum Elem {
+   | ^^^^^^^^^^^^^
+   = 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
 
-For more information about this error, try `rustc --explain E0072`.
+Some errors have detailed explanations: E0072, E0391.
+For more information about an error, try `rustc --explain E0072`.
diff --git a/tests/ui/for-loop-while/issue-69841.rs b/tests/ui/for-loop-while/issue-69841.rs
index 1aca16ca804..942b99b742b 100644
--- a/tests/ui/for-loop-while/issue-69841.rs
+++ b/tests/ui/for-loop-while/issue-69841.rs
@@ -2,7 +2,6 @@
 // LLVM bug which needed a fix to be backported.
 
 // run-pass
-// no-system-llvm
 
 fn main() {
     let buffer = [49u8, 10];
diff --git a/tests/ui/generic-associated-types/issue-79422.extended.stderr b/tests/ui/generic-associated-types/issue-79422.extended.stderr
index 14492266cda..ae1526296a7 100644
--- a/tests/ui/generic-associated-types/issue-79422.extended.stderr
+++ b/tests/ui/generic-associated-types/issue-79422.extended.stderr
@@ -27,6 +27,7 @@ LL |     type VRefCont<'a> = &'a V where Self: 'a;
    |                         ^^^^^
    = note: expected trait object `(dyn RefCont<'_, u8> + 'static)`
                  found reference `&u8`
+   = help: `&u8` implements `RefCont` so you could box the found value and coerce it to the trait object `Box<dyn RefCont>`, you will have to change the expected type as well
    = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/impl-trait/dyn-impl-type-mismatch.rs b/tests/ui/impl-trait/dyn-impl-type-mismatch.rs
new file mode 100644
index 00000000000..c6170abb582
--- /dev/null
+++ b/tests/ui/impl-trait/dyn-impl-type-mismatch.rs
@@ -0,0 +1,18 @@
+trait Trait {}
+struct Struct;
+impl Trait for Struct {}
+fn foo() -> impl Trait {
+    Struct
+}
+fn main() {
+    let a: Box<dyn Trait> = if true {
+        Box::new(Struct)
+    } else {
+        foo() //~ ERROR E0308
+    };
+    let a: dyn Trait = if true {
+        Struct //~ ERROR E0308
+    } else {
+        foo() //~ ERROR E0308
+    };
+}
diff --git a/tests/ui/impl-trait/dyn-impl-type-mismatch.stderr b/tests/ui/impl-trait/dyn-impl-type-mismatch.stderr
new file mode 100644
index 00000000000..ddbdaf3eb4b
--- /dev/null
+++ b/tests/ui/impl-trait/dyn-impl-type-mismatch.stderr
@@ -0,0 +1,43 @@
+error[E0308]: mismatched types
+  --> $DIR/dyn-impl-type-mismatch.rs:11:9
+   |
+LL | fn foo() -> impl Trait {
+   |             ---------- the found opaque type
+...
+LL |         foo()
+   |         ^^^^^ expected `Box<dyn Trait>`, found opaque type
+   |
+   = note:   expected struct `Box<dyn Trait>`
+           found opaque type `impl Trait`
+   = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+help: store this in the heap by calling `Box::new`
+   |
+LL |         Box::new(foo())
+   |         +++++++++     +
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-impl-type-mismatch.rs:14:9
+   |
+LL |         Struct
+   |         ^^^^^^ expected `dyn Trait`, found `Struct`
+   |
+   = note: expected trait object `dyn Trait`
+                    found struct `Struct`
+   = help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
+
+error[E0308]: mismatched types
+  --> $DIR/dyn-impl-type-mismatch.rs:16:9
+   |
+LL | fn foo() -> impl Trait {
+   |             ---------- the found opaque type
+...
+LL |         foo()
+   |         ^^^^^ expected `dyn Trait`, found opaque type
+   |
+   = note: expected trait object `dyn Trait`
+               found opaque type `impl Trait`
+   = help: you can box the `impl Trait` to coerce it to `Box<dyn Trait>`, but you'll have to change the expected type as well
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index 4a52f82540d..9cc199d1e0e 100644
--- a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -6,6 +6,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) }
    |
    = note: expected trait object `(dyn Trait + 'static)`
                     found struct `Struct`
+   = help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
 
 error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:7:13
@@ -27,6 +28,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
    |
    = note: expected trait object `(dyn Trait + 'static)`
                     found struct `Struct`
+   = help: `Struct` implements `Trait` so you could box the found value and coerce it to the trait object `Box<dyn Trait>`, you will have to change the expected type as well
 
 error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:10:13
diff --git a/tests/ui/issue-76387-llvm-miscompile.rs b/tests/ui/issue-76387-llvm-miscompile.rs
index a9b4686c970..a7fc9da6339 100644
--- a/tests/ui/issue-76387-llvm-miscompile.rs
+++ b/tests/ui/issue-76387-llvm-miscompile.rs
@@ -1,4 +1,3 @@
-// no-system-llvm
 // compile-flags: -C opt-level=3
 // aux-build: issue-76387.rs
 // run-pass
diff --git a/tests/ui/methods/issues/issue-61525.stderr b/tests/ui/methods/issues/issue-61525.stderr
index a329b52e373..2670a3e4755 100644
--- a/tests/ui/methods/issues/issue-61525.stderr
+++ b/tests/ui/methods/issues/issue-61525.stderr
@@ -27,6 +27,7 @@ LL |         1.query::<dyn ToString>("")
    |
    = note: expected trait object `dyn ToString`
                  found reference `&'static str`
+   = help: `&'static str` implements `ToString` so you could box the found value and coerce it to the trait object `Box<dyn ToString>`, you will have to change the expected type as well
 note: method defined here
   --> $DIR/issue-61525.rs:2:8
    |
diff --git a/tests/ui/pattern/issue-115599.rs b/tests/ui/pattern/issue-115599.rs
index 7a222b90aec..1521d728d95 100644
--- a/tests/ui/pattern/issue-115599.rs
+++ b/tests/ui/pattern/issue-115599.rs
@@ -3,5 +3,5 @@ const CONST_STRING: String = String::new();
 fn main() {
     let empty_str = String::from("");
     if let CONST_STRING = empty_str {}
-    //~^ ERROR to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]`
+    //~^ ERROR to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq)]`
 }
diff --git a/tests/ui/pattern/issue-115599.stderr b/tests/ui/pattern/issue-115599.stderr
index c1e85d0bb48..adab4e4d241 100644
--- a/tests/ui/pattern/issue-115599.stderr
+++ b/tests/ui/pattern/issue-115599.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `Vec<u8>` in a pattern, `Vec<u8>` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-115599.rs:5:12
    |
 LL |     if let CONST_STRING = empty_str {}
    |            ^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
index 02599d7c05b..f34093ef149 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.rs
@@ -12,7 +12,7 @@ const CONSTANT: &&MyType = &&MyType;
 
 fn main() {
     if let CONSTANT = &&MyType {
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
         println!("did match!");
     }
 }
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
index 2352ecd0a47..0b4d9972758 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `MyType` in a pattern, `MyType` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/const-partial_eq-fallback-ice.rs:14:12
    |
 LL |     if let CONSTANT = &&MyType {
    |            ^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs
index 27e305a3972..3e461785182 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.rs
+++ b/tests/ui/pattern/usefulness/consts-opaque.rs
@@ -29,65 +29,63 @@ const BAZ: Baz = Baz::Baz1;
 fn main() {
     match FOO {
         FOO => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         _ => {}
     }
 
     match FOO_REF {
         FOO_REF => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         Foo(_) => {}
     }
 
     // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071)
     match FOO_REF_REF {
         FOO_REF_REF => {}
-        //~^ WARNING must be annotated with `#[derive(PartialEq, Eq)]`
-        //~| WARNING this was previously accepted by the compiler but is being phased out
         Foo(_) => {}
     }
 
     match BAR {
         Bar => {}
         BAR => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR unreachable pattern
         _ => {}
+        //~^ ERROR unreachable pattern
     }
 
     match BAR {
         BAR => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         Bar => {}
+        //~^ ERROR unreachable pattern
         _ => {}
+        //~^ ERROR unreachable pattern
     }
 
     match BAR {
         BAR => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        BAR => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        _ => {}
+        BAR => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
+        _ => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
     }
 
     match BAZ {
         BAZ => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        Baz::Baz1 => {}
+        Baz::Baz1 => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
         _ => {}
     }
 
     match BAZ {
         Baz::Baz1 => {}
         BAZ => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR unreachable pattern
         _ => {}
     }
 
     match BAZ {
         BAZ => {}
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
         Baz::Baz2 => {}
-        _ => {}
+        _ => {} // should not be emitting unreachable warning
+        //~^ ERROR unreachable pattern
     }
 
     type Quux = fn(usize, usize) -> usize;
diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr
index 09f72ba927e..0b1a2e2736e 100644
--- a/tests/ui/pattern/usefulness/consts-opaque.stderr
+++ b/tests/ui/pattern/usefulness/consts-opaque.stderr
@@ -1,98 +1,5 @@
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:31:9
-   |
-LL |         FOO => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:37:9
-   |
-LL |         FOO_REF => {}
-   |         ^^^^^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:44:9
-   |
-LL |         FOO_REF_REF => {}
-   |         ^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-   = note: `#[warn(indirect_structural_match)]` on by default
-
-error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:52:9
-   |
-LL |         BAR => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:58:9
-   |
-LL |         BAR => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:65:9
-   |
-LL |         BAR => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:67:9
-   |
-LL |         BAR => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:73:9
-   |
-LL |         BAZ => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:81:9
-   |
-LL |         BAZ => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/consts-opaque.rs:87:9
-   |
-LL |         BAZ => {}
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:98:9
+  --> $DIR/consts-opaque.rs:96:9
    |
 LL |         QUUX => {}
    |         ^^^^
@@ -102,7 +9,7 @@ LL |         QUUX => {}
    = note: `#[warn(pointer_structural_match)]` on by default
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:100:9
+  --> $DIR/consts-opaque.rs:98:9
    |
 LL |         QUUX => {}
    |         ^^^^
@@ -111,7 +18,7 @@ LL |         QUUX => {}
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:110:9
+  --> $DIR/consts-opaque.rs:108:9
    |
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
@@ -120,7 +27,7 @@ LL |         WRAPQUUX => {}
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:112:9
+  --> $DIR/consts-opaque.rs:110:9
    |
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
@@ -129,7 +36,7 @@ LL |         WRAPQUUX => {}
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:119:9
+  --> $DIR/consts-opaque.rs:117:9
    |
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
@@ -138,7 +45,7 @@ LL |         WRAPQUUX => {}
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:129:9
+  --> $DIR/consts-opaque.rs:127:9
    |
 LL |         WRAPQUUX => {}
    |         ^^^^^^^^
@@ -147,7 +54,7 @@ LL |         WRAPQUUX => {}
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:141:9
+  --> $DIR/consts-opaque.rs:139:9
    |
 LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
@@ -156,7 +63,7 @@ LL |         WHOKNOWSQUUX => {}
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
 
 warning: function pointers and raw pointers not derived from integers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-  --> $DIR/consts-opaque.rs:144:9
+  --> $DIR/consts-opaque.rs:142:9
    |
 LL |         WHOKNOWSQUUX => {}
    |         ^^^^^^^^^^^^
@@ -164,14 +71,89 @@ LL |         WHOKNOWSQUUX => {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/70861>
 
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:48:9
+   |
+LL |         Bar => {}
+   |         --- matches any value
+LL |         BAR => {}
+   |         ^^^ unreachable pattern
+   |
+note: the lint level is defined here
+  --> $DIR/consts-opaque.rs:6:9
+   |
+LL | #![deny(unreachable_patterns)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:50:9
+   |
+LL |         Bar => {}
+   |         --- matches any value
+...
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:56:9
+   |
+LL |         BAR => {}
+   |         --- matches any value
+LL |         Bar => {}
+   |         ^^^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:58:9
+   |
+LL |         BAR => {}
+   |         --- matches any value
+...
+LL |         _ => {}
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:64:9
+   |
+LL |         BAR => {}
+   |         --- matches any value
+LL |         BAR => {} // should not be emitting unreachable warning
+   |         ^^^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:66:9
+   |
+LL |         BAR => {}
+   |         --- matches any value
+...
+LL |         _ => {} // should not be emitting unreachable warning
+   |         ^ unreachable pattern
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:72:9
+   |
+LL |         Baz::Baz1 => {} // should not be emitting unreachable warning
+   |         ^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:79:9
+   |
+LL |         BAZ => {}
+   |         ^^^
+
+error: unreachable pattern
+  --> $DIR/consts-opaque.rs:87:9
+   |
+LL |         _ => {} // should not be emitting unreachable warning
+   |         ^
+
 error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered
-  --> $DIR/consts-opaque.rs:127:11
+  --> $DIR/consts-opaque.rs:125:11
    |
 LL |     match WRAPQUUX {
    |           ^^^^^^^^ pattern `Wrap(_)` not covered
    |
 note: `Wrap<fn(usize, usize) -> usize>` defined here
-  --> $DIR/consts-opaque.rs:106:12
+  --> $DIR/consts-opaque.rs:104:12
    |
 LL |     struct Wrap<T>(T);
    |            ^^^^
@@ -181,6 +163,6 @@ help: ensure that all possible cases are being handled by adding a match arm wit
 LL |         WRAPQUUX => {}, Wrap(_) => todo!()
    |                       ++++++++++++++++++++
 
-error: aborting due to 10 previous errors; 9 warnings emitted
+error: aborting due to 10 previous errors; 8 warnings emitted
 
 For more information about this error, try `rustc --explain E0004`.
diff --git a/tests/ui/privacy/private-type-in-interface.rs b/tests/ui/privacy/private-type-in-interface.rs
index 39e0bf23cac..9f55127fd16 100644
--- a/tests/ui/privacy/private-type-in-interface.rs
+++ b/tests/ui/privacy/private-type-in-interface.rs
@@ -26,6 +26,7 @@ type A = <m::Alias as m::Trait>::X; //~ ERROR type `Priv` is private
 trait Tr2<T> {}
 impl<T> Tr2<T> for u8 {}
 fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `Priv` is private
+                                   //~| ERROR type `Priv` is private
 fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private
-
+                                         //~| ERROR type `ext::Priv` is private
 fn main() {}
diff --git a/tests/ui/privacy/private-type-in-interface.stderr b/tests/ui/privacy/private-type-in-interface.stderr
index 03225d84fdb..a5e80d6962d 100644
--- a/tests/ui/privacy/private-type-in-interface.stderr
+++ b/tests/ui/privacy/private-type-in-interface.stderr
@@ -46,11 +46,23 @@ error: type `Priv` is private
 LL | fn g() -> impl Tr2<m::Alias> { 0 }
    |           ^^^^^^^^^^^^^^^^^^ private type
 
+error: type `Priv` is private
+  --> $DIR/private-type-in-interface.rs:28:16
+   |
+LL | fn g() -> impl Tr2<m::Alias> { 0 }
+   |                ^^^^^^^^^^^^^ private type
+
 error: type `ext::Priv` is private
-  --> $DIR/private-type-in-interface.rs:29:15
+  --> $DIR/private-type-in-interface.rs:30:15
    |
 LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 }
    |               ^^^^^^^^^^^^^^^^^^^^ private type
 
-error: aborting due to 9 previous errors
+error: type `ext::Priv` is private
+  --> $DIR/private-type-in-interface.rs:30:20
+   |
+LL | fn g_ext() -> impl Tr2<ext::Alias> { 0 }
+   |                    ^^^^^^^^^^^^^^^ private type
+
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr b/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
index f3fe8c10c02..1f7487e68be 100644
--- a/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
+++ b/tests/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
@@ -6,7 +6,7 @@ LL |     let _ = [ a; 5 ];
    |
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 help: consider annotating `Foo` with `#[derive(Copy)]`
    |
 LL + #[derive(Copy)]
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
index bb5e243d934..65a85a5ed68 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
@@ -20,7 +20,7 @@ const WRAP_DIRECT_INLINE: WrapInline = WrapInline(NoDerive(0));
 fn main() {
     match WRAP_DIRECT_INLINE {
         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
         _ => { println!("WRAP_DIRECT_INLINE did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
index 334bd7618ad..cc5d4106331 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9
    |
 LL |         WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); }
    |         ^^^^^^^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
index 93022a23dbf..112021c783f 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.rs
@@ -20,7 +20,7 @@ const WRAP_DIRECT_PARAM: WrapParam<NoDerive> = WrapParam(NoDerive(0));
 fn main() {
     match WRAP_DIRECT_PARAM {
         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
         _ => { println!("WRAP_DIRECT_PARAM did not match itself"); }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
index 58bfcbb451d..8bca7d9889c 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-param.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9
    |
 LL |         WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); }
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
index e3abb47cf73..7a853631d43 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
@@ -22,7 +22,7 @@ const WRAP_DOUBLY_INDIRECT_INLINE: & &WrapInline = & &WrapInline(& & NoDerive(0)
 fn main() {
     match WRAP_DOUBLY_INDIRECT_INLINE {
         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); }
-        //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ WARN must be annotated with `#[derive(PartialEq)]`
         //~| WARN this was previously accepted
         _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); }
     }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
index 94ee2216e9e..910d491baaf 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.stderr
@@ -1,4 +1,4 @@
-warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:24:9
    |
 LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); }
@@ -7,7 +7,7 @@ LL |         WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLIN
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/cant-hide-behind-doubly-indirect-embedded.rs:7:9
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
index 2d3788eea8a..3093f227e6f 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
@@ -22,7 +22,7 @@ const WRAP_DOUBLY_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(& & NoDe
 fn main() {
     match WRAP_DOUBLY_INDIRECT_PARAM {
         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); }
-        //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ WARN must be annotated with `#[derive(PartialEq)]`
         //~| WARN this was previously accepted
         _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); }
     }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
index 666b7b95ec9..cadd9be023c 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.stderr
@@ -1,4 +1,4 @@
-warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-doubly-indirect-param.rs:24:9
    |
 LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); }
@@ -7,7 +7,7 @@ LL |         WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/cant-hide-behind-doubly-indirect-param.rs:7:9
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
index 65df7788d90..2b6ec850241 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
@@ -22,7 +22,7 @@ const WRAP_INDIRECT_INLINE: & &WrapInline = & &WrapInline(NoDerive(0));
 fn main() {
     match WRAP_INDIRECT_INLINE {
         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); }
-        //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ WARN must be annotated with `#[derive(PartialEq)]`
         //~| WARN this was previously accepted
         _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); }
     }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
index ecbe83f3dec..e4321cc6a4c 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.stderr
@@ -1,4 +1,4 @@
-warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:24:9
    |
 LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); }
@@ -7,7 +7,7 @@ LL |         WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itse
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/cant-hide-behind-indirect-struct-embedded.rs:7:9
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
index 88260fd1081..5738d14d97b 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
@@ -22,7 +22,7 @@ const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &WrapParam(NoDerive(0));
 fn main() {
     match WRAP_INDIRECT_PARAM {
         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); }
-        //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ WARN must be annotated with `#[derive(PartialEq)]`
         //~| WARN this was previously accepted
         _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); }
     }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
index 2119908013b..decc29ad67c 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.stderr
@@ -1,4 +1,4 @@
-warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/cant-hide-behind-indirect-struct-param.rs:24:9
    |
 LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); }
@@ -7,7 +7,7 @@ LL |         WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/cant-hide-behind-indirect-struct-param.rs:7:9
    |
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr
index f047afa985d..af6d05c1f96 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.no_gate.stderr
@@ -8,16 +8,6 @@ LL | impl std::marker::StructuralPartialEq for Foo { }
    = help: add `#![feature(structural_match)]` 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 'structural_match'
-  --> $DIR/feature-gate.rs:31:6
-   |
-LL | impl std::marker::StructuralEq for Foo { }
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #31434 <https://github.com/rust-lang/rust/issues/31434> for more information
-   = help: add `#![feature(structural_match)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs
index ee6674097ce..024226a0116 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/feature-gate.rs
@@ -28,8 +28,6 @@ fn main() { //[with_gate]~ ERROR fatal error triggered by #[rustc_error]
 
 impl std::marker::StructuralPartialEq for Foo { }
 //[no_gate]~^ ERROR use of unstable library feature 'structural_match'
-impl std::marker::StructuralEq for Foo { }
-//[no_gate]~^ ERROR use of unstable library feature 'structural_match'
 
 impl PartialEq<Foo> for Foo {
     fn eq(&self, other: &Self) -> bool {
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
index 2a915d61e3d..c69fe145f77 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs
@@ -13,7 +13,7 @@ const A: &[B] = &[];
 pub fn main() {
     match &[][..] {
         A => (),
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
         _ => (),
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
index 729e747def3..02e2bab4d0a 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-61188-match-slice-forbidden-without-eq.rs:15:9
    |
 LL |         A => (),
    |         ^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
index 46d8ee3b6be..fdb67bcf2d8 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs
@@ -29,14 +29,14 @@ fn main() {
 
     match RR_B0 {
         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); }
-        //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ WARN must be annotated with `#[derive(PartialEq)]`
         //~| WARN this was previously accepted
         _ => { }
     }
 
     match RR_B1 {
         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); }
-        //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ WARN must be annotated with `#[derive(PartialEq)]`
         //~| WARN this was previously accepted
         _ => { }
     }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
index 435812306de..d0f2b820afa 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.stderr
@@ -1,4 +1,4 @@
-warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:31:9
    |
 LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); }
@@ -7,14 +7,14 @@ LL |         RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 note: the lint level is defined here
   --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9
    |
 LL | #![warn(indirect_structural_match, nontrivial_structural_match)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]`
+warning: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:38:9
    |
 LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); }
@@ -23,7 +23,7 @@ LL |         RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #62411 <https://github.com/rust-lang/rust/issues/62411>
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs
deleted file mode 100644
index 59a22c33778..00000000000
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-#[derive(PartialEq)]
-struct Foo {
-    x: u32
-}
-
-const FOO: Foo = Foo { x: 0 };
-
-fn main() {
-    let y = Foo { x: 1 };
-    match y {
-        FOO => { }
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-        _ => { }
-    }
-
-    let x = 0.0;
-    match x {
-        f32::INFINITY => { }
-        //~^ WARNING floating-point types cannot be used in patterns
-        //~| WARNING this was previously accepted by the compiler but is being phased out
-        _ => { }
-    }
-}
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr
deleted file mode 100644
index c2000df88f6..00000000000
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-forbidden-without-eq.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/match-forbidden-without-eq.rs:11:9
-   |
-LL |         FOO => { }
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-warning: floating-point types cannot be used in patterns
-  --> $DIR/match-forbidden-without-eq.rs:18:9
-   |
-LL |         f32::INFINITY => { }
-   |         ^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-   = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
-
-error: aborting due to 1 previous error; 1 warning emitted
-
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs
deleted file mode 100644
index 151a475c919..00000000000
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Issue 62307 pointed out a case where the structural-match checking
-// was too shallow.
-//
-// Here we check similar behavior for non-empty arrays of types that
-// do not derive `Eq`.
-//
-// (Current behavior for empty arrays differs and thus is not tested
-// here; see rust-lang/rust#62336.)
-
-#[derive(PartialEq, Debug)]
-struct B(i32);
-
-fn main() {
-    const FOO: [B; 1] = [B(0)];
-    match [B(1)] {
-        FOO => { }
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
-    }
-}
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr
deleted file mode 100644
index 477789f33df..00000000000
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-nonempty-array-forbidden-without-eq.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]`
-  --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9
-   |
-LL |         FOO => { }
-   |         ^^^
-   |
-   = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
index a8deb8a7550..9020eb291f5 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.rs
@@ -15,7 +15,7 @@ fn main() {
     let y = Foo { x: 1 };
     match y {
         FOO => { }
-        //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]`
+        //~^ ERROR must be annotated with `#[derive(PartialEq)]`
         _ => { }
     }
 }
diff --git a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
index b806046db14..efd9c8c45af 100644
--- a/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
+++ b/tests/ui/rfcs/rfc-1445-restrict-constants-in-patterns/match-requires-both-partialeq-and-eq.stderr
@@ -1,11 +1,11 @@
-error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]`
+error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq)]`
   --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9
    |
 LL |         FOO => { }
    |         ^^^
    |
    = note: the traits must be derived, manual `impl`s are not sufficient
-   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
+   = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
index 84d9bcd7ac9..d6a82ca3a08 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
@@ -507,9 +507,6 @@ trait Clone: Sized {
 #[lang = "structural_peq"]
 trait StructuralPartialEq {}
 
-#[lang = "structural_teq"]
-trait StructuralEq {}
-
 const fn drop<T: ~const Destruct>(_: T) {}
 
 extern "rust-intrinsic" {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
index e5b9493b3ce..5210a694201 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/specializing-constness-2.stderr
@@ -7,16 +7,6 @@ LL | impl<T: Default> A for T {
 LL | impl<T: Default + ~const Sup> const A for T {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
 
-error[E0308]: mismatched types
-  --> $DIR/specializing-constness-2.rs:27:5
-   |
-LL |     <T as A>::a();
-   |     ^^^^^^^^^^^^^ expected `host`, found `true`
-   |
-   = note: expected constant `host`
-              found constant `true`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0119, E0308.
-For more information about an error, try `rustc --explain E0119`.
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
index 8ceecd801d3..a0ee7714417 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.rs
@@ -6,7 +6,6 @@
 struct S<const L: usize>;
 
 impl<const N: i32> Copy for S<N> {}
-//~^ ERROR the constant `N` is not of type `usize`
 impl<const M: usize> Copy for S<M> {}
 //~^ ERROR: conflicting implementations of trait `Copy` for type `S<_>`
 
diff --git a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
index 3268a876733..2953bc95917 100644
--- a/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
+++ b/tests/ui/specialization/min_specialization/bad-const-wf-doesnt-specialize.stderr
@@ -1,29 +1,11 @@
 error[E0119]: conflicting implementations of trait `Copy` for type `S<_>`
-  --> $DIR/bad-const-wf-doesnt-specialize.rs:10:1
+  --> $DIR/bad-const-wf-doesnt-specialize.rs:9:1
    |
 LL | impl<const N: i32> Copy for S<N> {}
    | -------------------------------- first implementation here
-LL |
 LL | impl<const M: usize> Copy for S<M> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S<_>`
 
-error: the constant `N` is not of type `usize`
-  --> $DIR/bad-const-wf-doesnt-specialize.rs:8:29
-   |
-LL | impl<const N: i32> Copy for S<N> {}
-   |                             ^^^^ expected `usize`, found `i32`
-   |
-note: required for `S<N>` to implement `Clone`
-  --> $DIR/bad-const-wf-doesnt-specialize.rs:5:10
-   |
-LL | #[derive(Clone)]
-   |          ^^^^^
-LL | struct S<const L: usize>;
-   |          ----- unsatisfied trait bound introduced in this `derive` macro
-note: required by a bound in `Copy`
-  --> $SRC_DIR/core/src/marker.rs:LL:COL
-   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.stderr b/tests/ui/symbol-names/const-generics-structural-demangling.stderr
index 96dea154d05..270c126e3f5 100644
--- a/tests/ui/symbol-names/const-generics-structural-demangling.stderr
+++ b/tests/ui/symbol-names/const-generics-structural-demangling.stderr
@@ -124,7 +124,7 @@ error: demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_RMsf_CsCRATE_HASH_1cINtB<REF>_4Bar_KVNtB<REF>_3BarS1xh7b_s_1xt1000_EE)
+error: symbol-name(_RMsd_CsCRATE_HASH_1cINtB<REF>_4Bar_KVNtB<REF>_3BarS1xh7b_s_1xt1000_EE)
   --> $DIR/const-generics-structural-demangling.rs:93:5
    |
 LL |     #[rustc_symbol_name]
diff --git a/tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr b/tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr
index f394c4cf027..9217637901b 100644
--- a/tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr
+++ b/tests/ui/trait-bounds/issue-119530-sugg-from-fn.stderr
@@ -6,7 +6,7 @@ LL |     let string_arr = [foo(); 64];
    |
    = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider using `core::array::from_fn` to initialize the array
-   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html# for more information
+   = help: see https://doc.rust-lang.org/stable/std/array/fn.from_fn.html for more information
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.rs b/tests/ui/typeck/typeck_type_placeholder_item.rs
index f6d1fb6a23d..4eba14f5a93 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.rs
+++ b/tests/ui/typeck/typeck_type_placeholder_item.rs
@@ -198,7 +198,6 @@ trait Qux {
     //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
 }
 impl Qux for Struct {
-    //~^ ERROR: not all trait items implemented, missing: `F`
     type A = _;
     //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
     type B = _;
diff --git a/tests/ui/typeck/typeck_type_placeholder_item.stderr b/tests/ui/typeck/typeck_type_placeholder_item.stderr
index bfcc76c1dae..a4325b01f02 100644
--- a/tests/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/tests/ui/typeck/typeck_type_placeholder_item.stderr
@@ -29,7 +29,7 @@ LL | struct BadStruct2<_, T>(_, T);
    |                   ^ expected identifier, found reserved identifier
 
 error: associated constant in `impl` without body
-  --> $DIR/typeck_type_placeholder_item.rs:206:5
+  --> $DIR/typeck_type_placeholder_item.rs:205:5
    |
 LL |     const C: _;
    |     ^^^^^^^^^^-
@@ -411,7 +411,7 @@ LL | type Y = impl Trait<_>;
    |                     ^ not allowed in type signatures
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
-  --> $DIR/typeck_type_placeholder_item.rs:217:31
+  --> $DIR/typeck_type_placeholder_item.rs:216:31
    |
 LL | fn value() -> Option<&'static _> {
    |               ----------------^-
@@ -420,7 +420,7 @@ LL | fn value() -> Option<&'static _> {
    |               help: replace with the correct return type: `Option<&'static u8>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
-  --> $DIR/typeck_type_placeholder_item.rs:222:10
+  --> $DIR/typeck_type_placeholder_item.rs:221:10
    |
 LL | const _: Option<_> = map(value);
    |          ^^^^^^^^^
@@ -429,7 +429,7 @@ LL | const _: Option<_> = map(value);
    |          help: replace with the correct type: `Option<u8>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
-  --> $DIR/typeck_type_placeholder_item.rs:225:31
+  --> $DIR/typeck_type_placeholder_item.rs:224:31
    |
 LL | fn evens_squared(n: usize) -> _ {
    |                               ^
@@ -438,13 +438,13 @@ LL | fn evens_squared(n: usize) -> _ {
    |                               help: replace with an appropriate return type: `impl Iterator<Item = usize>`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
-  --> $DIR/typeck_type_placeholder_item.rs:230:10
+  --> $DIR/typeck_type_placeholder_item.rs:229:10
    |
 LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
    |          ^ not allowed in type signatures
    |
-note: however, the inferred type `Map<Filter<Range<i32>, {closure@typeck_type_placeholder_item.rs:230:29}>, {closure@typeck_type_placeholder_item.rs:230:49}>` cannot be named
-  --> $DIR/typeck_type_placeholder_item.rs:230:14
+note: however, the inferred type `Map<Filter<Range<i32>, {closure@typeck_type_placeholder_item.rs:229:29}>, {closure@typeck_type_placeholder_item.rs:229:49}>` cannot be named
+  --> $DIR/typeck_type_placeholder_item.rs:229:14
    |
 LL | const _: _ = (1..10).filter(|x| x % 2 == 0).map(|x| x * x);
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -631,25 +631,25 @@ LL |         fn clone_from(&mut self, other: &FnTest9) { *self = FnTest9; }
    |                                         ~~~~~~~~
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
-  --> $DIR/typeck_type_placeholder_item.rs:202:14
+  --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type A = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
-  --> $DIR/typeck_type_placeholder_item.rs:204:14
+  --> $DIR/typeck_type_placeholder_item.rs:203:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
-  --> $DIR/typeck_type_placeholder_item.rs:206:14
+  --> $DIR/typeck_type_placeholder_item.rs:205:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
-  --> $DIR/typeck_type_placeholder_item.rs:209:14
+  --> $DIR/typeck_type_placeholder_item.rs:208:14
    |
 LL |     const D: _ = 42;
    |              ^
@@ -657,16 +657,7 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
-error[E0046]: not all trait items implemented, missing: `F`
-  --> $DIR/typeck_type_placeholder_item.rs:200:1
-   |
-LL |     type F: std::ops::Fn(_);
-   |     ----------------------- `F` from trait
-...
-LL | impl Qux for Struct {
-   | ^^^^^^^^^^^^^^^^^^^ missing `F` in implementation
-
-error: aborting due to 72 previous errors
+error: aborting due to 71 previous errors
 
-Some errors have detailed explanations: E0046, E0121, E0282, E0403.
-For more information about an error, try `rustc --explain E0046`.
+Some errors have detailed explanations: E0121, E0282, E0403.
+For more information about an error, try `rustc --explain E0121`.
diff --git a/triagebot.toml b/triagebot.toml
index 36e58f0f9d8..264f6efd982 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -646,6 +646,7 @@ compiler-team = [
     "@estebank",
     "@oli-obk",
     "@wesleywiser",
+    "@michaelwoerister",
 ]
 compiler-team-contributors = [
     "@TaKO8Ki",
@@ -738,6 +739,10 @@ ast_lowering = [
     "@estebank",
     "@spastorino",
 ]
+debuginfo = [
+    "@michaelwoerister",
+    "@davidtwco"
+]
 fallback = [
     "@Mark-Simulacrum"
 ]
@@ -761,66 +766,71 @@ project-stable-mir = [
 ]
 
 [assign.owners]
-"/.github/workflows" =                       ["infra-ci"]
-"/Cargo.lock" =                              ["@Mark-Simulacrum"]
-"/Cargo.toml" =                              ["@Mark-Simulacrum"]
-"/compiler" =                                ["compiler"]
-"/compiler/rustc_arena" =                    ["compiler", "arena"]
-"/compiler/rustc_ast" =                      ["compiler", "parser"]
-"/compiler/rustc_ast_lowering" =             ["compiler", "ast_lowering"]
-"/compiler/rustc_hir_analysis" =             ["compiler", "types"]
-"/compiler/rustc_lexer" =                    ["compiler", "lexer"]
-"/compiler/rustc_llvm" =                     ["@cuviper"]
-"/compiler/rustc_middle/src/mir" =           ["compiler", "mir"]
-"/compiler/rustc_middle/src/traits" =        ["compiler", "types"]
-"/compiler/rustc_middle/src/ty" =            ["compiler", "types"]
-"/compiler/rustc_const_eval/src/interpret" = ["compiler", "mir"]
-"/compiler/rustc_const_eval/src/transform" = ["compiler", "mir-opt"]
-"/compiler/rustc_mir_build/src/build" =      ["compiler", "mir"]
-"/compiler/rustc_smir" =                     ["project-stable-mir"]
-"/compiler/rustc_parse" =                    ["compiler", "parser"]
-"/compiler/rustc_parse/src/lexer" =          ["compiler", "lexer"]
-"/compiler/rustc_query_impl" =               ["compiler", "query-system"]
-"/compiler/rustc_query_system" =             ["compiler", "query-system"]
-"/compiler/rustc_trait_selection" =          ["compiler", "types"]
-"/compiler/rustc_traits" =                   ["compiler", "types"]
-"/compiler/rustc_type_ir" =                  ["compiler", "types"]
-"/compiler/stable_mir" =                     ["project-stable-mir"]
-"/library/alloc" =                           ["libs"]
-"/library/core" =                            ["libs"]
-"/library/panic_abort" =                     ["libs"]
-"/library/panic_unwind" =                    ["libs"]
-"/library/proc_macro" =                      ["@petrochenkov"]
-"/library/std" =                             ["libs"]
-"/library/std/src/sys/pal/windows" =         ["@ChrisDenton", "@thomcc"]
-"/library/stdarch" =                         ["libs"]
-"/library/test" =                            ["libs"]
-"/src/bootstrap" =                           ["bootstrap"]
-"/src/ci" =                                  ["infra-ci"]
-"/src/doc" =                                 ["docs"]
-"/src/doc/book" =                            ["@ehuss"]
-"/src/doc/edition-guide" =                   ["@ehuss"]
-"/src/doc/embedded-book" =                   ["@ehuss"]
-"/src/doc/nomicon" =                         ["@ehuss"]
-"/src/doc/reference" =                       ["@ehuss"]
-"/src/doc/rust-by-example" =                 ["@ehuss"]
-"/src/doc/rustc-dev-guide" =                 ["@ehuss"]
-"/src/doc/rustdoc" =                         ["rustdoc"]
-"/src/doc/style-guide" =                     ["style-team"]
-"/src/etc" =                                 ["@Mark-Simulacrum"]
-"/src/librustdoc" =                          ["rustdoc"]
-"/src/llvm-project" =                        ["@cuviper"]
-"/src/rustdoc-json-types" =                  ["rustdoc"]
-"/src/stage0.json" =                         ["bootstrap"]
-"/tests/ui" =                                ["compiler"]
-"/src/tools/cargo" =                         ["@ehuss", "@joshtriplett"]
-"/src/tools/compiletest" =                   ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors"]
-"/src/tools/linkchecker" =                   ["@ehuss"]
-"/src/tools/rust-installer" =                ["bootstrap"]
-"/src/tools/rustbook" =                      ["@ehuss"]
-"/src/tools/rustdoc" =                       ["rustdoc"]
-"/src/tools/rustdoc-js" =                    ["rustdoc"]
-"/src/tools/rustdoc-themes" =                ["rustdoc"]
-"/src/tools/tidy" =                          ["bootstrap"]
-"/src/tools/x" =                             ["bootstrap"]
-"/src/tools/rustdoc-gui-test" =              ["bootstrap", "@onur-ozkan"]
+"/.github/workflows" =                                   ["infra-ci"]
+"/Cargo.lock" =                                          ["@Mark-Simulacrum"]
+"/Cargo.toml" =                                          ["@Mark-Simulacrum"]
+"/compiler" =                                            ["compiler"]
+"/compiler/rustc_arena" =                                ["compiler", "arena"]
+"/compiler/rustc_ast" =                                  ["compiler", "parser"]
+"/compiler/rustc_ast_lowering" =                         ["compiler", "ast_lowering"]
+"/compiler/rustc_data_structures/src/stable_hasher.rs" = ["compiler", "incremental"]
+"/compiler/rustc_hir_analysis" =                         ["compiler", "types"]
+"/compiler/rustc_incremental" =                          ["compiler", "incremental"]
+"/compiler/rustc_lexer" =                                ["compiler", "lexer"]
+"/compiler/rustc_llvm" =                                 ["@cuviper"]
+"/compiler/rustc_codegen_llvm/src/debuginfo" =           ["compiler", "debuginfo"]
+"/compiler/rustc_middle/src/mir" =                       ["compiler", "mir"]
+"/compiler/rustc_middle/src/traits" =                    ["compiler", "types"]
+"/compiler/rustc_middle/src/ty" =                        ["compiler", "types"]
+"/compiler/rustc_const_eval/src/interpret" =             ["compiler", "mir"]
+"/compiler/rustc_const_eval/src/transform" =             ["compiler", "mir-opt"]
+"/compiler/rustc_mir_build/src/build" =                  ["compiler", "mir"]
+"/compiler/rustc_smir" =                                 ["project-stable-mir"]
+"/compiler/rustc_parse" =                                ["compiler", "parser"]
+"/compiler/rustc_parse/src/lexer" =                      ["compiler", "lexer"]
+"/compiler/rustc_query_impl" =                           ["compiler", "query-system"]
+"/compiler/rustc_query_system" =                         ["compiler", "query-system"]
+"/compiler/rustc_query_system/src/dep_graph" =           ["compiler", "incremental", "query-system"]
+"/compiler/rustc_query_system/src/ich" =                 ["compiler", "incremental", "query-system"]
+"/compiler/rustc_trait_selection" =                      ["compiler", "types"]
+"/compiler/rustc_traits" =                               ["compiler", "types"]
+"/compiler/rustc_type_ir" =                              ["compiler", "types"]
+"/compiler/stable_mir" =                                 ["project-stable-mir"]
+"/library/alloc" =                                       ["libs"]
+"/library/core" =                                        ["libs"]
+"/library/panic_abort" =                                 ["libs"]
+"/library/panic_unwind" =                                ["libs"]
+"/library/proc_macro" =                                  ["@petrochenkov"]
+"/library/std" =                                         ["libs"]
+"/library/std/src/sys/pal/windows" =                     ["@ChrisDenton", "@thomcc"]
+"/library/stdarch" =                                     ["libs"]
+"/library/test" =                                        ["libs"]
+"/src/bootstrap" =                                       ["bootstrap"]
+"/src/ci" =                                              ["infra-ci"]
+"/src/doc" =                                             ["docs"]
+"/src/doc/book" =                                        ["@ehuss"]
+"/src/doc/edition-guide" =                               ["@ehuss"]
+"/src/doc/embedded-book" =                               ["@ehuss"]
+"/src/doc/nomicon" =                                     ["@ehuss"]
+"/src/doc/reference" =                                   ["@ehuss"]
+"/src/doc/rust-by-example" =                             ["@ehuss"]
+"/src/doc/rustc-dev-guide" =                             ["@ehuss"]
+"/src/doc/rustdoc" =                                     ["rustdoc"]
+"/src/doc/style-guide" =                                 ["style-team"]
+"/src/etc" =                                             ["@Mark-Simulacrum"]
+"/src/librustdoc" =                                      ["rustdoc"]
+"/src/llvm-project" =                                    ["@cuviper"]
+"/src/rustdoc-json-types" =                              ["rustdoc"]
+"/src/stage0.json" =                                     ["bootstrap"]
+"/tests/ui" =                                            ["compiler"]
+"/src/tools/cargo" =                                     ["@ehuss", "@joshtriplett"]
+"/src/tools/compiletest" =                               ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors"]
+"/src/tools/linkchecker" =                               ["@ehuss"]
+"/src/tools/rust-installer" =                            ["bootstrap"]
+"/src/tools/rustbook" =                                  ["@ehuss"]
+"/src/tools/rustdoc" =                                   ["rustdoc"]
+"/src/tools/rustdoc-js" =                                ["rustdoc"]
+"/src/tools/rustdoc-themes" =                            ["rustdoc"]
+"/src/tools/tidy" =                                      ["bootstrap"]
+"/src/tools/x" =                                         ["bootstrap"]
+"/src/tools/rustdoc-gui-test" =                          ["bootstrap", "@onur-ozkan"]