about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock91
-rw-r--r--bootstrap.example.toml4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs5
-rw-r--r--compiler/rustc_fs_util/Cargo.toml1
-rw-r--r--compiler/rustc_fs_util/src/lib.rs46
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs44
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs5
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs4
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs16
-rw-r--r--compiler/rustc_interface/src/tests.rs8
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs5
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs2
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs4
-rw-r--r--compiler/rustc_llvm/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/fs.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs4
-rw-r--r--compiler/rustc_middle/src/ty/generic_args.rs17
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs15
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/values.rs32
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs73
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs18
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs13
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs27
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs4
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs7
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs12
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/config.rs3
-rw-r--r--compiler/rustc_session/src/utils.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs4
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs2
-rw-r--r--compiler/rustc_span/src/hygiene.rs172
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs35
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs37
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs41
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs23
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs80
-rw-r--r--compiler/rustc_transmute/src/layout/mod.rs7
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs146
-rw-r--r--compiler/rustc_transmute/src/layout/tree/tests.rs24
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/tests.rs82
-rw-r--r--compiler/rustc_type_ir/src/flags.rs6
-rw-r--r--compiler/rustc_type_ir/src/interner.rs2
-rw-r--r--compiler/rustc_type_ir/src/predicate_kind.rs2
-rw-r--r--library/Cargo.lock8
-rw-r--r--library/alloc/src/ffi/c_str.rs13
-rw-r--r--library/alloc/src/ffi/mod.rs2
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/str.rs4
-rw-r--r--library/alloc/src/sync.rs79
-rw-r--r--library/core/src/ffi/c_str.rs5
-rw-r--r--library/core/src/ffi/mod.rs2
-rw-r--r--library/core/src/iter/adapters/peekable.rs6
-rw-r--r--library/core/src/str/converts.rs2
-rw-r--r--library/core/src/str/mod.rs8
-rw-r--r--library/core/src/sync/atomic.rs94
-rw-r--r--library/proc_macro/src/lib.rs8
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/src/alloc.rs4
-rw-r--r--library/std/src/backtrace.rs4
-rw-r--r--library/std/src/ffi/mod.rs2
-rw-r--r--library/std/src/fs.rs15
-rw-r--r--library/std/src/io/mod.rs4
-rw-r--r--library/std/src/io/stdio.rs4
-rw-r--r--library/std/src/keyword_docs.rs8
-rw-r--r--library/std/src/lib.rs12
-rw-r--r--library/std/src/os/uefi/env.rs8
-rw-r--r--library/std/src/os/xous/services.rs4
-rw-r--r--library/std/src/os/xous/services/dns.rs4
-rw-r--r--library/std/src/os/xous/services/log.rs4
-rw-r--r--library/std/src/os/xous/services/net.rs4
-rw-r--r--library/std/src/os/xous/services/systime.rs4
-rw-r--r--library/std/src/os/xous/services/ticktimer.rs4
-rw-r--r--library/std/src/panic.rs4
-rw-r--r--library/std/src/panicking.rs8
-rw-r--r--library/std/src/sync/mpmc/array.rs8
-rw-r--r--library/std/src/sync/mpmc/context.rs6
-rw-r--r--library/std/src/sync/mpmc/counter.rs8
-rw-r--r--library/std/src/sync/mpmc/list.rs14
-rw-r--r--library/std/src/sync/mpmc/waker.rs4
-rw-r--r--library/std/src/sync/mpmc/zero.rs4
-rw-r--r--library/std/src/sync/poison.rs4
-rw-r--r--library/std/src/sync/reentrant_lock.rs7
-rw-r--r--library/std/src/sys/alloc/sgx.rs4
-rw-r--r--library/std/src/sys/alloc/wasm.rs4
-rw-r--r--library/std/src/sys/alloc/xous.rs4
-rw-r--r--library/std/src/sys/args/sgx.rs4
-rw-r--r--library/std/src/sys/args/unix.rs6
-rw-r--r--library/std/src/sys/env/sgx.rs4
-rw-r--r--library/std/src/sys/env/xous.rs4
-rw-r--r--library/std/src/sys/fs/unix.rs4
-rw-r--r--library/std/src/sys/fs/windows/remove_dir_all.rs4
-rw-r--r--library/std/src/sys/net/connection/xous/tcplistener.rs8
-rw-r--r--library/std/src/sys/net/connection/xous/tcpstream.rs10
-rw-r--r--library/std/src/sys/net/connection/xous/udp.rs4
-rw-r--r--library/std/src/sys/pal/hermit/futex.rs12
-rw-r--r--library/std/src/sys/pal/itron/spin.rs8
-rw-r--r--library/std/src/sys/pal/itron/thread.rs4
-rw-r--r--library/std/src/sys/pal/sgx/abi/mod.rs4
-rw-r--r--library/std/src/sys/pal/sgx/abi/tls/mod.rs10
-rw-r--r--library/std/src/sys/pal/sgx/abi/tls/sync_bitset.rs6
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs4
-rw-r--r--library/std/src/sys/pal/sgx/waitqueue/spin_mutex.rs4
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs8
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs4
-rw-r--r--library/std/src/sys/pal/uefi/time.rs4
-rw-r--r--library/std/src/sys/pal/unix/futex.rs85
-rw-r--r--library/std/src/sys/pal/unix/kernel_copy.rs8
-rw-r--r--library/std/src/sys/pal/unix/mod.rs2
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs8
-rw-r--r--library/std/src/sys/pal/unix/weak.rs4
-rw-r--r--library/std/src/sys/pal/wasm/atomics/futex.rs23
-rw-r--r--library/std/src/sys/pal/windows/compat.rs8
-rw-r--r--library/std/src/sys/pal/windows/futex.rs12
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs4
-rw-r--r--library/std/src/sys/pal/windows/time.rs4
-rw-r--r--library/std/src/sys/pal/xous/os.rs4
-rw-r--r--library/std/src/sys/process/unix/unix.rs4
-rw-r--r--library/std/src/sys/random/linux.rs8
-rw-r--r--library/std/src/sys/random/vxworks.rs4
-rw-r--r--library/std/src/sys/sync/condvar/pthread.rs4
-rw-r--r--library/std/src/sys/sync/condvar/xous.rs6
-rw-r--r--library/std/src/sys/sync/mutex/fuchsia.rs4
-rw-r--r--library/std/src/sys/sync/mutex/xous.rs6
-rw-r--r--library/std/src/sys/sync/once/queue.rs10
-rw-r--r--library/std/src/sys/sync/once_box.rs4
-rw-r--r--library/std/src/sys/sync/rwlock/queue.rs8
-rw-r--r--library/std/src/sys/sync/thread_parking/darwin.rs4
-rw-r--r--library/std/src/sys/sync/thread_parking/id.rs4
-rw-r--r--library/std/src/sys/sync/thread_parking/pthread.rs4
-rw-r--r--library/std/src/sys/sync/thread_parking/windows7.rs8
-rw-r--r--library/std/src/sys/sync/thread_parking/xous.rs4
-rw-r--r--library/std/src/sys/thread_local/key/racy.rs6
-rw-r--r--library/std/src/sys/thread_local/key/windows.rs8
-rw-r--r--library/std/src/sys/thread_local/key/xous.rs10
-rw-r--r--library/std/src/thread/mod.rs16
-rw-r--r--library/std/src/thread/scoped.rs6
-rw-r--r--library/test/src/cli.rs13
-rw-r--r--src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock6
-rw-r--r--src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml2
-rwxr-xr-xsrc/ci/run.sh3
-rw-r--r--src/doc/rustc/src/tests/index.md10
-rw-r--r--src/librustdoc/doctest/runner.rs17
m---------src/tools/cargo0
-rw-r--r--src/tools/compiletest/src/common.rs11
-rw-r--r--src/tools/compiletest/src/lib.rs7
-rw-r--r--src/tools/lint-docs/src/lib.rs22
-rw-r--r--src/tools/wasm-component-ld/Cargo.toml2
-rw-r--r--tests/pretty/hir-if-else.pp39
-rw-r--r--tests/pretty/hir-if-else.rs59
-rw-r--r--tests/pretty/if-else.pp52
-rw-r--r--tests/pretty/if-else.rs65
-rw-r--r--tests/pretty/never-pattern.pp17
-rw-r--r--tests/pretty/never-pattern.rs16
-rw-r--r--tests/rustdoc-ui/doctest/edition-2024-error-output.stdout4
-rw-r--r--tests/rustdoc-ui/doctest/stdout-and-stderr.rs26
-rw-r--r--tests/rustdoc-ui/doctest/stdout-and-stderr.stdout46
-rw-r--r--tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs22
-rw-r--r--tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr21
-rw-r--r--tests/ui/const-generics/defaults/concrete-const-param-type.rs13
-rw-r--r--tests/ui/const-generics/defaults/concrete-const-param-type.stderr25
-rw-r--r--tests/ui/coroutine/dont-drop-stalled-generators.rs25
-rw-r--r--tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout94
-rw-r--r--tests/ui/match/issue-82392.stdout14
-rw-r--r--tests/ui/parser/or-in-let-chain.edition2021.stderr28
-rw-r--r--tests/ui/parser/or-in-let-chain.edition2024.stderr28
-rw-r--r--tests/ui/parser/or-in-let-chain.rs17
-rw-r--r--tests/ui/proc-macro/quote/debug.stdout24
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr9
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr18
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr18
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr18
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs4
-rw-r--r--tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr12
-rw-r--r--tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr12
-rw-r--r--tests/ui/specialization/prefer-specializing-impl-over-default.rs29
-rw-r--r--tests/ui/specialization/specialization-default-projection.current.stderr (renamed from tests/ui/specialization/specialization-default-projection.stderr)6
-rw-r--r--tests/ui/specialization/specialization-default-projection.next.stderr43
-rw-r--r--tests/ui/specialization/specialization-default-projection.rs4
-rw-r--r--tests/ui/specialization/specialization-default-types.current.stderr (renamed from tests/ui/specialization/specialization-default-types.stderr)6
-rw-r--r--tests/ui/specialization/specialization-default-types.next.stderr39
-rw-r--r--tests/ui/specialization/specialization-default-types.rs4
-rw-r--r--tests/ui/traits/next-solver/coerce-depth.rs31
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.rs8
-rw-r--r--tests/ui/traits/next-solver/specialization-transmute.stderr37
-rw-r--r--tests/ui/traits/next-solver/specialization-unconstrained.rs2
-rw-r--r--tests/ui/traits/next-solver/specialization-unconstrained.stderr8
-rw-r--r--tests/ui/transmutability/char.rs41
-rw-r--r--tests/ui/transmutability/char.stderr48
209 files changed, 2219 insertions, 1013 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d9263f60203..be704e84a50 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3700,6 +3700,9 @@ dependencies = [
 [[package]]
 name = "rustc_fs_util"
 version = "0.0.0"
+dependencies = [
+ "tempfile",
+]
 
 [[package]]
 name = "rustc_graphviz"
@@ -4012,7 +4015,6 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
- "tempfile",
  "tracing",
 ]
 
@@ -4917,15 +4919,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "spdx"
-version = "0.10.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
 name = "spdx-expression"
 version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5744,9 +5737,9 @@ dependencies = [
 
 [[package]]
 name = "wasi-preview1-component-adapter-provider"
-version = "29.0.1"
+version = "31.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcd9f21bbde82ba59e415a8725e6ad0d0d7e9e460b1a3ccbca5bdee952c1a324"
+checksum = "86fabda09a0d89ffd1615b297b4a5d4b4d99df9598aeb24685837e63019e927b"
 
 [[package]]
 name = "wasm-bindgen"
@@ -5808,9 +5801,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-component-ld"
-version = "0.5.12"
+version = "0.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "580305a8e3f1b7a79859a8db897de643533b2851c5eb080fe5800233f16dec88"
+checksum = "a60a07a994a3538b57d8c5f8caba19f4793fb4c7156276e5e90e90acbb829e20"
 dependencies = [
  "anyhow",
  "clap",
@@ -5818,7 +5811,7 @@ dependencies = [
  "libc",
  "tempfile",
  "wasi-preview1-component-adapter-provider",
- "wasmparser 0.223.1",
+ "wasmparser 0.229.0",
  "wat",
  "windows-sys 0.59.0",
  "winsplit",
@@ -5845,39 +5838,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-encoder"
-version = "0.223.1"
+version = "0.229.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a0a96fdeaee8fbeb4bd917fb8157d48c0d61c3b1f4ee4c363c8e8d68b2f4fe8"
-dependencies = [
- "leb128",
- "wasmparser 0.223.1",
-]
-
-[[package]]
-name = "wasm-encoder"
-version = "0.228.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d30290541f2d4242a162bbda76b8f2d8b1ac59eab3568ed6f2327d52c9b2c4"
+checksum = "38ba1d491ecacb085a2552025c10a675a6fddcbd03b1fc9b36c536010ce265d2"
 dependencies = [
  "leb128fmt",
- "wasmparser 0.228.0",
+ "wasmparser 0.229.0",
 ]
 
 [[package]]
 name = "wasm-metadata"
-version = "0.223.1"
+version = "0.229.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7e37883181704d96b89dbd8f1291be13694c71cd0663aebb94b46d235a377"
+checksum = "78fdb7d29a79191ab363dc90c1ddd3a1e880ffd5348d92d48482393a9e6c5f4d"
 dependencies = [
  "anyhow",
  "indexmap",
- "serde",
- "serde_derive",
- "serde_json",
- "spdx",
- "url",
- "wasm-encoder 0.223.1",
- "wasmparser 0.223.1",
+ "wasm-encoder 0.229.0",
+ "wasmparser 0.229.0",
 ]
 
 [[package]]
@@ -5901,9 +5879,9 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.223.1"
+version = "0.229.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "664b980991ed9a8c834eb528a8979ab1109edcf52dc05dd5751e2cc3fb31035d"
+checksum = "0cc3b1f053f5d41aa55640a1fa9b6d1b8a9e4418d118ce308d20e24ff3575a8c"
 dependencies = [
  "bitflags",
  "hashbrown",
@@ -5913,34 +5891,23 @@ dependencies = [
 ]
 
 [[package]]
-name = "wasmparser"
-version = "0.228.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3"
-dependencies = [
- "bitflags",
- "indexmap",
- "semver",
-]
-
-[[package]]
 name = "wast"
-version = "228.0.0"
+version = "229.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e5aae124478cb51439f6587f074a3a5e835afd22751c59a87b2e2a882727c97"
+checksum = "63fcaff613c12225696bb163f79ca38ffb40e9300eff0ff4b8aa8b2f7eadf0d9"
 dependencies = [
  "bumpalo",
  "leb128fmt",
  "memchr",
  "unicode-width 0.2.0",
- "wasm-encoder 0.228.0",
+ "wasm-encoder 0.229.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.228.0"
+version = "1.229.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ec29c89a8d055df988de7236483bf569988ac3d6905899f6af5ef920f9385ad"
+checksum = "4189bad08b70455a9e9e67dc126d2dcf91fac143a80f1046747a5dde6d4c33e0"
 dependencies = [
  "wast",
 ]
@@ -6399,9 +6366,9 @@ dependencies = [
 
 [[package]]
 name = "wit-component"
-version = "0.223.1"
+version = "0.229.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fc2fcc52a79f6f010a89c867e53e06d4227f86c58984add3e37f32b8e7af5f0"
+checksum = "7f550067740e223bfe6c4878998e81cdbe2529dd9a793dc49248dd6613394e8b"
 dependencies = [
  "anyhow",
  "bitflags",
@@ -6410,17 +6377,17 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "wasm-encoder 0.223.1",
+ "wasm-encoder 0.229.0",
  "wasm-metadata",
- "wasmparser 0.223.1",
+ "wasmparser 0.229.0",
  "wit-parser",
 ]
 
 [[package]]
 name = "wit-parser"
-version = "0.223.1"
+version = "0.229.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "263fde17f1fbe55a413f16eb59094bf751795c6da469a05c3d45ea6c77df6b40"
+checksum = "459c6ba62bf511d6b5f2a845a2a736822e38059c1cfa0b644b467bbbfae4efa6"
 dependencies = [
  "anyhow",
  "id-arena",
@@ -6431,7 +6398,7 @@ dependencies = [
  "serde_derive",
  "serde_json",
  "unicode-xid",
- "wasmparser 0.223.1",
+ "wasmparser 0.229.0",
 ]
 
 [[package]]
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 72c4492d465..b8f863bbed1 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -180,7 +180,7 @@
 # Note that this will attempt to download GCC even if there are local
 # modifications to the `src/gcc` submodule.
 # Currently, this is only supported for the `x86_64-unknown-linux-gnu` target.
-# download-ci-gcc = false
+#download-ci-gcc = false
 
 # =============================================================================
 # General build configuration options
@@ -500,7 +500,7 @@
 # building without optimizations takes much longer than optimizing. Further, some platforms
 # fail to build without this optimization (c.f. #65352).
 # The valid options are:
-# true - Enable optimizations.
+# true - Enable optimizations (same as 3).
 # false - Disable optimizations.
 # 0 - Disable optimizations.
 # 1 - Basic optimizations.
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index df848a26d39..48da9fc63b8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -21,7 +21,7 @@ impl<'a> State<'a> {
             match &_else.kind {
                 // Another `else if` block.
                 ast::ExprKind::If(i, then, e) => {
-                    self.cbox(INDENT_UNIT - 1);
+                    self.cbox(0);
                     self.ibox(0);
                     self.word(" else if ");
                     self.print_expr_as_cond(i);
@@ -30,8 +30,8 @@ impl<'a> State<'a> {
                     self.print_else(e.as_deref())
                 }
                 // Final `else` block.
-                ast::ExprKind::Block(b, _) => {
-                    self.cbox(INDENT_UNIT - 1);
+                ast::ExprKind::Block(b, None) => {
+                    self.cbox(0);
                     self.ibox(0);
                     self.word(" else ");
                     self.print_block(b)
@@ -45,7 +45,9 @@ impl<'a> State<'a> {
     }
 
     fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
-        self.head("if");
+        self.cbox(0);
+        self.ibox(0);
+        self.word_nbsp("if");
         self.print_expr_as_cond(test);
         self.space();
         self.print_block(blk);
@@ -876,6 +878,7 @@ impl<'a> State<'a> {
                 }
             }
         } else {
+            self.end(); // Close the ibox for the pattern.
             self.word(",");
         }
         self.end(); // Close enclosing cbox.
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 34c84c64070..1e1bdfb5977 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -13,9 +13,9 @@ use object::read::archive::ArchiveFile;
 use object::read::macho::FatArch;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::memmap::Mmap;
+use rustc_fs_util::TempDirBuilder;
 use rustc_session::Session;
 use rustc_span::Symbol;
-use tempfile::Builder as TempFileBuilder;
 use tracing::trace;
 
 use super::metadata::search_for_section;
@@ -501,7 +501,7 @@ impl<'a> ArArchiveBuilder<'a> {
         // it creates. We need it to be the default mode for back compat reasons however. (See
         // #107495) To handle this we are telling tempfile to create a temporary directory instead
         // and then inside this directory create a file using File::create.
-        let archive_tmpdir = TempFileBuilder::new()
+        let archive_tmpdir = TempDirBuilder::new()
             .suffix(".temp-archive")
             .tempdir_in(output.parent().unwrap_or_else(|| Path::new("")))
             .map_err(|err| {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index f0c47ac41e8..323538969d7 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
-use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
+use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_macros::LintDiagnostic;
 use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
@@ -48,7 +48,6 @@ use rustc_target::spec::{
     LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel,
     SanitizerSet, SplitDebuginfo,
 };
-use tempfile::Builder as TempFileBuilder;
 use tracing::{debug, info, warn};
 
 use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
@@ -100,7 +99,7 @@ pub fn link_binary(
         });
 
         if outputs.outputs.should_link() {
-            let tmpdir = TempFileBuilder::new()
+            let tmpdir = TempDirBuilder::new()
                 .prefix("rustc")
                 .tempdir()
                 .unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error }));
diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml
index baca3bc7d49..90a6acade8b 100644
--- a/compiler/rustc_fs_util/Cargo.toml
+++ b/compiler/rustc_fs_util/Cargo.toml
@@ -5,4 +5,5 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
+tempfile = "3.7.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index 0df1b243d69..7a883a13b72 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -1,6 +1,8 @@
-use std::ffi::CString;
+use std::ffi::{CString, OsStr};
 use std::path::{Path, PathBuf, absolute};
-use std::{fs, io};
+use std::{env, fs, io};
+
+use tempfile::TempDir;
 
 // Unfortunately, on windows, it looks like msvcrt.dll is silently translating
 // verbatim paths under the hood to non-verbatim paths! This manifests itself as
@@ -102,3 +104,43 @@ pub fn path_to_c_string(p: &Path) -> CString {
 pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
     fs::canonicalize(&path).or_else(|_| absolute(&path))
 }
+
+pub struct TempDirBuilder<'a, 'b> {
+    builder: tempfile::Builder<'a, 'b>,
+}
+
+impl<'a, 'b> TempDirBuilder<'a, 'b> {
+    pub fn new() -> Self {
+        Self { builder: tempfile::Builder::new() }
+    }
+
+    pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self {
+        self.builder.prefix(prefix);
+        self
+    }
+
+    pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self {
+        self.builder.suffix(suffix);
+        self
+    }
+
+    pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> {
+        let dir = dir.as_ref();
+        // On Windows in CI, we had been getting fairly frequent "Access is denied"
+        // errors when creating temporary directories.
+        // So this implements a simple retry with backoff loop.
+        #[cfg(windows)]
+        for wait in 1..11 {
+            match self.builder.tempdir_in(dir) {
+                Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {}
+                t => return t,
+            }
+            std::thread::sleep(std::time::Duration::from_millis(1 << wait));
+        }
+        self.builder.tempdir_in(dir)
+    }
+
+    pub fn tempdir(&self) -> io::Result<TempDir> {
+        self.tempdir_in(env::temp_dir())
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 4f338c6a19e..f92b2aea160 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -730,7 +730,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                     .is_ok()
                 {
                     check_impl_items_against_trait(tcx, def_id, impl_trait_header);
-                    check_on_unimplemented(tcx, def_id);
                 }
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 06a7b1f6c29..bbf36fef1dd 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -379,13 +379,13 @@ fn compare_method_predicate_entailment<'tcx>(
         // Annoyingly, asking for the WF predicates of an array (with an unevaluated const (only?))
         // will give back the well-formed predicate of the same array.
         let mut wf_args_seen: FxHashSet<_> = wf_args.iter().copied().collect();
-        while let Some(arg) = wf_args.pop() {
+        while let Some(term) = wf_args.pop() {
             let Some(obligations) = rustc_trait_selection::traits::wf::obligations(
                 infcx,
                 param_env,
                 impl_m_def_id,
                 0,
-                arg,
+                term,
                 impl_m_span,
             ) else {
                 continue;
@@ -402,9 +402,9 @@ fn compare_method_predicate_entailment<'tcx>(
                         | ty::ClauseKind::TypeOutlives(..)
                         | ty::ClauseKind::Projection(..),
                     ) => ocx.register_obligation(obligation),
-                    ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                        if wf_args_seen.insert(arg) {
-                            wf_args.push(arg)
+                    ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
+                        if wf_args_seen.insert(term) {
+                            wf_args.push(term)
                         }
                     }
                     _ => {}
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 33d5a86beb3..d13fafae4e8 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -76,12 +76,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
         )
     }
 
-    fn register_wf_obligation(
-        &self,
-        span: Span,
-        loc: Option<WellFormedLoc>,
-        arg: ty::GenericArg<'tcx>,
-    ) {
+    fn register_wf_obligation(&self, span: Span, loc: Option<WellFormedLoc>, term: ty::Term<'tcx>) {
         let cause = traits::ObligationCause::new(
             span,
             self.body_def_id,
@@ -91,7 +86,7 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
             self.tcx(),
             cause,
             self.param_env,
-            ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))),
+            ty::ClauseKind::WellFormed(term),
         ));
     }
 }
@@ -1486,8 +1481,41 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                     tcx.def_span(param.def_id),
                     matches!(param.kind, GenericParamDefKind::Type { .. })
                         .then(|| WellFormedLoc::Ty(param.def_id.expect_local())),
-                    default,
+                    default.as_term().unwrap(),
                 );
+            } else {
+                // If we've got a generic const parameter we still want to check its
+                // type is correct in case both it and the param type are fully concrete.
+                let GenericArgKind::Const(ct) = default.unpack() else {
+                    continue;
+                };
+
+                let ct_ty = match ct.kind() {
+                    ty::ConstKind::Infer(_)
+                    | ty::ConstKind::Placeholder(_)
+                    | ty::ConstKind::Bound(_, _) => unreachable!(),
+                    ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => continue,
+                    ty::ConstKind::Value(cv) => cv.ty,
+                    ty::ConstKind::Unevaluated(uv) => {
+                        infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args)
+                    }
+                    ty::ConstKind::Param(param_ct) => param_ct.find_ty_from_env(wfcx.param_env),
+                };
+
+                let param_ty = tcx.type_of(param.def_id).instantiate_identity();
+                if !ct_ty.has_param() && !param_ty.has_param() {
+                    let cause = traits::ObligationCause::new(
+                        tcx.def_span(param.def_id),
+                        wfcx.body_def_id,
+                        ObligationCauseCode::WellFormed(None),
+                    );
+                    wfcx.register_obligation(Obligation::new(
+                        tcx,
+                        cause,
+                        wfcx.param_env,
+                        ty::ClauseKind::ConstArgHasType(ct, param_ty),
+                    ));
+                }
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index af1107b499f..309221f9a12 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -374,9 +374,12 @@ fn check_predicates<'tcx>(
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args {
+        let Some(term) = arg.as_term() else {
+            continue;
+        };
         let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let obligations =
-            wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span)
+            wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, term, span)
                 .unwrap();
 
         assert!(!obligations.has_infer());
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 779fae80f19..c95d6a277c7 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1064,18 +1064,18 @@ impl<'a> State<'a> {
         if let Some(els_inner) = els {
             match els_inner.kind {
                 // Another `else if` block.
-                hir::ExprKind::If(i, then, e) => {
-                    self.cbox(INDENT_UNIT - 1);
+                hir::ExprKind::If(i, hir::Expr { kind: hir::ExprKind::Block(t, None), .. }, e) => {
+                    self.cbox(0);
                     self.ibox(0);
                     self.word(" else if ");
                     self.print_expr_as_cond(i);
                     self.space();
-                    self.print_expr(then);
+                    self.print_block(t);
                     self.print_else(e);
                 }
                 // Final `else` block.
-                hir::ExprKind::Block(b, _) => {
-                    self.cbox(INDENT_UNIT - 1);
+                hir::ExprKind::Block(b, None) => {
+                    self.cbox(0);
                     self.ibox(0);
                     self.word(" else ");
                     self.print_block(b);
@@ -1094,11 +1094,18 @@ impl<'a> State<'a> {
         blk: &hir::Expr<'_>,
         elseopt: Option<&hir::Expr<'_>>,
     ) {
-        self.head("if");
+        self.cbox(0);
+        self.ibox(0);
+        self.word_nbsp("if");
         self.print_expr_as_cond(test);
         self.space();
-        self.print_expr(blk);
-        self.print_else(elseopt)
+        match blk.kind {
+            hir::ExprKind::Block(blk, None) => {
+                self.print_block(blk);
+                self.print_else(elseopt)
+            }
+            _ => panic!("non-block then expr"),
+        }
     }
 
     fn print_anon_const(&mut self, constant: &hir::AnonConst) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index cac8237f8f6..362c7d8efac 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -22,8 +22,8 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
 use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, GenericArgKind, GenericArgsRef, GenericParamDefKind,
-    IsIdentity, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, UserSelfTy,
+    self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity, Ty, TyCtxt,
+    TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, UserSelfTy,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -573,7 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
     pub(crate) fn register_wf_obligation(
         &self,
-        arg: ty::GenericArg<'tcx>,
+        term: ty::Term<'tcx>,
         span: Span,
         code: traits::ObligationCauseCode<'tcx>,
     ) {
@@ -583,16 +583,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.tcx,
             cause,
             self.param_env,
-            ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg))),
+            ty::ClauseKind::WellFormed(term),
         ));
     }
 
     /// Registers obligations that all `args` are well-formed.
     pub(crate) fn add_wf_bounds(&self, args: GenericArgsRef<'tcx>, span: Span) {
-        for arg in args.iter().filter(|arg| {
-            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
-        }) {
-            self.register_wf_obligation(arg, span, ObligationCauseCode::WellFormed(None));
+        for term in args.iter().filter_map(ty::GenericArg::as_term) {
+            self.register_wf_obligation(term, span, ObligationCauseCode::WellFormed(None));
         }
     }
 
@@ -1320,27 +1318,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 infer_args: bool,
             ) -> ty::GenericArg<'tcx> {
                 let tcx = self.fcx.tcx();
-                match param.kind {
-                    GenericParamDefKind::Lifetime => self
-                        .fcx
-                        .re_infer(
-                            self.span,
-                            rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param),
-                        )
-                        .into(),
-                    GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
-                        if !infer_args && let Some(default) = param.default_value(tcx) {
-                            // If we have a default, then it doesn't matter that we're not inferring
-                            // the type/const arguments: We provide the default where any is missing.
-                            return default.instantiate(tcx, preceding_args);
-                        }
-                        // If no type/const arguments were provided, we have to infer them.
-                        // This case also occurs as a result of some malformed input, e.g.,
-                        // a lifetime argument being given instead of a type/const parameter.
-                        // Using inference instead of `Error` gives better error messages.
-                        self.fcx.var_for_def(self.span, param)
-                    }
+                if !infer_args && let Some(default) = param.default_value(tcx) {
+                    // If we have a default, then it doesn't matter that we're not inferring
+                    // the type/const arguments: We provide the default where any is missing.
+                    return default.instantiate(tcx, preceding_args);
                 }
+                // If no type/const arguments were provided, we have to infer them.
+                // This case also occurs as a result of some malformed input, e.g.,
+                // a lifetime argument being given instead of a type/const parameter.
+                // Using inference instead of `Error` gives better error messages.
+                self.fcx.var_for_def(self.span, param)
             }
         }
 
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 3caaa7f9a9d..c5000171ad7 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -863,7 +863,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
         Resolver { fcx, span, body, nested_goals, should_normalize }
     }
 
-    fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
+    fn report_error(&self, p: impl Into<ty::Term<'tcx>>) -> ErrorGuaranteed {
         if let Some(guar) = self.fcx.tainted_by_errors() {
             guar
         } else {
@@ -887,7 +887,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
         new_err: impl Fn(TyCtxt<'tcx>, ErrorGuaranteed) -> T,
     ) -> T
     where
-        T: Into<ty::GenericArg<'tcx>> + TypeSuperFoldable<TyCtxt<'tcx>> + Copy,
+        T: Into<ty::Term<'tcx>> + TypeSuperFoldable<TyCtxt<'tcx>> + Copy,
     {
         let tcx = self.fcx.tcx;
         // We must deeply normalize in the new solver, since later lints expect
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index c4698e5cbb4..d25542dadd5 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -31,9 +31,9 @@ use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{
     self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs,
-    GenericArgsRef, GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Ty, TyCtxt,
-    TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv,
-    TypingMode, fold_regions,
+    GenericArgsRef, GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Term, TermKind,
+    Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+    TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
 };
 use rustc_span::{Span, Symbol};
 use snapshot::undo_log::InferCtxtUndoLogs;
@@ -1401,6 +1401,16 @@ impl<'tcx> TyOrConstInferVar {
         }
     }
 
+    /// Tries to extract an inference variable from a type or a constant, returns `None`
+    /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
+    /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
+    pub fn maybe_from_term(term: Term<'tcx>) -> Option<Self> {
+        match term.unpack() {
+            TermKind::Ty(ty) => Self::maybe_from_ty(ty),
+            TermKind::Const(ct) => Self::maybe_from_const(ct),
+        }
+    }
+
     /// Tries to extract an inference variable from a type, returns `None`
     /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`).
     fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> {
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 5c8c51c8bbc..0ceda220134 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -1,7 +1,7 @@
 #![allow(rustc::bad_opt_access)]
-use std::collections::{BTreeMap, BTreeSet};
+use std::collections::BTreeMap;
 use std::num::NonZero;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::sync::atomic::AtomicBool;
 
 use rustc_abi::Align;
@@ -89,8 +89,8 @@ where
     S: Into<String>,
     I: IntoIterator<Item = S>,
 {
-    let locations: BTreeSet<CanonicalizedPath> =
-        locations.into_iter().map(|s| CanonicalizedPath::new(Path::new(&s.into()))).collect();
+    let locations =
+        locations.into_iter().map(|s| CanonicalizedPath::new(PathBuf::from(s.into()))).collect();
 
     ExternEntry {
         location: ExternLocation::ExactPaths(locations),
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index e65f4beab24..41b43f64798 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -948,7 +948,7 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,compile_fail
+    /// ```rust,compile_fail,edition2021
     /// #[no_mangle]
     /// const FOO: i32 = 5;
     /// ```
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 3660bb3f780..5679d4566dc 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -812,7 +812,10 @@ impl<'tcx> LateContext<'tcx> {
                     return Ok(());
                 }
 
-                self.path.push(Symbol::intern(&disambiguated_data.data.to_string()));
+                self.path.push(match disambiguated_data.data.get_opt_name() {
+                    Some(sym) => sym,
+                    None => Symbol::intern(&disambiguated_data.data.to_string()),
+                });
                 Ok(())
             }
 
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index f1dc420aa3c..7f4789ad0d9 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -41,7 +41,7 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,compile_fail
+    /// ```rust,compile_fail,edition2021
     /// # #![deny(impl_trait_overcaptures)]
     /// # use std::fmt::Display;
     /// let mut x = vec![];
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 17d501c5730..03b8112938c 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1424,7 +1424,7 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,compile_fail
+    /// ```rust,compile_fail,edition2021
     /// macro_rules! foo {
     ///    () => {};
     ///    ($name) => { };
@@ -4128,7 +4128,7 @@ declare_lint! {
     ///
     /// ### Example
     ///
-    /// ```rust,compile_fail
+    /// ```rust,compile_fail,edition2021
     /// #![deny(dependency_on_unit_never_type_fallback)]
     /// fn main() {
     ///     if true {
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index 68058250a26..ed5edeef161 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -229,6 +229,7 @@ pub fn initialize_available_targets() {
         LLVMInitializeXtensaTargetInfo,
         LLVMInitializeXtensaTarget,
         LLVMInitializeXtensaTargetMC,
+        LLVMInitializeXtensaAsmPrinter,
         LLVMInitializeXtensaAsmParser
     );
     init_target!(
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 08dcc3d519a..b11f9260be7 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -26,7 +26,6 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-tempfile = "3.2"
 tracing = "0.1"
 # tidy-alphabetical-end
 
diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs
index c4e1e0f1d1a..e57534b847e 100644
--- a/compiler/rustc_metadata/src/fs.rs
+++ b/compiler/rustc_metadata/src/fs.rs
@@ -2,11 +2,11 @@ use std::path::{Path, PathBuf};
 use std::{fs, io};
 
 use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_fs_util::TempDirBuilder;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{CrateType, OutFileName, OutputType};
 use rustc_session::output::filename_for_metadata;
 use rustc_session::{MetadataKind, Session};
-use tempfile::Builder as TempFileBuilder;
 
 use crate::errors::{
     BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
@@ -45,7 +45,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
     // final destination, with an `fs::rename` call. In order for the rename to
     // always succeed, the temporary file needs to be on the same filesystem,
     // which is why we create it inside the output directory specifically.
-    let metadata_tmpdir = TempFileBuilder::new()
+    let metadata_tmpdir = TempDirBuilder::new()
         .prefix("rmeta")
         .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
         .unwrap_or_else(|err| tcx.dcx().emit_fatal(FailedCreateTempdir { err }));
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 98057a25f04..e8dad1e056c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -590,6 +590,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.defaultness(def_id).has_value()
     }
 
+    fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool {
+        self.specializes((impl_def_id, victim_def_id))
+    }
+
     fn impl_is_default(self, impl_def_id: DefId) -> bool {
         self.defaultness(impl_def_id).is_default()
     }
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 8de64b3bfac..542c0b3e6eb 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -250,17 +250,17 @@ impl<'tcx> GenericArg<'tcx> {
     }
 
     #[inline]
-    pub fn as_type(self) -> Option<Ty<'tcx>> {
+    pub fn as_region(self) -> Option<ty::Region<'tcx>> {
         match self.unpack() {
-            GenericArgKind::Type(ty) => Some(ty),
+            GenericArgKind::Lifetime(re) => Some(re),
             _ => None,
         }
     }
 
     #[inline]
-    pub fn as_region(self) -> Option<ty::Region<'tcx>> {
+    pub fn as_type(self) -> Option<Ty<'tcx>> {
         match self.unpack() {
-            GenericArgKind::Lifetime(re) => Some(re),
+            GenericArgKind::Type(ty) => Some(ty),
             _ => None,
         }
     }
@@ -273,6 +273,15 @@ impl<'tcx> GenericArg<'tcx> {
         }
     }
 
+    #[inline]
+    pub fn as_term(self) -> Option<ty::Term<'tcx>> {
+        match self.unpack() {
+            GenericArgKind::Lifetime(_) => None,
+            GenericArgKind::Type(ty) => Some(ty.into()),
+            GenericArgKind::Const(ct) => Some(ct.into()),
+        }
+    }
+
     /// Unpack the `GenericArg` as a region when it is known certainly to be a region.
     pub fn expect_region(self) -> ty::Region<'tcx> {
         self.as_region().unwrap_or_else(|| bug!("expected a region, but found another kind"))
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 3698cfb9870..be00c0e116d 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -110,6 +110,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder};
 pub use crate::ty::diagnostics::*;
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::util::Discr;
+use crate::ty::walk::TypeWalker;
 
 pub mod abstract_const;
 pub mod adjustment;
@@ -631,6 +632,20 @@ impl<'tcx> Term<'tcx> {
             TermKind::Const(ct) => ct.is_ct_infer(),
         }
     }
+
+    /// Iterator that walks `self` and any types reachable from
+    /// `self`, in depth-first order. Note that just walks the types
+    /// that appear in `self`, it does not descend into the fields of
+    /// structs or variants. For example:
+    ///
+    /// ```text
+    /// isize => { isize }
+    /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+    /// [isize] => { [isize], isize }
+    /// ```
+    pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
+        TypeWalker::new(self.into())
+    }
 }
 
 const TAG_MASK: usize = 0b11;
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index d739218af5e..1df3bff5244 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3247,7 +3247,7 @@ define_print! {
             ty::ClauseKind::ConstArgHasType(ct, ty) => {
                 p!("the constant `", print(ct), "` has type `", print(ty), "`")
             },
-            ty::ClauseKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+            ty::ClauseKind::WellFormed(term) => p!(print(term), " well-formed"),
             ty::ClauseKind::ConstEvaluatable(ct) => {
                 p!("the constant `", print(ct), "` can be evaluated")
             }
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 39fcc686c55..4d70a708732 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -138,18 +138,26 @@ impl<'tcx> Value<TyCtxt<'tcx>> for &[ty::Variance] {
         cycle_error: &CycleError,
         _guar: ErrorGuaranteed,
     ) -> Self {
-        if let Some(frame) = cycle_error.cycle.get(0)
-            && frame.query.dep_kind == dep_kinds::variances_of
-            && let Some(def_id) = frame.query.def_id
-        {
-            let n = tcx.generics_of(def_id).own_params.len();
-            vec![ty::Bivariant; n].leak()
-        } else {
-            span_bug!(
-                cycle_error.usage.as_ref().unwrap().0,
-                "only `variances_of` returns `&[ty::Variance]`"
-            );
-        }
+        search_for_cycle_permutation(
+            &cycle_error.cycle,
+            |cycle| {
+                if let Some(frame) = cycle.get(0)
+                    && frame.query.dep_kind == dep_kinds::variances_of
+                    && let Some(def_id) = frame.query.def_id
+                {
+                    let n = tcx.generics_of(def_id).own_params.len();
+                    ControlFlow::Break(vec![ty::Bivariant; n].leak())
+                } else {
+                    ControlFlow::Continue(())
+                }
+            },
+            || {
+                span_bug!(
+                    cycle_error.usage.as_ref().unwrap().0,
+                    "only `variances_of` returns `&[ty::Variance]`"
+                )
+            },
+        )
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 51c4e95e74b..f2e8f9e1bcd 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -89,7 +89,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
 
     // Use the coverage graph to prepare intermediate data that will eventually
     // be used to assign physical counters and counter expressions to points in
-    // the control-flow graph
+    // the control-flow graph.
     let BcbCountersData { node_flow_data, priority_list } =
         counters::prepare_bcb_counters_data(&graph);
 
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index c4b6b18c45d..25493970a0c 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -36,7 +36,7 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
     fn well_formed_goals(
         &self,
         param_env: <Self::Interner as Interner>::ParamEnv,
-        arg: <Self::Interner as Interner>::GenericArg,
+        term: <Self::Interner as Interner>::Term,
     ) -> Option<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>>;
 
     fn clone_opaque_types_for_query_response(
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index ecb57cc0ad7..381a732b8de 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -10,6 +10,7 @@ use rustc_type_ir::{
 };
 use tracing::{debug, instrument};
 
+use super::has_only_region_constraints;
 use super::trait_goals::TraitGoalProvenVia;
 use crate::delegate::SolverDelegate;
 use crate::solve::inspect::ProbeKind;
@@ -771,6 +772,69 @@ where
             }
         })
     }
+}
+
+pub(super) enum AllowInferenceConstraints {
+    Yes,
+    No,
+}
+
+impl<D, I> EvalCtxt<'_, D>
+where
+    D: SolverDelegate<Interner = I>,
+    I: Interner,
+{
+    /// Check whether we can ignore impl candidates due to specialization.
+    ///
+    /// This is only necessary for `feature(specialization)` and seems quite ugly.
+    pub(super) fn filter_specialized_impls(
+        &mut self,
+        allow_inference_constraints: AllowInferenceConstraints,
+        candidates: &mut Vec<Candidate<I>>,
+    ) {
+        match self.typing_mode() {
+            TypingMode::Coherence => return,
+            TypingMode::Analysis { .. }
+            | TypingMode::Borrowck { .. }
+            | TypingMode::PostBorrowckAnalysis { .. }
+            | TypingMode::PostAnalysis => {}
+        }
+
+        let mut i = 0;
+        'outer: while i < candidates.len() {
+            let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
+                i += 1;
+                continue;
+            };
+
+            for (j, c) in candidates.iter().enumerate() {
+                if i == j {
+                    continue;
+                }
+
+                let CandidateSource::Impl(other_def_id) = c.source else {
+                    continue;
+                };
+
+                // See if we can toss out `victim` based on specialization.
+                //
+                // While this requires us to know *for sure* that the `lhs` impl applies
+                // we still use modulo regions here. This is fine as specialization currently
+                // assumes that specializing impls have to be always applicable, meaning that
+                // the only allowed region constraints may be constraints also present on the default impl.
+                if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
+                    || has_only_region_constraints(c.result)
+                {
+                    if self.cx().impl_specializes(other_def_id, victim_def_id) {
+                        candidates.remove(i);
+                        continue 'outer;
+                    }
+                }
+            }
+
+            i += 1;
+        }
+    }
 
     /// Assemble and merge candidates for goals which are related to an underlying trait
     /// goal. Right now, this is normalizes-to and host effect goals.
@@ -857,7 +921,7 @@ where
                 }
             }
             TraitGoalProvenVia::Misc => {
-                let candidates =
+                let mut candidates =
                     self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
 
                 // Prefer "orphaned" param-env normalization predicates, which are used
@@ -871,6 +935,13 @@ where
                     return Ok(response);
                 }
 
+                // We drop specialized impls to allow normalization via a final impl here. In case
+                // the specializing impl has different inference constraints from the specialized
+                // impl, proving the trait goal is already ambiguous, so we never get here. This
+                // means we can just ignore inference constraints and don't have to special-case
+                // constraining the normalized-to `term`.
+                self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);
+
                 let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
                 if let Some(response) = self.try_merge_responses(&responses) {
                     Ok(response)
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 27ca8787db5..6dd554299a6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -16,6 +16,7 @@ use rustc_type_ir::{
 };
 use tracing::{instrument, trace};
 
+use super::has_only_region_constraints;
 use crate::coherence;
 use crate::delegate::SolverDelegate;
 use crate::solve::inspect::{self, ProofTreeBuilder};
@@ -476,13 +477,8 @@ where
             Ok(response) => response,
         };
 
-        let has_changed = if !response.value.var_values.is_identity_modulo_regions()
-            || !response.value.external_constraints.opaque_types.is_empty()
-        {
-            HasChanged::Yes
-        } else {
-            HasChanged::No
-        };
+        let has_changed =
+            if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };
 
         let (normalization_nested_goals, certainty) =
             self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
@@ -533,8 +529,8 @@ where
                 ty::PredicateKind::DynCompatible(trait_def_id) => {
                     self.compute_dyn_compatible_goal(trait_def_id)
                 }
-                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                    self.compute_well_formed_goal(Goal { param_env, predicate: arg })
+                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
+                    self.compute_well_formed_goal(Goal { param_env, predicate: term })
                 }
                 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => {
                     self.compute_const_evaluatable_goal(Goal { param_env, predicate: ct })
@@ -1012,9 +1008,9 @@ where
     pub(super) fn well_formed_goals(
         &self,
         param_env: I::ParamEnv,
-        arg: I::GenericArg,
+        term: I::Term,
     ) -> Option<Vec<Goal<I, I::Predicate>>> {
-        self.delegate.well_formed_goals(param_env, arg)
+        self.delegate.well_formed_goals(param_env, term)
     }
 
     pub(super) fn trait_ref_is_knowable(
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 0695c5acdca..c9f4fc649b5 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -70,6 +70,17 @@ fn has_no_inference_or_external_constraints<I: Interner>(
         && normalization_nested_goals.is_empty()
 }
 
+fn has_only_region_constraints<I: Interner>(response: ty::Canonical<I, Response<I>>) -> bool {
+    let ExternalConstraintsData {
+        region_constraints: _,
+        ref opaque_types,
+        ref normalization_nested_goals,
+    } = *response.value.external_constraints;
+    response.value.var_values.is_identity_modulo_regions()
+        && opaque_types.is_empty()
+        && normalization_nested_goals.is_empty()
+}
+
 impl<'a, D, I> EvalCtxt<'a, D>
 where
     D: SolverDelegate<Interner = I>,
@@ -126,7 +137,7 @@ where
     }
 
     #[instrument(level = "trace", skip(self))]
-    fn compute_well_formed_goal(&mut self, goal: Goal<I, I::GenericArg>) -> QueryResult<I> {
+    fn compute_well_formed_goal(&mut self, goal: Goal<I, I::Term>) -> QueryResult<I> {
         match self.well_formed_goals(goal.param_env, goal.predicate) {
             Some(goals) => {
                 self.add_goals(GoalSource::Misc, goals);
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 9466901683e..119d197de13 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -213,9 +213,6 @@ where
                 ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             };
 
-            // In case the associated item is hidden due to specialization, we have to
-            // return ambiguity this would otherwise be incomplete, resulting in
-            // unsoundness during coherence (#105782).
             let target_item_def_id = match ecx.fetch_eligible_assoc_item(
                 goal_trait_ref,
                 goal.predicate.def_id(),
@@ -223,8 +220,28 @@ where
             ) {
                 Ok(Some(target_item_def_id)) => target_item_def_id,
                 Ok(None) => {
-                    return ecx
-                        .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+                    match ecx.typing_mode() {
+                        // In case the associated item is hidden due to specialization, we have to
+                        // return ambiguity this would otherwise be incomplete, resulting in
+                        // unsoundness during coherence (#105782).
+                        ty::TypingMode::Coherence => {
+                            return ecx.evaluate_added_goals_and_make_canonical_response(
+                                Certainty::AMBIGUOUS,
+                            );
+                        }
+                        // Outside of coherence, we treat the associated item as rigid instead.
+                        ty::TypingMode::Analysis { .. }
+                        | ty::TypingMode::Borrowck { .. }
+                        | ty::TypingMode::PostBorrowckAnalysis { .. }
+                        | ty::TypingMode::PostAnalysis => {
+                            ecx.structurally_instantiate_normalizes_to_term(
+                                goal,
+                                goal.predicate.alias,
+                            );
+                            return ecx
+                                .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
+                        }
+                    };
                 }
                 Err(guar) => return error_response(ecx, guar),
             };
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 3404c47bba2..24657496df6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -13,7 +13,7 @@ use tracing::{instrument, trace};
 
 use crate::delegate::SolverDelegate;
 use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
-use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate};
+use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate};
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
@@ -1338,6 +1338,8 @@ where
             };
         }
 
+        self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);
+
         // If there are *only* global where bounds, then make sure to return that this
         // is still reported as being proven-via the param-env so that rigid projections
         // operate correctly. Otherwise, drop all global where-bounds before merging the
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index ae9143486ee..ac4f7ed64e2 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -675,6 +675,8 @@ parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns ar
 
 parse_nul_in_c_str = null characters in C string literals are not supported
 
+parse_or_in_let_chain = `||` operators are not supported in let chain conditions
+
 parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
 parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
 parse_out_of_range_hex_escape = out of range hex escape
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 35cf4c1b00d..6a6fb0eb9b5 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -478,6 +478,13 @@ pub(crate) struct ExpectedExpressionFoundLet {
     pub comparison: Option<MaybeComparison>,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_or_in_let_chain)]
+pub(crate) struct OrInLetChain {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(Subdiagnostic, Clone, Copy)]
 #[multipart_suggestion(
     parse_maybe_missing_let,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 370eb3f402d..f3b53971b29 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -4073,14 +4073,18 @@ impl MutVisitor for CondChecker<'_> {
         match e.kind {
             ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
                 if let Some(reason) = self.forbid_let_reason {
-                    *recovered = Recovered::Yes(self.parser.dcx().emit_err(
-                        errors::ExpectedExpressionFoundLet {
+                    let error = match reason {
+                        NotSupportedOr(or_span) => {
+                            self.parser.dcx().emit_err(errors::OrInLetChain { span: or_span })
+                        }
+                        _ => self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
                             span,
                             reason,
                             missing_let: self.missing_let,
                             comparison: self.comparison,
-                        },
-                    ));
+                        }),
+                    };
+                    *recovered = Recovered::Yes(error);
                 } else if self.depth > 1 {
                     // Top level `let` is always allowed; only gate chains
                     match self.let_chains_policy {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 0bde289c85f..b56f3e1971c 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -157,7 +157,7 @@ where
                 ty.visit_with(self)
             }
             ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
-            ty::ClauseKind::WellFormed(arg) => arg.visit_with(self),
+            ty::ClauseKind::WellFormed(term) => term.visit_with(self),
         }
     }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 43955cc23a9..e2d36f6a4e2 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2323,14 +2323,13 @@ pub fn parse_externs(
         let ExternOpt { crate_name: name, path, options } =
             split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
 
-        let path = path.map(|p| CanonicalizedPath::new(p.as_path()));
-
         let entry = externs.entry(name.to_owned());
 
         use std::collections::btree_map::Entry;
 
         let entry = if let Some(path) = path {
             // --extern prelude_name=some_file.rlib
+            let path = CanonicalizedPath::new(path);
             match entry {
                 Entry::Vacant(vacant) => {
                     let files = BTreeSet::from_iter(iter::once(path));
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 2243e831b66..e9ddd66b5e8 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,4 +1,4 @@
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::sync::OnceLock;
 
 use rustc_data_structures::profiling::VerboseTimingGuard;
@@ -104,8 +104,8 @@ pub struct CanonicalizedPath {
 }
 
 impl CanonicalizedPath {
-    pub fn new(path: &Path) -> Self {
-        Self { original: path.to_owned(), canonicalized: try_canonicalize(path).ok() }
+    pub fn new(path: PathBuf) -> Self {
+        Self { canonicalized: try_canonicalize(&path).ok(), original: path }
     }
 
     pub fn canonicalized(&self) -> &PathBuf {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index a757329bcf2..c0ed3b90eb4 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -638,8 +638,8 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> {
                 const_.stable(tables),
                 ty.stable(tables),
             ),
-            ClauseKind::WellFormed(generic_arg) => {
-                stable_mir::ty::ClauseKind::WellFormed(generic_arg.unpack().stable(tables))
+            ClauseKind::WellFormed(term) => {
+                stable_mir::ty::ClauseKind::WellFormed(term.unpack().stable(tables))
             }
             ClauseKind::ConstEvaluatable(const_) => {
                 stable_mir::ty::ClauseKind::ConstEvaluatable(const_.stable(tables))
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 4b153007bd8..0ac9a0fb647 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -1462,7 +1462,7 @@ pub enum ClauseKind {
     TypeOutlives(TypeOutlivesPredicate),
     Projection(ProjectionPredicate),
     ConstArgHasType(TyConst, Ty),
-    WellFormed(GenericArgKind),
+    WellFormed(TermKind),
     ConstEvaluatable(TyConst),
 }
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 53908914965..ab0a802dc7f 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -72,21 +72,6 @@ struct SyntaxContextData {
 }
 
 impl SyntaxContextData {
-    fn new(
-        (parent, outer_expn, outer_transparency): SyntaxContextKey,
-        opaque: SyntaxContext,
-        opaque_and_semiopaque: SyntaxContext,
-    ) -> SyntaxContextData {
-        SyntaxContextData {
-            outer_expn,
-            outer_transparency,
-            parent,
-            opaque,
-            opaque_and_semiopaque,
-            dollar_crate_name: kw::DollarCrate,
-        }
-    }
-
     fn root() -> SyntaxContextData {
         SyntaxContextData {
             outer_expn: ExpnId::root(),
@@ -98,14 +83,6 @@ impl SyntaxContextData {
         }
     }
 
-    fn decode_placeholder() -> SyntaxContextData {
-        SyntaxContextData { dollar_crate_name: kw::Empty, ..SyntaxContextData::root() }
-    }
-
-    fn is_decode_placeholder(&self) -> bool {
-        self.dollar_crate_name == kw::Empty
-    }
-
     fn key(&self) -> SyntaxContextKey {
         (self.parent, self.outer_expn, self.outer_transparency)
     }
@@ -148,7 +125,7 @@ impl !PartialOrd for LocalExpnId {}
 /// with a non-default mode. With this check in place, we can avoid the need
 /// to maintain separate versions of `ExpnData` hashes for each permutation
 /// of `HashingControls` settings.
-fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
+fn assert_default_hashing_controls(ctx: &impl HashStableContext, msg: &str) {
     match ctx.hashing_controls() {
         // Note that we require that `hash_spans` be set according to the global
         // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
@@ -416,7 +393,7 @@ impl HygieneData {
         }
     }
 
-    fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
+    fn with<R>(f: impl FnOnce(&mut HygieneData) -> R) -> R {
         with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
     }
 
@@ -460,28 +437,23 @@ impl HygieneData {
     }
 
     fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
-        debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
         self.syntax_context_data[ctxt.0 as usize].opaque
     }
 
     fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
-        debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
         self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
     }
 
     fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
-        debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
         self.syntax_context_data[ctxt.0 as usize].outer_expn
     }
 
     fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
-        debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
         let data = &self.syntax_context_data[ctxt.0 as usize];
         (data.outer_expn, data.outer_transparency)
     }
 
     fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
-        debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
         self.syntax_context_data[ctxt.0 as usize].parent
     }
 
@@ -592,8 +564,6 @@ impl HygieneData {
         expn_id: ExpnId,
         transparency: Transparency,
     ) -> SyntaxContext {
-        debug_assert!(!self.syntax_context_data[parent.0 as usize].is_decode_placeholder());
-
         // Look into the cache first.
         let key = (parent, expn_id, transparency);
         if let Some(ctxt) = self.syntax_context_map.get(&key) {
@@ -601,16 +571,20 @@ impl HygieneData {
         }
 
         // Reserve a new syntax context.
+        // The inserted dummy data can only be potentially accessed by nested `alloc_ctxt` calls,
+        // the assert below ensures that it doesn't happen.
         let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len());
-        self.syntax_context_data.push(SyntaxContextData::decode_placeholder());
+        self.syntax_context_data
+            .push(SyntaxContextData { dollar_crate_name: sym::dummy, ..SyntaxContextData::root() });
         self.syntax_context_map.insert(key, ctxt);
 
         // Opaque and semi-opaque versions of the parent. Note that they may be equal to the
         // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques,
         // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques.
-        let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque;
-        let parent_opaque_and_semiopaque =
-            self.syntax_context_data[parent.0 as usize].opaque_and_semiopaque;
+        let parent_data = &self.syntax_context_data[parent.0 as usize];
+        assert_ne!(parent_data.dollar_crate_name, sym::dummy);
+        let parent_opaque = parent_data.opaque;
+        let parent_opaque_and_semiopaque = parent_data.opaque_and_semiopaque;
 
         // Evaluate opaque and semi-opaque versions of the new syntax context.
         let (opaque, opaque_and_semiopaque) = match transparency {
@@ -629,8 +603,14 @@ impl HygieneData {
         };
 
         // Fill the full data, now that we have it.
-        self.syntax_context_data[ctxt.as_u32() as usize] =
-            SyntaxContextData::new(key, opaque, opaque_and_semiopaque);
+        self.syntax_context_data[ctxt.as_u32() as usize] = SyntaxContextData {
+            outer_expn: expn_id,
+            outer_transparency: transparency,
+            parent,
+            opaque,
+            opaque_and_semiopaque,
+            dollar_crate_name: kw::DollarCrate,
+        };
         ctxt
     }
 }
@@ -650,13 +630,12 @@ pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
 
 pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
     // The new contexts that need updating are at the end of the list and have `$crate` as a name.
-    // Also decoding placeholders can be encountered among both old and new contexts.
     let mut to_update = vec![];
     HygieneData::with(|data| {
         for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() {
             if scdata.dollar_crate_name == kw::DollarCrate {
                 to_update.push((idx, kw::DollarCrate));
-            } else if !scdata.is_decode_placeholder() {
+            } else {
                 break;
             }
         }
@@ -922,10 +901,7 @@ impl SyntaxContext {
     }
 
     pub(crate) fn dollar_crate_name(self) -> Symbol {
-        HygieneData::with(|data| {
-            debug_assert!(!data.syntax_context_data[self.0 as usize].is_decode_placeholder());
-            data.syntax_context_data[self.0 as usize].dollar_crate_name
-        })
+        HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
     }
 
     pub fn edition(self) -> Edition {
@@ -1293,49 +1269,47 @@ impl HygieneEncodeContext {
                 self.latest_ctxts
             );
 
-            // Consume the current round of SyntaxContexts.
-            // Drop the lock() temporary early
-            let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) };
-
-            // It's fine to iterate over a HashMap, because the serialization
-            // of the table that we insert data into doesn't depend on insertion
-            // order
+            // Consume the current round of syntax contexts.
+            // Drop the lock() temporary early.
+            // It's fine to iterate over a HashMap, because the serialization of the table
+            // that we insert data into doesn't depend on insertion order.
             #[allow(rustc::potential_query_instability)]
-            for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
+            let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) }.into_iter();
+            let all_ctxt_data: Vec<_> = HygieneData::with(|data| {
+                latest_ctxts
+                    .map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].key()))
+                    .collect()
+            });
+            for (ctxt, ctxt_key) in all_ctxt_data {
                 if self.serialized_ctxts.lock().insert(ctxt) {
-                    encode_ctxt(encoder, index, data);
+                    encode_ctxt(encoder, ctxt.0, &ctxt_key);
                 }
-            });
-
-            let latest_expns = { mem::take(&mut *self.latest_expns.lock()) };
+            }
 
-            // Same as above, this is fine as we are inserting into a order-independent hashset
+            // Same as above, but for expansions instead of syntax contexts.
             #[allow(rustc::potential_query_instability)]
-            for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
+            let latest_expns = { mem::take(&mut *self.latest_expns.lock()) }.into_iter();
+            let all_expn_data: Vec<_> = HygieneData::with(|data| {
+                latest_expns
+                    .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn)))
+                    .collect()
+            });
+            for (expn, expn_data, expn_hash) in all_expn_data {
                 if self.serialized_expns.lock().insert(expn) {
-                    encode_expn(encoder, expn, data, hash);
+                    encode_expn(encoder, expn, &expn_data, expn_hash);
                 }
-            });
+            }
         }
         debug!("encode_hygiene: Done serializing SyntaxContextData");
     }
 }
 
-#[derive(Default)]
 /// Additional information used to assist in decoding hygiene data
-struct HygieneDecodeContextInner {
-    // Maps serialized `SyntaxContext` ids to a `SyntaxContext` in the current
-    // global `HygieneData`. When we deserialize a `SyntaxContext`, we need to create
-    // a new id in the global `HygieneData`. This map tracks the ID we end up picking,
-    // so that multiple occurrences of the same serialized id are decoded to the same
-    // `SyntaxContext`. This only stores `SyntaxContext`s which are completely decoded.
-    remapped_ctxts: Vec<Option<SyntaxContext>>,
-}
-
 #[derive(Default)]
-/// Additional information used to assist in decoding hygiene data
 pub struct HygieneDecodeContext {
-    inner: Lock<HygieneDecodeContextInner>,
+    // A cache mapping raw serialized per-crate syntax context ids to corresponding decoded
+    // `SyntaxContext`s in the current global `HygieneData`.
+    remapped_ctxts: Lock<IndexVec<u32, Option<SyntaxContext>>>,
 }
 
 /// Register an expansion which has been decoded from the on-disk-cache for the local crate.
@@ -1406,10 +1380,10 @@ pub fn decode_expn_id(
 // to track which `SyntaxContext`s we have already decoded.
 // The provided closure will be invoked to deserialize a `SyntaxContextData`
 // if we haven't already seen the id of the `SyntaxContext` we are deserializing.
-pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextKey>(
+pub fn decode_syntax_context<D: Decoder>(
     d: &mut D,
     context: &HygieneDecodeContext,
-    decode_data: F,
+    decode_data: impl FnOnce(&mut D, u32) -> SyntaxContextKey,
 ) -> SyntaxContext {
     let raw_id: u32 = Decodable::decode(d);
     if raw_id == 0 {
@@ -1418,12 +1392,11 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
         return SyntaxContext::root();
     }
 
+    // Look into the cache first.
     // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between
     // raw ids from different crate metadatas.
-    if let Some(ctxt) = context.inner.lock().remapped_ctxts.get(raw_id as usize).copied().flatten()
-    {
-        // This has already been decoded.
-        return ctxt;
+    if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(raw_id) {
+        return *ctxt;
     }
 
     // Don't try to decode data while holding the lock, since we need to
@@ -1432,48 +1405,11 @@ pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContext
     let ctxt =
         HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency));
 
-    let mut inner = context.inner.lock();
-    let new_len = raw_id as usize + 1;
-    if inner.remapped_ctxts.len() < new_len {
-        inner.remapped_ctxts.resize(new_len, None);
-    }
-    inner.remapped_ctxts[raw_id as usize] = Some(ctxt);
+    context.remapped_ctxts.lock().insert(raw_id, ctxt);
 
     ctxt
 }
 
-fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextKey)>(
-    ctxts: impl Iterator<Item = SyntaxContext>,
-    mut f: F,
-) {
-    let all_data: Vec<_> = HygieneData::with(|data| {
-        ctxts
-            .map(|ctxt| {
-                (ctxt, {
-                    let item = data.syntax_context_data[ctxt.0 as usize];
-                    debug_assert!(!item.is_decode_placeholder());
-                    item.key()
-                })
-            })
-            .collect()
-    });
-    for (ctxt, data) in all_data.into_iter() {
-        f(ctxt.0, ctxt, &data);
-    }
-}
-
-fn for_all_expns_in(
-    expns: impl Iterator<Item = ExpnId>,
-    mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash),
-) {
-    let all_data: Vec<_> = HygieneData::with(|data| {
-        expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect()
-    });
-    for (expn, data, hash) in all_data.into_iter() {
-        f(expn, &data, hash);
-    }
-}
-
 impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
     fn encode(&self, e: &mut E) {
         self.to_expn_id().encode(e);
@@ -1486,10 +1422,10 @@ impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
     }
 }
 
-pub fn raw_encode_syntax_context<E: Encoder>(
+pub fn raw_encode_syntax_context(
     ctxt: SyntaxContext,
     context: &HygieneEncodeContext,
-    e: &mut E,
+    e: &mut impl Encoder,
 ) {
     if !context.serialized_ctxts.lock().contains(&ctxt) {
         context.latest_ctxts.lock().insert(ctxt);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index f45e3904212..eba195cb99c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -14,8 +14,8 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::{
-    self, GenericArg, GenericArgKind, GenericArgsRef, InferConst, IsSuggestable, Ty, TyCtxt,
-    TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults,
+    self, GenericArg, GenericArgKind, GenericArgsRef, InferConst, IsSuggestable, Term, TermKind,
+    Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults,
 };
 use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym};
 use rustc_type_ir::TypeVisitableExt;
@@ -344,12 +344,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     /// which were stuck during inference.
     pub fn extract_inference_diagnostics_data(
         &self,
-        arg: GenericArg<'tcx>,
+        term: Term<'tcx>,
         highlight: ty::print::RegionHighlightMode<'tcx>,
     ) -> InferenceDiagnosticsData {
         let tcx = self.tcx;
-        match arg.unpack() {
-            GenericArgKind::Type(ty) => {
+        match term.unpack() {
+            TermKind::Ty(ty) => {
                 if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() {
                     let var_origin = self.infcx.type_var_origin(ty_vid);
                     if let Some(def_id) = var_origin.param_def_id
@@ -375,7 +375,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     parent: None,
                 }
             }
-            GenericArgKind::Const(ct) => {
+            TermKind::Const(ct) => {
                 if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() {
                     let origin = self.const_var_origin(vid).expect("expected unresolved const var");
                     if let Some(def_id) = origin.param_def_id {
@@ -411,7 +411,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     }
                 }
             }
-            GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
         }
     }
 
@@ -472,13 +471,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         body_def_id: LocalDefId,
         failure_span: Span,
-        arg: GenericArg<'tcx>,
+        term: Term<'tcx>,
         error_code: TypeAnnotationNeeded,
         should_label_span: bool,
     ) -> Diag<'a> {
-        let arg = self.resolve_vars_if_possible(arg);
-        let arg_data =
-            self.extract_inference_diagnostics_data(arg, ty::print::RegionHighlightMode::default());
+        let term = self.resolve_vars_if_possible(term);
+        let arg_data = self
+            .extract_inference_diagnostics_data(term, ty::print::RegionHighlightMode::default());
 
         let Some(typeck_results) = &self.typeck_results else {
             // If we don't have any typeck results we're outside
@@ -487,7 +486,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             return self.bad_inference_failure_err(failure_span, arg_data, error_code);
         };
 
-        let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg);
+        let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, term);
         if let Some(body) = self.tcx.hir_maybe_body_owned_by(
             self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(),
         ) {
@@ -542,7 +541,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 have_turbofish,
             } => {
                 let generics = self.tcx.generics_of(generics_def_id);
-                let is_type = matches!(arg.unpack(), GenericArgKind::Type(_));
+                let is_type = term.as_type().is_some();
 
                 let (parent_exists, parent_prefix, parent_name) =
                     InferenceDiagnosticsParentData::for_parent_def_id(self.tcx, generics_def_id)
@@ -811,7 +810,7 @@ struct FindInferSourceVisitor<'a, 'tcx> {
     tecx: &'a TypeErrCtxt<'a, 'tcx>,
     typeck_results: &'a TypeckResults<'tcx>,
 
-    target: GenericArg<'tcx>,
+    target: Term<'tcx>,
 
     attempt: usize,
     infer_source_cost: usize,
@@ -822,7 +821,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
     fn new(
         tecx: &'a TypeErrCtxt<'a, 'tcx>,
         typeck_results: &'a TypeckResults<'tcx>,
-        target: GenericArg<'tcx>,
+        target: Term<'tcx>,
     ) -> Self {
         FindInferSourceVisitor {
             tecx,
@@ -938,12 +937,12 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
     // Check whether this generic argument is the inference variable we
     // are looking for.
     fn generic_arg_is_target(&self, arg: GenericArg<'tcx>) -> bool {
-        if arg == self.target {
+        if arg == self.target.into() {
             return true;
         }
 
         match (arg.unpack(), self.target.unpack()) {
-            (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+            (GenericArgKind::Type(inner_ty), TermKind::Ty(target_ty)) => {
                 use ty::{Infer, TyVar};
                 match (inner_ty.kind(), target_ty.kind()) {
                     (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
@@ -952,7 +951,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                     _ => false,
                 }
             }
-            (GenericArgKind::Const(inner_ct), GenericArgKind::Const(target_ct)) => {
+            (GenericArgKind::Const(inner_ct), TermKind::Const(target_ct)) => {
                 use ty::InferConst::*;
                 match (inner_ct.kind(), target_ct.kind()) {
                     (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 54b50851b74..275b580d794 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -228,13 +228,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // Pick the first generic parameter that still contains inference variables as the one
                 // we're going to emit an error for. If there are none (see above), fall back to
                 // a more general error.
-                let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
+                let term = data
+                    .trait_ref
+                    .args
+                    .iter()
+                    .filter_map(ty::GenericArg::as_term)
+                    .find(|s| s.has_non_region_infer());
 
-                let mut err = if let Some(arg) = arg {
+                let mut err = if let Some(term) = term {
                     self.emit_inference_failure_err(
                         obligation.cause.body_id,
                         span,
-                        arg,
+                        term,
                         TypeAnnotationNeeded::E0283,
                         true,
                     )
@@ -276,7 +281,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
                 if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
                     if let Some(e) = self.tainted_by_errors()
-                        && arg.is_none()
+                        && term.is_none()
                     {
                         // If `arg.is_none()`, then this is probably two param-env
                         // candidates or impl candidates that are equal modulo lifetimes.
@@ -313,7 +318,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     self.suggest_fully_qualified_path(&mut err, def_id, span, trait_pred.def_id());
                 }
 
-                if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
+                if term.is_some_and(|term| term.as_type().is_some())
                     && let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id)
                 {
                     let mut expr_finder = FindExprBySpan::new(span, self.tcx);
@@ -464,11 +469,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 err
             }
 
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
 
-                if let Err(e) = arg.error_reported() {
+                if let Err(e) = term.error_reported() {
                     return e;
                 }
                 if let Some(e) = self.tainted_by_errors() {
@@ -478,7 +483,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 self.emit_inference_failure_err(
                     obligation.cause.body_id,
                     span,
-                    arg,
+                    term,
                     TypeAnnotationNeeded::E0282,
                     false,
                 )
@@ -519,18 +524,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     // other `Foo` impls are incoherent.
                     return guar;
                 }
-                let arg = data
+                let term = data
                     .projection_term
                     .args
                     .iter()
-                    .chain(Some(data.term.into_arg()))
+                    .filter_map(ty::GenericArg::as_term)
+                    .chain([data.term])
                     .find(|g| g.has_non_region_infer());
                 let predicate = self.tcx.short_string(predicate, &mut file);
-                if let Some(arg) = arg {
+                if let Some(term) = term {
                     self.emit_inference_failure_err(
                         obligation.cause.body_id,
                         span,
-                        arg,
+                        term,
                         TypeAnnotationNeeded::E0284,
                         true,
                     )
@@ -554,12 +560,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let Some(e) = self.tainted_by_errors() {
                     return e;
                 }
-                let arg = data.walk().find(|g| g.is_non_region_infer());
-                if let Some(arg) = arg {
+                let term =
+                    data.walk().filter_map(ty::GenericArg::as_term).find(|term| term.is_infer());
+                if let Some(term) = term {
                     let err = self.emit_inference_failure_err(
                         obligation.cause.body_id,
                         span,
-                        arg,
+                        term,
                         TypeAnnotationNeeded::E0284,
                         true,
                     );
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 4330f1f2292..d8e05d9ad97 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -813,38 +813,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         mut trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<ErrorGuaranteed> {
-        // If `AsyncFnKindHelper` is not implemented, that means that the closure kind
-        // doesn't extend the goal kind. This is worth reporting, but we can only do so
-        // if we actually know which closure this goal comes from, so look at the cause
-        // to see if we can extract that information.
-        if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper)
-            && let Some(found_kind) =
-                trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind()
-            && let Some(expected_kind) =
-                trait_pred.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
-            && !found_kind.extends(expected_kind)
-        {
-            if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
-                // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
+        // If we end up on an `AsyncFnKindHelper` goal, try to unwrap the parent
+        // `AsyncFn*` goal.
+        if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper) {
+            let mut code = obligation.cause.code();
+            // Unwrap a `FunctionArg` cause, which has been refined from a derived obligation.
+            if let ObligationCauseCode::FunctionArg { parent_code, .. } = code {
+                code = &**parent_code;
+            }
+            // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
+            if let Some((_, Some(parent))) = code.parent_with_predicate() {
                 trait_pred = parent;
-            } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
-                obligation.cause.code()
-                && let Some(typeck_results) = &self.typeck_results
-                && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
-                    *typeck_results.node_type(arg_hir_id).kind()
-            {
-                // Otherwise, extract the closure kind from the obligation,
-                // but only if we actually have an argument to deduce the
-                // closure type from...
-                let mut err = self.report_closure_error(
-                    &obligation,
-                    closure_def_id,
-                    found_kind,
-                    expected_kind,
-                    "Async",
-                );
-                self.note_obligation_cause(&mut err, &obligation);
-                return Some(err.emit());
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index e0b425fa739..a87c5ad6db9 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -92,12 +92,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
     fn well_formed_goals(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        arg: ty::GenericArg<'tcx>,
+        term: ty::Term<'tcx>,
     ) -> Option<Vec<Goal<'tcx, ty::Predicate<'tcx>>>> {
-        crate::traits::wf::unnormalized_obligations(&self.0, param_env, arg, DUMMY_SP, CRATE_DEF_ID)
-            .map(|obligations| {
-                obligations.into_iter().map(|obligation| obligation.as_goal()).collect()
-            })
+        crate::traits::wf::unnormalized_obligations(
+            &self.0,
+            param_env,
+            term,
+            DUMMY_SP,
+            CRATE_DEF_ID,
+        )
+        .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect())
     }
 
     fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 848d0646d00..1f4fa5aac10 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -163,15 +163,15 @@ where
     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
         assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots());
         let mut errors = Vec::new();
-        for i in 0.. {
-            if !infcx.tcx.recursion_limit().value_within_limit(i) {
-                self.obligations.on_fulfillment_overflow(infcx);
-                // Only return true errors that we have accumulated while processing.
-                return errors;
-            }
-
+        loop {
             let mut has_changed = false;
-            for obligation in self.obligations.drain_pending(|_| true) {
+            for mut obligation in self.obligations.drain_pending(|_| true) {
+                if !infcx.tcx.recursion_limit().value_within_limit(obligation.recursion_depth) {
+                    self.obligations.on_fulfillment_overflow(infcx);
+                    // Only return true errors that we have accumulated while processing.
+                    return errors;
+                }
+
                 let goal = obligation.as_goal();
                 let result = <&SolverDelegate<'tcx>>::from(infcx)
                     .evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
@@ -189,6 +189,13 @@ where
                 };
 
                 if changed == HasChanged::Yes {
+                    // We increment the recursion depth here to track the number of times
+                    // this goal has resulted in inference progress. This doesn't precisely
+                    // model the way that we track recursion depth in the old solver due
+                    // to the fact that we only process root obligations, but it is a good
+                    // approximation and should only result in fulfillment overflow in
+                    // pathological cases.
+                    obligation.recursion_depth += 1;
                     has_changed = true;
                 }
 
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index f6c650c68c0..a024f432450 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -241,13 +241,13 @@ impl<'tcx> BestObligation<'tcx> {
     fn visit_well_formed_goal(
         &mut self,
         candidate: &inspect::InspectCandidate<'_, 'tcx>,
-        arg: ty::GenericArg<'tcx>,
+        term: ty::Term<'tcx>,
     ) -> ControlFlow<PredicateObligation<'tcx>> {
         let infcx = candidate.goal().infcx();
         let param_env = candidate.goal().goal().param_env;
         let body_id = self.obligation.cause.body_id;
 
-        for obligation in wf::unnormalized_obligations(infcx, param_env, arg, self.span(), body_id)
+        for obligation in wf::unnormalized_obligations(infcx, param_env, term, self.span(), body_id)
             .into_iter()
             .flatten()
         {
@@ -443,8 +443,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
                     polarity: ty::PredicatePolarity::Positive,
                 }))
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                return self.visit_well_formed_goal(candidate, arg);
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
+                return self.visit_well_formed_goal(candidate, term);
             }
             _ => ChildMode::PassThrough,
         };
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index a11f8d3a9ec..34c3c905bd9 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -540,18 +540,18 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     self.selcx.infcx.err_ctxt().report_overflow_obligation(&obligation, false);
                 }
 
-                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
                     match wf::obligations(
                         self.selcx.infcx,
                         obligation.param_env,
                         obligation.cause.body_id,
                         obligation.recursion_depth + 1,
-                        arg,
+                        term,
                         obligation.cause.span,
                     ) {
                         None => {
                             pending_obligation.stalled_on =
-                                vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()];
+                                vec![TyOrConstInferVar::maybe_from_term(term).unwrap()];
                             ProcessResult::Unchanged
                         }
                         Some(os) => ProcessResult::Changed(mk_pending(obligation, os)),
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
index f059bd00768..81b5a131a32 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -131,12 +131,12 @@ fn relate_mir_and_user_args<'tcx>(
     //     const CONST: () = { /* arbitrary code that depends on T being WF */ };
     // }
     // ```
-    for arg in args {
+    for term in args.iter().filter_map(ty::GenericArg::as_term) {
         ocx.register_obligation(Obligation::new(
             tcx,
             cause.clone(),
             param_env,
-            ty::ClauseKind::WellFormed(arg),
+            ty::ClauseKind::WellFormed(term),
         ));
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index f98529860ff..1df69932c64 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -113,8 +113,8 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>(
                 | ty::PredicateKind::AliasRelate(..) => {}
 
                 // We need to search through *all* WellFormed predicates
-                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                    wf_args.push(arg);
+                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
+                    wf_args.push(term);
                 }
 
                 // We need to register region relationships
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 87fc532adaf..18971c47831 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -19,10 +19,10 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
             return Some(());
         }
 
-        if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) =
+        if let ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) =
             key.value.predicate.kind().skip_binder()
         {
-            match arg.as_type()?.kind() {
+            match term.as_type()?.kind() {
                 ty::Param(_)
                 | ty::Bool
                 | ty::Char
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index c7ce13c8014..89febd6ce3d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -658,7 +658,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
                 }
 
-                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
                     // So, there is a bit going on here. First, `WellFormed` predicates
                     // are coinductive, like trait predicates with auto traits.
                     // This means that we need to detect if we have recursively
@@ -682,11 +682,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     let cache = previous_stack.cache;
                     let dfn = cache.next_dfn();
 
-                    for stack_arg in previous_stack.cache.wf_args.borrow().iter().rev() {
-                        if stack_arg.0 != arg {
+                    for stack_term in previous_stack.cache.wf_args.borrow().iter().rev() {
+                        if stack_term.0 != term {
                             continue;
                         }
-                        debug!("WellFormed({:?}) on stack", arg);
+                        debug!("WellFormed({:?}) on stack", term);
                         if let Some(stack) = previous_stack.head {
                             // Okay, let's imagine we have two different stacks:
                             //   `T: NonAutoTrait -> WF(T) -> T: NonAutoTrait`
@@ -702,11 +702,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             // would contain `(T, 1)`. We want to check all
                             // trait predicates greater than `1`. The previous
                             // stack would be `T: Auto`.
-                            let cycle = stack.iter().take_while(|s| s.depth > stack_arg.1);
+                            let cycle = stack.iter().take_while(|s| s.depth > stack_term.1);
                             let tcx = self.tcx();
                             let cycle = cycle.map(|stack| stack.obligation.predicate.upcast(tcx));
                             if self.coinductive_match(cycle) {
-                                stack.update_reached_depth(stack_arg.1);
+                                stack.update_reached_depth(stack_term.1);
                                 return Ok(EvaluatedToOk);
                             } else {
                                 return Ok(EvaluatedToAmbigStackDependent);
@@ -720,11 +720,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         obligation.param_env,
                         obligation.cause.body_id,
                         obligation.recursion_depth + 1,
-                        arg,
+                        term,
                         obligation.cause.span,
                     ) {
                         Some(obligations) => {
-                            cache.wf_args.borrow_mut().push((arg, previous_stack.depth()));
+                            cache.wf_args.borrow_mut().push((term, previous_stack.depth()));
                             let result =
                                 self.evaluate_predicates_recursively(previous_stack, obligations);
                             cache.wf_args.borrow_mut().pop();
@@ -2969,14 +2969,14 @@ struct ProvisionalEvaluationCache<'tcx> {
     ///   means the cached value for `F`.
     map: RefCell<FxIndexMap<ty::PolyTraitPredicate<'tcx>, ProvisionalEvaluation>>,
 
-    /// The stack of args that we assume to be true because a `WF(arg)` predicate
+    /// The stack of terms that we assume to be well-formed because a `WF(term)` predicate
     /// is on the stack above (and because of wellformedness is coinductive).
     /// In an "ideal" world, this would share a stack with trait predicates in
     /// `TraitObligationStack`. However, trait predicates are *much* hotter than
     /// `WellFormed` predicates, and it's very likely that the additional matches
     /// will have a perf effect. The value here is the well-formed `GenericArg`
     /// and the depth of the trait predicate *above* that well-formed predicate.
-    wf_args: RefCell<Vec<(ty::GenericArg<'tcx>, usize)>>,
+    wf_args: RefCell<Vec<(ty::Term<'tcx>, usize)>>,
 }
 
 /// A cache value for the provisional cache: contains the depth-first
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index cad7e42fd82..62bd8e1af05 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -10,8 +10,8 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::traits::{ObligationCauseCode, PredicateObligations};
 use rustc_middle::bug;
 use rustc_middle::ty::{
-    self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, GenericArgsRef, Term, TermKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+    TypeVisitableExt, TypeVisitor,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -32,12 +32,12 @@ pub fn obligations<'tcx>(
     param_env: ty::ParamEnv<'tcx>,
     body_id: LocalDefId,
     recursion_depth: usize,
-    arg: GenericArg<'tcx>,
+    term: Term<'tcx>,
     span: Span,
 ) -> Option<PredicateObligations<'tcx>> {
     // Handle the "cycle" case (see comment above) by bailing out if necessary.
-    let arg = match arg.unpack() {
-        GenericArgKind::Type(ty) => {
+    let term = match term.unpack() {
+        TermKind::Ty(ty) => {
             match ty.kind() {
                 ty::Infer(ty::TyVar(_)) => {
                     let resolved_ty = infcx.shallow_resolve(ty);
@@ -52,7 +52,7 @@ pub fn obligations<'tcx>(
             }
             .into()
         }
-        GenericArgKind::Const(ct) => {
+        TermKind::Const(ct) => {
             match ct.kind() {
                 ty::ConstKind::Infer(_) => {
                     let resolved = infcx.shallow_resolve_const(ct);
@@ -67,8 +67,6 @@ pub fn obligations<'tcx>(
             }
             .into()
         }
-        // There is nothing we have to do for lifetimes.
-        GenericArgKind::Lifetime(..) => return Some(PredicateObligations::new()),
     };
 
     let mut wf = WfPredicates {
@@ -80,11 +78,11 @@ pub fn obligations<'tcx>(
         recursion_depth,
         item: None,
     };
-    wf.add_wf_preds_for_generic_arg(arg);
-    debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
+    wf.add_wf_preds_for_term(term);
+    debug!("wf::obligations({:?}, body_id={:?}) = {:?}", term, body_id, wf.out);
 
     let result = wf.normalize(infcx);
-    debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result);
+    debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", term, body_id, result);
     Some(result)
 }
 
@@ -95,23 +93,19 @@ pub fn obligations<'tcx>(
 pub fn unnormalized_obligations<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    arg: GenericArg<'tcx>,
+    term: Term<'tcx>,
     span: Span,
     body_id: LocalDefId,
 ) -> Option<PredicateObligations<'tcx>> {
-    debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
+    debug_assert_eq!(term, infcx.resolve_vars_if_possible(term));
 
     // However, if `arg` IS an unresolved inference variable, returns `None`,
     // because we are not able to make any progress at all. This is to prevent
     // cycles where we say "?0 is WF if ?0 is WF".
-    if arg.is_non_region_infer() {
+    if term.is_infer() {
         return None;
     }
 
-    if let ty::GenericArgKind::Lifetime(..) = arg.unpack() {
-        return Some(PredicateObligations::new());
-    }
-
     let mut wf = WfPredicates {
         infcx,
         param_env,
@@ -121,7 +115,7 @@ pub fn unnormalized_obligations<'tcx>(
         recursion_depth: 0,
         item: None,
     };
-    wf.add_wf_preds_for_generic_arg(arg);
+    wf.add_wf_preds_for_term(term);
     Some(wf.out)
 }
 
@@ -185,22 +179,22 @@ pub fn clause_obligations<'tcx>(
         }
         ty::ClauseKind::RegionOutlives(..) => {}
         ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
-            wf.add_wf_preds_for_generic_arg(ty.into());
+            wf.add_wf_preds_for_term(ty.into());
         }
         ty::ClauseKind::Projection(t) => {
             wf.add_wf_preds_for_alias_term(t.projection_term);
-            wf.add_wf_preds_for_generic_arg(t.term.into_arg());
+            wf.add_wf_preds_for_term(t.term);
         }
         ty::ClauseKind::ConstArgHasType(ct, ty) => {
-            wf.add_wf_preds_for_generic_arg(ct.into());
-            wf.add_wf_preds_for_generic_arg(ty.into());
+            wf.add_wf_preds_for_term(ct.into());
+            wf.add_wf_preds_for_term(ty.into());
         }
-        ty::ClauseKind::WellFormed(arg) => {
-            wf.add_wf_preds_for_generic_arg(arg);
+        ty::ClauseKind::WellFormed(term) => {
+            wf.add_wf_preds_for_term(term);
         }
 
         ty::ClauseKind::ConstEvaluatable(ct) => {
-            wf.add_wf_preds_for_generic_arg(ct.into());
+            wf.add_wf_preds_for_term(ct.into());
         }
     }
 
@@ -426,11 +420,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                 .args
                 .iter()
                 .enumerate()
-                .filter(|(_, arg)| {
-                    matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
-                })
-                .filter(|(_, arg)| !arg.has_escaping_bound_vars())
-                .map(|(i, arg)| {
+                .filter_map(|(i, arg)| arg.as_term().map(|t| (i, t)))
+                .filter(|(_, term)| !term.has_escaping_bound_vars())
+                .map(|(i, term)| {
                     let mut cause = traits::ObligationCause::misc(self.span, self.body_id);
                     // The first arg is the self ty - use the correct span for it.
                     if i == 0 {
@@ -445,9 +437,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                         cause,
                         depth,
                         param_env,
-                        ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
-                            arg,
-                        ))),
+                        ty::ClauseKind::WellFormed(term),
                     )
                 }),
         );
@@ -457,7 +447,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     // given that it is a *negative* trait predicate.
     fn add_wf_preds_for_negative_trait_pred(&mut self, trait_ref: ty::TraitRef<'tcx>) {
         for arg in trait_ref.args {
-            self.add_wf_preds_for_generic_arg(arg);
+            if let Some(term) = arg.as_term() {
+                self.add_wf_preds_for_term(term);
+            }
         }
     }
 
@@ -529,19 +521,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
         self.out.extend(
             args.iter()
-                .filter(|arg| {
-                    matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
-                })
-                .filter(|arg| !arg.has_escaping_bound_vars())
-                .map(|arg| {
+                .filter_map(|arg| arg.as_term())
+                .filter(|term| !term.has_escaping_bound_vars())
+                .map(|term| {
                     traits::Obligation::with_depth(
                         tcx,
                         cause.clone(),
                         depth,
                         param_env,
-                        ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(
-                            arg,
-                        ))),
+                        ty::ClauseKind::WellFormed(term),
                     )
                 }),
         );
@@ -565,10 +553,10 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         }
     }
 
-    /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
+    /// Pushes all the predicates needed to validate that `term` is WF into `out`.
     #[instrument(level = "debug", skip(self))]
-    fn add_wf_preds_for_generic_arg(&mut self, arg: GenericArg<'tcx>) {
-        arg.visit_with(self);
+    fn add_wf_preds_for_term(&mut self, term: Term<'tcx>) {
+        term.visit_with(self);
         debug!(?self.out);
     }
 
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index d555ea702a9..4d5f630ae22 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -65,7 +65,12 @@ impl fmt::Debug for Byte {
     }
 }
 
-#[cfg(test)]
+impl From<RangeInclusive<u8>> for Byte {
+    fn from(src: RangeInclusive<u8>) -> Self {
+        Self::new(src)
+    }
+}
+
 impl From<u8> for Byte {
     fn from(src: u8) -> Self {
         Self::from_val(src)
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 6a09be18ef9..7cf712ce9e9 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -1,4 +1,4 @@
-use std::ops::ControlFlow;
+use std::ops::{ControlFlow, RangeInclusive};
 
 use super::{Byte, Def, Ref};
 
@@ -32,6 +32,22 @@ where
     Byte(Byte),
 }
 
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub(crate) enum Endian {
+    Little,
+    Big,
+}
+
+#[cfg(feature = "rustc")]
+impl From<rustc_abi::Endian> for Endian {
+    fn from(order: rustc_abi::Endian) -> Endian {
+        match order {
+            rustc_abi::Endian::Little => Endian::Little,
+            rustc_abi::Endian::Big => Endian::Big,
+        }
+    }
+}
+
 impl<D, R> Tree<D, R>
 where
     D: Def,
@@ -59,22 +75,60 @@ where
 
     /// A `Tree` representing the layout of `bool`.
     pub(crate) fn bool() -> Self {
-        Self::Byte(Byte::new(0x00..=0x01))
+        Self::byte(0x00..=0x01)
     }
 
     /// A `Tree` whose layout matches that of a `u8`.
     pub(crate) fn u8() -> Self {
-        Self::Byte(Byte::new(0x00..=0xFF))
+        Self::byte(0x00..=0xFF)
+    }
+
+    /// A `Tree` whose layout matches that of a `char`.
+    pub(crate) fn char(order: Endian) -> Self {
+        // `char`s can be in the following ranges:
+        // - [0, 0xD7FF]
+        // - [0xE000, 10FFFF]
+        //
+        // All other `char` values are illegal. We can thus represent a `char`
+        // as a union of three possible layouts:
+        // - 00 00 [00, D7] XX
+        // - 00 00 [E0, FF] XX
+        // - 00 [01, 10] XX XX
+
+        const _0: RangeInclusive<u8> = 0..=0;
+        const BYTE: RangeInclusive<u8> = 0x00..=0xFF;
+        let x = Self::from_big_endian(order, [_0, _0, 0x00..=0xD7, BYTE]);
+        let y = Self::from_big_endian(order, [_0, _0, 0xE0..=0xFF, BYTE]);
+        let z = Self::from_big_endian(order, [_0, 0x01..=0x10, BYTE, BYTE]);
+        Self::alt([x, y, z])
     }
 
-    /// A `Tree` whose layout accepts exactly the given bit pattern.
-    pub(crate) fn from_bits(bits: u8) -> Self {
-        Self::Byte(Byte::from_val(bits))
+    /// A `Tree` whose layout matches `std::num::NonZeroXxx`.
+    #[allow(dead_code)]
+    pub(crate) fn nonzero(width_in_bytes: u64) -> Self {
+        const BYTE: RangeInclusive<u8> = 0x00..=0xFF;
+        const NONZERO: RangeInclusive<u8> = 0x01..=0xFF;
+
+        (0..width_in_bytes)
+            .map(|nz_idx| {
+                (0..width_in_bytes)
+                    .map(|pos| Self::byte(if pos == nz_idx { NONZERO } else { BYTE }))
+                    .fold(Self::unit(), Self::then)
+            })
+            .fold(Self::uninhabited(), Self::or)
+    }
+
+    pub(crate) fn bytes<const N: usize, B: Into<Byte>>(bytes: [B; N]) -> Self {
+        Self::seq(bytes.map(B::into).map(Self::Byte))
+    }
+
+    pub(crate) fn byte(byte: impl Into<Byte>) -> Self {
+        Self::Byte(byte.into())
     }
 
     /// A `Tree` whose layout is a number of the given width.
-    pub(crate) fn number(width_in_bytes: usize) -> Self {
-        Self::Seq(vec![Self::u8(); width_in_bytes])
+    pub(crate) fn number(width_in_bytes: u64) -> Self {
+        Self::Seq(vec![Self::u8(); width_in_bytes.try_into().unwrap()])
     }
 
     /// A `Tree` whose layout is entirely padding of the given width.
@@ -125,13 +179,35 @@ where
             Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true,
         }
     }
-}
 
-impl<D, R> Tree<D, R>
-where
-    D: Def,
-    R: Ref,
-{
+    /// Produces a `Tree` which represents a sequence of bytes stored in
+    /// `order`.
+    ///
+    /// `bytes` is taken to be in big-endian byte order, and its order will be
+    /// swapped if `order == Endian::Little`.
+    pub(crate) fn from_big_endian<const N: usize, B: Into<Byte>>(
+        order: Endian,
+        mut bytes: [B; N],
+    ) -> Self {
+        if order == Endian::Little {
+            (&mut bytes[..]).reverse();
+        }
+
+        Self::bytes(bytes)
+    }
+
+    /// Produces a `Tree` where each of the trees in `trees` are sequenced one
+    /// after another.
+    pub(crate) fn seq<const N: usize>(trees: [Tree<D, R>; N]) -> Self {
+        trees.into_iter().fold(Tree::unit(), Self::then)
+    }
+
+    /// Produces a `Tree` where each of the trees in `trees` are accepted as
+    /// alternative layouts.
+    pub(crate) fn alt<const N: usize>(trees: [Tree<D, R>; N]) -> Self {
+        trees.into_iter().fold(Tree::uninhabited(), Self::or)
+    }
+
     /// Produces a new `Tree` where `other` is sequenced after `self`.
     pub(crate) fn then(self, other: Self) -> Self {
         match (self, other) {
@@ -222,17 +298,17 @@ pub(crate) mod rustc {
 
                 ty::Float(nty) => {
                     let width = nty.bit_width() / 8;
-                    Ok(Self::number(width as _))
+                    Ok(Self::number(width.try_into().unwrap()))
                 }
 
                 ty::Int(nty) => {
                     let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
-                    Ok(Self::number(width as _))
+                    Ok(Self::number(width.try_into().unwrap()))
                 }
 
                 ty::Uint(nty) => {
                     let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
-                    Ok(Self::number(width as _))
+                    Ok(Self::number(width.try_into().unwrap()))
                 }
 
                 ty::Tuple(members) => Self::from_tuple((ty, layout), members, cx),
@@ -249,11 +325,33 @@ pub(crate) mod rustc {
                         .fold(Tree::unit(), |tree, elt| tree.then(elt)))
                 }
 
-                ty::Adt(adt_def, _args_ref) if !ty.is_box() => match adt_def.adt_kind() {
-                    AdtKind::Struct => Self::from_struct((ty, layout), *adt_def, cx),
-                    AdtKind::Enum => Self::from_enum((ty, layout), *adt_def, cx),
-                    AdtKind::Union => Self::from_union((ty, layout), *adt_def, cx),
-                },
+                ty::Adt(adt_def, _args_ref) if !ty.is_box() => {
+                    let (lo, hi) = cx.tcx().layout_scalar_valid_range(adt_def.did());
+
+                    use core::ops::Bound::*;
+                    let is_transparent = adt_def.repr().transparent();
+                    match (adt_def.adt_kind(), lo, hi) {
+                        (AdtKind::Struct, Unbounded, Unbounded) => {
+                            Self::from_struct((ty, layout), *adt_def, cx)
+                        }
+                        (AdtKind::Struct, Included(1), Included(_hi)) if is_transparent => {
+                            // FIXME(@joshlf): Support `NonZero` types:
+                            // - Check to make sure that the first field is
+                            //   numerical
+                            // - Check to make sure that the upper bound is the
+                            //   maximum value for the field's type
+                            // - Construct `Self::nonzero`
+                            Err(Err::NotYetSupported)
+                        }
+                        (AdtKind::Enum, Unbounded, Unbounded) => {
+                            Self::from_enum((ty, layout), *adt_def, cx)
+                        }
+                        (AdtKind::Union, Unbounded, Unbounded) => {
+                            Self::from_union((ty, layout), *adt_def, cx)
+                        }
+                        _ => Err(Err::NotYetSupported),
+                    }
+                }
 
                 ty::Ref(lifetime, ty, mutability) => {
                     let layout = layout_of(cx, *ty)?;
@@ -268,6 +366,8 @@ pub(crate) mod rustc {
                     }))
                 }
 
+                ty::Char => Ok(Self::char(cx.tcx().data_layout.endian.into())),
+
                 _ => Err(Err::NotYetSupported),
             }
         }
@@ -450,7 +550,7 @@ pub(crate) mod rustc {
                     &bytes[bytes.len() - size.bytes_usize()..]
                 }
             };
-            Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect())
+            Self::Seq(bytes.iter().map(|&b| Self::byte(b)).collect())
         }
 
         /// Constructs a `Tree` from a union.
diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs
index 44f50a25c93..8c3dbbe37ab 100644
--- a/compiler/rustc_transmute/src/layout/tree/tests.rs
+++ b/compiler/rustc_transmute/src/layout/tree/tests.rs
@@ -20,23 +20,18 @@ mod prune {
 
         #[test]
         fn seq_1() {
-            let layout: Tree<Def, !> =
-                Tree::def(Def::NoSafetyInvariants).then(Tree::from_bits(0x00));
-            assert_eq!(
-                layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
-                Tree::from_bits(0x00)
-            );
+            let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants).then(Tree::byte(0x00));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00));
         }
 
         #[test]
         fn seq_2() {
-            let layout: Tree<Def, !> = Tree::from_bits(0x00)
-                .then(Tree::def(Def::NoSafetyInvariants))
-                .then(Tree::from_bits(0x01));
+            let layout: Tree<Def, !> =
+                Tree::byte(0x00).then(Tree::def(Def::NoSafetyInvariants)).then(Tree::byte(0x01));
 
             assert_eq!(
                 layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
-                Tree::from_bits(0x00).then(Tree::from_bits(0x01))
+                Tree::byte(0x00).then(Tree::byte(0x01))
             );
         }
     }
@@ -66,7 +61,7 @@ mod prune {
         #[test]
         fn invisible_def_in_seq_len_3() {
             let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants)
-                .then(Tree::from_bits(0x00))
+                .then(Tree::byte(0x00))
                 .then(Tree::def(Def::HasSafetyInvariants));
             assert_eq!(
                 layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
@@ -94,12 +89,9 @@ mod prune {
         #[test]
         fn visible_def_in_seq_len_3() {
             let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants)
-                .then(Tree::from_bits(0x00))
+                .then(Tree::byte(0x00))
                 .then(Tree::def(Def::NoSafetyInvariants));
-            assert_eq!(
-                layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
-                Tree::from_bits(0x00)
-            );
+            assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00));
         }
     }
 }
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
index 24e2a1acadd..992fcb7cc4c 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
@@ -177,9 +177,9 @@ mod bool {
 
     #[test]
     fn should_permit_validity_expansion_and_reject_contraction() {
-        let b0 = layout::Tree::<Def, !>::from_bits(0);
-        let b1 = layout::Tree::<Def, !>::from_bits(1);
-        let b2 = layout::Tree::<Def, !>::from_bits(2);
+        let b0 = layout::Tree::<Def, !>::byte(0);
+        let b1 = layout::Tree::<Def, !>::byte(1);
+        let b2 = layout::Tree::<Def, !>::byte(2);
 
         let alts = [b0, b1, b2];
 
@@ -279,8 +279,8 @@ mod alt {
     fn should_permit_identity_transmutation() {
         type Tree = layout::Tree<Def, !>;
 
-        let x = Tree::Seq(vec![Tree::from_bits(0), Tree::from_bits(0)]);
-        let y = Tree::Seq(vec![Tree::bool(), Tree::from_bits(1)]);
+        let x = Tree::Seq(vec![Tree::byte(0), Tree::byte(0)]);
+        let y = Tree::Seq(vec![Tree::bool(), Tree::byte(1)]);
         let layout = Tree::Alt(vec![x, y]);
 
         let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
@@ -323,6 +323,76 @@ mod union {
     }
 }
 
+mod char {
+    use super::*;
+    use crate::layout::tree::Endian;
+
+    #[test]
+    fn should_permit_valid_transmutation() {
+        for order in [Endian::Big, Endian::Little] {
+            use Answer::*;
+            let char_layout = layout::Tree::<Def, !>::char(order);
+
+            // `char`s can be in the following ranges:
+            // - [0, 0xD7FF]
+            // - [0xE000, 10FFFF]
+            //
+            // This loop synthesizes a singleton-validity type for the extremes
+            // of each range, and for one past the end of the extremes of each
+            // range.
+            let no = No(Reason::DstIsBitIncompatible);
+            for (src, answer) in [
+                (0u32, Yes),
+                (0xD7FF, Yes),
+                (0xD800, no.clone()),
+                (0xDFFF, no.clone()),
+                (0xE000, Yes),
+                (0x10FFFF, Yes),
+                (0x110000, no.clone()),
+                (0xFFFF0000, no.clone()),
+                (0xFFFFFFFF, no),
+            ] {
+                let src_layout =
+                    layout::tree::Tree::<Def, !>::from_big_endian(order, src.to_be_bytes());
+
+                let a = is_transmutable(&src_layout, &char_layout, Assume::default());
+                assert_eq!(a, answer, "endian:{order:?},\nsrc:{src:x}");
+            }
+        }
+    }
+}
+
+mod nonzero {
+    use super::*;
+    use crate::{Answer, Reason};
+
+    const NONZERO_BYTE_WIDTHS: [u64; 5] = [1, 2, 4, 8, 16];
+
+    #[test]
+    fn should_permit_identity_transmutation() {
+        for width in NONZERO_BYTE_WIDTHS {
+            let layout = layout::Tree::<Def, !>::nonzero(width);
+            assert_eq!(is_transmutable(&layout, &layout, Assume::default()), Answer::Yes);
+        }
+    }
+
+    #[test]
+    fn should_permit_valid_transmutation() {
+        for width in NONZERO_BYTE_WIDTHS {
+            use Answer::*;
+
+            let num = layout::Tree::<Def, !>::number(width);
+            let nz = layout::Tree::<Def, !>::nonzero(width);
+
+            let a = is_transmutable(&num, &nz, Assume::default());
+            assert_eq!(a, No(Reason::DstIsBitIncompatible), "width:{width}");
+
+            let a = is_transmutable(&nz, &num, Assume::default());
+            assert_eq!(a, Yes, "width:{width}");
+        }
+    }
+}
+
 mod r#ref {
     use super::*;
 
@@ -330,7 +400,7 @@ mod r#ref {
     fn should_permit_identity_transmutation() {
         type Tree = crate::layout::Tree<Def, [(); 1]>;
 
-        let layout = Tree::Seq(vec![Tree::from_bits(0), Tree::Ref([()])]);
+        let layout = Tree::Seq(vec![Tree::byte(0x00), Tree::Ref([()])]);
 
         let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
             layout.clone(),
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index e9d3a149a73..74fb148a7cc 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -1,5 +1,3 @@
-use std::slice;
-
 use crate::inherent::*;
 use crate::visit::Flags;
 use crate::{self as ty, Interner};
@@ -388,8 +386,8 @@ impl<I: Interner> FlagComputation<I> {
                 self.add_alias_term(projection_term);
                 self.add_term(term);
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                self.add_args(slice::from_ref(&arg));
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
+                self.add_term(term);
             }
             ty::PredicateKind::DynCompatible(_def_id) => {}
             ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index ab38556589e..9758cecaf6a 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -286,6 +286,8 @@ pub trait Interner:
 
     fn has_item_definition(self, def_id: Self::DefId) -> bool;
 
+    fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool;
+
     fn impl_is_default(self, impl_def_id: Self::DefId) -> bool;
 
     fn impl_trait_ref(self, impl_def_id: Self::DefId) -> ty::EarlyBinder<Self, ty::TraitRef<Self>>;
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index 847dff156fe..4e41fd16ffd 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -36,7 +36,7 @@ pub enum ClauseKind<I: Interner> {
     ConstArgHasType(I::Const, I::Ty),
 
     /// No syntax: `T` well-formed.
-    WellFormed(I::GenericArg),
+    WellFormed(I::Term),
 
     /// Constant initializer must evaluate successfully.
     ConstEvaluatable(I::Const),
diff --git a/library/Cargo.lock b/library/Cargo.lock
index f7f09a11f3a..c21dec14986 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -257,9 +257,9 @@ dependencies = [
 
 [[package]]
 name = "r-efi"
-version = "4.5.0"
+version = "5.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -267,9 +267,9 @@ dependencies = [
 
 [[package]]
 name = "r-efi-alloc"
-version = "1.0.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
+checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203"
 dependencies = [
  "compiler_builtins",
  "r-efi",
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index d5b19470e31..8b448a18402 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -351,9 +351,14 @@ impl CString {
     /// # Safety
     ///
     /// This should only ever be called with a pointer that was earlier
-    /// obtained by calling [`CString::into_raw`]. Other usage (e.g., trying to take
-    /// ownership of a string that was allocated by foreign code) is likely to lead
-    /// to undefined behavior or allocator corruption.
+    /// obtained by calling [`CString::into_raw`], and the memory it points to must not be accessed
+    /// through any other pointer during the lifetime of reconstructed `CString`.
+    /// Other usage (e.g., trying to take ownership of a string that was allocated by foreign code)
+    /// is likely to lead to undefined behavior or allocator corruption.
+    ///
+    /// This function does not validate ownership of the raw pointer's memory.
+    /// A double-free may occur if the function is called twice on the same raw pointer.
+    /// Additionally, the caller must ensure the pointer is not dangling.
     ///
     /// It should be noted that the length isn't just "recomputed," but that
     /// the recomputed length must match the original length from the
@@ -818,6 +823,7 @@ impl From<Vec<NonZero<u8>>> for CString {
     }
 }
 
+#[stable(feature = "c_string_from_str", since = "1.85.0")]
 impl FromStr for CString {
     type Err = NulError;
 
@@ -830,6 +836,7 @@ impl FromStr for CString {
     }
 }
 
+#[stable(feature = "c_string_from_str", since = "1.85.0")]
 impl TryFrom<CString> for String {
     type Error = IntoStringError;
 
diff --git a/library/alloc/src/ffi/mod.rs b/library/alloc/src/ffi/mod.rs
index 695d7ad07cf..05a2763a225 100644
--- a/library/alloc/src/ffi/mod.rs
+++ b/library/alloc/src/ffi/mod.rs
@@ -87,5 +87,5 @@ pub use self::c_str::CString;
 #[stable(feature = "alloc_c_string", since = "1.64.0")]
 pub use self::c_str::{FromVecWithNulError, IntoStringError, NulError};
 
-#[unstable(feature = "c_str_module", issue = "112134")]
+#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")]
 pub mod c_str;
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index e70e6ca0d55..abda5aefab6 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -122,6 +122,7 @@
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
 #![feature(formatting_options)]
+#![feature(generic_atomic)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index 0664f2c3cf2..24c5d4c92f7 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -603,6 +603,10 @@ impl str {
 /// Converts a boxed slice of bytes to a boxed string slice without checking
 /// that the string contains valid UTF-8.
 ///
+/// # Safety
+///
+/// * The provided bytes must contain a valid UTF-8 sequence.
+///
 /// # Examples
 ///
 /// ```
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index be581661f4c..17090925cfa 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -26,8 +26,8 @@ use core::pin::{Pin, PinCoerceUnsized};
 use core::ptr::{self, NonNull};
 #[cfg(not(no_global_oom_handling))]
 use core::slice::from_raw_parts_mut;
-use core::sync::atomic;
 use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use core::sync::atomic::{self, Atomic};
 use core::{borrow, fmt, hint};
 
 #[cfg(not(no_global_oom_handling))]
@@ -369,12 +369,12 @@ impl<T: ?Sized, A: Allocator> fmt::Debug for Weak<T, A> {
 // inner types.
 #[repr(C)]
 struct ArcInner<T: ?Sized> {
-    strong: atomic::AtomicUsize,
+    strong: Atomic<usize>,
 
     // the value usize::MAX acts as a sentinel for temporarily "locking" the
     // ability to upgrade weak pointers or downgrade strong ones; this is used
     // to avoid races in `make_mut` and `get_mut`.
-    weak: atomic::AtomicUsize,
+    weak: Atomic<usize>,
 
     data: T,
 }
@@ -2446,7 +2446,7 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     #[inline]
     #[stable(feature = "arc_unique", since = "1.4.0")]
     pub fn get_mut(this: &mut Self) -> Option<&mut T> {
-        if this.is_unique() {
+        if Self::is_unique(this) {
             // This unsafety is ok because we're guaranteed that the pointer
             // returned is the *only* pointer that will ever be returned to T. Our
             // reference count is guaranteed to be 1 at this point, and we required
@@ -2526,11 +2526,64 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
         unsafe { &mut (*this.ptr.as_ptr()).data }
     }
 
-    /// Determine whether this is the unique reference (including weak refs) to
-    /// the underlying data.
+    /// Determine whether this is the unique reference to the underlying data.
     ///
-    /// Note that this requires locking the weak ref count.
-    fn is_unique(&mut self) -> bool {
+    /// Returns `true` if there are no other `Arc` or [`Weak`] pointers to the same allocation;
+    /// returns `false` otherwise.
+    ///
+    /// If this function returns `true`, then is guaranteed to be safe to call [`get_mut_unchecked`]
+    /// on this `Arc`, so long as no clones occur in between.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(arc_is_unique)]
+    ///
+    /// use std::sync::Arc;
+    ///
+    /// let x = Arc::new(3);
+    /// assert!(Arc::is_unique(&x));
+    ///
+    /// let y = Arc::clone(&x);
+    /// assert!(!Arc::is_unique(&x));
+    /// drop(y);
+    ///
+    /// // Weak references also count, because they could be upgraded at any time.
+    /// let z = Arc::downgrade(&x);
+    /// assert!(!Arc::is_unique(&x));
+    /// ```
+    ///
+    /// # Pointer invalidation
+    ///
+    /// This function will always return the same value as `Arc::get_mut(arc).is_some()`. However,
+    /// unlike that operation it does not produce any mutable references to the underlying data,
+    /// meaning no pointers to the data inside the `Arc` are invalidated by the call. Thus, the
+    /// following code is valid, even though it would be UB if it used `Arc::get_mut`:
+    ///
+    /// ```
+    /// #![feature(arc_is_unique)]
+    ///
+    /// use std::sync::Arc;
+    ///
+    /// let arc = Arc::new(5);
+    /// let pointer: *const i32 = &*arc;
+    /// assert!(Arc::is_unique(&arc));
+    /// assert_eq!(unsafe { *pointer }, 5);
+    /// ```
+    ///
+    /// # Atomic orderings
+    ///
+    /// Concurrent drops to other `Arc` pointers to the same allocation will synchronize with this
+    /// call - that is, this call performs an `Acquire` operation on the underlying strong and weak
+    /// ref counts. This ensures that calling `get_mut_unchecked` is safe.
+    ///
+    /// Note that this operation requires locking the weak ref count, so concurrent calls to
+    /// `downgrade` may spin-loop for a short period of time.
+    ///
+    /// [`get_mut_unchecked`]: Self::get_mut_unchecked
+    #[inline]
+    #[unstable(feature = "arc_is_unique", issue = "138938")]
+    pub fn is_unique(this: &Self) -> bool {
         // lock the weak pointer count if we appear to be the sole weak pointer
         // holder.
         //
@@ -2538,16 +2591,16 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
         // writes to `strong` (in particular in `Weak::upgrade`) prior to decrements
         // of the `weak` count (via `Weak::drop`, which uses release). If the upgraded
         // weak ref was never dropped, the CAS here will fail so we do not care to synchronize.
-        if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
+        if this.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() {
             // This needs to be an `Acquire` to synchronize with the decrement of the `strong`
             // counter in `drop` -- the only access that happens when any but the last reference
             // is being dropped.
-            let unique = self.inner().strong.load(Acquire) == 1;
+            let unique = this.inner().strong.load(Acquire) == 1;
 
             // The release write here synchronizes with a read in `downgrade`,
             // effectively preventing the above read of `strong` from happening
             // after the write.
-            self.inner().weak.store(1, Release); // release the lock
+            this.inner().weak.store(1, Release); // release the lock
             unique
         } else {
             false
@@ -2760,8 +2813,8 @@ impl<T, A: Allocator> Weak<T, A> {
 /// Helper type to allow accessing the reference counts without
 /// making any assertions about the data field.
 struct WeakInner<'a> {
-    weak: &'a atomic::AtomicUsize,
-    strong: &'a atomic::AtomicUsize,
+    weak: &'a Atomic<usize>,
+    strong: &'a Atomic<usize>,
 }
 
 impl<T: ?Sized> Weak<T> {
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 85e87445a1b..ac07c645c01 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -79,8 +79,9 @@ use crate::{fmt, ops, slice, str};
 ///
 /// fn my_string_safe() -> String {
 ///     let cstr = unsafe { CStr::from_ptr(my_string()) };
-///     // Get copy-on-write Cow<'_, str>, then guarantee a freshly-owned String allocation
-///     String::from_utf8_lossy(cstr.to_bytes()).to_string()
+///     // Get a copy-on-write Cow<'_, str>, then extract the
+///     // allocated String (or allocate a fresh one if needed).
+///     cstr.to_string_lossy().into_owned()
 /// }
 ///
 /// println!("string: {}", my_string_safe());
diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs
index 9bae5fd466a..c9c73a25d89 100644
--- a/library/core/src/ffi/mod.rs
+++ b/library/core/src/ffi/mod.rs
@@ -20,7 +20,7 @@ pub use self::c_str::FromBytesUntilNulError;
 pub use self::c_str::FromBytesWithNulError;
 use crate::fmt;
 
-#[unstable(feature = "c_str_module", issue = "112134")]
+#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")]
 pub mod c_str;
 
 #[unstable(
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs
index cc12cd9c356..a6522659620 100644
--- a/library/core/src/iter/adapters/peekable.rs
+++ b/library/core/src/iter/adapters/peekable.rs
@@ -271,7 +271,7 @@ impl<I: Iterator> Peekable<I> {
     /// assert_eq!(iter.next_if(|&x| x == 0), Some(0));
     /// // The next item returned is now 1, so `next_if` will return `None`.
     /// assert_eq!(iter.next_if(|&x| x == 0), None);
-    /// // `next_if` saves the value of the next item if it was not equal to `expected`.
+    /// // `next_if` retains the next item if the predicate evaluates to `false` for it.
     /// assert_eq!(iter.next(), Some(1));
     /// ```
     ///
@@ -304,9 +304,9 @@ impl<I: Iterator> Peekable<I> {
     /// let mut iter = (0..5).peekable();
     /// // The first item of the iterator is 0; consume it.
     /// assert_eq!(iter.next_if_eq(&0), Some(0));
-    /// // The next item returned is now 1, so `next_if` will return `None`.
+    /// // The next item returned is now 1, so `next_if_eq` will return `None`.
     /// assert_eq!(iter.next_if_eq(&0), None);
-    /// // `next_if_eq` saves the value of the next item if it was not equal to `expected`.
+    /// // `next_if_eq` retains the next item if it was not equal to `expected`.
     /// assert_eq!(iter.next(), Some(1));
     /// ```
     #[stable(feature = "peekable_next_if", since = "1.51.0")]
diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs
index 37854a4da64..058628797ea 100644
--- a/library/core/src/str/converts.rs
+++ b/library/core/src/str/converts.rs
@@ -178,7 +178,7 @@ pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
 /// Converts a slice of bytes to a string slice without checking
 /// that the string contains valid UTF-8; mutable version.
 ///
-/// See the immutable version, [`from_utf8_unchecked()`] for more information.
+/// See the immutable version, [`from_utf8_unchecked()`] for documentation and safety requirements.
 ///
 /// # Examples
 ///
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 79b4953fcc1..818dcc2125f 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -306,7 +306,7 @@ impl str {
     /// Converts a slice of bytes to a string slice without checking
     /// that the string contains valid UTF-8; mutable version.
     ///
-    /// See the immutable version, [`from_utf8_unchecked()`] for more information.
+    /// See the immutable version, [`from_utf8_unchecked()`] for documentation and safety requirements.
     ///
     /// # Examples
     ///
@@ -2115,7 +2115,7 @@ impl str {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "str_trim"]
     pub fn trim(&self) -> &str {
-        self.trim_matches(|c: char| c.is_whitespace())
+        self.trim_matches(char::is_whitespace)
     }
 
     /// Returns a string slice with leading whitespace removed.
@@ -2154,7 +2154,7 @@ impl str {
     #[stable(feature = "trim_direction", since = "1.30.0")]
     #[rustc_diagnostic_item = "str_trim_start"]
     pub fn trim_start(&self) -> &str {
-        self.trim_start_matches(|c: char| c.is_whitespace())
+        self.trim_start_matches(char::is_whitespace)
     }
 
     /// Returns a string slice with trailing whitespace removed.
@@ -2193,7 +2193,7 @@ impl str {
     #[stable(feature = "trim_direction", since = "1.30.0")]
     #[rustc_diagnostic_item = "str_trim_end"]
     pub fn trim_end(&self) -> &str {
-        self.trim_end_matches(|c: char| c.is_whitespace())
+        self.trim_end_matches(char::is_whitespace)
     }
 
     /// Returns a string slice with leading whitespace removed.
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 9b1b13e7129..84c7f1aafe1 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -247,6 +247,100 @@ use crate::cell::UnsafeCell;
 use crate::hint::spin_loop;
 use crate::{fmt, intrinsics};
 
+trait Sealed {}
+
+/// A marker trait for primitive types which can be modified atomically.
+///
+/// This is an implementation detail for <code>[Atomic]\<T></code> which may disappear or be replaced at any time.
+///
+/// # Safety
+///
+/// Types implementing this trait must be primitives that can be modified atomically.
+///
+/// The associated `Self::AtomicInner` type must have the same size and bit validity as `Self`,
+/// but may have a higher alignment requirement, so the following `transmute`s are sound:
+///
+/// - `&mut Self::AtomicInner` as `&mut Self`
+/// - `Self` as `Self::AtomicInner` or the reverse
+#[unstable(
+    feature = "atomic_internals",
+    reason = "implementation detail which may disappear or be replaced at any time",
+    issue = "none"
+)]
+#[expect(private_bounds)]
+pub unsafe trait AtomicPrimitive: Sized + Copy + Sealed {
+    /// Temporary implementation detail.
+    type AtomicInner: Sized;
+}
+
+macro impl_atomic_primitive(
+    $Atom:ident $(<$T:ident>)? ($Primitive:ty),
+    size($size:literal),
+    align($align:literal) $(,)?
+) {
+    impl $(<$T>)? Sealed for $Primitive {}
+
+    #[unstable(
+        feature = "atomic_internals",
+        reason = "implementation detail which may disappear or be replaced at any time",
+        issue = "none"
+    )]
+    #[cfg(target_has_atomic_load_store = $size)]
+    unsafe impl $(<$T>)? AtomicPrimitive for $Primitive {
+        type AtomicInner = $Atom $(<$T>)?;
+    }
+}
+
+impl_atomic_primitive!(AtomicBool(bool), size("8"), align(1));
+impl_atomic_primitive!(AtomicI8(i8), size("8"), align(1));
+impl_atomic_primitive!(AtomicU8(u8), size("8"), align(1));
+impl_atomic_primitive!(AtomicI16(i16), size("16"), align(2));
+impl_atomic_primitive!(AtomicU16(u16), size("16"), align(2));
+impl_atomic_primitive!(AtomicI32(i32), size("32"), align(4));
+impl_atomic_primitive!(AtomicU32(u32), size("32"), align(4));
+impl_atomic_primitive!(AtomicI64(i64), size("64"), align(8));
+impl_atomic_primitive!(AtomicU64(u64), size("64"), align(8));
+impl_atomic_primitive!(AtomicI128(i128), size("128"), align(16));
+impl_atomic_primitive!(AtomicU128(u128), size("128"), align(16));
+
+#[cfg(target_pointer_width = "16")]
+impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(2));
+#[cfg(target_pointer_width = "32")]
+impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(4));
+#[cfg(target_pointer_width = "64")]
+impl_atomic_primitive!(AtomicIsize(isize), size("ptr"), align(8));
+
+#[cfg(target_pointer_width = "16")]
+impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(2));
+#[cfg(target_pointer_width = "32")]
+impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(4));
+#[cfg(target_pointer_width = "64")]
+impl_atomic_primitive!(AtomicUsize(usize), size("ptr"), align(8));
+
+#[cfg(target_pointer_width = "16")]
+impl_atomic_primitive!(AtomicPtr<T>(*mut T), size("ptr"), align(2));
+#[cfg(target_pointer_width = "32")]
+impl_atomic_primitive!(AtomicPtr<T>(*mut T), size("ptr"), align(4));
+#[cfg(target_pointer_width = "64")]
+impl_atomic_primitive!(AtomicPtr<T>(*mut T), size("ptr"), align(8));
+
+/// A memory location which can be safely modified from multiple threads.
+///
+/// This has the same size and bit validity as the underlying type `T`. However,
+/// the alignment of this type is always equal to its size, even on targets where
+/// `T` has alignment less than its size.
+///
+/// For more about the differences between atomic types and non-atomic types as
+/// well as information about the portability of this type, please see the
+/// [module-level documentation].
+///
+/// **Note:** This type is only available on platforms that support atomic loads
+/// and stores of `T`.
+///
+/// [module-level documentation]: crate::sync::atomic
+#[unstable(feature = "generic_atomic", issue = "130539")]
+pub type Atomic<T> = <T as AtomicPrimitive>::AtomicInner;
+
 // Some architectures don't have byte-sized atomics, which results in LLVM
 // emulating them using a LL/SC loop. However for AtomicBool we can take
 // advantage of the fact that it only ever contains 0 or 1 and use atomic OR/AND
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index c46dcebedca..36a1c57b020 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -513,13 +513,13 @@ impl Span {
     }
 
     /// Creates an empty span pointing to directly before this span.
-    #[unstable(feature = "proc_macro_span", issue = "54725")]
+    #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
     pub fn start(&self) -> Span {
         Span(self.0.start())
     }
 
     /// Creates an empty span pointing to directly after this span.
-    #[unstable(feature = "proc_macro_span", issue = "54725")]
+    #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
     pub fn end(&self) -> Span {
         Span(self.0.end())
     }
@@ -527,7 +527,7 @@ impl Span {
     /// The one-indexed line of the source file where the span starts.
     ///
     /// To obtain the line of the span's end, use `span.end().line()`.
-    #[unstable(feature = "proc_macro_span", issue = "54725")]
+    #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
     pub fn line(&self) -> usize {
         self.0.line()
     }
@@ -535,7 +535,7 @@ impl Span {
     /// The one-indexed column of the source file where the span starts.
     ///
     /// To obtain the column of the span's end, use `span.end().column()`.
-    #[unstable(feature = "proc_macro_span", issue = "54725")]
+    #[stable(feature = "proc_macro_span_location", since = "CURRENT_RUSTC_VERSION")]
     pub fn column(&self) -> usize {
         self.0.column()
     }
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 3536e84d58b..602af4a0447 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -83,8 +83,8 @@ wasi = { version = "0.11.0", features = [
 ], default-features = false }
 
 [target.'cfg(target_os = "uefi")'.dependencies]
-r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] }
-r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] }
+r-efi = { version = "5.2.0", features = ['rustc-dep-of-std'] }
+r-efi-alloc = { version = "2.0.0", features = ['rustc-dep-of-std'] }
 
 [features]
 backtrace = [
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index 75971ac90e7..b574e9f3a25 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -57,7 +57,7 @@
 #![stable(feature = "alloc_module", since = "1.28.0")]
 
 use core::ptr::NonNull;
-use core::sync::atomic::{AtomicPtr, Ordering};
+use core::sync::atomic::{Atomic, AtomicPtr, Ordering};
 use core::{hint, mem, ptr};
 
 #[stable(feature = "alloc_module", since = "1.28.0")]
@@ -287,7 +287,7 @@ unsafe impl Allocator for System {
     }
 }
 
-static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
+static HOOK: Atomic<*mut ()> = AtomicPtr::new(ptr::null_mut());
 
 /// Registers a custom allocation error hook, replacing any that was previously registered.
 ///
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 3683485640c..c3fcb0e2e42 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -92,8 +92,8 @@ use crate::backtrace_rs::{self, BytesOrWideString};
 use crate::ffi::c_void;
 use crate::panic::UnwindSafe;
 use crate::sync::LazyLock;
-use crate::sync::atomic::AtomicU8;
 use crate::sync::atomic::Ordering::Relaxed;
+use crate::sync::atomic::{Atomic, AtomicU8};
 use crate::sys::backtrace::{lock, output_filename, set_image_base};
 use crate::{env, fmt};
 
@@ -254,7 +254,7 @@ impl Backtrace {
         // Cache the result of reading the environment variables to make
         // backtrace captures speedy, because otherwise reading environment
         // variables every time can be somewhat slow.
-        static ENABLED: AtomicU8 = AtomicU8::new(0);
+        static ENABLED: Atomic<u8> = AtomicU8::new(0);
         match ENABLED.load(Relaxed) {
             0 => {}
             1 => return false,
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index d34e3ca00b9..bd9446f5aba 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -161,7 +161,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#[unstable(feature = "c_str_module", issue = "112134")]
+#[stable(feature = "c_str_module", since = "CURRENT_RUSTC_VERSION")]
 pub mod c_str;
 
 #[stable(feature = "core_c_void", since = "1.30.0")]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 801baf3d990..3340a5dc23d 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2980,6 +2980,21 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
 ///
 /// [changes]: io#platform-specific-behavior
 ///
+/// ## Symlinks
+/// On UNIX-like systems, this function will update the permission bits
+/// of the file pointed to by the symlink.
+///
+/// Note that this behavior can lead to privalage escalation vulnerabilites,
+/// where the ability to create a symlink in one directory allows you to
+/// cause the permissions of another file or directory to be modified.
+///
+/// For this reason, using this function with symlinks should be avoided.
+/// When possible, permissions should be set at creation time instead.
+///
+/// # Rationale
+/// POSIX does not specify an `lchown` function,
+/// and symlinks can be followed regardless of what permission bits are set.
+///
 /// # Errors
 ///
 /// This function will return an error in the following situations, but is not
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 5242261cf93..96fac4f6bde 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -2319,9 +2319,9 @@ pub trait BufRead: Read {
     /// Checks if there is any data left to be `read`.
     ///
     /// This function may fill the buffer to check for data,
-    /// so this functions returns `Result<bool>`, not `bool`.
+    /// so this function returns `Result<bool>`, not `bool`.
     ///
-    /// Default implementation calls `fill_buf` and checks that
+    /// The default implementation calls `fill_buf` and checks that the
     /// returned slice is empty (which means that there is no data left,
     /// since EOF is reached).
     ///
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 8fc16331339..2d80fe49e80 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -11,7 +11,7 @@ use crate::io::{
     self, BorrowedCursor, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, SpecReadByte,
 };
 use crate::panic::{RefUnwindSafe, UnwindSafe};
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 use crate::sync::{Arc, Mutex, MutexGuard, OnceLock, ReentrantLock, ReentrantLockGuard};
 use crate::sys::stdio;
 use crate::thread::AccessError;
@@ -37,7 +37,7 @@ thread_local! {
 /// have a consistent order between set_output_capture and print_to *within
 /// the same thread*. Within the same thread, things always have a perfectly
 /// consistent order. So Ordering::Relaxed is fine.
-static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false);
+static OUTPUT_CAPTURE_USED: Atomic<bool> = AtomicBool::new(false);
 
 /// A handle to a raw instance of the standard input stream of this process.
 ///
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 91701576130..c9595b051e2 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -388,11 +388,15 @@ mod enum_keyword {}
 /// lazy_static;`. The other use is in foreign function interfaces (FFI).
 ///
 /// `extern` is used in two different contexts within FFI. The first is in the form of external
-/// blocks, for declaring function interfaces that Rust code can call foreign code by.
+/// blocks, for declaring function interfaces that Rust code can call foreign code by. This use
+/// of `extern` is unsafe, since we are asserting to the compiler that all function declarations
+/// are correct. If they are not, using these items may lead to undefined behavior.
 ///
 /// ```rust ignore
+/// // SAFETY: The function declarations given below are in
+/// // line with the header files of `my_c_library`.
 /// #[link(name = "my_c_library")]
-/// extern "C" {
+/// unsafe extern "C" {
 ///     fn my_c_function(x: i32) -> bool;
 /// }
 /// ```
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index f77bf92a806..ba57ad9bae3 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -329,7 +329,6 @@
 #![feature(array_chunks)]
 #![feature(bstr)]
 #![feature(bstr_internals)]
-#![feature(c_str_module)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
 #![feature(core_intrinsics)]
@@ -344,6 +343,7 @@
 #![feature(float_gamma)]
 #![feature(float_minimum_maximum)]
 #![feature(fmt_internals)]
+#![feature(generic_atomic)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
 #![feature(hint_must_use)]
@@ -704,8 +704,14 @@ pub use core::cfg_match;
     reason = "`concat_bytes` is not stable enough for use and is subject to change"
 )]
 pub use core::concat_bytes;
+#[stable(feature = "matches_macro", since = "1.42.0")]
+#[allow(deprecated, deprecated_in_future)]
+pub use core::matches;
 #[stable(feature = "core_primitive", since = "1.43.0")]
 pub use core::primitive;
+#[stable(feature = "todo_macro", since = "1.40.0")]
+#[allow(deprecated, deprecated_in_future)]
+pub use core::todo;
 // Re-export built-in macros defined through core.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
 #[allow(deprecated)]
@@ -719,8 +725,8 @@ pub use core::{
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::{
-    assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, todo, r#try,
-    unimplemented, unreachable, write, writeln,
+    assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, r#try, unimplemented,
+    unreachable, write, writeln,
 };
 
 // Include a number of private modules that exist solely to provide
diff --git a/library/std/src/os/uefi/env.rs b/library/std/src/os/uefi/env.rs
index cf8ae697e38..ab5406e605c 100644
--- a/library/std/src/os/uefi/env.rs
+++ b/library/std/src/os/uefi/env.rs
@@ -4,13 +4,13 @@
 
 use crate::ffi::c_void;
 use crate::ptr::NonNull;
-use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, Ordering};
 
-static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
-static IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
+static SYSTEM_TABLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut());
+static IMAGE_HANDLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut());
 // Flag to check if BootServices are still valid.
 // Start with assuming that they are not available
-static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false);
+static BOOT_SERVICES_FLAG: Atomic<bool> = AtomicBool::new(false);
 
 /// Initializes the global System Table and Image Handle pointers.
 ///
diff --git a/library/std/src/os/xous/services.rs b/library/std/src/os/xous/services.rs
index 93916750c05..0681485ea06 100644
--- a/library/std/src/os/xous/services.rs
+++ b/library/std/src/os/xous/services.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicU32, Ordering};
+use core::sync::atomic::{Atomic, AtomicU32, Ordering};
 
 use crate::os::xous::ffi::Connection;
 
@@ -106,7 +106,7 @@ pub fn try_connect(name: &str) -> Option<Connection> {
     ns::try_connect_with_name(name)
 }
 
-static NAME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+static NAME_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);
 
 /// Returns a `Connection` to the name server. If the name server has not been started,
 /// then this call will block until the name server has been started. The `Connection`
diff --git a/library/std/src/os/xous/services/dns.rs b/library/std/src/os/xous/services/dns.rs
index 02881648393..7641d1f15e4 100644
--- a/library/std/src/os/xous/services/dns.rs
+++ b/library/std/src/os/xous/services/dns.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicU32, Ordering};
+use core::sync::atomic::{Atomic, AtomicU32, Ordering};
 
 use crate::os::xous::ffi::Connection;
 use crate::os::xous::services::connect;
@@ -17,7 +17,7 @@ impl Into<usize> for DnsLendMut {
 /// Returns a `Connection` to the DNS lookup server. This server is used for
 /// querying domain name values.
 pub(crate) fn dns_server() -> Connection {
-    static DNS_CONNECTION: AtomicU32 = AtomicU32::new(0);
+    static DNS_CONNECTION: Atomic<u32> = AtomicU32::new(0);
     let cid = DNS_CONNECTION.load(Ordering::Relaxed);
     if cid != 0 {
         return cid.into();
diff --git a/library/std/src/os/xous/services/log.rs b/library/std/src/os/xous/services/log.rs
index 095d4f4a3e7..e7717c8515d 100644
--- a/library/std/src/os/xous/services/log.rs
+++ b/library/std/src/os/xous/services/log.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicU32, Ordering};
+use core::sync::atomic::{Atomic, AtomicU32, Ordering};
 
 use crate::os::xous::ffi::Connection;
 
@@ -64,7 +64,7 @@ impl Into<usize> for LogLend {
 /// running. It is safe to call this multiple times, because the address is
 /// shared among all threads in a process.
 pub(crate) fn log_server() -> Connection {
-    static LOG_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+    static LOG_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);
 
     let cid = LOG_SERVER_CONNECTION.load(Ordering::Relaxed);
     if cid != 0 {
diff --git a/library/std/src/os/xous/services/net.rs b/library/std/src/os/xous/services/net.rs
index 83acc7961b3..c20bf1a7ad5 100644
--- a/library/std/src/os/xous/services/net.rs
+++ b/library/std/src/os/xous/services/net.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicU32, Ordering};
+use core::sync::atomic::{Atomic, AtomicU32, Ordering};
 
 use crate::os::xous::ffi::Connection;
 use crate::os::xous::services::connect;
@@ -84,7 +84,7 @@ impl<'a> Into<[usize; 5]> for NetBlockingScalar {
 /// Returns a `Connection` to the Network server. This server provides all
 /// OS-level networking functions.
 pub(crate) fn net_server() -> Connection {
-    static NET_CONNECTION: AtomicU32 = AtomicU32::new(0);
+    static NET_CONNECTION: Atomic<u32> = AtomicU32::new(0);
     let cid = NET_CONNECTION.load(Ordering::Relaxed);
     if cid != 0 {
         return cid.into();
diff --git a/library/std/src/os/xous/services/systime.rs b/library/std/src/os/xous/services/systime.rs
index de87694b4cd..e54cffdc4c0 100644
--- a/library/std/src/os/xous/services/systime.rs
+++ b/library/std/src/os/xous/services/systime.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicU32, Ordering};
+use core::sync::atomic::{Atomic, AtomicU32, Ordering};
 
 use crate::os::xous::ffi::{Connection, connect};
 
@@ -17,7 +17,7 @@ impl Into<[usize; 5]> for SystimeScalar {
 /// Returns a `Connection` to the systime server. This server is used for reporting the
 /// realtime clock.
 pub(crate) fn systime_server() -> Connection {
-    static SYSTIME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+    static SYSTIME_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);
     let cid = SYSTIME_SERVER_CONNECTION.load(Ordering::Relaxed);
     if cid != 0 {
         return cid.into();
diff --git a/library/std/src/os/xous/services/ticktimer.rs b/library/std/src/os/xous/services/ticktimer.rs
index 66ade6da65c..bf51ecde8e5 100644
--- a/library/std/src/os/xous/services/ticktimer.rs
+++ b/library/std/src/os/xous/services/ticktimer.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicU32, Ordering};
+use core::sync::atomic::{Atomic, AtomicU32, Ordering};
 
 use crate::os::xous::ffi::Connection;
 
@@ -31,7 +31,7 @@ impl Into<[usize; 5]> for TicktimerScalar {
 /// Returns a `Connection` to the ticktimer server. This server is used for synchronization
 /// primitives such as sleep, Mutex, and Condvar.
 pub(crate) fn ticktimer_server() -> Connection {
-    static TICKTIMER_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+    static TICKTIMER_SERVER_CONNECTION: Atomic<u32> = AtomicU32::new(0);
     let cid = TICKTIMER_SERVER_CONNECTION.load(Ordering::Relaxed);
     if cid != 0 {
         return cid.into();
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 22776ae2bc4..f3b26ac64df 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -3,7 +3,7 @@
 #![stable(feature = "std_panic", since = "1.9.0")]
 
 use crate::any::Any;
-use crate::sync::atomic::{AtomicU8, Ordering};
+use crate::sync::atomic::{Atomic, AtomicU8, Ordering};
 use crate::sync::{Condvar, Mutex, RwLock};
 use crate::thread::Result;
 use crate::{collections, fmt, panicking};
@@ -469,7 +469,7 @@ impl BacktraceStyle {
 // that backtrace.
 //
 // Internally stores equivalent of an Option<BacktraceStyle>.
-static SHOULD_CAPTURE: AtomicU8 = AtomicU8::new(0);
+static SHOULD_CAPTURE: Atomic<u8> = AtomicU8::new(0);
 
 /// Configures whether the default panic hook will capture and display a
 /// backtrace.
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index a3950980b5e..4bfedf78366 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -21,7 +21,7 @@ use crate::any::Any;
 use crate::io::try_set_output_capture;
 use crate::mem::{self, ManuallyDrop};
 use crate::panic::{BacktraceStyle, PanicHookInfo};
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 use crate::sync::{PoisonError, RwLock};
 use crate::sys::backtrace;
 use crate::sys::stdio::panic_output;
@@ -289,7 +289,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
             };
         });
 
-        static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
+        static FIRST_PANIC: Atomic<bool> = AtomicBool::new(true);
 
         match backtrace {
             // SAFETY: we took out a lock just a second ago.
@@ -374,7 +374,7 @@ pub mod panic_count {
 #[unstable(feature = "update_panic_count", issue = "none")]
 pub mod panic_count {
     use crate::cell::Cell;
-    use crate::sync::atomic::{AtomicUsize, Ordering};
+    use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 
     const ALWAYS_ABORT_FLAG: usize = 1 << (usize::BITS - 1);
 
@@ -416,7 +416,7 @@ pub mod panic_count {
     //
     // Stealing a bit is fine because it just amounts to assuming that each
     // panicking thread consumes at least 2 bytes of address space.
-    static GLOBAL_PANIC_COUNT: AtomicUsize = AtomicUsize::new(0);
+    static GLOBAL_PANIC_COUNT: Atomic<usize> = AtomicUsize::new(0);
 
     // Increases the global and local panic count, and returns whether an
     // immediate abort is required.
diff --git a/library/std/src/sync/mpmc/array.rs b/library/std/src/sync/mpmc/array.rs
index a467237fef1..880d8b5f57c 100644
--- a/library/std/src/sync/mpmc/array.rs
+++ b/library/std/src/sync/mpmc/array.rs
@@ -16,13 +16,13 @@ use super::waker::SyncWaker;
 use crate::cell::UnsafeCell;
 use crate::mem::MaybeUninit;
 use crate::ptr;
-use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::sync::atomic::{self, Atomic, AtomicUsize, Ordering};
 use crate::time::Instant;
 
 /// A slot in a channel.
 struct Slot<T> {
     /// The current stamp.
-    stamp: AtomicUsize,
+    stamp: Atomic<usize>,
 
     /// The message in this slot. Either read out in `read` or dropped through
     /// `discard_all_messages`.
@@ -55,7 +55,7 @@ pub(crate) struct Channel<T> {
     /// represent the lap. The mark bit in the head is always zero.
     ///
     /// Messages are popped from the head of the channel.
-    head: CachePadded<AtomicUsize>,
+    head: CachePadded<Atomic<usize>>,
 
     /// The tail of the channel.
     ///
@@ -64,7 +64,7 @@ pub(crate) struct Channel<T> {
     /// represent the lap. The mark bit indicates that the channel is disconnected.
     ///
     /// Messages are pushed into the tail of the channel.
-    tail: CachePadded<AtomicUsize>,
+    tail: CachePadded<Atomic<usize>>,
 
     /// The buffer holding slots.
     buffer: Box<[Slot<T>]>,
diff --git a/library/std/src/sync/mpmc/context.rs b/library/std/src/sync/mpmc/context.rs
index 51aa7e82e78..6b2f4cb6ffd 100644
--- a/library/std/src/sync/mpmc/context.rs
+++ b/library/std/src/sync/mpmc/context.rs
@@ -5,7 +5,7 @@ use super::waker::current_thread_id;
 use crate::cell::Cell;
 use crate::ptr;
 use crate::sync::Arc;
-use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicPtr, AtomicUsize, Ordering};
 use crate::thread::{self, Thread};
 use crate::time::Instant;
 
@@ -19,10 +19,10 @@ pub struct Context {
 #[derive(Debug)]
 struct Inner {
     /// Selected operation.
-    select: AtomicUsize,
+    select: Atomic<usize>,
 
     /// A slot into which another thread may store a pointer to its `Packet`.
-    packet: AtomicPtr<()>,
+    packet: Atomic<*mut ()>,
 
     /// Thread handle.
     thread: Thread,
diff --git a/library/std/src/sync/mpmc/counter.rs b/library/std/src/sync/mpmc/counter.rs
index d1bfe612f53..efa6af11483 100644
--- a/library/std/src/sync/mpmc/counter.rs
+++ b/library/std/src/sync/mpmc/counter.rs
@@ -1,16 +1,16 @@
-use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering};
 use crate::{ops, process};
 
 /// Reference counter internals.
 struct Counter<C> {
     /// The number of senders associated with the channel.
-    senders: AtomicUsize,
+    senders: Atomic<usize>,
 
     /// The number of receivers associated with the channel.
-    receivers: AtomicUsize,
+    receivers: Atomic<usize>,
 
     /// Set to `true` if the last sender or the last receiver reference deallocates the channel.
-    destroy: AtomicBool,
+    destroy: Atomic<bool>,
 
     /// The internal channel.
     chan: C,
diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs
index 1c6acb29e37..3fcfb85cf2a 100644
--- a/library/std/src/sync/mpmc/list.rs
+++ b/library/std/src/sync/mpmc/list.rs
@@ -9,7 +9,7 @@ use crate::cell::UnsafeCell;
 use crate::marker::PhantomData;
 use crate::mem::MaybeUninit;
 use crate::ptr;
-use crate::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
+use crate::sync::atomic::{self, Atomic, AtomicPtr, AtomicUsize, Ordering};
 use crate::time::Instant;
 
 // Bits indicating the state of a slot:
@@ -37,7 +37,7 @@ struct Slot<T> {
     msg: UnsafeCell<MaybeUninit<T>>,
 
     /// The state of the slot.
-    state: AtomicUsize,
+    state: Atomic<usize>,
 }
 
 impl<T> Slot<T> {
@@ -55,7 +55,7 @@ impl<T> Slot<T> {
 /// Each block in the list can hold up to `BLOCK_CAP` messages.
 struct Block<T> {
     /// The next block in the linked list.
-    next: AtomicPtr<Block<T>>,
+    next: Atomic<*mut Block<T>>,
 
     /// Slots for messages.
     slots: [Slot<T>; BLOCK_CAP],
@@ -65,11 +65,11 @@ impl<T> Block<T> {
     /// Creates an empty block.
     fn new() -> Box<Block<T>> {
         // SAFETY: This is safe because:
-        //  [1] `Block::next` (AtomicPtr) may be safely zero initialized.
+        //  [1] `Block::next` (Atomic<*mut _>) may be safely zero initialized.
         //  [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
         //  [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it
         //       holds a MaybeUninit.
-        //  [4] `Slot::state` (AtomicUsize) may be safely zero initialized.
+        //  [4] `Slot::state` (Atomic<usize>) may be safely zero initialized.
         unsafe { Box::new_zeroed().assume_init() }
     }
 
@@ -110,10 +110,10 @@ impl<T> Block<T> {
 #[derive(Debug)]
 struct Position<T> {
     /// The index in the channel.
-    index: AtomicUsize,
+    index: Atomic<usize>,
 
     /// The block in the linked list.
-    block: AtomicPtr<Block<T>>,
+    block: Atomic<*mut Block<T>>,
 }
 
 /// The token type for the list flavor.
diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs
index f5e764e69bd..4216fb7ac59 100644
--- a/library/std/src/sync/mpmc/waker.rs
+++ b/library/std/src/sync/mpmc/waker.rs
@@ -4,7 +4,7 @@ use super::context::Context;
 use super::select::{Operation, Selected};
 use crate::ptr;
 use crate::sync::Mutex;
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 
 /// Represents a thread blocked on a specific channel operation.
 pub(crate) struct Entry {
@@ -137,7 +137,7 @@ pub(crate) struct SyncWaker {
     inner: Mutex<Waker>,
 
     /// `true` if the waker is empty.
-    is_empty: AtomicBool,
+    is_empty: Atomic<bool>,
 }
 
 impl SyncWaker {
diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs
index 577997c07a6..f1ecf80fcb9 100644
--- a/library/std/src/sync/mpmc/zero.rs
+++ b/library/std/src/sync/mpmc/zero.rs
@@ -10,7 +10,7 @@ use super::waker::Waker;
 use crate::cell::UnsafeCell;
 use crate::marker::PhantomData;
 use crate::sync::Mutex;
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 use crate::time::Instant;
 use crate::{fmt, ptr};
 
@@ -35,7 +35,7 @@ struct Packet<T> {
     on_stack: bool,
 
     /// Equals `true` once the packet is ready for reading or writing.
-    ready: AtomicBool,
+    ready: Atomic<bool>,
 
     /// The message.
     msg: UnsafeCell<Option<T>>,
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index 1b8809734b8..cc1d0b30152 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -76,7 +76,7 @@ pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
 use crate::error::Error;
 use crate::fmt;
 #[cfg(panic = "unwind")]
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 #[cfg(panic = "unwind")]
 use crate::thread;
 
@@ -88,7 +88,7 @@ mod rwlock;
 
 pub(crate) struct Flag {
     #[cfg(panic = "unwind")]
-    failed: AtomicBool,
+    failed: Atomic<bool>,
 }
 
 // Note that the Ordering uses to access the `failed` field of `Flag` below is
diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs
index e009eb410ef..24539d4e830 100644
--- a/library/std/src/sync/reentrant_lock.rs
+++ b/library/std/src/sync/reentrant_lock.rs
@@ -89,9 +89,9 @@ pub struct ReentrantLock<T: ?Sized> {
 
 cfg_if!(
     if #[cfg(target_has_atomic = "64")] {
-        use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
+        use crate::sync::atomic::{Atomic, AtomicU64, Ordering::Relaxed};
 
-        struct Tid(AtomicU64);
+        struct Tid(Atomic<u64>);
 
         impl Tid {
             const fn new() -> Self {
@@ -120,6 +120,7 @@ cfg_if!(
         }
 
         use crate::sync::atomic::{
+            Atomic,
             AtomicUsize,
             Ordering,
         };
@@ -137,7 +138,7 @@ cfg_if!(
             // the current thread, or by a thread that has terminated before
             // the current thread was created. In either case, no further
             // synchronization is needed (as per <https://github.com/rust-lang/miri/issues/3450>)
-            tls_addr: AtomicUsize,
+            tls_addr: Atomic<usize>,
             tid: UnsafeCell<u64>,
         }
 
diff --git a/library/std/src/sys/alloc/sgx.rs b/library/std/src/sys/alloc/sgx.rs
index 7a846e2376b..afdef7a5cb6 100644
--- a/library/std/src/sys/alloc/sgx.rs
+++ b/library/std/src/sys/alloc/sgx.rs
@@ -1,6 +1,6 @@
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ptr;
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 use crate::sys::pal::abi::mem as sgx_mem;
 use crate::sys::pal::waitqueue::SpinMutex;
 
@@ -22,7 +22,7 @@ struct Sgx;
 unsafe impl dlmalloc::Allocator for Sgx {
     /// Allocs system resources
     fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {
-        static INIT: AtomicBool = AtomicBool::new(false);
+        static INIT: Atomic<bool> = AtomicBool::new(false);
 
         // No ordering requirement since this function is protected by the global lock.
         if !INIT.swap(true, Ordering::Relaxed) {
diff --git a/library/std/src/sys/alloc/wasm.rs b/library/std/src/sys/alloc/wasm.rs
index 53fbc9529e5..c8fab992a88 100644
--- a/library/std/src/sys/alloc/wasm.rs
+++ b/library/std/src/sys/alloc/wasm.rs
@@ -60,10 +60,10 @@ unsafe impl GlobalAlloc for System {
 
 #[cfg(target_feature = "atomics")]
 mod lock {
-    use crate::sync::atomic::AtomicI32;
     use crate::sync::atomic::Ordering::{Acquire, Release};
+    use crate::sync::atomic::{Atomic, AtomicI32};
 
-    static LOCKED: AtomicI32 = AtomicI32::new(0);
+    static LOCKED: Atomic<i32> = AtomicI32::new(0);
 
     pub struct DropLock;
 
diff --git a/library/std/src/sys/alloc/xous.rs b/library/std/src/sys/alloc/xous.rs
index ccaa972c22d..c7f973b8027 100644
--- a/library/std/src/sys/alloc/xous.rs
+++ b/library/std/src/sys/alloc/xous.rs
@@ -49,10 +49,10 @@ unsafe impl GlobalAlloc for System {
 }
 
 mod lock {
-    use crate::sync::atomic::AtomicI32;
     use crate::sync::atomic::Ordering::{Acquire, Release};
+    use crate::sync::atomic::{Atomic, AtomicI32};
 
-    static LOCKED: AtomicI32 = AtomicI32::new(0);
+    static LOCKED: Atomic<i32> = AtomicI32::new(0);
 
     pub struct DropLock;
 
diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs
index 0185a8a6000..2a4bc76aefb 100644
--- a/library/std/src/sys/args/sgx.rs
+++ b/library/std/src/sys/args/sgx.rs
@@ -1,7 +1,7 @@
 #![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
 
 use crate::ffi::OsString;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 use crate::sys::os_str::Buf;
 use crate::sys::pal::abi::usercalls::alloc;
 use crate::sys::pal::abi::usercalls::raw::ByteBuffer;
@@ -11,7 +11,7 @@ use crate::{fmt, slice};
 // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
 #[cfg_attr(test, linkage = "available_externally")]
 #[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx4args4ARGSE")]
-static ARGS: AtomicUsize = AtomicUsize::new(0);
+static ARGS: Atomic<usize> = AtomicUsize::new(0);
 type ArgsStore = Vec<OsString>;
 
 #[cfg_attr(test, allow(dead_code))]
diff --git a/library/std/src/sys/args/unix.rs b/library/std/src/sys/args/unix.rs
index a7b79ad396e..0dfbd5f03eb 100644
--- a/library/std/src/sys/args/unix.rs
+++ b/library/std/src/sys/args/unix.rs
@@ -88,7 +88,7 @@ pub fn args() -> Args {
 mod imp {
     use crate::ffi::c_char;
     use crate::ptr;
-    use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
+    use crate::sync::atomic::{Atomic, AtomicIsize, AtomicPtr, Ordering};
 
     // The system-provided argc and argv, which we store in static memory
     // here so that we can defer the work of parsing them until its actually
@@ -96,8 +96,8 @@ mod imp {
     //
     // Note that we never mutate argv/argc, the argv array, or the argv
     // strings, which allows the code in this file to be very simple.
-    static ARGC: AtomicIsize = AtomicIsize::new(0);
-    static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
+    static ARGC: Atomic<isize> = AtomicIsize::new(0);
+    static ARGV: Atomic<*mut *const u8> = AtomicPtr::new(ptr::null_mut());
 
     unsafe fn really_init(argc: isize, argv: *const *const u8) {
         // These don't need to be ordered with each other or other stores,
diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs
index 85be9cd6ad4..09090ec7cf0 100644
--- a/library/std/src/sys/env/sgx.rs
+++ b/library/std/src/sys/env/sgx.rs
@@ -4,13 +4,13 @@ pub use super::common::Env;
 use crate::collections::HashMap;
 use crate::ffi::{OsStr, OsString};
 use crate::io;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 use crate::sync::{Mutex, Once};
 
 // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
 #[cfg_attr(test, linkage = "available_externally")]
 #[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")]
-static ENV: AtomicUsize = AtomicUsize::new(0);
+static ENV: Atomic<usize> = AtomicUsize::new(0);
 // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
 #[cfg_attr(test, linkage = "available_externally")]
 #[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")]
diff --git a/library/std/src/sys/env/xous.rs b/library/std/src/sys/env/xous.rs
index 232a3dafb0b..8f65f30d35f 100644
--- a/library/std/src/sys/env/xous.rs
+++ b/library/std/src/sys/env/xous.rs
@@ -2,11 +2,11 @@ pub use super::common::Env;
 use crate::collections::HashMap;
 use crate::ffi::{OsStr, OsString};
 use crate::io;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 use crate::sync::{Mutex, Once};
 use crate::sys::pal::os::{get_application_parameters, params};
 
-static ENV: AtomicUsize = AtomicUsize::new(0);
+static ENV: Atomic<usize> = AtomicUsize::new(0);
 static ENV_INIT: Once = Once::new();
 type EnvStore = Mutex<HashMap<OsString, OsString>>;
 
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 351a9f9413f..5af59a2a914 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -147,14 +147,14 @@ cfg_has_statx! {{
         flags: i32,
         mask: u32,
     ) -> Option<io::Result<FileAttr>> {
-        use crate::sync::atomic::{AtomicU8, Ordering};
+        use crate::sync::atomic::{Atomic, AtomicU8, Ordering};
 
         // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx`.
         // We check for it on first failure and remember availability to avoid having to
         // do it again.
         #[repr(u8)]
         enum STATX_STATE{ Unknown = 0, Present, Unavailable }
-        static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8);
+        static STATX_SAVED_STATE: Atomic<u8> = AtomicU8::new(STATX_STATE::Unknown as u8);
 
         syscall!(
             fn statx(
diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs
index b213c49bcb0..06734f9e309 100644
--- a/library/std/src/sys/fs/windows/remove_dir_all.rs
+++ b/library/std/src/sys/fs/windows/remove_dir_all.rs
@@ -29,7 +29,7 @@
 //! race but we do make a best effort such that it *should* do so.
 
 use core::ptr;
-use core::sync::atomic::{AtomicU32, Ordering};
+use core::sync::atomic::{Atomic, AtomicU32, Ordering};
 
 use super::{AsRawHandle, DirBuff, File, FromRawHandle};
 use crate::sys::c;
@@ -87,7 +87,7 @@ fn open_link_no_reparse(
     // The `OBJ_DONT_REPARSE` attribute ensures that we haven't been
     // tricked into following a symlink. However, it may not be available in
     // earlier versions of Windows.
-    static ATTRIBUTES: AtomicU32 = AtomicU32::new(c::OBJ_DONT_REPARSE);
+    static ATTRIBUTES: Atomic<u32> = AtomicU32::new(c::OBJ_DONT_REPARSE);
 
     let result = unsafe {
         let mut path_str = c::UNICODE_STRING::from_ref(path);
diff --git a/library/std/src/sys/net/connection/xous/tcplistener.rs b/library/std/src/sys/net/connection/xous/tcplistener.rs
index 7f13ca55920..bdf1fcd9302 100644
--- a/library/std/src/sys/net/connection/xous/tcplistener.rs
+++ b/library/std/src/sys/net/connection/xous/tcplistener.rs
@@ -1,5 +1,5 @@
 use core::convert::TryInto;
-use core::sync::atomic::{AtomicBool, AtomicU16, AtomicUsize, Ordering};
+use core::sync::atomic::{Atomic, AtomicBool, AtomicU16, AtomicUsize, Ordering};
 
 use super::*;
 use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
@@ -18,10 +18,10 @@ macro_rules! unimpl {
 
 #[derive(Clone)]
 pub struct TcpListener {
-    fd: Arc<AtomicU16>,
+    fd: Arc<Atomic<u16>>,
     local: SocketAddr,
-    handle_count: Arc<AtomicUsize>,
-    nonblocking: Arc<AtomicBool>,
+    handle_count: Arc<Atomic<usize>>,
+    nonblocking: Arc<Atomic<bool>>,
 }
 
 impl TcpListener {
diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs
index e8aea8b706a..54524767452 100644
--- a/library/std/src/sys/net/connection/xous/tcpstream.rs
+++ b/library/std/src/sys/net/connection/xous/tcpstream.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
+use core::sync::atomic::{Atomic, AtomicBool, AtomicU32, AtomicUsize, Ordering};
 
 use super::*;
 use crate::fmt;
@@ -29,11 +29,11 @@ pub struct TcpStream {
     remote_port: u16,
     peer_addr: SocketAddr,
     // milliseconds
-    read_timeout: Arc<AtomicU32>,
+    read_timeout: Arc<Atomic<u32>>,
     // milliseconds
-    write_timeout: Arc<AtomicU32>,
-    handle_count: Arc<AtomicUsize>,
-    nonblocking: Arc<AtomicBool>,
+    write_timeout: Arc<Atomic<u32>>,
+    handle_count: Arc<Atomic<usize>>,
+    nonblocking: Arc<Atomic<bool>>,
 }
 
 fn sockaddr_to_buf(duration: Duration, addr: &SocketAddr, buf: &mut [u8]) {
diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs
index c112c04ce94..2127d3267ed 100644
--- a/library/std/src/sys/net/connection/xous/udp.rs
+++ b/library/std/src/sys/net/connection/xous/udp.rs
@@ -1,5 +1,5 @@
 use core::convert::TryInto;
-use core::sync::atomic::{AtomicUsize, Ordering};
+use core::sync::atomic::{Atomic, AtomicUsize, Ordering};
 
 use super::*;
 use crate::cell::Cell;
@@ -27,7 +27,7 @@ pub struct UdpSocket {
     read_timeout: Cell<u64>,
     // in milliseconds. The setting applies only to `send` calls after the timeout is set.
     write_timeout: Cell<u64>,
-    handle_count: Arc<AtomicUsize>,
+    handle_count: Arc<Atomic<usize>>,
     nonblocking: Cell<bool>,
 }
 
diff --git a/library/std/src/sys/pal/hermit/futex.rs b/library/std/src/sys/pal/hermit/futex.rs
index 670383b45ac..78c86071fdd 100644
--- a/library/std/src/sys/pal/hermit/futex.rs
+++ b/library/std/src/sys/pal/hermit/futex.rs
@@ -1,19 +1,19 @@
 use super::hermit_abi;
 use crate::ptr::null;
-use crate::sync::atomic::AtomicU32;
+use crate::sync::atomic::Atomic;
 use crate::time::Duration;
 
 /// An atomic for use as a futex that is at least 32-bits but may be larger
-pub type Futex = AtomicU32;
+pub type Futex = Atomic<Primitive>;
 /// Must be the underlying type of Futex
 pub type Primitive = u32;
 
 /// An atomic for use as a futex that is at least 8-bits but may be larger.
-pub type SmallFutex = AtomicU32;
+pub type SmallFutex = Atomic<SmallPrimitive>;
 /// Must be the underlying type of SmallFutex
 pub type SmallPrimitive = u32;
 
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
     // Calculate the timeout as a relative timespec.
     //
     // Overflows are rounded up to an infinite timeout (None).
@@ -37,12 +37,12 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 }
 
 #[inline]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
     unsafe { hermit_abi::futex_wake(futex.as_ptr(), 1) > 0 }
 }
 
 #[inline]
-pub fn futex_wake_all(futex: &AtomicU32) {
+pub fn futex_wake_all(futex: &Atomic<u32>) {
     unsafe {
         hermit_abi::futex_wake(futex.as_ptr(), i32::MAX);
     }
diff --git a/library/std/src/sys/pal/itron/spin.rs b/library/std/src/sys/pal/itron/spin.rs
index 6a9a7c72deb..bc4f83260bb 100644
--- a/library/std/src/sys/pal/itron/spin.rs
+++ b/library/std/src/sys/pal/itron/spin.rs
@@ -1,12 +1,12 @@
 use super::abi;
 use crate::cell::UnsafeCell;
 use crate::mem::MaybeUninit;
-use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering};
 
 /// A mutex implemented by `dis_dsp` (for intra-core synchronization) and a
 /// spinlock (for inter-core synchronization).
 pub struct SpinMutex<T = ()> {
-    locked: AtomicBool,
+    locked: Atomic<bool>,
     data: UnsafeCell<T>,
 }
 
@@ -19,7 +19,7 @@ impl<T> SpinMutex<T> {
     /// Acquire a lock.
     #[inline]
     pub fn with_locked<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
-        struct SpinMutexGuard<'a>(&'a AtomicBool);
+        struct SpinMutexGuard<'a>(&'a Atomic<bool>);
 
         impl Drop for SpinMutexGuard<'_> {
             #[inline]
@@ -50,7 +50,7 @@ impl<T> SpinMutex<T> {
 /// It's assumed that `0` is not a valid ID, and all kernel
 /// object IDs fall into range `1..=usize::MAX`.
 pub struct SpinIdOnceCell<T = ()> {
-    id: AtomicUsize,
+    id: Atomic<usize>,
     spin: SpinMutex<()>,
     extra: UnsafeCell<MaybeUninit<T>>,
 }
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index d1481f827e1..a974f4f17ae 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -9,7 +9,7 @@ use crate::ffi::CStr;
 use crate::mem::ManuallyDrop;
 use crate::num::NonZero;
 use crate::ptr::NonNull;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 use crate::time::Duration;
 use crate::{hint, io};
 
@@ -64,7 +64,7 @@ struct ThreadInner {
     ///                 '--> JOIN_FINALIZE ---'
     ///                          (-1)
     ///
-    lifecycle: AtomicUsize,
+    lifecycle: Atomic<usize>,
 }
 
 // Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
diff --git a/library/std/src/sys/pal/sgx/abi/mod.rs b/library/std/src/sys/pal/sgx/abi/mod.rs
index 2c805a4d0af..57247cffad3 100644
--- a/library/std/src/sys/pal/sgx/abi/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/mod.rs
@@ -1,7 +1,7 @@
 #![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test
 
 use core::arch::global_asm;
-use core::sync::atomic::{AtomicUsize, Ordering};
+use core::sync::atomic::{Atomic, AtomicUsize, Ordering};
 
 use crate::io::Write;
 
@@ -31,7 +31,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
     const BUSY: usize = 1;
     const DONE: usize = 2;
     // Three-state spin-lock
-    static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);
+    static RELOC_STATE: Atomic<usize> = AtomicUsize::new(UNINIT);
 
     if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
         rtabort!("Entered secondary TCS before main TCS!")
diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
index f082d94614b..41e38b69616 100644
--- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
@@ -3,7 +3,7 @@ mod sync_bitset;
 use self::sync_bitset::*;
 use crate::cell::Cell;
 use crate::num::NonZero;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 use crate::{mem, ptr};
 
 #[cfg(target_pointer_width = "64")]
@@ -15,14 +15,10 @@ const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS;
 #[cfg_attr(test, linkage = "available_externally")]
 #[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx3abi3tls14TLS_KEY_IN_USEE")]
 static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT;
-macro_rules! dup {
-    ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* ));
-    (() $($val:tt)*) => ([$($val),*])
-}
 // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
 #[cfg_attr(test, linkage = "available_externally")]
 #[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx3abi3tls14TLS_DESTRUCTORE")]
-static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0)));
+static TLS_DESTRUCTOR: [Atomic<usize>; TLS_KEYS] = [const { AtomicUsize::new(0) }; TLS_KEYS];
 
 unsafe extern "C" {
     fn get_tls_ptr() -> *const u8;
@@ -84,7 +80,7 @@ impl<'a> Drop for ActiveTls<'a> {
 
 impl Tls {
     pub fn new() -> Tls {
-        Tls { data: dup!((* * * * * * *) (Cell::new(ptr::null_mut()))) }
+        Tls { data: [const { Cell::new(ptr::null_mut()) }; TLS_KEYS] }
     }
 
     pub unsafe fn activate(&self) -> ActiveTls<'_> {
diff --git a/library/std/src/sys/pal/sgx/abi/tls/sync_bitset.rs b/library/std/src/sys/pal/sgx/abi/tls/sync_bitset.rs
index 4eeff8f6ef7..9087168589a 100644
--- a/library/std/src/sys/pal/sgx/abi/tls/sync_bitset.rs
+++ b/library/std/src/sys/pal/sgx/abi/tls/sync_bitset.rs
@@ -4,10 +4,10 @@ mod tests;
 use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS};
 use crate::iter::{Enumerate, Peekable};
 use crate::slice::Iter;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 
 /// A bitset that can be used synchronously.
-pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]);
+pub(super) struct SyncBitset([Atomic<usize>; TLS_KEYS_BITSET_SIZE]);
 
 pub(super) const SYNC_BITSET_INIT: SyncBitset =
     SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]);
@@ -58,7 +58,7 @@ impl SyncBitset {
 }
 
 pub(super) struct SyncBitsetIter<'a> {
-    iter: Peekable<Enumerate<Iter<'a, AtomicUsize>>>,
+    iter: Peekable<Enumerate<Iter<'a, Atomic<usize>>>>,
     elem_idx: usize,
 }
 
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 99735947e2c..3932f64c0ef 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -6,7 +6,7 @@
 #![allow(fuzzy_provenance_casts)] // FIXME: this entire module systematically confuses pointers and integers
 
 use crate::io::ErrorKind;
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 
 pub mod abi;
 mod libunwind_integration;
@@ -46,7 +46,7 @@ pub fn unsupported_err() -> crate::io::Error {
 /// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is
 /// `false`, the behavior is the same as `unsupported`.
 pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
-    static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
+    static SGX_INEFFECTIVE_ERROR: Atomic<bool> = AtomicBool::new(false);
     if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
         Err(crate::io::const_error!(
             ErrorKind::Uncategorized,
diff --git a/library/std/src/sys/pal/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/pal/sgx/waitqueue/spin_mutex.rs
index f6e851ccadd..73c7a101d60 100644
--- a/library/std/src/sys/pal/sgx/waitqueue/spin_mutex.rs
+++ b/library/std/src/sys/pal/sgx/waitqueue/spin_mutex.rs
@@ -7,12 +7,12 @@ mod tests;
 use crate::cell::UnsafeCell;
 use crate::hint;
 use crate::ops::{Deref, DerefMut};
-use crate::sync::atomic::{AtomicBool, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, Ordering};
 
 #[derive(Default)]
 pub struct SpinMutex<T> {
     value: UnsafeCell<T>,
-    lock: AtomicBool,
+    lock: Atomic<bool>,
 }
 
 unsafe impl<T: Send> Send for SpinMutex<T> {}
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 309022bcccf..6ee3e0a8b66 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -22,7 +22,7 @@ use crate::os::uefi::{self};
 use crate::path::Path;
 use crate::ptr::NonNull;
 use crate::slice;
-use crate::sync::atomic::{AtomicPtr, Ordering};
+use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
 use crate::sys_common::wstr::WStrUnits;
 
 type BootInstallMultipleProtocolInterfaces =
@@ -157,7 +157,7 @@ pub(crate) fn device_path_to_text(path: NonNull<device_path::Protocol>) -> io::R
         Ok(path)
     }
 
-    static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+    static LAST_VALID_HANDLE: Atomic<*mut crate::ffi::c_void> =
         AtomicPtr::new(crate::ptr::null_mut());
 
     if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
@@ -269,7 +269,7 @@ impl OwnedDevicePath {
                 .ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "invalid Device Path"))
         }
 
-        static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+        static LAST_VALID_HANDLE: Atomic<*mut crate::ffi::c_void> =
             AtomicPtr::new(crate::ptr::null_mut());
 
         if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
@@ -606,7 +606,7 @@ pub(crate) fn os_string_to_raw(s: &OsStr) -> Option<Box<[r_efi::efi::Char16]>> {
 }
 
 pub(crate) fn open_shell() -> Option<NonNull<shell::Protocol>> {
-    static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+    static LAST_VALID_HANDLE: Atomic<*mut crate::ffi::c_void> =
         AtomicPtr::new(crate::ptr::null_mut());
 
     if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index bd6a36021f4..78fcfcb3b77 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -28,9 +28,9 @@ pub type RawOsError = usize;
 use crate::io as std_io;
 use crate::os::uefi;
 use crate::ptr::NonNull;
-use crate::sync::atomic::{AtomicPtr, Ordering};
+use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
 
-static EXIT_BOOT_SERVICE_EVENT: AtomicPtr<crate::ffi::c_void> =
+static EXIT_BOOT_SERVICE_EVENT: Atomic<*mut crate::ffi::c_void> =
     AtomicPtr::new(crate::ptr::null_mut());
 
 /// # SAFETY
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
index c4ff3015ac6..eeb2c35ffbb 100644
--- a/library/std/src/sys/pal/uefi/time.rs
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -121,7 +121,7 @@ pub(crate) mod instant_internal {
     use super::*;
     use crate::mem::MaybeUninit;
     use crate::ptr::NonNull;
-    use crate::sync::atomic::{AtomicPtr, Ordering};
+    use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
     use crate::sys_common::mul_div_u64;
 
     const NS_PER_SEC: u64 = 1_000_000_000;
@@ -142,7 +142,7 @@ pub(crate) mod instant_internal {
             Some(mul_div_u64(ts, NS_PER_SEC, freq))
         }
 
-        static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+        static LAST_VALID_HANDLE: Atomic<*mut crate::ffi::c_void> =
             AtomicPtr::new(crate::ptr::null_mut());
 
         if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs
index 87ba13ca932..8d89163c42c 100644
--- a/library/std/src/sys/pal/unix/futex.rs
+++ b/library/std/src/sys/pal/unix/futex.rs
@@ -8,16 +8,16 @@
     target_os = "fuchsia",
 ))]
 
-use crate::sync::atomic::AtomicU32;
+use crate::sync::atomic::Atomic;
 use crate::time::Duration;
 
 /// An atomic for use as a futex that is at least 32-bits but may be larger
-pub type Futex = AtomicU32;
+pub type Futex = Atomic<Primitive>;
 /// Must be the underlying type of Futex
 pub type Primitive = u32;
 
 /// An atomic for use as a futex that is at least 8-bits but may be larger.
-pub type SmallFutex = AtomicU32;
+pub type SmallFutex = Atomic<SmallPrimitive>;
 /// Must be the underlying type of SmallFutex
 pub type SmallPrimitive = u32;
 
@@ -27,7 +27,7 @@ pub type SmallPrimitive = u32;
 ///
 /// Returns false on timeout, and true in all other cases.
 #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
     use super::time::Timespec;
     use crate::ptr::null;
     use crate::sync::atomic::Ordering::Relaxed;
@@ -60,7 +60,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
                     let umtx_timeout_ptr = umtx_timeout.as_ref().map_or(null(), |t| t as *const _);
                     let umtx_timeout_size = umtx_timeout.as_ref().map_or(0, |t| size_of_val(t));
                     libc::_umtx_op(
-                        futex as *const AtomicU32 as *mut _,
+                        futex as *const Atomic<u32> as *mut _,
                         libc::UMTX_OP_WAIT_UINT_PRIVATE,
                         expected as libc::c_ulong,
                         crate::ptr::without_provenance_mut(umtx_timeout_size),
@@ -71,7 +71,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
                     // absolute time rather than a relative time.
                     libc::syscall(
                         libc::SYS_futex,
-                        futex as *const AtomicU32,
+                        futex as *const Atomic<u32>,
                         libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG,
                         expected,
                         timespec.as_ref().map_or(null(), |t| t as *const libc::timespec),
@@ -99,16 +99,16 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 ///
 /// On some platforms, this always returns false.
 #[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
-    let ptr = futex as *const AtomicU32;
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
+    let ptr = futex as *const Atomic<u32>;
     let op = libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG;
     unsafe { libc::syscall(libc::SYS_futex, ptr, op, 1) > 0 }
 }
 
 /// Wakes up all threads that are waiting on `futex_wait` on this futex.
 #[cfg(any(target_os = "linux", target_os = "android"))]
-pub fn futex_wake_all(futex: &AtomicU32) {
-    let ptr = futex as *const AtomicU32;
+pub fn futex_wake_all(futex: &Atomic<u32>) {
+    let ptr = futex as *const Atomic<u32>;
     let op = libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG;
     unsafe {
         libc::syscall(libc::SYS_futex, ptr, op, i32::MAX);
@@ -117,11 +117,11 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 
 // FreeBSD doesn't tell us how many threads are woken up, so this always returns false.
 #[cfg(target_os = "freebsd")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
     use crate::ptr::null_mut;
     unsafe {
         libc::_umtx_op(
-            futex as *const AtomicU32 as *mut _,
+            futex as *const Atomic<u32> as *mut _,
             libc::UMTX_OP_WAKE_PRIVATE,
             1,
             null_mut(),
@@ -132,11 +132,11 @@ pub fn futex_wake(futex: &AtomicU32) -> bool {
 }
 
 #[cfg(target_os = "freebsd")]
-pub fn futex_wake_all(futex: &AtomicU32) {
+pub fn futex_wake_all(futex: &Atomic<u32>) {
     use crate::ptr::null_mut;
     unsafe {
         libc::_umtx_op(
-            futex as *const AtomicU32 as *mut _,
+            futex as *const Atomic<u32> as *mut _,
             libc::UMTX_OP_WAKE_PRIVATE,
             i32::MAX as libc::c_ulong,
             null_mut(),
@@ -146,7 +146,7 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 }
 
 #[cfg(target_os = "openbsd")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
     use super::time::Timespec;
     use crate::ptr::{null, null_mut};
 
@@ -157,7 +157,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 
     let r = unsafe {
         libc::futex(
-            futex as *const AtomicU32 as *mut u32,
+            futex as *const Atomic<u32> as *mut u32,
             libc::FUTEX_WAIT,
             expected as i32,
             timespec.as_ref().map_or(null(), |t| t as *const libc::timespec),
@@ -169,20 +169,25 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 }
 
 #[cfg(target_os = "openbsd")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
     use crate::ptr::{null, null_mut};
     unsafe {
-        libc::futex(futex as *const AtomicU32 as *mut u32, libc::FUTEX_WAKE, 1, null(), null_mut())
-            > 0
+        libc::futex(
+            futex as *const Atomic<u32> as *mut u32,
+            libc::FUTEX_WAKE,
+            1,
+            null(),
+            null_mut(),
+        ) > 0
     }
 }
 
 #[cfg(target_os = "openbsd")]
-pub fn futex_wake_all(futex: &AtomicU32) {
+pub fn futex_wake_all(futex: &Atomic<u32>) {
     use crate::ptr::{null, null_mut};
     unsafe {
         libc::futex(
-            futex as *const AtomicU32 as *mut u32,
+            futex as *const Atomic<u32> as *mut u32,
             libc::FUTEX_WAKE,
             i32::MAX,
             null(),
@@ -192,7 +197,7 @@ pub fn futex_wake_all(futex: &AtomicU32) {
 }
 
 #[cfg(target_os = "dragonfly")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
     // A timeout of 0 means infinite.
     // We round smaller timeouts up to 1 millisecond.
     // Overflows are rounded up to an infinite timeout.
@@ -200,7 +205,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
         timeout.and_then(|d| Some(i32::try_from(d.as_millis()).ok()?.max(1))).unwrap_or(0);
 
     let r = unsafe {
-        libc::umtx_sleep(futex as *const AtomicU32 as *const i32, expected as i32, timeout_ms)
+        libc::umtx_sleep(futex as *const Atomic<u32> as *const i32, expected as i32, timeout_ms)
     };
 
     r == 0 || super::os::errno() != libc::ETIMEDOUT
@@ -208,28 +213,28 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 
 // DragonflyBSD doesn't tell us how many threads are woken up, so this always returns false.
 #[cfg(target_os = "dragonfly")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
-    unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, 1) };
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
+    unsafe { libc::umtx_wakeup(futex as *const Atomic<u32> as *const i32, 1) };
     false
 }
 
 #[cfg(target_os = "dragonfly")]
-pub fn futex_wake_all(futex: &AtomicU32) {
-    unsafe { libc::umtx_wakeup(futex as *const AtomicU32 as *const i32, i32::MAX) };
+pub fn futex_wake_all(futex: &Atomic<u32>) {
+    unsafe { libc::umtx_wakeup(futex as *const Atomic<u32> as *const i32, i32::MAX) };
 }
 
 #[cfg(target_os = "emscripten")]
 unsafe extern "C" {
-    fn emscripten_futex_wake(addr: *const AtomicU32, count: libc::c_int) -> libc::c_int;
+    fn emscripten_futex_wake(addr: *const Atomic<u32>, count: libc::c_int) -> libc::c_int;
     fn emscripten_futex_wait(
-        addr: *const AtomicU32,
+        addr: *const Atomic<u32>,
         val: libc::c_uint,
         max_wait_ms: libc::c_double,
     ) -> libc::c_int;
 }
 
 #[cfg(target_os = "emscripten")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
     unsafe {
         emscripten_futex_wait(
             futex,
@@ -240,18 +245,18 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 }
 
 #[cfg(target_os = "emscripten")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
     unsafe { emscripten_futex_wake(futex, 1) > 0 }
 }
 
 #[cfg(target_os = "emscripten")]
-pub fn futex_wake_all(futex: &AtomicU32) {
+pub fn futex_wake_all(futex: &Atomic<u32>) {
     unsafe { emscripten_futex_wake(futex, i32::MAX) };
 }
 
 #[cfg(target_os = "fuchsia")]
 pub mod zircon {
-    pub type zx_futex_t = crate::sync::atomic::AtomicU32;
+    pub type zx_futex_t = crate::sync::atomic::Atomic<u32>;
     pub type zx_handle_t = u32;
     pub type zx_status_t = i32;
     pub type zx_time_t = i64;
@@ -282,7 +287,7 @@ pub mod zircon {
 }
 
 #[cfg(target_os = "fuchsia")]
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
     // Sleep forever if the timeout is longer than fits in a i64.
     let deadline = timeout
         .and_then(|d| {
@@ -293,19 +298,23 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
         .unwrap_or(zircon::ZX_TIME_INFINITE);
 
     unsafe {
-        zircon::zx_futex_wait(futex, AtomicU32::new(expected), zircon::ZX_HANDLE_INVALID, deadline)
-            != zircon::ZX_ERR_TIMED_OUT
+        zircon::zx_futex_wait(
+            futex,
+            core::sync::atomic::AtomicU32::new(expected),
+            zircon::ZX_HANDLE_INVALID,
+            deadline,
+        ) != zircon::ZX_ERR_TIMED_OUT
     }
 }
 
 // Fuchsia doesn't tell us how many threads are woken up, so this always returns false.
 #[cfg(target_os = "fuchsia")]
-pub fn futex_wake(futex: &AtomicU32) -> bool {
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
     unsafe { zircon::zx_futex_wake(futex, 1) };
     false
 }
 
 #[cfg(target_os = "fuchsia")]
-pub fn futex_wake_all(futex: &AtomicU32) {
+pub fn futex_wake_all(futex: &Atomic<u32>) {
     unsafe { zircon::zx_futex_wake(futex, u32::MAX) };
 }
diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/pal/unix/kernel_copy.rs
index d42a7e2a7fc..b984afa149d 100644
--- a/library/std/src/sys/pal/unix/kernel_copy.rs
+++ b/library/std/src/sys/pal/unix/kernel_copy.rs
@@ -62,7 +62,7 @@ use crate::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 use crate::os::unix::net::UnixStream;
 use crate::process::{ChildStderr, ChildStdin, ChildStdout};
 use crate::ptr;
-use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicU8, Ordering};
 use crate::sys::cvt;
 use crate::sys::fs::CachedFileMetadata;
 use crate::sys::weak::syscall;
@@ -596,7 +596,7 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
 
     // Kernel prior to 4.5 don't have copy_file_range
     // We store the availability in a global to avoid unnecessary syscalls
-    static HAS_COPY_FILE_RANGE: AtomicU8 = AtomicU8::new(NOT_PROBED);
+    static HAS_COPY_FILE_RANGE: Atomic<u8> = AtomicU8::new(NOT_PROBED);
 
     let mut have_probed = match HAS_COPY_FILE_RANGE.load(Ordering::Relaxed) {
         NOT_PROBED => false,
@@ -721,8 +721,8 @@ enum SpliceMode {
 /// performs splice or sendfile between file descriptors
 /// Does _not_ fall back to a generic copy loop.
 fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> CopyResult {
-    static HAS_SENDFILE: AtomicBool = AtomicBool::new(true);
-    static HAS_SPLICE: AtomicBool = AtomicBool::new(true);
+    static HAS_SENDFILE: Atomic<bool> = AtomicBool::new(true);
+    static HAS_SPLICE: Atomic<bool> = AtomicBool::new(true);
 
     // Android builds use feature level 14, but the libc wrapper for splice is
     // gated on feature level 21+, so we have to invoke the syscall directly.
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index a4702ae1b18..ba9e14b8009 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -204,7 +204,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     target_os = "vxworks",
     target_os = "vita",
 )))]
-static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
+static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::Atomic<bool> =
     crate::sync::atomic::AtomicBool::new(false);
 
 #[cfg(not(any(
diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index 34b3948e3f6..8bf6d833515 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -49,7 +49,7 @@ mod imp {
     use crate::cell::Cell;
     use crate::ops::Range;
     use crate::sync::OnceLock;
-    use crate::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering};
+    use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering};
     use crate::sys::pal::unix::os;
     use crate::{io, mem, ptr, thread};
 
@@ -118,9 +118,9 @@ mod imp {
         }
     }
 
-    static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
-    static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut());
-    static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false);
+    static PAGE_SIZE: Atomic<usize> = AtomicUsize::new(0);
+    static MAIN_ALTSTACK: Atomic<*mut libc::c_void> = AtomicPtr::new(ptr::null_mut());
+    static NEED_ALTSTACK: Atomic<bool> = AtomicBool::new(false);
 
     /// # Safety
     /// Must be called only once
diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs
index a034995e652..c8cf75b876c 100644
--- a/library/std/src/sys/pal/unix/weak.rs
+++ b/library/std/src/sys/pal/unix/weak.rs
@@ -24,7 +24,7 @@
 
 use crate::ffi::CStr;
 use crate::marker::PhantomData;
-use crate::sync::atomic::{self, AtomicPtr, Ordering};
+use crate::sync::atomic::{self, Atomic, AtomicPtr, Ordering};
 use crate::{mem, ptr};
 
 // We can use true weak linkage on ELF targets.
@@ -80,7 +80,7 @@ pub(crate) macro dlsym {
 }
 pub(crate) struct DlsymWeak<F> {
     name: &'static str,
-    func: AtomicPtr<libc::c_void>,
+    func: Atomic<*mut libc::c_void>,
     _marker: PhantomData<F>,
 }
 
diff --git a/library/std/src/sys/pal/wasm/atomics/futex.rs b/library/std/src/sys/pal/wasm/atomics/futex.rs
index bdad0da73f0..6676aa7e8e3 100644
--- a/library/std/src/sys/pal/wasm/atomics/futex.rs
+++ b/library/std/src/sys/pal/wasm/atomics/futex.rs
@@ -3,16 +3,16 @@ use core::arch::wasm32 as wasm;
 #[cfg(target_arch = "wasm64")]
 use core::arch::wasm64 as wasm;
 
-use crate::sync::atomic::AtomicU32;
+use crate::sync::atomic::Atomic;
 use crate::time::Duration;
 
 /// An atomic for use as a futex that is at least 32-bits but may be larger
-pub type Futex = AtomicU32;
+pub type Futex = Atomic<Primitive>;
 /// Must be the underlying type of Futex
 pub type Primitive = u32;
 
 /// An atomic for use as a futex that is at least 8-bits but may be larger.
-pub type SmallFutex = AtomicU32;
+pub type SmallFutex = Atomic<SmallPrimitive>;
 /// Must be the underlying type of SmallFutex
 pub type SmallPrimitive = u32;
 
@@ -21,11 +21,14 @@ pub type SmallPrimitive = u32;
 /// Returns directly if the futex doesn't hold the expected value.
 ///
 /// Returns false on timeout, and true in all other cases.
-pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
+pub fn futex_wait(futex: &Atomic<u32>, expected: u32, timeout: Option<Duration>) -> bool {
     let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
     unsafe {
-        wasm::memory_atomic_wait32(futex as *const AtomicU32 as *mut i32, expected as i32, timeout)
-            < 2
+        wasm::memory_atomic_wait32(
+            futex as *const Atomic<u32> as *mut i32,
+            expected as i32,
+            timeout,
+        ) < 2
     }
 }
 
@@ -33,13 +36,13 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -
 ///
 /// Returns true if this actually woke up such a thread,
 /// or false if no thread was waiting on this futex.
-pub fn futex_wake(futex: &AtomicU32) -> bool {
-    unsafe { wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, 1) > 0 }
+pub fn futex_wake(futex: &Atomic<u32>) -> bool {
+    unsafe { wasm::memory_atomic_notify(futex as *const Atomic<u32> as *mut i32, 1) > 0 }
 }
 
 /// Wakes up all threads that are waiting on `futex_wait` on this futex.
-pub fn futex_wake_all(futex: &AtomicU32) {
+pub fn futex_wake_all(futex: &Atomic<u32>) {
     unsafe {
-        wasm::memory_atomic_notify(futex as *const AtomicU32 as *mut i32, i32::MAX as u32);
+        wasm::memory_atomic_notify(futex as *const Atomic<u32> as *mut i32, i32::MAX as u32);
     }
 }
diff --git a/library/std/src/sys/pal/windows/compat.rs b/library/std/src/sys/pal/windows/compat.rs
index 2b9838437e9..14f2c8d881c 100644
--- a/library/std/src/sys/pal/windows/compat.rs
+++ b/library/std/src/sys/pal/windows/compat.rs
@@ -145,7 +145,7 @@ macro_rules! compat_fn_with_fallback {
             use super::*;
             use crate::mem;
             use crate::ffi::CStr;
-            use crate::sync::atomic::{AtomicPtr, Ordering};
+            use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
             use crate::sys::compat::Module;
 
             type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
@@ -155,7 +155,7 @@ macro_rules! compat_fn_with_fallback {
             /// When that is called it attempts to load the requested symbol.
             /// If it succeeds, `PTR` is set to the address of that symbol.
             /// If it fails, then `PTR` is set to `fallback`.
-            static PTR: AtomicPtr<c_void> = AtomicPtr::new(load as *mut _);
+            static PTR: Atomic<*mut c_void> = AtomicPtr::new(load as *mut _);
 
             unsafe extern "system" fn load($($argname: $argtype),*) -> $rettype {
                 unsafe {
@@ -212,9 +212,9 @@ macro_rules! compat_fn_optional {
                 use crate::ffi::c_void;
                 use crate::mem;
                 use crate::ptr::{self, NonNull};
-                use crate::sync::atomic::{AtomicPtr, Ordering};
+                use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
 
-                pub(in crate::sys) static PTR: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
+                pub(in crate::sys) static PTR: Atomic<*mut c_void> = AtomicPtr::new(ptr::null_mut());
 
                 type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?;
 
diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs
index aebf638239c..cfa0a6b3815 100644
--- a/library/std/src/sys/pal/windows/futex.rs
+++ b/library/std/src/sys/pal/windows/futex.rs
@@ -1,8 +1,8 @@
 use core::ffi::c_void;
 use core::ptr;
 use core::sync::atomic::{
-    AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr, AtomicU8,
-    AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
+    Atomic, AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr,
+    AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
 };
 use core::time::Duration;
 
@@ -10,12 +10,12 @@ use super::api::{self, WinError};
 use crate::sys::{c, dur2timeout};
 
 /// An atomic for use as a futex that is at least 32-bits but may be larger
-pub type Futex = AtomicU32;
+pub type Futex = Atomic<Primitive>;
 /// Must be the underlying type of Futex
 pub type Primitive = u32;
 
 /// An atomic for use as a futex that is at least 8-bits but may be larger.
-pub type SmallFutex = AtomicU8;
+pub type SmallFutex = Atomic<SmallPrimitive>;
 /// Must be the underlying type of SmallFutex
 pub type SmallPrimitive = u8;
 
@@ -47,10 +47,10 @@ unsafe_waitable_int! {
     (usize, AtomicUsize),
 }
 unsafe impl<T> Waitable for *const T {
-    type Futex = AtomicPtr<T>;
+    type Futex = Atomic<*mut T>;
 }
 unsafe impl<T> Waitable for *mut T {
-    type Futex = AtomicPtr<T>;
+    type Futex = Atomic<*mut T>;
 }
 unsafe impl<T> Futexable for AtomicPtr<T> {}
 
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 7fd62339619..00d469fbaf8 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -3,8 +3,8 @@ use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
 use crate::os::windows::prelude::*;
 use crate::path::Path;
 use crate::random::{DefaultRandomSource, Random};
-use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::Relaxed;
+use crate::sync::atomic::{Atomic, AtomicUsize};
 use crate::sys::c;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
@@ -192,7 +192,7 @@ pub fn spawn_pipe_relay(
 }
 
 fn random_number() -> usize {
-    static N: AtomicUsize = AtomicUsize::new(0);
+    static N: Atomic<usize> = AtomicUsize::new(0);
     loop {
         if N.load(Relaxed) != 0 {
             return N.fetch_add(1, Relaxed);
diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs
index d9010e39961..68126bd8d2f 100644
--- a/library/std/src/sys/pal/windows/time.rs
+++ b/library/std/src/sys/pal/windows/time.rs
@@ -164,7 +164,7 @@ fn intervals2dur(intervals: u64) -> Duration {
 
 mod perf_counter {
     use super::NANOS_PER_SEC;
-    use crate::sync::atomic::{AtomicU64, Ordering};
+    use crate::sync::atomic::{Atomic, AtomicU64, Ordering};
     use crate::sys::{c, cvt};
     use crate::sys_common::mul_div_u64;
     use crate::time::Duration;
@@ -199,7 +199,7 @@ mod perf_counter {
         // uninitialized. Storing this as a single `AtomicU64` allows us to use
         // `Relaxed` operations, as we are only interested in the effects on a
         // single memory location.
-        static FREQUENCY: AtomicU64 = AtomicU64::new(0);
+        static FREQUENCY: Atomic<u64> = AtomicU64::new(0);
 
         let cached = FREQUENCY.load(Ordering::Relaxed);
         // If a previous thread has filled in this global state, use that.
diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs
index 1b41575358f..2230dabe096 100644
--- a/library/std/src/sys/pal/xous/os.rs
+++ b/library/std/src/sys/pal/xous/os.rs
@@ -4,12 +4,12 @@ use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::os::xous::ffi::Error as XousError;
 use crate::path::{self, PathBuf};
-use crate::sync::atomic::{AtomicPtr, Ordering};
+use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
 use crate::{fmt, io};
 
 pub(crate) mod params;
 
-static PARAMS_ADDRESS: AtomicPtr<u8> = AtomicPtr::new(core::ptr::null_mut());
+static PARAMS_ADDRESS: Atomic<*mut u8> = AtomicPtr::new(core::ptr::null_mut());
 
 #[cfg(not(test))]
 #[cfg(feature = "panic_unwind")]
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 478f6583b1f..ae1c9558281 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -442,7 +442,7 @@ impl Command {
         envp: Option<&CStringArray>,
     ) -> io::Result<Option<Process>> {
         #[cfg(target_os = "linux")]
-        use core::sync::atomic::{AtomicU8, Ordering};
+        use core::sync::atomic::{Atomic, AtomicU8, Ordering};
 
         use crate::mem::MaybeUninit;
         use crate::sys::{self, cvt_nz, on_broken_pipe_flag_used};
@@ -475,7 +475,7 @@ impl Command {
                     fn pidfd_getpid(pidfd: libc::c_int) -> libc::c_int;
                 );
 
-                static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0);
+                static PIDFD_SUPPORTED: Atomic<u8> = AtomicU8::new(0);
                 const UNKNOWN: u8 = 0;
                 const SPAWN: u8 = 1;
                 // Obtaining a pidfd via the fork+exec path might work
diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs
index c0591ec0c15..18196fae28b 100644
--- a/library/std/src/sys/random/linux.rs
+++ b/library/std/src/sys/random/linux.rs
@@ -64,8 +64,8 @@ use crate::fs::File;
 use crate::io::Read;
 use crate::os::fd::AsRawFd;
 use crate::sync::OnceLock;
-use crate::sync::atomic::AtomicBool;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sync::atomic::{Atomic, AtomicBool};
 use crate::sys::pal::os::errno;
 use crate::sys::pal::weak::syscall;
 
@@ -81,9 +81,9 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) {
         ) -> libc::ssize_t;
     );
 
-    static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true);
-    static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true);
-    static URANDOM_READY: AtomicBool = AtomicBool::new(false);
+    static GETRANDOM_AVAILABLE: Atomic<bool> = AtomicBool::new(true);
+    static GRND_INSECURE_AVAILABLE: Atomic<bool> = AtomicBool::new(true);
+    static URANDOM_READY: Atomic<bool> = AtomicBool::new(false);
     static DEVICE: OnceLock<File> = OnceLock::new();
 
     if GETRANDOM_AVAILABLE.load(Relaxed) {
diff --git a/library/std/src/sys/random/vxworks.rs b/library/std/src/sys/random/vxworks.rs
index d549ccebdb2..14f02e8ecd2 100644
--- a/library/std/src/sys/random/vxworks.rs
+++ b/library/std/src/sys/random/vxworks.rs
@@ -1,7 +1,7 @@
-use crate::sync::atomic::AtomicBool;
 use crate::sync::atomic::Ordering::Relaxed;
+use crate::sync::atomic::{Atomic, AtomicBool};
 
-static RNG_INIT: AtomicBool = AtomicBool::new(false);
+static RNG_INIT: Atomic<bool> = AtomicBool::new(false);
 
 pub fn fill_bytes(mut bytes: &mut [u8]) {
     while !RNG_INIT.load(Relaxed) {
diff --git a/library/std/src/sys/sync/condvar/pthread.rs b/library/std/src/sys/sync/condvar/pthread.rs
index 5bb7431eecf..938b7071b88 100644
--- a/library/std/src/sys/sync/condvar/pthread.rs
+++ b/library/std/src/sys/sync/condvar/pthread.rs
@@ -2,15 +2,15 @@
 
 use crate::pin::Pin;
 use crate::ptr;
-use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::Relaxed;
+use crate::sync::atomic::{Atomic, AtomicUsize};
 use crate::sys::pal::sync as pal;
 use crate::sys::sync::{Mutex, OnceBox};
 use crate::time::{Duration, Instant};
 
 pub struct Condvar {
     cvar: OnceBox<pal::Condvar>,
-    mutex: AtomicUsize,
+    mutex: Atomic<usize>,
 }
 
 impl Condvar {
diff --git a/library/std/src/sys/sync/condvar/xous.rs b/library/std/src/sys/sync/condvar/xous.rs
index b9e5f47abfc..21a1587214a 100644
--- a/library/std/src/sys/sync/condvar/xous.rs
+++ b/library/std/src/sys/sync/condvar/xous.rs
@@ -1,4 +1,4 @@
-use core::sync::atomic::{AtomicUsize, Ordering};
+use core::sync::atomic::{Atomic, AtomicUsize, Ordering};
 
 use crate::os::xous::ffi::{blocking_scalar, scalar};
 use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
@@ -11,8 +11,8 @@ use crate::time::Duration;
 const NOTIFY_TRIES: usize = 3;
 
 pub struct Condvar {
-    counter: AtomicUsize,
-    timed_out: AtomicUsize,
+    counter: Atomic<usize>,
+    timed_out: Atomic<usize>,
 }
 
 unsafe impl Send for Condvar {}
diff --git a/library/std/src/sys/sync/mutex/fuchsia.rs b/library/std/src/sys/sync/mutex/fuchsia.rs
index 3e871285bea..3d388a4564a 100644
--- a/library/std/src/sys/sync/mutex/fuchsia.rs
+++ b/library/std/src/sys/sync/mutex/fuchsia.rs
@@ -37,8 +37,8 @@
 //!
 //! [mutex in Fuchsia's libsync]: https://cs.opensource.google/fuchsia/fuchsia/+/main:zircon/system/ulib/sync/mutex.c
 
-use crate::sync::atomic::AtomicU32;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sync::atomic::{Atomic, AtomicU32};
 use crate::sys::futex::zircon::{
     ZX_ERR_BAD_HANDLE, ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE,
     ZX_OK, ZX_TIME_INFINITE, zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t,
@@ -52,7 +52,7 @@ const CONTESTED_BIT: u32 = 1;
 const UNLOCKED: u32 = 0;
 
 pub struct Mutex {
-    futex: AtomicU32,
+    futex: Atomic<u32>,
 }
 
 #[inline]
diff --git a/library/std/src/sys/sync/mutex/xous.rs b/library/std/src/sys/sync/mutex/xous.rs
index c6b954c1711..d16faa5aea3 100644
--- a/library/std/src/sys/sync/mutex/xous.rs
+++ b/library/std/src/sys/sync/mutex/xous.rs
@@ -1,7 +1,7 @@
 use crate::os::xous::ffi::{blocking_scalar, do_yield};
 use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sync::atomic::{AtomicBool, AtomicUsize};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize};
 
 pub struct Mutex {
     /// The "locked" value indicates how many threads are waiting on this
@@ -14,12 +14,12 @@ pub struct Mutex {
     /// for a lock, or it is locked for long periods of time. Rather than
     /// spinning, these locks send a Message to the ticktimer server
     /// requesting that they be woken up when a lock is unlocked.
-    locked: AtomicUsize,
+    locked: Atomic<usize>,
 
     /// Whether this Mutex ever was contended, and therefore made a trip
     /// to the ticktimer server. If this was never set, then we were never
     /// on the slow path and can skip deregistering the mutex.
-    contended: AtomicBool,
+    contended: Atomic<bool>,
 }
 
 impl Mutex {
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index fde1e0ca510..6a2ab0dcf1b 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -57,7 +57,7 @@
 
 use crate::cell::Cell;
 use crate::sync::atomic::Ordering::{AcqRel, Acquire, Release};
-use crate::sync::atomic::{AtomicBool, AtomicPtr};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr};
 use crate::sync::poison::once::ExclusiveState;
 use crate::thread::{self, Thread};
 use crate::{fmt, ptr, sync as public};
@@ -65,7 +65,7 @@ use crate::{fmt, ptr, sync as public};
 type StateAndQueue = *mut ();
 
 pub struct Once {
-    state_and_queue: AtomicPtr<()>,
+    state_and_queue: Atomic<*mut ()>,
 }
 
 pub struct OnceState {
@@ -94,7 +94,7 @@ const QUEUE_MASK: usize = !STATE_MASK;
 #[repr(align(4))] // Ensure the two lower bits are free to use as state bits.
 struct Waiter {
     thread: Thread,
-    signaled: AtomicBool,
+    signaled: Atomic<bool>,
     next: Cell<*const Waiter>,
 }
 
@@ -102,7 +102,7 @@ struct Waiter {
 // Every node is a struct on the stack of a waiting thread.
 // Will wake up the waiters when it gets dropped, i.e. also on panic.
 struct WaiterQueue<'a> {
-    state_and_queue: &'a AtomicPtr<()>,
+    state_and_queue: &'a Atomic<*mut ()>,
     set_state_on_drop_to: StateAndQueue,
 }
 
@@ -232,7 +232,7 @@ impl Once {
 }
 
 fn wait(
-    state_and_queue: &AtomicPtr<()>,
+    state_and_queue: &Atomic<*mut ()>,
     mut current: StateAndQueue,
     return_on_poisoned: bool,
 ) -> StateAndQueue {
diff --git a/library/std/src/sys/sync/once_box.rs b/library/std/src/sys/sync/once_box.rs
index 6953b91999a..088f51aae78 100644
--- a/library/std/src/sys/sync/once_box.rs
+++ b/library/std/src/sys/sync/once_box.rs
@@ -8,11 +8,11 @@
 use crate::mem::replace;
 use crate::pin::Pin;
 use crate::ptr::null_mut;
-use crate::sync::atomic::AtomicPtr;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sync::atomic::{Atomic, AtomicPtr};
 
 pub(crate) struct OnceBox<T> {
-    ptr: AtomicPtr<T>,
+    ptr: Atomic<*mut T>,
 }
 
 impl<T> OnceBox<T> {
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index bd15f8ee952..62f084acfd2 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -117,11 +117,11 @@ use crate::hint::spin_loop;
 use crate::mem;
 use crate::ptr::{self, NonNull, null_mut, without_provenance_mut};
 use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
-use crate::sync::atomic::{AtomicBool, AtomicPtr};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr};
 use crate::thread::{self, Thread};
 
 /// The atomic lock state.
-type AtomicState = AtomicPtr<()>;
+type AtomicState = Atomic<State>;
 /// The inner lock state.
 type State = *mut ();
 
@@ -181,11 +181,11 @@ struct Node {
     tail: AtomicLink,
     write: bool,
     thread: OnceCell<Thread>,
-    completed: AtomicBool,
+    completed: Atomic<bool>,
 }
 
 /// An atomic node pointer with relaxed operations.
-struct AtomicLink(AtomicPtr<Node>);
+struct AtomicLink(Atomic<*mut Node>);
 
 impl AtomicLink {
     fn new(v: Option<NonNull<Node>>) -> AtomicLink {
diff --git a/library/std/src/sys/sync/thread_parking/darwin.rs b/library/std/src/sys/sync/thread_parking/darwin.rs
index a0d24a91e7c..b9bcc538c65 100644
--- a/library/std/src/sys/sync/thread_parking/darwin.rs
+++ b/library/std/src/sys/sync/thread_parking/darwin.rs
@@ -13,8 +13,8 @@
 #![allow(non_camel_case_types)]
 
 use crate::pin::Pin;
-use crate::sync::atomic::AtomicI8;
 use crate::sync::atomic::Ordering::{Acquire, Release};
+use crate::sync::atomic::{Atomic, AtomicI8};
 use crate::time::Duration;
 
 type dispatch_semaphore_t = *mut crate::ffi::c_void;
@@ -38,7 +38,7 @@ const PARKED: i8 = -1;
 
 pub struct Parker {
     semaphore: dispatch_semaphore_t,
-    state: AtomicI8,
+    state: Atomic<i8>,
 }
 
 unsafe impl Sync for Parker {}
diff --git a/library/std/src/sys/sync/thread_parking/id.rs b/library/std/src/sys/sync/thread_parking/id.rs
index 64964351837..fcc6ecca628 100644
--- a/library/std/src/sys/sync/thread_parking/id.rs
+++ b/library/std/src/sys/sync/thread_parking/id.rs
@@ -10,12 +10,12 @@
 use crate::cell::UnsafeCell;
 use crate::pin::Pin;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sync::atomic::{AtomicI8, fence};
+use crate::sync::atomic::{Atomic, AtomicI8, fence};
 use crate::sys::thread_parking::{ThreadId, current, park, park_timeout, unpark};
 use crate::time::Duration;
 
 pub struct Parker {
-    state: AtomicI8,
+    state: Atomic<i8>,
     tid: UnsafeCell<Option<ThreadId>>,
 }
 
diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs
index 19cabd7dd75..14bc793c15d 100644
--- a/library/std/src/sys/sync/thread_parking/pthread.rs
+++ b/library/std/src/sys/sync/thread_parking/pthread.rs
@@ -1,8 +1,8 @@
 //! Thread parking without `futex` using the `pthread` synchronization primitives.
 
 use crate::pin::Pin;
-use crate::sync::atomic::AtomicUsize;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
+use crate::sync::atomic::{Atomic, AtomicUsize};
 use crate::sys::pal::sync::{Condvar, Mutex};
 use crate::time::Duration;
 
@@ -11,7 +11,7 @@ const PARKED: usize = 1;
 const NOTIFIED: usize = 2;
 
 pub struct Parker {
-    state: AtomicUsize,
+    state: Atomic<usize>,
     lock: Mutex,
     cvar: Condvar,
 }
diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs
index a1a0f8427cd..96e94a8053c 100644
--- a/library/std/src/sys/sync/thread_parking/windows7.rs
+++ b/library/std/src/sys/sync/thread_parking/windows7.rs
@@ -60,13 +60,13 @@
 use core::ffi::c_void;
 
 use crate::pin::Pin;
-use crate::sync::atomic::AtomicI8;
 use crate::sync::atomic::Ordering::{Acquire, Release};
+use crate::sync::atomic::{Atomic, AtomicI8};
 use crate::sys::{c, dur2timeout};
 use crate::time::Duration;
 
 pub struct Parker {
-    state: AtomicI8,
+    state: Atomic<i8>,
 }
 
 const PARKED: i8 = -1;
@@ -186,8 +186,8 @@ impl Parker {
 mod keyed_events {
     use core::pin::Pin;
     use core::ptr;
-    use core::sync::atomic::AtomicPtr;
     use core::sync::atomic::Ordering::{Acquire, Relaxed};
+    use core::sync::atomic::{Atomic, AtomicPtr};
     use core::time::Duration;
 
     use super::{EMPTY, NOTIFIED, Parker};
@@ -244,7 +244,7 @@ mod keyed_events {
 
     fn keyed_event_handle() -> c::HANDLE {
         const INVALID: c::HANDLE = ptr::without_provenance_mut(!0);
-        static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(INVALID);
+        static HANDLE: Atomic<*mut crate::ffi::c_void> = AtomicPtr::new(INVALID);
         match HANDLE.load(Relaxed) {
             INVALID => {
                 let mut handle = c::INVALID_HANDLE_VALUE;
diff --git a/library/std/src/sys/sync/thread_parking/xous.rs b/library/std/src/sys/sync/thread_parking/xous.rs
index 28c90249dc2..0f451c0ac29 100644
--- a/library/std/src/sys/sync/thread_parking/xous.rs
+++ b/library/std/src/sys/sync/thread_parking/xous.rs
@@ -2,8 +2,8 @@ use crate::os::xous::ffi::{blocking_scalar, scalar};
 use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
 use crate::pin::Pin;
 use crate::ptr;
-use crate::sync::atomic::AtomicI8;
 use crate::sync::atomic::Ordering::{Acquire, Release};
+use crate::sync::atomic::{Atomic, AtomicI8};
 use crate::time::Duration;
 
 const NOTIFIED: i8 = 1;
@@ -11,7 +11,7 @@ const EMPTY: i8 = 0;
 const PARKED: i8 = -1;
 
 pub struct Parker {
-    state: AtomicI8,
+    state: Atomic<i8>,
 }
 
 impl Parker {
diff --git a/library/std/src/sys/thread_local/key/racy.rs b/library/std/src/sys/thread_local/key/racy.rs
index e1bc08eabb3..a12ff7ac36b 100644
--- a/library/std/src/sys/thread_local/key/racy.rs
+++ b/library/std/src/sys/thread_local/key/racy.rs
@@ -6,7 +6,7 @@
 //! should be more lightweight and avoids circular dependencies with the rest of
 //! `std`.
 
-use crate::sync::atomic::{self, AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 
 /// A type for TLS keys that are statically allocated.
 ///
@@ -14,7 +14,7 @@ use crate::sync::atomic::{self, AtomicUsize, Ordering};
 /// dependencies with the rest of `std`.
 pub struct LazyKey {
     /// Inner static TLS key (internals).
-    key: AtomicUsize,
+    key: Atomic<usize>,
     /// Destructor for the TLS value.
     dtor: Option<unsafe extern "C" fn(*mut u8)>,
 }
@@ -31,7 +31,7 @@ const KEY_SENTVAL: usize = libc::PTHREAD_KEYS_MAX + 1;
 
 impl LazyKey {
     pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> LazyKey {
-        LazyKey { key: atomic::AtomicUsize::new(KEY_SENTVAL), dtor }
+        LazyKey { key: AtomicUsize::new(KEY_SENTVAL), dtor }
     }
 
     #[inline]
diff --git a/library/std/src/sys/thread_local/key/windows.rs b/library/std/src/sys/thread_local/key/windows.rs
index f4e0f25a476..c34c7bc204f 100644
--- a/library/std/src/sys/thread_local/key/windows.rs
+++ b/library/std/src/sys/thread_local/key/windows.rs
@@ -27,7 +27,7 @@
 use crate::cell::UnsafeCell;
 use crate::ptr;
 use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
-use crate::sync::atomic::{AtomicPtr, AtomicU32};
+use crate::sync::atomic::{Atomic, AtomicPtr, AtomicU32};
 use crate::sys::c;
 use crate::sys::thread_local::guard;
 
@@ -38,9 +38,9 @@ pub struct LazyKey {
     /// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == u32::MAX
     /// is not a valid key value, this allows us to use zero as sentinel value
     /// without risking overflow.
-    key: AtomicU32,
+    key: Atomic<Key>,
     dtor: Option<Dtor>,
-    next: AtomicPtr<LazyKey>,
+    next: Atomic<*mut LazyKey>,
     /// Currently, destructors cannot be unregistered, so we cannot use racy
     /// initialization for keys. Instead, we need synchronize initialization.
     /// Use the Windows-provided `Once` since it does not require TLS.
@@ -142,7 +142,7 @@ pub unsafe fn get(key: Key) -> *mut u8 {
     unsafe { c::TlsGetValue(key).cast() }
 }
 
-static DTORS: AtomicPtr<LazyKey> = AtomicPtr::new(ptr::null_mut());
+static DTORS: Atomic<*mut LazyKey> = AtomicPtr::new(ptr::null_mut());
 
 /// Should only be called once per key, otherwise loops or breaks may occur in
 /// the linked list.
diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs
index 48dfe17ab32..a27cec5ca1a 100644
--- a/library/std/src/sys/thread_local/key/xous.rs
+++ b/library/std/src/sys/thread_local/key/xous.rs
@@ -42,7 +42,7 @@ use crate::mem::ManuallyDrop;
 use crate::os::xous::ffi::{MemoryFlags, map_memory, unmap_memory};
 use crate::ptr;
 use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sync::atomic::{AtomicPtr, AtomicUsize};
+use crate::sync::atomic::{Atomic, AtomicPtr, AtomicUsize};
 
 pub type Key = usize;
 pub type Dtor = unsafe extern "C" fn(*mut u8);
@@ -52,19 +52,19 @@ const TLS_MEMORY_SIZE: usize = 4096;
 /// TLS keys start at `1`. Index `0` is unused
 #[cfg(not(test))]
 #[unsafe(export_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key13TLS_KEY_INDEXE")]
-static TLS_KEY_INDEX: AtomicUsize = AtomicUsize::new(1);
+static TLS_KEY_INDEX: Atomic<usize> = AtomicUsize::new(1);
 
 #[cfg(not(test))]
 #[unsafe(export_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key9DTORSE")]
-static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
+static DTORS: Atomic<*mut Node> = AtomicPtr::new(ptr::null_mut());
 
 #[cfg(test)]
 unsafe extern "Rust" {
     #[link_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key13TLS_KEY_INDEXE"]
-    static TLS_KEY_INDEX: AtomicUsize;
+    static TLS_KEY_INDEX: Atomic<usize>;
 
     #[link_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key9DTORSE"]
-    static DTORS: AtomicPtr<Node>;
+    static DTORS: Atomic<*mut Node>;
 }
 
 fn tls_ptr_addr() -> *mut *mut u8 {
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 2097f1e304c..6838f15e174 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -166,7 +166,7 @@ use crate::mem::{self, ManuallyDrop, forget};
 use crate::num::NonZero;
 use crate::pin::Pin;
 use crate::sync::Arc;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
 use crate::sys::sync::Parker;
 use crate::sys::thread as imp;
 use crate::sys_common::{AsInner, IntoInner};
@@ -481,7 +481,7 @@ impl Builder {
         let Builder { name, stack_size, no_hooks } = self;
 
         let stack_size = stack_size.unwrap_or_else(|| {
-            static MIN: AtomicUsize = AtomicUsize::new(0);
+            static MIN: Atomic<usize> = AtomicUsize::new(0);
 
             match MIN.load(Ordering::Relaxed) {
                 0 => {}
@@ -1195,9 +1195,9 @@ impl ThreadId {
 
         cfg_if::cfg_if! {
             if #[cfg(target_has_atomic = "64")] {
-                use crate::sync::atomic::AtomicU64;
+                use crate::sync::atomic::{Atomic, AtomicU64};
 
-                static COUNTER: AtomicU64 = AtomicU64::new(0);
+                static COUNTER: Atomic<u64> = AtomicU64::new(0);
 
                 let mut last = COUNTER.load(Ordering::Relaxed);
                 loop {
@@ -1302,10 +1302,10 @@ pub(crate) mod main_thread {
     cfg_if::cfg_if! {
         if #[cfg(target_has_atomic = "64")] {
             use super::ThreadId;
-            use crate::sync::atomic::AtomicU64;
+            use crate::sync::atomic::{Atomic, AtomicU64};
             use crate::sync::atomic::Ordering::Relaxed;
 
-            static MAIN: AtomicU64 = AtomicU64::new(0);
+            static MAIN: Atomic<u64> = AtomicU64::new(0);
 
             pub(super) fn get() -> Option<ThreadId> {
                 ThreadId::from_u64(MAIN.load(Relaxed))
@@ -1319,10 +1319,10 @@ pub(crate) mod main_thread {
         } else {
             use super::ThreadId;
             use crate::mem::MaybeUninit;
-            use crate::sync::atomic::AtomicBool;
+            use crate::sync::atomic::{Atomic, AtomicBool};
             use crate::sync::atomic::Ordering::{Acquire, Release};
 
-            static INIT: AtomicBool = AtomicBool::new(false);
+            static INIT: Atomic<bool> = AtomicBool::new(false);
             static mut MAIN: MaybeUninit<ThreadId> = MaybeUninit::uninit();
 
             pub(super) fn get() -> Option<ThreadId> {
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
index 0033fc3a732..a4c0ca5417d 100644
--- a/library/std/src/thread/scoped.rs
+++ b/library/std/src/thread/scoped.rs
@@ -2,7 +2,7 @@ use super::{Builder, JoinInner, Result, Thread, current_or_unnamed};
 use crate::marker::PhantomData;
 use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
 use crate::sync::Arc;
-use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::sync::atomic::{Atomic, AtomicBool, AtomicUsize, Ordering};
 use crate::{fmt, io};
 
 /// A scope to spawn scoped threads in.
@@ -35,8 +35,8 @@ pub struct Scope<'scope, 'env: 'scope> {
 pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>);
 
 pub(super) struct ScopeData {
-    num_running_threads: AtomicUsize,
-    a_thread_panicked: AtomicBool,
+    num_running_threads: Atomic<usize>,
+    a_thread_panicked: Atomic<bool>,
     main_thread: Thread,
 }
 
diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs
index ef6786f4316..8840714a662 100644
--- a/library/test/src/cli.rs
+++ b/library/test/src/cli.rs
@@ -61,7 +61,7 @@ fn optgroups() -> getopts::Options {
         .optopt("", "logfile", "Write logs to the specified file (deprecated)", "PATH")
         .optflag(
             "",
-            "nocapture",
+            "no-capture",
             "don't capture stdout/stderr of each \
              task, allow printing directly",
         )
@@ -172,7 +172,7 @@ tests in the same order again. Note that --shuffle and --shuffle-seed do not
 affect whether the tests are run in parallel.
 
 All tests have their standard output and standard error captured by default.
-This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
+This can be overridden with the --no-capture flag or setting RUST_TEST_NOCAPTURE
 environment variable to a value other than "0". Logging is not captured by default.
 
 Test Attributes:
@@ -199,7 +199,10 @@ Test Attributes:
 /// otherwise creates a `TestOpts` object and returns it.
 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     // Parse matches.
-    let opts = optgroups();
+    let mut opts = optgroups();
+    // Flags hidden from `usage`
+    opts.optflag("", "nocapture", "Deprecated, use `--no-capture`");
+
     let binary = args.first().map(|c| &**c).unwrap_or("...");
     let args = args.get(1..).unwrap_or(args);
     let matches = match opts.parse(args) {
@@ -210,7 +213,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     // Check if help was requested.
     if matches.opt_present("h") {
         // Show help and do nothing more.
-        usage(binary, &opts);
+        usage(binary, &optgroups());
         return None;
     }
 
@@ -447,7 +450,7 @@ fn get_color_config(matches: &getopts::Matches) -> OptPartRes<ColorConfig> {
 }
 
 fn get_nocapture(matches: &getopts::Matches) -> OptPartRes<bool> {
-    let mut nocapture = matches.opt_present("nocapture");
+    let mut nocapture = matches.opt_present("nocapture") || matches.opt_present("no-capture");
     if !nocapture {
         nocapture = match env::var("RUST_TEST_NOCAPTURE") {
             Ok(val) => &val != "0",
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock
index dacf531e404..8b6a664ad93 100644
--- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock
+++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock
@@ -1,12 +1,12 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "r-efi"
-version = "4.5.0"
+version = "5.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
 
 [[package]]
 name = "uefi_qemu_test"
diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml
index 976245f5bdd..1a8d0d94368 100644
--- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml
+++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
 resolver = "2"
 
 [dependencies]
-r-efi = "4.1.0"
+r-efi = "5.2.0"
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 6980d8220e5..b6143af632d 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -183,6 +183,9 @@ else
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.static-libstdcpp"
   fi
 
+  # Download GCC from CI on test builders
+  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set gcc.download-ci-gcc=true"
+
   if [ "$NO_DOWNLOAD_CI_RUSTC" = "" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.download-rustc=if-unchanged"
   fi
diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md
index d2026513d2f..12de69a4c9e 100644
--- a/src/doc/rustc/src/tests/index.md
+++ b/src/doc/rustc/src/tests/index.md
@@ -81,7 +81,7 @@ behavior.
 
 > Note: When running with [`cargo test`], the libtest CLI arguments must be
 > passed after the `--` argument to differentiate between flags for Cargo and
-> those for the harness. For example: `cargo test -- --nocapture`
+> those for the harness. For example: `cargo test -- --no-capture`
 
 ### Filters
 
@@ -225,7 +225,7 @@ The following options affect the output behavior.
 Displays one character per test instead of one line per test. This is an alias
 for [`--format=terse`](#--format-format).
 
-#### `--nocapture`
+#### `--no-capture`
 
 Does not capture the stdout and stderr of the test, and allows tests to print
 to the console. Usually the output is captured, and only displayed if the test
@@ -234,11 +234,13 @@ fails.
 This may also be specified by setting the `RUST_TEST_NOCAPTURE` environment
 variable to anything but `0`.
 
+`--nocapture` is a deprecated alias for `--no-capture`.
+
 #### `--show-output`
 
 Displays the stdout and stderr of successful tests after all tests have run.
 
-Contrast this with [`--nocapture`](#--nocapture) which allows tests to print
+Contrast this with [`--no-capture`](#--no-capture) which allows tests to print
 *while they are running*, which can cause interleaved output if there are
 multiple tests running in parallel, `--show-output` ensures the output is
 contiguous, but requires waiting for all tests to finish.
@@ -247,7 +249,7 @@ contiguous, but requires waiting for all tests to finish.
 
 Control when colored terminal output is used. Valid options:
 
-* `auto`: Colorize if stdout is a tty and [`--nocapture`](#--nocapture) is not
+* `auto`: Colorize if stdout is a tty and [`--no-capture`](#--no-capture) is not
   used. This is the default.
 * `always`: Always colorize the output.
 * `never`: Never colorize the output.
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index 784d628805d..39a4f23560a 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -131,7 +131,22 @@ mod __doctest_mod {{
             .output()
             .expect(\"failed to run command\");
         if !out.status.success() {{
-            eprint!(\"{{}}\", String::from_utf8_lossy(&out.stderr));
+            if let Some(code) = out.status.code() {{
+                eprintln!(\"Test executable failed (exit status: {{code}}).\");
+            }} else {{
+                eprintln!(\"Test executable failed (terminated by signal).\");
+            }}
+            if !out.stdout.is_empty() || !out.stderr.is_empty() {{
+                eprintln!();
+            }}
+            if !out.stdout.is_empty() {{
+                eprintln!(\"stdout:\");
+                eprintln!(\"{{}}\", String::from_utf8_lossy(&out.stdout));
+            }}
+            if !out.stderr.is_empty() {{
+                eprintln!(\"stderr:\");
+                eprintln!(\"{{}}\", String::from_utf8_lossy(&out.stderr));
+            }}
             ExitCode::FAILURE
         }} else {{
             ExitCode::SUCCESS
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject d811228b14ae2707323f37346aee3f4147e247e
+Subproject 7918c7eb59614c39f1c4e27e99d557720976bdd
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index b5bbe70c48c..e0132056d6c 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -414,10 +414,13 @@ pub struct Config {
     /// ABI tests.
     pub minicore_path: Utf8PathBuf,
 
-    /// If true, run tests with the "new" executor that was written to replace
-    /// compiletest's dependency on libtest. Eventually this will become the
-    /// default, and the libtest dependency will be removed.
-    pub new_executor: bool,
+    /// If true, disable the "new" executor, and use the older libtest-based
+    /// executor to run tests instead. This is a temporary fallback, to make
+    /// manual comparative testing easier if bugs are found in the new executor.
+    ///
+    /// FIXME(Zalathar): Eventually remove this flag and remove the libtest
+    /// dependency.
+    pub no_new_executor: bool,
 }
 
 impl Config {
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 159b81cefa0..788bafaa724 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -203,7 +203,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
             "COMMAND",
         )
         .reqopt("", "minicore-path", "path to minicore aux library", "PATH")
-        .optflag("n", "new-executor", "enables the new test executor instead of using libtest")
+        .optflag("N", "no-new-executor", "disables the new test executor, and uses libtest instead")
         .optopt(
             "",
             "debugger",
@@ -449,7 +449,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
         minicore_path: opt_path(matches, "minicore-path"),
 
-        new_executor: matches.opt_present("new-executor"),
+        no_new_executor: matches.opt_present("no-new-executor"),
     }
 }
 
@@ -576,9 +576,10 @@ pub fn run_tests(config: Arc<Config>) {
     // Delegate to the executor to filter and run the big list of test structures
     // created during test discovery. When the executor decides to run a test,
     // it will return control to the rest of compiletest by calling `runtest::run`.
-    let res = if config.new_executor {
+    let res = if !config.no_new_executor {
         Ok(executor::run_tests(&config, tests))
     } else {
+        // FIXME(Zalathar): Eventually remove the libtest executor entirely.
         crate::executor::libtest::execute_tests(&config, tests)
     };
 
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 9fd33e23204..d6c69d39e17 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -444,21 +444,15 @@ impl<'a> LintExtractor<'a> {
         fs::write(&tempfile, source)
             .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
         let mut cmd = Command::new(self.rustc_path);
-        if options.contains(&"edition2024") {
-            cmd.arg("--edition=2024");
-            cmd.arg("-Zunstable-options");
-        } else if options.contains(&"edition2021") {
-            cmd.arg("--edition=2021");
-        } else if options.contains(&"edition2018") {
-            cmd.arg("--edition=2018");
-        } else if options.contains(&"edition2015") {
-            cmd.arg("--edition=2015");
-        } else if options.contains(&"edition") {
-            panic!("lint-docs: unknown edition");
-        } else {
+        let edition = options
+            .iter()
+            .filter_map(|opt| opt.strip_prefix("edition"))
+            .next()
             // defaults to latest edition
-            cmd.arg("--edition=2021");
-        }
+            .unwrap_or("2024");
+        cmd.arg(format!("--edition={edition}"));
+        // Just in case this is an unstable edition.
+        cmd.arg("-Zunstable-options");
         cmd.arg("--error-format=json");
         cmd.arg("--target").arg(self.rustc_target);
         if let Some(target_linker) = self.rustc_linker {
diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml
index f8ae91f9e6f..642d48b9952 100644
--- a/src/tools/wasm-component-ld/Cargo.toml
+++ b/src/tools/wasm-component-ld/Cargo.toml
@@ -10,4 +10,4 @@ name = "wasm-component-ld"
 path = "src/main.rs"
 
 [dependencies]
-wasm-component-ld = "0.5.12"
+wasm-component-ld = "0.5.13"
diff --git a/tests/pretty/hir-if-else.pp b/tests/pretty/hir-if-else.pp
new file mode 100644
index 00000000000..200e34ac4f5
--- /dev/null
+++ b/tests/pretty/hir-if-else.pp
@@ -0,0 +1,39 @@
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:hir-if-else.pp
+
+fn f(x: u32,
+    y:
+        u32) {
+    let mut a = 0;
+    if x > y { a = 1; } else { a = 2; }
+
+    if x < 1 {
+        a = 1;
+    } else if x < 2 {
+        a = 2;
+    } else if x < 3 { a = 3; } else if x < 4 { a = 4; } else { a = 5; }
+
+    if x < y {
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+    } else { a += 1; a += 1; a += 1; a += 1; a += 1; a += 1; }
+
+    if x < 1 {
+        if x < 2 {
+            if x < 3 {
+                a += 1;
+            } else if x < 4 { a += 1; if x < 5 { a += 1; } }
+        } else if x < 6 { a += 1; }
+    }
+}
+
+fn main() { f(3, 4); }
diff --git a/tests/pretty/hir-if-else.rs b/tests/pretty/hir-if-else.rs
new file mode 100644
index 00000000000..a1cc7504f89
--- /dev/null
+++ b/tests/pretty/hir-if-else.rs
@@ -0,0 +1,59 @@
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:hir-if-else.pp
+
+fn f(x: u32, y: u32) {
+    let mut a = 0;
+    if x > y {
+        a = 1;
+    } else {
+        a = 2;
+    }
+
+    if x < 1 {
+        a = 1;
+    } else if x < 2 {
+        a = 2;
+    } else if x < 3 {
+        a = 3;
+    } else if x < 4 {
+        a = 4;
+    } else {
+        a = 5;
+    }
+
+    if x < y {
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+    } else {
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+    }
+
+    if x < 1 {
+        if x < 2 {
+            if x < 3 {
+                a += 1;
+            } else if x < 4 {
+                a += 1;
+                if x < 5 {
+                    a += 1;
+                }
+            }
+        } else if x < 6 {
+            a += 1;
+        }
+    }
+}
+
+fn main() {
+    f(3, 4);
+}
diff --git a/tests/pretty/if-else.pp b/tests/pretty/if-else.pp
new file mode 100644
index 00000000000..d4ff02c5441
--- /dev/null
+++ b/tests/pretty/if-else.pp
@@ -0,0 +1,52 @@
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ pretty-compare-only
+//@ pretty-mode:expanded
+//@ pp-exact:if-else.pp
+
+fn f(x: u32, y: u32) {
+    let mut a = 0;
+    if x > y { a = 1; } else { a = 2; }
+
+    if x < 1 {
+        a = 1;
+    } else if x < 2 {
+        a = 2;
+    } else if x < 3 { a = 3; } else if x < 4 { a = 4; } else { a = 5; }
+
+    if x < y {
+        a += 1;
+        a += 1;
+        a += 1;
+    } else {
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+    }
+
+    if x < 1 {
+        if x < 2 {
+            if x < 3 {
+                a += 1;
+            } else if x < 4 { a += 1; if x < 5 { a += 1; } }
+        } else if x < 6 { a += 1; }
+    }
+}
+
+fn main() { f(3, 4); }
diff --git a/tests/pretty/if-else.rs b/tests/pretty/if-else.rs
new file mode 100644
index 00000000000..b4085ea5606
--- /dev/null
+++ b/tests/pretty/if-else.rs
@@ -0,0 +1,65 @@
+//@ pretty-compare-only
+//@ pretty-mode:expanded
+//@ pp-exact:if-else.pp
+
+fn f(x: u32, y: u32) {
+    let mut a = 0;
+    if x > y {
+        a = 1;
+    } else {
+        a = 2;
+    }
+
+    if x < 1 {
+        a = 1;
+    } else if x < 2 {
+        a = 2;
+    } else if x < 3 {
+        a = 3;
+    } else if x < 4 {
+        a = 4;
+    } else {
+        a = 5;
+    }
+
+    if x < y {
+        a += 1;
+        a += 1;
+        a += 1;
+    } else {
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+        a += 1;
+    }
+
+    if x < 1 {
+        if x < 2 {
+            if x < 3 {
+                a += 1;
+            } else if x < 4 {
+                a += 1;
+                if x < 5 {
+                    a += 1;
+                }
+            }
+        } else if x < 6 {
+            a += 1;
+        }
+    }
+}
+
+fn main() {
+    f(3, 4);
+}
diff --git a/tests/pretty/never-pattern.pp b/tests/pretty/never-pattern.pp
new file mode 100644
index 00000000000..923ad9b82c7
--- /dev/null
+++ b/tests/pretty/never-pattern.pp
@@ -0,0 +1,17 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ pretty-mode:expanded
+//@ pp-exact:never-pattern.pp
+//@ only-x86_64
+
+#![allow(incomplete_features)]
+#![feature(never_patterns)]
+#![feature(never_type)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+fn f(x: Result<u32, !>) { _ = match x { Ok(x) => x, Err(!) , }; }
+
+fn main() {}
diff --git a/tests/pretty/never-pattern.rs b/tests/pretty/never-pattern.rs
new file mode 100644
index 00000000000..fe170bafc66
--- /dev/null
+++ b/tests/pretty/never-pattern.rs
@@ -0,0 +1,16 @@
+//@ pretty-mode:expanded
+//@ pp-exact:never-pattern.pp
+//@ only-x86_64
+
+#![allow(incomplete_features)]
+#![feature(never_patterns)]
+#![feature(never_type)]
+
+fn f(x: Result<u32, !>) {
+    _ = match x {
+        Ok(x) => x,
+        Err(!),
+    };
+}
+
+fn main() {}
diff --git a/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout b/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout
index 8f056a5f703..273d7071237 100644
--- a/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout
+++ b/tests/rustdoc-ui/doctest/edition-2024-error-output.stdout
@@ -5,6 +5,9 @@ test $DIR/edition-2024-error-output.rs - (line 12) ... FAILED
 failures:
 
 ---- $DIR/edition-2024-error-output.rs - (line 12) stdout ----
+Test executable failed (exit status: 101).
+
+stderr:
 
 thread 'main' panicked at $TMP:6:1:
 assertion `left == right` failed
@@ -13,6 +16,7 @@ assertion `left == right` failed
 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 
+
 failures:
     $DIR/edition-2024-error-output.rs - (line 12)
 
diff --git a/tests/rustdoc-ui/doctest/stdout-and-stderr.rs b/tests/rustdoc-ui/doctest/stdout-and-stderr.rs
new file mode 100644
index 00000000000..9b0c69d8839
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/stdout-and-stderr.rs
@@ -0,0 +1,26 @@
+// This test ensures that the output is correctly generated when the
+// doctest fails. It checks when there is stderr and stdout, no stdout
+// and no stderr/stdout.
+//
+// This is a regression test for <https://github.com/rust-lang/rust/issues/140289>.
+
+//@ edition: 2024
+//@ compile-flags:--test --test-args=--test-threads=1
+//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "panicked at .+rs:" -> "panicked at $$TMP:"
+//@ failure-status: 101
+//@ rustc-env:RUST_BACKTRACE=0
+
+//! ```
+//! println!("######## from a DOC TEST ########");
+//! assert_eq!("doc", "test");
+//! ```
+//!
+//! ```
+//! assert_eq!("doc", "test");
+//! ```
+//!
+//! ```
+//! std::process::exit(1);
+//! ```
diff --git a/tests/rustdoc-ui/doctest/stdout-and-stderr.stdout b/tests/rustdoc-ui/doctest/stdout-and-stderr.stdout
new file mode 100644
index 00000000000..b2febe1344f
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/stdout-and-stderr.stdout
@@ -0,0 +1,46 @@
+
+running 3 tests
+test $DIR/stdout-and-stderr.rs - (line 15) ... FAILED
+test $DIR/stdout-and-stderr.rs - (line 20) ... FAILED
+test $DIR/stdout-and-stderr.rs - (line 24) ... FAILED
+
+failures:
+
+---- $DIR/stdout-and-stderr.rs - (line 15) stdout ----
+Test executable failed (exit status: 101).
+
+stdout:
+######## from a DOC TEST ########
+
+stderr:
+
+thread 'main' panicked at $TMP:7:1:
+assertion `left == right` failed
+  left: "doc"
+ right: "test"
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+
+---- $DIR/stdout-and-stderr.rs - (line 20) stdout ----
+Test executable failed (exit status: 101).
+
+stderr:
+
+thread 'main' panicked at $TMP:15:1:
+assertion `left == right` failed
+  left: "doc"
+ right: "test"
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+
+---- $DIR/stdout-and-stderr.rs - (line 24) stdout ----
+Test executable failed (exit status: 1).
+
+
+failures:
+    $DIR/stdout-and-stderr.rs - (line 15)
+    $DIR/stdout-and-stderr.rs - (line 20)
+    $DIR/stdout-and-stderr.rs - (line 24)
+
+test result: FAILED. 0 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs
new file mode 100644
index 00000000000..650fb10d94b
--- /dev/null
+++ b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs
@@ -0,0 +1,22 @@
+//@ edition: 2024
+
+// Regression test for <https://github.com/rust-lang/rust/issues/140292>.
+
+struct Test;
+
+impl Test {
+    async fn an_async_fn(&mut self) {
+        todo!()
+    }
+
+    pub async fn uses_takes_asyncfn(&mut self) {
+        takes_asyncfn(Box::new(async || self.an_async_fn().await));
+        //~^ ERROR expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnMut`
+    }
+}
+
+async fn takes_asyncfn(_: impl AsyncFn()) {
+    todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr
new file mode 100644
index 00000000000..e79f95c197b
--- /dev/null
+++ b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr
@@ -0,0 +1,21 @@
+error[E0525]: expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnMut`
+  --> $DIR/kind-due-to-arg-with-box-wrap.rs:13:32
+   |
+LL |         takes_asyncfn(Box::new(async || self.an_async_fn().await));
+   |         ------------- ---------^^^^^^^^--------------------------
+   |         |             |        |        |
+   |         |             |        |        closure is `AsyncFnMut` because it mutates the variable `*self` here
+   |         |             |        this closure implements `AsyncFnMut`, not `AsyncFn`
+   |         |             the requirement to implement `AsyncFn` derives from here
+   |         required by a bound introduced by this call
+   |
+   = note: required for `Box<{async closure@$DIR/kind-due-to-arg-with-box-wrap.rs:13:32: 13:40}>` to implement `AsyncFn()`
+note: required by a bound in `takes_asyncfn`
+  --> $DIR/kind-due-to-arg-with-box-wrap.rs:18:32
+   |
+LL | async fn takes_asyncfn(_: impl AsyncFn()) {
+   |                                ^^^^^^^^^ required by this bound in `takes_asyncfn`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/const-generics/defaults/concrete-const-param-type.rs b/tests/ui/const-generics/defaults/concrete-const-param-type.rs
new file mode 100644
index 00000000000..c411f81192b
--- /dev/null
+++ b/tests/ui/const-generics/defaults/concrete-const-param-type.rs
@@ -0,0 +1,13 @@
+#![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)]
+//~^ WARN the feature `generic_const_parameter_types` is incomplete
+//~| WARN the feature `unsized_const_params` is incomplete
+// Make sure that we test the const param type of default const parameters
+// if both the type of the default and the type of the parameter are concrete.
+
+use std::marker::ConstParamTy_;
+
+struct Foo<const N: u32, const M: u64 = N>; //~ ERROR the constant `N` is not of type `u64`
+struct Bar<T: ConstParamTy_, const N: T, const M: u64 = N>(T); // ok
+struct Baz<T: ConstParamTy_, const N: u32, const M: T = N>(T); // ok
+
+fn main() {}
diff --git a/tests/ui/const-generics/defaults/concrete-const-param-type.stderr b/tests/ui/const-generics/defaults/concrete-const-param-type.stderr
new file mode 100644
index 00000000000..ad077f87e5d
--- /dev/null
+++ b/tests/ui/const-generics/defaults/concrete-const-param-type.stderr
@@ -0,0 +1,25 @@
+warning: the feature `generic_const_parameter_types` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/concrete-const-param-type.rs:1:12
+   |
+LL | #![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #137626 <https://github.com/rust-lang/rust/issues/137626> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/concrete-const-param-type.rs:1:43
+   |
+LL | #![feature(generic_const_parameter_types, unsized_const_params, adt_const_params)]
+   |                                           ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
+
+error: the constant `N` is not of type `u64`
+  --> $DIR/concrete-const-param-type.rs:9:26
+   |
+LL | struct Foo<const N: u32, const M: u64 = N>;
+   |                          ^^^^^^^^^^^^^^^^ expected `u64`, found `u32`
+
+error: aborting due to 1 previous error; 2 warnings emitted
+
diff --git a/tests/ui/coroutine/dont-drop-stalled-generators.rs b/tests/ui/coroutine/dont-drop-stalled-generators.rs
new file mode 100644
index 00000000000..8e0c45a9773
--- /dev/null
+++ b/tests/ui/coroutine/dont-drop-stalled-generators.rs
@@ -0,0 +1,25 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+//@ edition: 2024
+
+// This test previously used the `is_copy_raw` query during
+// HIR typeck, dropping the list of generators from the current
+// body. This then caused a query cycle.
+
+struct W<T>(*const T);
+
+impl<T: Send> Clone for W<T> {
+    fn clone(&self) -> Self { W(self.0) }
+}
+
+impl<T: Send> Copy for W<T> {}
+
+fn main() {
+    let coro = async {};
+    let x = W(&raw const coro);
+    let c = || {
+        let x = x;
+    };
+}
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
index 9300f610f8e..33193c78334 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
@@ -18,18 +18,18 @@ fn arbitrary_consuming_method_for_demonstration_purposes() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!(*{
-                                    (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                                    __local_bind0
-                                } as usize)) {
+                                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+                                __local_bind0
+                            } as usize)) {
 
 
 
 
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem as usize\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: elem as usize\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
 }
 fn addr_of() {
@@ -40,12 +40,12 @@ fn addr_of() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!&*__local_bind0) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: &elem\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: &elem\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
 }
 fn binary() {
@@ -56,12 +56,12 @@ fn binary() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem == 1\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: elem == 1\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
     {
         #[allow(unused_imports)]
@@ -69,12 +69,12 @@ fn binary() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem >= 1\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: elem >= 1\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
     {
         #[allow(unused_imports)]
@@ -82,12 +82,12 @@ fn binary() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem > 0\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: elem > 0\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
     {
         #[allow(unused_imports)]
@@ -95,12 +95,12 @@ fn binary() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem < 3\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: elem < 3\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
     {
         #[allow(unused_imports)]
@@ -108,12 +108,12 @@ fn binary() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem <= 3\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: elem <= 3\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
     {
         #[allow(unused_imports)]
@@ -121,12 +121,12 @@ fn binary() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem != 3\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: elem != 3\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
 }
 fn unary() {
@@ -137,12 +137,12 @@ fn unary() {
         let mut __capture0 = ::core::asserting::Capture::new();
         let __local_bind0 = &elem;
         if ::core::intrinsics::unlikely(!**__local_bind0) {
-                (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
-                {
-                    ::std::rt::panic_fmt(format_args!("Assertion failed: *elem\nWith captures:\n  elem = {0:?}\n",
-                            __capture0));
-                }
+            (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
+            {
+                ::std::rt::panic_fmt(format_args!("Assertion failed: *elem\nWith captures:\n  elem = {0:?}\n",
+                        __capture0));
             }
+        }
     };
 }
 fn main() {}
diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout
index 8b7edabf004..a0d83d962e7 100644
--- a/tests/ui/match/issue-82392.stdout
+++ b/tests/ui/match/issue-82392.stdout
@@ -8,10 +8,10 @@ extern crate std;
 //@ edition:2015
 
 fn main() ({
-    (if (true as bool)
-            ({ } as
-                ()) else if (let Some(a) =
-                   ((Some as
-                           fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
-                       Option<i32>) as bool) ({ } as ()) as ())
-           } as ())
+    (if (true as bool) {
+    } else if (let Some(a) =
+            ((Some as
+                    fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
+                Option<i32>) as bool) {
+    } as ())
+} as ())
diff --git a/tests/ui/parser/or-in-let-chain.edition2021.stderr b/tests/ui/parser/or-in-let-chain.edition2021.stderr
new file mode 100644
index 00000000000..a97095cc3b8
--- /dev/null
+++ b/tests/ui/parser/or-in-let-chain.edition2021.stderr
@@ -0,0 +1,28 @@
+error: `||` operators are not supported in let chain conditions
+  --> $DIR/or-in-let-chain.rs:6:24
+   |
+LL |     if let true = true || false {}
+   |                        ^^
+
+error: expected expression, found `let` statement
+  --> $DIR/or-in-let-chain.rs:9:9
+   |
+LL |     if (let true = true) || false {}
+   |         ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: `||` operators are not supported in let chain conditions
+  --> $DIR/or-in-let-chain.rs:12:24
+   |
+LL |     if let true = true || false || true {}
+   |                        ^^
+
+error: `||` operators are not supported in let chain conditions
+  --> $DIR/or-in-let-chain.rs:15:33
+   |
+LL |     if let true = true && false || true {}
+   |                                 ^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/parser/or-in-let-chain.edition2024.stderr b/tests/ui/parser/or-in-let-chain.edition2024.stderr
new file mode 100644
index 00000000000..a97095cc3b8
--- /dev/null
+++ b/tests/ui/parser/or-in-let-chain.edition2024.stderr
@@ -0,0 +1,28 @@
+error: `||` operators are not supported in let chain conditions
+  --> $DIR/or-in-let-chain.rs:6:24
+   |
+LL |     if let true = true || false {}
+   |                        ^^
+
+error: expected expression, found `let` statement
+  --> $DIR/or-in-let-chain.rs:9:9
+   |
+LL |     if (let true = true) || false {}
+   |         ^^^^^^^^^^^^^^^
+   |
+   = note: only supported directly in conditions of `if` and `while` expressions
+
+error: `||` operators are not supported in let chain conditions
+  --> $DIR/or-in-let-chain.rs:12:24
+   |
+LL |     if let true = true || false || true {}
+   |                        ^^
+
+error: `||` operators are not supported in let chain conditions
+  --> $DIR/or-in-let-chain.rs:15:33
+   |
+LL |     if let true = true && false || true {}
+   |                                 ^^
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/parser/or-in-let-chain.rs b/tests/ui/parser/or-in-let-chain.rs
new file mode 100644
index 00000000000..4c4372bb00f
--- /dev/null
+++ b/tests/ui/parser/or-in-let-chain.rs
@@ -0,0 +1,17 @@
+//@ revisions: edition2021 edition2024
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+
+fn main() {
+    if let true = true || false {}
+    //~^ ERROR `||` operators are not supported in let chain conditions
+    // With parentheses
+    if (let true = true) || false {}
+    //~^ ERROR expected expression, found `let` statement
+    // Multiple || operators
+    if let true = true || false || true {}
+    //~^ ERROR `||` operators are not supported in let chain conditions
+    // Mixed operators (should still show error for ||)
+    if let true = true && false || true {}
+    //~^ ERROR `||` operators are not supported in let chain conditions
+}
diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout
index 6ebb3a37951..3acb472d9c0 100644
--- a/tests/ui/proc-macro/quote/debug.stdout
+++ b/tests/ui/proc-macro/quote/debug.stdout
@@ -32,12 +32,12 @@ fn main() {
                         let mut iter =
                             "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
                         if let (Some(crate::TokenTree::Literal(mut lit)), None) =
-                                    (iter.next(), iter.next()) {
-                                lit.set_span(crate::Span::recover_proc_macro_span(2));
-                                lit
-                            } else {
-                               ::core::panicking::panic("internal error: entered unreachable code")
-                           }
+                                (iter.next(), iter.next()) {
+                            lit.set_span(crate::Span::recover_proc_macro_span(2));
+                            lit
+                        } else {
+                            ::core::panicking::panic("internal error: entered unreachable code")
+                        }
                     }), &mut ts);
         crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';',
                         crate::Spacing::Alone)), &mut ts);
@@ -51,12 +51,12 @@ fn main() {
                         let mut iter =
                             "r#\"raw\"literal\"#".parse::<crate::TokenStream>().unwrap().into_iter();
                         if let (Some(crate::TokenTree::Literal(mut lit)), None) =
-                                    (iter.next(), iter.next()) {
-                                lit.set_span(crate::Span::recover_proc_macro_span(5));
-                                lit
-                            } else {
-                               ::core::panicking::panic("internal error: entered unreachable code")
-                           }
+                                (iter.next(), iter.next()) {
+                            lit.set_span(crate::Span::recover_proc_macro_span(5));
+                            lit
+                        } else {
+                            ::core::panicking::panic("internal error: entered unreachable code")
+                        }
                     }), &mut ts);
         crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(';',
                         crate::Spacing::Alone)), &mut ts);
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
index ae13f7c76ba..ed461af66aa 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
@@ -3,7 +3,7 @@
 fn let_or_guard(x: Result<Option<i32>, ()>) {
     match x {
         Ok(opt) if let Some(4) = opt || false  => {}
-        //~^ ERROR expected expression, found `let` statement
+        //~^ ERROR `||` operators are not supported in let chain conditions
         _ => {}
     }
 }
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr
index 4b85fdd5050..0566d96fddc 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.stderr
@@ -1,11 +1,4 @@
-error: expected expression, found `let` statement
-  --> $DIR/ast-validate-guards.rs:5:20
-   |
-LL |         Ok(opt) if let Some(4) = opt || false  => {}
-   |                    ^^^^^^^^^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-note: `||` operators are not supported in let chain expressions
+error: `||` operators are not supported in let chain conditions
   --> $DIR/ast-validate-guards.rs:5:38
    |
 LL |         Ok(opt) if let Some(4) = opt || false  => {}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr
index 817e226bc45..141a6d255d0 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.feature.stderr
@@ -272,14 +272,7 @@ LL |     if (let 0 = 0)? {}
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:121:16
-   |
-LL |     if true || let 0 = 0 {}
-   |                ^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-note: `||` operators are not supported in let chain expressions
+error: `||` operators are not supported in let chain conditions
   --> $DIR/disallowed-positions.rs:121:13
    |
 LL |     if true || let 0 = 0 {}
@@ -485,14 +478,7 @@ LL |     while (let 0 = 0)? {}
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:212:19
-   |
-LL |     while true || let 0 = 0 {}
-   |                   ^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-note: `||` operators are not supported in let chain expressions
+error: `||` operators are not supported in let chain conditions
   --> $DIR/disallowed-positions.rs:212:16
    |
 LL |     while true || let 0 = 0 {}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr
index bab50c22c03..dda09de4c53 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.no_feature.stderr
@@ -272,14 +272,7 @@ LL |     if (let 0 = 0)? {}
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:121:16
-   |
-LL |     if true || let 0 = 0 {}
-   |                ^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-note: `||` operators are not supported in let chain expressions
+error: `||` operators are not supported in let chain conditions
   --> $DIR/disallowed-positions.rs:121:13
    |
 LL |     if true || let 0 = 0 {}
@@ -485,14 +478,7 @@ LL |     while (let 0 = 0)? {}
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:212:19
-   |
-LL |     while true || let 0 = 0 {}
-   |                   ^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-note: `||` operators are not supported in let chain expressions
+error: `||` operators are not supported in let chain conditions
   --> $DIR/disallowed-positions.rs:212:16
    |
 LL |     while true || let 0 = 0 {}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
index 943956feb4e..5b53691cbf5 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.nothing.stderr
@@ -272,14 +272,7 @@ LL |     if (let 0 = 0)? {}
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:121:16
-   |
-LL |     if true || let 0 = 0 {}
-   |                ^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-note: `||` operators are not supported in let chain expressions
+error: `||` operators are not supported in let chain conditions
   --> $DIR/disallowed-positions.rs:121:13
    |
 LL |     if true || let 0 = 0 {}
@@ -485,14 +478,7 @@ LL |     while (let 0 = 0)? {}
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:212:19
-   |
-LL |     while true || let 0 = 0 {}
-   |                   ^^^^^^^^^
-   |
-   = note: only supported directly in conditions of `if` and `while` expressions
-note: `||` operators are not supported in let chain expressions
+error: `||` operators are not supported in let chain conditions
   --> $DIR/disallowed-positions.rs:212:16
    |
 LL |     while true || let 0 = 0 {}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
index 0b0abe6ec17..65beccf2214 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -119,7 +119,7 @@ fn nested_within_if_expr() {
     //~^ ERROR expected expression, found `let` statement
 
     if true || let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
+    //~^ ERROR `||` operators are not supported in let chain conditions
     if (true || let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
     if true && (true || let 0 = 0) {}
@@ -210,7 +210,7 @@ fn nested_within_while_expr() {
     //~^ ERROR expected expression, found `let` statement
 
     while true || let 0 = 0 {}
-    //~^ ERROR expected expression, found `let` statement
+    //~^ ERROR `||` operators are not supported in let chain conditions
     while (true || let 0 = 0) {}
     //~^ ERROR expected expression, found `let` statement
     while true && (true || let 0 = 0) {}
diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr b/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr
new file mode 100644
index 00000000000..7e3df0c83f9
--- /dev/null
+++ b/tests/ui/specialization/prefer-specializing-impl-over-default.current.stderr
@@ -0,0 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/prefer-specializing-impl-over-default.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr b/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr
new file mode 100644
index 00000000000..7e3df0c83f9
--- /dev/null
+++ b/tests/ui/specialization/prefer-specializing-impl-over-default.next.stderr
@@ -0,0 +1,12 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/prefer-specializing-impl-over-default.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/specialization/prefer-specializing-impl-over-default.rs b/tests/ui/specialization/prefer-specializing-impl-over-default.rs
new file mode 100644
index 00000000000..af6837b30ca
--- /dev/null
+++ b/tests/ui/specialization/prefer-specializing-impl-over-default.rs
@@ -0,0 +1,29 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+#![feature(specialization)]
+//~^ WARN the feature `specialization` is incomplete
+
+trait WithAssoc: 'static {
+    type Assoc;
+}
+impl<T: 'static> WithAssoc for (T,) {
+    type Assoc = ();
+}
+
+struct GenericArray<U: WithAssoc>(U::Assoc);
+
+trait AbiExample {
+    fn example();
+}
+impl<U: WithAssoc> AbiExample for GenericArray<U> {
+    fn example() {}
+}
+impl<T> AbiExample for T {
+    default fn example() {}
+}
+
+fn main() {
+    let _ = GenericArray::<((),)>::example();
+}
diff --git a/tests/ui/specialization/specialization-default-projection.stderr b/tests/ui/specialization/specialization-default-projection.current.stderr
index b8b81876d81..038c379c43e 100644
--- a/tests/ui/specialization/specialization-default-projection.stderr
+++ b/tests/ui/specialization/specialization-default-projection.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/specialization-default-projection.rs:1:12
+  --> $DIR/specialization-default-projection.rs:5:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | #![feature(specialization)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0308]: mismatched types
-  --> $DIR/specialization-default-projection.rs:21:5
+  --> $DIR/specialization-default-projection.rs:25:5
    |
 LL | fn generic<T>() -> <T as Foo>::Assoc {
    |                    ----------------- expected `<T as Foo>::Assoc` because of return type
@@ -23,7 +23,7 @@ LL |     ()
    = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error[E0308]: mismatched types
-  --> $DIR/specialization-default-projection.rs:28:5
+  --> $DIR/specialization-default-projection.rs:32:5
    |
 LL | fn monomorphic() -> () {
    |                     -- expected `()` because of return type
diff --git a/tests/ui/specialization/specialization-default-projection.next.stderr b/tests/ui/specialization/specialization-default-projection.next.stderr
new file mode 100644
index 00000000000..9111f173a9c
--- /dev/null
+++ b/tests/ui/specialization/specialization-default-projection.next.stderr
@@ -0,0 +1,43 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-default-projection.rs:5:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/specialization-default-projection.rs:25:5
+   |
+LL | fn generic<T>() -> <T as Foo>::Assoc {
+   |                    ----------------- expected `<T as Foo>::Assoc` because of return type
+...
+LL |     ()
+   |     ^^ types differ
+   |
+   = note: expected associated type `<T as Foo>::Assoc`
+                    found unit type `()`
+   = help: consider constraining the associated type `<T as Foo>::Assoc` to `()` or calling a method that returns `<T as Foo>::Assoc`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error[E0308]: mismatched types
+  --> $DIR/specialization-default-projection.rs:32:5
+   |
+LL | fn monomorphic() -> () {
+   |                     -- expected `()` because of return type
+...
+LL |     generic::<()>()
+   |     ^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
+   |     |
+   |     types differ
+   |
+   = note:    expected unit type `()`
+           found associated type `<() as Foo>::Assoc`
+   = help: consider constraining the associated type `<() as Foo>::Assoc` to `()`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/specialization/specialization-default-projection.rs b/tests/ui/specialization/specialization-default-projection.rs
index 7f3ae951287..4f69ccb5974 100644
--- a/tests/ui/specialization/specialization-default-projection.rs
+++ b/tests/ui/specialization/specialization-default-projection.rs
@@ -1,3 +1,7 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 #![feature(specialization)] //~ WARN the feature `specialization` is incomplete
 
 // Make sure we can't project defaulted associated types
diff --git a/tests/ui/specialization/specialization-default-types.stderr b/tests/ui/specialization/specialization-default-types.current.stderr
index 774ac953617..67477f9a6d5 100644
--- a/tests/ui/specialization/specialization-default-types.stderr
+++ b/tests/ui/specialization/specialization-default-types.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/specialization-default-types.rs:5:12
+  --> $DIR/specialization-default-types.rs:9:12
    |
 LL | #![feature(specialization)]
    |            ^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | #![feature(specialization)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0308]: mismatched types
-  --> $DIR/specialization-default-types.rs:15:9
+  --> $DIR/specialization-default-types.rs:19:9
    |
 LL |     default type Output = Box<T>;
    |     ----------------------------- associated type is `default` and may be overridden
@@ -22,7 +22,7 @@ LL |         Box::new(self)
                        found struct `Box<T>`
 
 error[E0308]: mismatched types
-  --> $DIR/specialization-default-types.rs:25:5
+  --> $DIR/specialization-default-types.rs:29:5
    |
 LL | fn trouble<T>(t: T) -> Box<T> {
    |                        ------ expected `Box<T>` because of return type
diff --git a/tests/ui/specialization/specialization-default-types.next.stderr b/tests/ui/specialization/specialization-default-types.next.stderr
new file mode 100644
index 00000000000..4f7c4765446
--- /dev/null
+++ b/tests/ui/specialization/specialization-default-types.next.stderr
@@ -0,0 +1,39 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/specialization-default-types.rs:9:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/specialization-default-types.rs:19:9
+   |
+LL |     default type Output = Box<T>;
+   |     ----------------------------- associated type is `default` and may be overridden
+LL |     default fn generate(self) -> Self::Output {
+   |                                  ------------ expected `<T as Example>::Output` because of return type
+LL |         Box::new(self)
+   |         ^^^^^^^^^^^^^^ types differ
+   |
+   = note: expected associated type `<T as Example>::Output`
+                       found struct `Box<T>`
+
+error[E0308]: mismatched types
+  --> $DIR/specialization-default-types.rs:29:5
+   |
+LL | fn trouble<T>(t: T) -> Box<T> {
+   |                        ------ expected `Box<T>` because of return type
+LL |     Example::generate(t)
+   |     ^^^^^^^^^^^^^^^^^^^^ types differ
+   |
+   = note:       expected struct `Box<T>`
+           found associated type `<T as Example>::Output`
+   = help: consider constraining the associated type `<T as Example>::Output` to `Box<T>`
+   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/specialization/specialization-default-types.rs b/tests/ui/specialization/specialization-default-types.rs
index 346471f11e4..77817abea12 100644
--- a/tests/ui/specialization/specialization-default-types.rs
+++ b/tests/ui/specialization/specialization-default-types.rs
@@ -1,3 +1,7 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 // It should not be possible to use the concrete value of a defaulted
 // associated type in the impl defining it -- otherwise, what happens
 // if it's overridden?
diff --git a/tests/ui/traits/next-solver/coerce-depth.rs b/tests/ui/traits/next-solver/coerce-depth.rs
new file mode 100644
index 00000000000..c8fc3fcab59
--- /dev/null
+++ b/tests/ui/traits/next-solver/coerce-depth.rs
@@ -0,0 +1,31 @@
+//@ check-pass
+//@ compile-flags: -Znext-solver
+
+// Ensure that a stack of coerce predicates doesn't end up overflowing when they get procesed
+// in *reverse* order, which may require O(N) iterations of the fulfillment loop.
+
+#![recursion_limit = "16"]
+
+fn main() {
+    match 0 {
+        0 => None,
+        1 => None,
+        2 => None,
+        3 => None,
+        4 => None,
+        5 => None,
+        6 => None,
+        7 => None,
+        8 => None,
+        9 => None,
+        10 => None,
+        11 => None,
+        12 => None,
+        13 => None,
+        14 => None,
+        15 => None,
+        16 => None,
+        17 => None,
+        _ => Some(1u32),
+    };
+}
diff --git a/tests/ui/traits/next-solver/specialization-transmute.rs b/tests/ui/traits/next-solver/specialization-transmute.rs
index 376fa22ae19..f1447cd6a9e 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.rs
+++ b/tests/ui/traits/next-solver/specialization-transmute.rs
@@ -10,11 +10,8 @@ trait Default {
 
 impl<T> Default for T {
     default type Id = T;
-    // This will be fixed by #111994
     fn intu(&self) -> &Self::Id {
-        //~^ ERROR type annotations needed
-        //~| ERROR cannot normalize `<T as Default>::Id: '_`
-        self //~ ERROR cannot satisfy
+        self //~ ERROR mismatched types
     }
 }
 
@@ -25,6 +22,7 @@ fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
 use std::num::NonZero;
 
 fn main() {
-    let s = transmute::<u8, Option<NonZero<u8>>>(0); //~ ERROR cannot satisfy
+    let s = transmute::<u8, Option<NonZero<u8>>>(0);
+    //~^ ERROR type mismatch resolving `<u8 as Default>::Id == Option<NonZero<u8>>`
     assert_eq!(s, None);
 }
diff --git a/tests/ui/traits/next-solver/specialization-transmute.stderr b/tests/ui/traits/next-solver/specialization-transmute.stderr
index eeb101911c4..8bd290ea197 100644
--- a/tests/ui/traits/next-solver/specialization-transmute.stderr
+++ b/tests/ui/traits/next-solver/specialization-transmute.stderr
@@ -8,37 +8,32 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error: cannot normalize `<T as Default>::Id: '_`
-  --> $DIR/specialization-transmute.rs:14:5
+error[E0308]: mismatched types
+  --> $DIR/specialization-transmute.rs:14:9
    |
 LL |     fn intu(&self) -> &Self::Id {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0282]: type annotations needed
-  --> $DIR/specialization-transmute.rs:14:23
-   |
-LL |     fn intu(&self) -> &Self::Id {
-   |                       ^^^^^^^^^ cannot infer type for reference `&<T as Default>::Id`
-
-error[E0284]: type annotations needed: cannot satisfy `<T as Default>::Id normalizes-to T`
-  --> $DIR/specialization-transmute.rs:17:9
-   |
+   |                       --------- expected `&<T as Default>::Id` because of return type
 LL |         self
-   |         ^^^^ cannot satisfy `<T as Default>::Id normalizes-to T`
+   |         ^^^^ types differ
+   |
+   = note: expected reference `&<T as Default>::Id`
+              found reference `&T`
 
-error[E0284]: type annotations needed: cannot satisfy `<u8 as Default>::Id normalizes-to Option<NonZero<u8>>`
-  --> $DIR/specialization-transmute.rs:28:13
+error[E0271]: type mismatch resolving `<u8 as Default>::Id == Option<NonZero<u8>>`
+  --> $DIR/specialization-transmute.rs:25:50
    |
 LL |     let s = transmute::<u8, Option<NonZero<u8>>>(0);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `<u8 as Default>::Id normalizes-to Option<NonZero<u8>>`
+   |             ------------------------------------ ^ types differ
+   |             |
+   |             required by a bound introduced by this call
    |
 note: required by a bound in `transmute`
-  --> $DIR/specialization-transmute.rs:21:25
+  --> $DIR/specialization-transmute.rs:18:25
    |
 LL | fn transmute<T: Default<Id = U>, U: Copy>(t: T) -> U {
    |                         ^^^^^^ required by this bound in `transmute`
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0282, E0284.
-For more information about an error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0271, E0308.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.rs b/tests/ui/traits/next-solver/specialization-unconstrained.rs
index 2bbe7840110..6835c0764d6 100644
--- a/tests/ui/traits/next-solver/specialization-unconstrained.rs
+++ b/tests/ui/traits/next-solver/specialization-unconstrained.rs
@@ -18,5 +18,5 @@ fn test<T: Default<Id = U>, U>() {}
 
 fn main() {
     test::<u32, ()>();
-    //~^ ERROR cannot satisfy `<u32 as Default>::Id normalizes-to ()`
+    //~^ ERROR type mismatch resolving `<u32 as Default>::Id == ()`
 }
diff --git a/tests/ui/traits/next-solver/specialization-unconstrained.stderr b/tests/ui/traits/next-solver/specialization-unconstrained.stderr
index e1d785b554b..1bcf5eddb5b 100644
--- a/tests/ui/traits/next-solver/specialization-unconstrained.stderr
+++ b/tests/ui/traits/next-solver/specialization-unconstrained.stderr
@@ -8,11 +8,11 @@ LL | #![feature(specialization)]
    = help: consider using `min_specialization` instead, which is more stable and complete
    = note: `#[warn(incomplete_features)]` on by default
 
-error[E0284]: type annotations needed: cannot satisfy `<u32 as Default>::Id normalizes-to ()`
-  --> $DIR/specialization-unconstrained.rs:20:5
+error[E0271]: type mismatch resolving `<u32 as Default>::Id == ()`
+  --> $DIR/specialization-unconstrained.rs:20:12
    |
 LL |     test::<u32, ()>();
-   |     ^^^^^^^^^^^^^^^^^ cannot satisfy `<u32 as Default>::Id normalizes-to ()`
+   |            ^^^ types differ
    |
 note: required by a bound in `test`
   --> $DIR/specialization-unconstrained.rs:17:20
@@ -22,4 +22,4 @@ LL | fn test<T: Default<Id = U>, U>() {}
 
 error: aborting due to 1 previous error; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/transmutability/char.rs b/tests/ui/transmutability/char.rs
new file mode 100644
index 00000000000..55a61537329
--- /dev/null
+++ b/tests/ui/transmutability/char.rs
@@ -0,0 +1,41 @@
+#![feature(never_type)]
+#![feature(transmutability)]
+
+use std::mem::{Assume, TransmuteFrom};
+
+pub fn is_transmutable<Src, Dst>()
+where
+    Dst: TransmuteFrom<Src, { Assume::SAFETY }>,
+{
+}
+
+fn main() {
+    is_transmutable::<char, u32>();
+
+    // `char`s can be in the following ranges:
+    // - [0, 0xD7FF]
+    // - [0xE000, 10FFFF]
+    //
+    // `Char` has variants whose tags are in the top and bottom of each range.
+    // It also has generic variants which are out of bounds of these ranges, but
+    // are generic on types which may be set to `!` to "disable" them in the
+    // transmutability analysis.
+    #[repr(u32)]
+    enum Char<B, C, D> {
+        A = 0,
+        B = 0xD7FF,
+        OverB(B) = 0xD800,
+        UnderC(C) = 0xDFFF,
+        C = 0xE000,
+        D = 0x10FFFF,
+        OverD(D) = 0x110000,
+    }
+
+    is_transmutable::<Char<!, !, !>, char>();
+    is_transmutable::<Char<(), !, !>, char>();
+    //~^ ERROR cannot be safely transmuted into `char`
+    is_transmutable::<Char<!, (), !>, char>();
+    //~^ ERROR cannot be safely transmuted into `char`
+    is_transmutable::<Char<!, !, ()>, char>();
+    //~^ ERROR cannot be safely transmuted into `char`
+}
diff --git a/tests/ui/transmutability/char.stderr b/tests/ui/transmutability/char.stderr
new file mode 100644
index 00000000000..98e7ae9c0d4
--- /dev/null
+++ b/tests/ui/transmutability/char.stderr
@@ -0,0 +1,48 @@
+error[E0277]: `main::Char<(), !, !>` cannot be safely transmuted into `char`
+  --> $DIR/char.rs:35:39
+   |
+LL |     is_transmutable::<Char<(), !, !>, char>();
+   |                                       ^^^^ at least one value of `main::Char<(), !, !>` isn't a bit-valid value of `char`
+   |
+note: required by a bound in `is_transmutable`
+  --> $DIR/char.rs:8:10
+   |
+LL | pub fn is_transmutable<Src, Dst>()
+   |        --------------- required by a bound in this function
+LL | where
+LL |     Dst: TransmuteFrom<Src, { Assume::SAFETY }>,
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `main::Char<!, (), !>` cannot be safely transmuted into `char`
+  --> $DIR/char.rs:37:39
+   |
+LL |     is_transmutable::<Char<!, (), !>, char>();
+   |                                       ^^^^ at least one value of `main::Char<!, (), !>` isn't a bit-valid value of `char`
+   |
+note: required by a bound in `is_transmutable`
+  --> $DIR/char.rs:8:10
+   |
+LL | pub fn is_transmutable<Src, Dst>()
+   |        --------------- required by a bound in this function
+LL | where
+LL |     Dst: TransmuteFrom<Src, { Assume::SAFETY }>,
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `main::Char<!, !, ()>` cannot be safely transmuted into `char`
+  --> $DIR/char.rs:39:39
+   |
+LL |     is_transmutable::<Char<!, !, ()>, char>();
+   |                                       ^^^^ at least one value of `main::Char<!, !, ()>` isn't a bit-valid value of `char`
+   |
+note: required by a bound in `is_transmutable`
+  --> $DIR/char.rs:8:10
+   |
+LL | pub fn is_transmutable<Src, Dst>()
+   |        --------------- required by a bound in this function
+LL | where
+LL |     Dst: TransmuteFrom<Src, { Assume::SAFETY }>,
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.