about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock72
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs18
-rw-r--r--compiler/rustc_hir/src/def.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/ty/context.rs6
-rw-r--r--compiler/rustc_middle/src/ty/util.rs5
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs137
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs80
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs8
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs7
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs3
-rw-r--r--compiler/rustc_type_ir/src/interner.rs1
-rw-r--r--library/core/src/any.rs3
-rw-r--r--library/core/src/array/equality.rs46
-rw-r--r--library/core/src/ascii/ascii_char.rs3
-rw-r--r--library/core/src/cmp.rs162
-rw-r--r--library/core/src/convert/mod.rs9
-rw-r--r--library/core/src/num/nonzero.rs17
-rw-r--r--library/core/src/ops/control_flow.rs3
-rw-r--r--library/core/src/option.rs9
-rw-r--r--library/core/src/range.rs6
-rw-r--r--library/core/src/result.rs3
-rw-r--r--library/core/src/slice/cmp.rs43
-rw-r--r--library/core/src/str/traits.rs3
-rw-r--r--library/core/src/tuple.rs12
-rw-r--r--library/coretests/tests/cmp.rs6
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/mod.rs1
-rw-r--r--library/std/src/sys/net/connection/socket/hermit.rs3
-rw-r--r--library/std/src/sys/pal/hermit/mod.rs1
-rw-r--r--library/std/src/sys/pal/hermit/os.rs2
-rw-r--r--library/std/src/sys/pal/sgx/abi/mod.rs2
-rw-r--r--library/std/src/sys/pal/sgx/mod.rs1
-rw-r--r--library/std/src/sys/pal/solid/mod.rs4
-rw-r--r--library/std/src/sys/pal/teeos/mod.rs1
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs1
-rw-r--r--library/std/src/sys/pal/uefi/thread.rs66
-rw-r--r--library/std/src/sys/pal/unix/mod.rs3
-rw-r--r--library/std/src/sys/pal/unix/weak.rs130
-rw-r--r--library/std/src/sys/pal/unix/weak/tests.rs32
-rw-r--r--library/std/src/sys/pal/wasip1/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasip1/thread.rs214
-rw-r--r--library/std/src/sys/pal/wasip2/mod.rs1
-rw-r--r--library/std/src/sys/pal/wasip2/thread.rs73
-rw-r--r--library/std/src/sys/pal/wasip2/time.rs2
-rw-r--r--library/std/src/sys/pal/wasm/atomics/thread.rs75
-rw-r--r--library/std/src/sys/pal/wasm/mod.rs15
-rw-r--r--library/std/src/sys/pal/windows/mod.rs5
-rw-r--r--library/std/src/sys/pal/windows/time.rs2
-rw-r--r--library/std/src/sys/pal/xous/mod.rs1
-rw-r--r--library/std/src/sys/sync/once/queue.rs4
-rw-r--r--library/std/src/sys/thread/hermit.rs (renamed from library/std/src/sys/pal/hermit/thread.rs)66
-rw-r--r--library/std/src/sys/thread/mod.rs152
-rw-r--r--library/std/src/sys/thread/sgx.rs (renamed from library/std/src/sys/pal/sgx/thread.rs)49
-rw-r--r--library/std/src/sys/thread/solid.rs (renamed from library/std/src/sys/pal/itron/thread.rs)42
-rw-r--r--library/std/src/sys/thread/teeos.rs (renamed from library/std/src/sys/pal/teeos/thread.rs)71
-rw-r--r--library/std/src/sys/thread/uefi.rs25
-rw-r--r--library/std/src/sys/thread/unix.rs (renamed from library/std/src/sys/pal/unix/thread.rs)667
-rw-r--r--library/std/src/sys/thread/unsupported.rs (renamed from library/std/src/sys/pal/unsupported/thread.rs)39
-rw-r--r--library/std/src/sys/thread/wasip1.rs185
-rw-r--r--library/std/src/sys/thread/wasip2.rs32
-rw-r--r--library/std/src/sys/thread/wasm.rs23
-rw-r--r--library/std/src/sys/thread/windows.rs (renamed from library/std/src/sys/pal/windows/thread.rs)112
-rw-r--r--library/std/src/sys/thread/xous.rs (renamed from library/std/src/sys/pal/xous/thread.rs)54
-rw-r--r--library/std/src/thread/mod.rs75
-rw-r--r--library/std/src/thread/tests.rs4
-rw-r--r--library/std/tests/sync/condvar.rs18
-rw-r--r--library/std/tests/sync/lib.rs3
-rw-r--r--library/std/tests/sync/mutex.rs4
-rw-r--r--library/std/tests/sync/rwlock.rs8
-rw-r--r--library/std_detect/src/detect/os/linux/aarch64.rs77
-rw-r--r--package-lock.json8
-rw-r--r--package.json2
-rw-r--r--src/bootstrap/defaults/bootstrap.dist.toml4
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs14
-rw-r--r--src/bootstrap/src/core/config/mod.rs2
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/librustdoc/html/static/js/search.js6
-rw-r--r--src/librustdoc/passes/lint/bare_urls.rs57
m---------src/tools/cargo0
-rw-r--r--src/tools/miri/README.md1
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr4
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr4
-rw-r--r--src/tools/tidy/src/extra_checks/mod.rs52
-rw-r--r--src/tools/tidy/src/extra_checks/rustdoc_js.rs6
-rw-r--r--tests/assembly-llvm/c-variadic-arm.rs26
-rw-r--r--tests/codegen-llvm/c-variadic-lifetime.rs21
-rw-r--r--tests/rustdoc-js/literal-path.js23
-rw-r--r--tests/rustdoc-js/literal-path.rs7
-rw-r--r--tests/rustdoc-ui/lints/bare-urls.fixed14
-rw-r--r--tests/rustdoc-ui/lints/bare-urls.rs14
-rw-r--r--tests/rustdoc-ui/lints/bare-urls.stderr70
-rw-r--r--tests/ui/consts/const_cmp_type_id.rs5
-rw-r--r--tests/ui/consts/const_cmp_type_id.stderr8
-rw-r--r--tests/ui/consts/fn_trait_refs.rs3
-rw-r--r--tests/ui/consts/fn_trait_refs.stderr22
-rw-r--r--tests/ui/feature-gates/feature-gate-sanitize.rs1
-rw-r--r--tests/ui/feature-gates/feature-gate-sanitize.stderr4
-rw-r--r--tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.next.stderr16
-rw-r--r--tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.rs31
-rw-r--r--tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.rs25
-rw-r--r--tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.stderr25
-rw-r--r--tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket.rs25
-rw-r--r--tests/ui/impl-trait/non-defining-uses/multiple-opaques-ambig.rs23
-rw-r--r--tests/ui/impl-trait/non-defining-uses/multiple-opaques-ok.rs37
-rw-r--r--tests/ui/impl-trait/non-defining-uses/no-rigid-alias.rs27
-rw-r--r--tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs19
-rw-r--r--tests/ui/impl-trait/non-defining-uses/use-item-bound-over-blanket-impl.rs30
-rw-r--r--tests/ui/impl-trait/non-defining-uses/use-item-bound.rs25
-rw-r--r--tests/ui/macros/metavar-expressions/concat-allowed-operations.rs18
-rw-r--r--tests/ui/macros/metavar-expressions/concat-usage-errors.rs10
-rw-r--r--tests/ui/macros/metavar-expressions/concat-usage-errors.stderr40
-rw-r--r--tests/ui/traits/const-traits/const-impl-trait.rs4
-rw-r--r--tests/ui/traits/const-traits/const-impl-trait.stderr17
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-use.rs3
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-use.stderr11
131 files changed, 2291 insertions, 1592 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 8be13e84596..2dc6e8ff103 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2347,11 +2347,11 @@ dependencies = [
 
 [[package]]
 name = "miow"
-version = "0.6.0"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044"
+checksum = "536bfad37a309d62069485248eeaba1e8d9853aaf951caaeaed0585a95346f08"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -6316,15 +6316,6 @@ dependencies = [
 
 [[package]]
 name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
@@ -6352,21 +6343,6 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
-]
-
-[[package]]
-name = "windows-targets"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
@@ -6409,12 +6385,6 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
@@ -6427,12 +6397,6 @@ checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
@@ -6445,12 +6409,6 @@ checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
-[[package]]
-name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
@@ -6475,12 +6433,6 @@ checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
@@ -6493,12 +6445,6 @@ checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
-[[package]]
-name = "windows_x86_64_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
@@ -6511,12 +6457,6 @@ checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
@@ -6529,12 +6469,6 @@ checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
-[[package]]
-name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 7eb5d302058..ab08125217f 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -908,6 +908,21 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
             )
         }
         "aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
+        "arm" => {
+            // Types wider than 16 bytes are not currently supported. Clang has special logic for
+            // such types, but `VaArgSafe` is not implemented for any type that is this large.
+            assert!(bx.cx.size_of(target_ty).bytes() <= 16);
+
+            emit_ptr_va_arg(
+                bx,
+                addr,
+                target_ty,
+                PassMode::Direct,
+                SlotSize::Bytes4,
+                AllowHigherAlign::Yes,
+                ForceRightAdjust::No,
+            )
+        }
         "s390x" => emit_s390x_va_arg(bx, addr, target_ty),
         "powerpc" => emit_powerpc_va_arg(bx, addr, target_ty),
         "powerpc64" | "powerpc64le" => emit_ptr_va_arg(
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 5f6976f5d00..6492ef73956 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -520,7 +520,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 LocalRef::Place(va_list) => {
                     bx.va_end(va_list.val.llval);
 
-                    // Explicitly end the lifetime of the `va_list`, this matters for LLVM.
+                    // Explicitly end the lifetime of the `va_list`, improves LLVM codegen.
                     bx.lifetime_end(va_list.val.llval, va_list.layout.size);
                 }
                 _ => bug!("C-variadic function must have a `VaList` place"),
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 06873313e2e..6b109e8b8e2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -438,6 +438,10 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
             if fx.fn_abi.c_variadic && arg_index == fx.fn_abi.args.len() {
                 let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
+
+                // Explicitly start the lifetime of the `va_list`, improves LLVM codegen.
+                bx.lifetime_start(va_list.val.llval, va_list.layout.size);
+
                 bx.va_start(va_list.val.llval);
 
                 return LocalRef::Place(va_list);
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index e4e4866b64c..ed8aa71d59d 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -940,11 +940,27 @@ fn extract_symbol_from_pnr<'a>(
         {
             Ok(*symbol)
         }
+        ParseNtResult::Literal(expr)
+            if let ExprKind::Lit(lit @ Lit { kind: LitKind::Integer, symbol, suffix }) =
+                &expr.kind =>
+        {
+            if lit.is_semantic_float() {
+                Err(dcx
+                    .struct_err("floats are not supported as metavariables of `${concat(..)}`")
+                    .with_span(span_err))
+            } else if suffix.is_none() {
+                Ok(*symbol)
+            } else {
+                Err(dcx
+                    .struct_err("integer metavariables of `${concat(..)}` must not be suffixed")
+                    .with_span(span_err))
+            }
+        }
         _ => Err(dcx
             .struct_err(
                 "metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`",
             )
-            .with_note("currently only string literals are supported")
+            .with_note("currently only string and integer literals are supported")
             .with_span(span_err)),
     }
 }
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 8af4740f376..95abe5c40dd 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -440,6 +440,43 @@ impl DefKind {
             | DefKind::ExternCrate => false,
         }
     }
+
+    /// Returns `true` if `self` is a kind of definition that does not have its own
+    /// type-checking context, i.e. closure, coroutine or inline const.
+    #[inline]
+    pub fn is_typeck_child(self) -> bool {
+        match self {
+            DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody => true,
+            DefKind::Mod
+            | DefKind::Struct
+            | DefKind::Union
+            | DefKind::Enum
+            | DefKind::Variant
+            | DefKind::Trait
+            | DefKind::TyAlias
+            | DefKind::ForeignTy
+            | DefKind::TraitAlias
+            | DefKind::AssocTy
+            | DefKind::TyParam
+            | DefKind::Fn
+            | DefKind::Const
+            | DefKind::ConstParam
+            | DefKind::Static { .. }
+            | DefKind::Ctor(_, _)
+            | DefKind::AssocFn
+            | DefKind::AssocConst
+            | DefKind::Macro(_)
+            | DefKind::ExternCrate
+            | DefKind::Use
+            | DefKind::ForeignMod
+            | DefKind::AnonConst
+            | DefKind::OpaqueTy
+            | DefKind::Field
+            | DefKind::LifetimeParam
+            | DefKind::GlobalAsm
+            | DefKind::Impl { .. } => false,
+        }
+    }
 }
 
 /// The resolution of a path or export.
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 2562ab7542a..6659aff7111 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -238,7 +238,8 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             _ => (),
         }
         // Skip `AnonConst`s because we feed their `type_of`.
-        if !matches!(def_kind, DefKind::AnonConst) {
+        // Also skip items for which typeck forwards to parent typeck.
+        if !(matches!(def_kind, DefKind::AnonConst) || def_kind.is_typeck_child()) {
             tcx.ensure_ok().typeck(item_def_id);
         }
         // Ensure we generate the new `DefId` before finishing `check_crate`.
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 218ac2cfbc1..8ea767dccd3 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -651,7 +651,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
             | ty::Bound(_, _) => bug!("unexpected self type: {self_ty}"),
         }
 
-        let trait_impls = tcx.trait_impls_of(trait_def_id);
+        #[allow(rustc::usage_of_type_ir_traits)]
+        self.for_each_blanket_impl(trait_def_id, f)
+    }
+    fn for_each_blanket_impl(self, trait_def_id: DefId, mut f: impl FnMut(DefId)) {
+        let trait_impls = self.trait_impls_of(trait_def_id);
         for &impl_def_id in trait_impls.blanket_impls() {
             f(impl_def_id);
         }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 96fbdf44791..029586a9c55 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -608,10 +608,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Returns `true` if `def_id` refers to a definition that does not have its own
     /// type-checking context, i.e. closure, coroutine or inline const.
     pub fn is_typeck_child(self, def_id: DefId) -> bool {
-        matches!(
-            self.def_kind(def_id),
-            DefKind::Closure | DefKind::InlineConst | DefKind::SyntheticCoroutineBody
-        )
+        self.def_kind(def_id).is_typeck_child()
     }
 
     /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
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 e3cf0330b14..fb777496e31 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -11,8 +11,9 @@ use rustc_type_ir::lang_items::SolverTraitLangItem;
 use rustc_type_ir::search_graph::CandidateHeadUsages;
 use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::{
-    self as ty, Interner, TypeFlags, TypeFoldable, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt as _, TypeVisitor, TypingMode, Upcast as _, elaborate,
+    self as ty, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
+    elaborate,
 };
 use tracing::{debug, instrument};
 
@@ -187,6 +188,7 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
         impl_def_id: I::ImplId,
+        then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
     ) -> Result<Candidate<I>, NoSolution>;
 
     /// If the predicate contained an error, we want to avoid emitting unnecessary trait
@@ -365,6 +367,15 @@ pub(super) enum AssembleCandidatesFrom {
     EnvAndBounds,
 }
 
+impl AssembleCandidatesFrom {
+    fn should_assemble_impl_candidates(&self) -> bool {
+        match self {
+            AssembleCandidatesFrom::All => true,
+            AssembleCandidatesFrom::EnvAndBounds => false,
+        }
+    }
+}
+
 /// This is currently used to track the [CandidateHeadUsages] of all failed `ParamEnv`
 /// candidates. This is then used to ignore their head usages in case there's another
 /// always applicable `ParamEnv` candidate. Look at how `param_env_head_usages` is
@@ -397,14 +408,15 @@ where
             return (candidates, failed_candidate_info);
         };
 
+        let goal: Goal<I, G> = goal
+            .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
+
         if normalized_self_ty.is_ty_var() {
             debug!("self type has been normalized to infer");
-            candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
+            self.try_assemble_bounds_via_registered_opaques(goal, assemble_from, &mut candidates);
             return (candidates, failed_candidate_info);
         }
 
-        let goal: Goal<I, G> = goal
-            .with(self.cx(), goal.predicate.with_replaced_self_ty(self.cx(), normalized_self_ty));
         // Vars that show up in the rest of the goal substs may have been constrained by
         // normalizing the self type as well, since type variables are not uniquified.
         let goal = self.resolve_vars_if_possible(goal);
@@ -484,8 +496,9 @@ where
                 if cx.impl_is_default(impl_def_id) {
                     return;
                 }
-
-                match G::consider_impl_candidate(self, goal, impl_def_id) {
+                match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
+                    ecx.evaluate_added_goals_and_make_canonical_response(certainty)
+                }) {
                     Ok(candidate) => candidates.push(candidate),
                     Err(NoSolution) => (),
                 }
@@ -943,6 +956,116 @@ where
         }
     }
 
+    /// If the self type is the hidden type of an opaque, try to assemble
+    /// candidates for it by consider its item bounds and by using blanket
+    /// impls. This is used to incompletely guide type inference when handling
+    /// non-defining uses in the defining scope.
+    ///
+    /// We otherwise just fail fail with ambiguity. Even if we're using an
+    /// opaque type item bound or a blank impls, we still force its certainty
+    /// to be `Maybe` so that we properly prove this goal later.
+    ///
+    /// See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/182>
+    /// for why this is necessary.
+    fn try_assemble_bounds_via_registered_opaques<G: GoalKind<D>>(
+        &mut self,
+        goal: Goal<I, G>,
+        assemble_from: AssembleCandidatesFrom,
+        candidates: &mut Vec<Candidate<I>>,
+    ) {
+        let self_ty = goal.predicate.self_ty();
+        // If the self type is sub unified with any opaque type, we
+        // also look at blanket impls for it.
+        let mut assemble_blanket_impls = false;
+        for alias_ty in self.opaques_with_sub_unified_hidden_type(self_ty) {
+            assemble_blanket_impls = true;
+            debug!("self ty is sub unified with {alias_ty:?}");
+
+            struct ReplaceOpaque<I: Interner> {
+                cx: I,
+                alias_ty: ty::AliasTy<I>,
+                self_ty: I::Ty,
+            }
+            impl<I: Interner> TypeFolder<I> for ReplaceOpaque<I> {
+                fn cx(&self) -> I {
+                    self.cx
+                }
+                fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
+                    if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() {
+                        if alias_ty == self.alias_ty {
+                            return self.self_ty;
+                        }
+                    }
+                    ty.super_fold_with(self)
+                }
+            }
+
+            // We look at all item-bounds of the opaque, replacing the
+            // opaque with the current self type before considering
+            // them as a candidate. Imagine e've got `?x: Trait<?y>`
+            // and `?x` has been sub-unified with the hidden type of
+            // `impl Trait<u32>`, We take the item bound `opaque: Trait<u32>`
+            // and replace all occurrences of `opaque` with `?x`. This results
+            // in a `?x: Trait<u32>` alias-bound candidate.
+            for item_bound in self
+                .cx()
+                .item_self_bounds(alias_ty.def_id)
+                .iter_instantiated(self.cx(), alias_ty.args)
+            {
+                let assumption =
+                    item_bound.fold_with(&mut ReplaceOpaque { cx: self.cx(), alias_ty, self_ty });
+                candidates.extend(G::probe_and_match_goal_against_assumption(
+                    self,
+                    CandidateSource::AliasBound,
+                    goal,
+                    assumption,
+                    |ecx| {
+                        // We want to reprove this goal once we've inferred the
+                        // hidden type, so we force the certainty to `Maybe`.
+                        ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+                    },
+                ));
+            }
+        }
+
+        // We also need to consider blanket impls for not-yet-defined opaque types.
+        //
+        // See tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs for an example.
+        if assemble_blanket_impls && assemble_from.should_assemble_impl_candidates() {
+            let cx = self.cx();
+            cx.for_each_blanket_impl(goal.predicate.trait_def_id(cx), |impl_def_id| {
+                // For every `default impl`, there's always a non-default `impl`
+                // that will *also* apply. There's no reason to register a candidate
+                // for this impl, since it is *not* proof that the trait goal holds.
+                if cx.impl_is_default(impl_def_id) {
+                    return;
+                }
+
+                match G::consider_impl_candidate(self, goal, impl_def_id, |ecx, certainty| {
+                    if ecx.shallow_resolve(self_ty).is_ty_var() {
+                        // We force the certainty of impl candidates to be `Maybe`.
+                        let certainty = certainty.and(Certainty::AMBIGUOUS);
+                        ecx.evaluate_added_goals_and_make_canonical_response(certainty)
+                    } else {
+                        // We don't want to use impls if they constrain the opaque.
+                        //
+                        // FIXME(trait-system-refactor-initiative#229): This isn't
+                        // perfect yet as it still allows us to incorrectly constrain
+                        // other inference variables.
+                        Err(NoSolution)
+                    }
+                }) {
+                    Ok(candidate) => candidates.push(candidate),
+                    Err(NoSolution) => (),
+                }
+            });
+        }
+
+        if candidates.is_empty() {
+            candidates.extend(self.forced_ambiguity(MaybeCause::Ambiguity));
+        }
+    }
+
     /// Assemble and merge candidates for goals which are related to an underlying trait
     /// goal. Right now, this is normalizes-to and host effect goals.
     ///
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 6646857a136..cb72c1cd92b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -124,6 +124,7 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
         impl_def_id: I::ImplId,
+        then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
     ) -> Result<Candidate<I>, NoSolution> {
         let cx = ecx.cx();
 
@@ -175,7 +176,7 @@ where
                 });
             ecx.add_goals(GoalSource::ImplWhereBound, const_conditions);
 
-            ecx.evaluate_added_goals_and_make_canonical_response(certainty)
+            then(ecx, certainty)
         })
     }
 
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 5cd597d4fe6..3e3a5246f3d 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
@@ -407,20 +407,21 @@ where
         // If we have run this goal before, and it was stalled, check that any of the goal's
         // args have changed. Otherwise, we don't need to re-run the goal because it'll remain
         // stalled, since it'll canonicalize the same way and evaluation is pure.
-        if let Some(stalled_on) = stalled_on
-            && !stalled_on.stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
-            && !self
-                .delegate
-                .opaque_types_storage_num_entries()
-                .needs_reevaluation(stalled_on.num_opaques)
+        if let Some(GoalStalledOn { num_opaques, ref stalled_vars, ref sub_roots, stalled_cause }) =
+            stalled_on
+            && !stalled_vars.iter().any(|value| self.delegate.is_changed_arg(*value))
+            && !sub_roots
+                .iter()
+                .any(|&vid| self.delegate.sub_unification_table_root_var(vid) != vid)
+            && !self.delegate.opaque_types_storage_num_entries().needs_reevaluation(num_opaques)
         {
             return Ok((
                 NestedNormalizationGoals::empty(),
                 GoalEvaluation {
                     goal,
-                    certainty: Certainty::Maybe(stalled_on.stalled_cause),
+                    certainty: Certainty::Maybe(stalled_cause),
                     has_changed: HasChanged::No,
-                    stalled_on: Some(stalled_on),
+                    stalled_on,
                 },
             ));
         }
@@ -476,16 +477,6 @@ where
                 HasChanged::No => {
                     let mut stalled_vars = orig_values;
 
-                    // Remove the canonicalized universal vars, since we only care about stalled existentials.
-                    stalled_vars.retain(|arg| match arg.kind() {
-                        ty::GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Infer(_)),
-                        ty::GenericArgKind::Const(ct) => {
-                            matches!(ct.kind(), ty::ConstKind::Infer(_))
-                        }
-                        // Lifetimes can never stall goals.
-                        ty::GenericArgKind::Lifetime(_) => false,
-                    });
-
                     // Remove the unconstrained RHS arg, which is expected to have changed.
                     if let Some(normalizes_to) = goal.predicate.as_normalizes_to() {
                         let normalizes_to = normalizes_to.skip_binder();
@@ -497,6 +488,27 @@ where
                         stalled_vars.swap_remove(idx);
                     }
 
+                    // Remove the canonicalized universal vars, since we only care about stalled existentials.
+                    let mut sub_roots = Vec::new();
+                    stalled_vars.retain(|arg| match arg.kind() {
+                        // Lifetimes can never stall goals.
+                        ty::GenericArgKind::Lifetime(_) => false,
+                        ty::GenericArgKind::Type(ty) => match ty.kind() {
+                            ty::Infer(ty::TyVar(vid)) => {
+                                sub_roots.push(self.delegate.sub_unification_table_root_var(vid));
+                                true
+                            }
+                            ty::Infer(_) => true,
+                            ty::Param(_) | ty::Placeholder(_) => false,
+                            _ => unreachable!("unexpected orig_value: {ty:?}"),
+                        },
+                        ty::GenericArgKind::Const(ct) => match ct.kind() {
+                            ty::ConstKind::Infer(_) => true,
+                            ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(_) => false,
+                            _ => unreachable!("unexpected orig_value: {ct:?}"),
+                        },
+                    });
+
                     Some(GoalStalledOn {
                         num_opaques: canonical_goal
                             .canonical
@@ -505,6 +517,7 @@ where
                             .opaque_types
                             .len(),
                         stalled_vars,
+                        sub_roots,
                         stalled_cause,
                     })
                 }
@@ -1047,6 +1060,10 @@ where
         self.delegate.resolve_vars_if_possible(value)
     }
 
+    pub(super) fn shallow_resolve(&self, ty: I::Ty) -> I::Ty {
+        self.delegate.shallow_resolve(ty)
+    }
+
     pub(super) fn eager_resolve_region(&self, r: I::Region) -> I::Region {
         if let ty::ReVar(vid) = r.kind() {
             self.delegate.opportunistic_resolve_lt_var(vid)
@@ -1163,6 +1180,33 @@ where
     ) -> bool {
         may_use_unstable_feature(&**self.delegate, param_env, symbol)
     }
+
+    pub(crate) fn opaques_with_sub_unified_hidden_type(
+        &self,
+        self_ty: I::Ty,
+    ) -> impl Iterator<Item = ty::AliasTy<I>> + use<'a, D, I> {
+        let delegate = self.delegate;
+        delegate
+            .clone_opaque_types_lookup_table()
+            .into_iter()
+            .chain(delegate.clone_duplicate_opaque_types())
+            .filter_map(move |(key, hidden_ty)| {
+                if let ty::Infer(ty::TyVar(self_vid)) = self_ty.kind() {
+                    if let ty::Infer(ty::TyVar(hidden_vid)) = hidden_ty.kind() {
+                        if delegate.sub_unification_table_root_var(self_vid)
+                            == delegate.sub_unification_table_root_var(hidden_vid)
+                        {
+                            return Some(ty::AliasTy::new_from_args(
+                                delegate.cx(),
+                                key.def_id.into(),
+                                key.args,
+                            ));
+                        }
+                    }
+                }
+                None
+            })
+    }
 }
 
 /// Eagerly replace aliases with inference variables, emitting `AliasRelate`
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index db3460c4ff6..cd27c9c26c1 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -24,7 +24,7 @@ mod trait_goals;
 use derive_where::derive_where;
 use rustc_type_ir::inherent::*;
 pub use rustc_type_ir::solve::*;
-use rustc_type_ir::{self as ty, Interner, TypingMode};
+use rustc_type_ir::{self as ty, Interner, TyVid, TypingMode};
 use tracing::instrument;
 
 pub use self::eval_ctxt::{
@@ -418,11 +418,6 @@ pub struct GoalEvaluation<I: Interner> {
     pub has_changed: HasChanged,
     /// If the [`Certainty`] was `Maybe`, then keep track of whether the goal has changed
     /// before rerunning it.
-    ///
-    /// We knowingly ignore the `sub_root` of our inference variables here. This means we
-    /// may not reevaluate a goal even though a change to the `sub_root` could cause a goal
-    /// to make progress. Tracking them adds additional complexity for an incredibly minor
-    /// type inference improvement. We could look into properly handling this in the future.
     pub stalled_on: Option<GoalStalledOn<I>>,
 }
 
@@ -431,6 +426,7 @@ pub struct GoalEvaluation<I: Interner> {
 pub struct GoalStalledOn<I: Interner> {
     pub num_opaques: usize,
     pub stalled_vars: Vec<I::GenericArg>,
+    pub sub_roots: Vec<TyVid>,
     /// The cause that will be returned on subsequent evaluations if this goal remains stalled.
     pub stalled_cause: MaybeCause,
 }
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 6e6be829f52..54b92ebac1d 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
@@ -194,6 +194,7 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, NormalizesTo<I>>,
         impl_def_id: I::ImplId,
+        then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
     ) -> Result<Candidate<I>, NoSolution> {
         let cx = ecx.cx();
 
@@ -314,8 +315,7 @@ where
                         // nested goal for consistency.
                         ty::TypingMode::Coherence => {
                             ecx.add_goal(GoalSource::Misc, goal.with(cx, PredicateKind::Ambiguous));
-                            return ecx
-                                .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
+                            return then(ecx, Certainty::Yes);
                         }
                         ty::TypingMode::Analysis { .. }
                         | ty::TypingMode::Borrowck { .. }
@@ -325,8 +325,7 @@ where
                                 goal,
                                 goal.predicate.alias,
                             );
-                            return ecx
-                                .evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
+                            return then(ecx, Certainty::Yes);
                         }
                     }
                 } else {
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 3e720a47f32..a69e867289c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -55,6 +55,7 @@ where
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, TraitPredicate<I>>,
         impl_def_id: I::ImplId,
+        then: impl FnOnce(&mut EvalCtxt<'_, D>, Certainty) -> QueryResult<I>,
     ) -> Result<Candidate<I>, NoSolution> {
         let cx = ecx.cx();
 
@@ -112,7 +113,7 @@ where
                     .map(|pred| goal.with(cx, pred)),
             );
 
-            ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty)
+            then(ecx, maximal_certainty)
         })
     }
 
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 3a83b1739ff..cf58aec14a6 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -347,6 +347,7 @@ pub trait Interner:
         self_ty: Self::Ty,
         f: impl FnMut(Self::ImplId),
     );
+    fn for_each_blanket_impl(self, trait_def_id: Self::TraitId, f: impl FnMut(Self::ImplId));
 
     fn has_item_definition(self, def_id: Self::DefId) -> bool;
 
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index e7d9763d46e..76ea2d18a82 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -705,7 +705,8 @@ impl dyn Any + Send + Sync {
 ///     std::mem::forget(fake_one_ring);
 /// }
 /// ```
-#[derive(Clone, Copy, Eq, PartialOrd, Ord)]
+#[derive(Copy, PartialOrd, Ord)]
+#[derive_const(Clone, Eq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[lang = "type_id"]
 pub struct TypeId {
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs
index 1ad2cca64a3..c2c7ccf0daa 100644
--- a/library/core/src/array/equality.rs
+++ b/library/core/src/array/equality.rs
@@ -1,9 +1,10 @@
 use crate::cmp::BytewiseEq;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U, const N: usize> PartialEq<[U; N]> for [T; N]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U, const N: usize> const PartialEq<[U; N]> for [T; N]
 where
-    T: PartialEq<U>,
+    T: [const] PartialEq<U>,
 {
     #[inline]
     fn eq(&self, other: &[U; N]) -> bool {
@@ -16,9 +17,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U, const N: usize> PartialEq<[U]> for [T; N]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U, const N: usize> const PartialEq<[U]> for [T; N]
 where
-    T: PartialEq<U>,
+    T: [const] PartialEq<U>,
 {
     #[inline]
     fn eq(&self, other: &[U]) -> bool {
@@ -37,9 +39,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U, const N: usize> PartialEq<[U; N]> for [T]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U, const N: usize> const PartialEq<[U; N]> for [T]
 where
-    T: PartialEq<U>,
+    T: [const] PartialEq<U>,
 {
     #[inline]
     fn eq(&self, other: &[U; N]) -> bool {
@@ -58,9 +61,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U, const N: usize> PartialEq<&[U]> for [T; N]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U, const N: usize> const PartialEq<&[U]> for [T; N]
 where
-    T: PartialEq<U>,
+    T: [const] PartialEq<U>,
 {
     #[inline]
     fn eq(&self, other: &&[U]) -> bool {
@@ -73,9 +77,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U, const N: usize> PartialEq<[U; N]> for &[T]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U, const N: usize> const PartialEq<[U; N]> for &[T]
 where
-    T: PartialEq<U>,
+    T: [const] PartialEq<U>,
 {
     #[inline]
     fn eq(&self, other: &[U; N]) -> bool {
@@ -88,9 +93,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U, const N: usize> PartialEq<&mut [U]> for [T; N]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U, const N: usize> const PartialEq<&mut [U]> for [T; N]
 where
-    T: PartialEq<U>,
+    T: [const] PartialEq<U>,
 {
     #[inline]
     fn eq(&self, other: &&mut [U]) -> bool {
@@ -103,9 +109,10 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T, U, const N: usize> PartialEq<[U; N]> for &mut [T]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T, U, const N: usize> const PartialEq<[U; N]> for &mut [T]
 where
-    T: PartialEq<U>,
+    T: [const] PartialEq<U>,
 {
     #[inline]
     fn eq(&self, other: &[U; N]) -> bool {
@@ -122,14 +129,18 @@ where
 // __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq, const N: usize> Eq for [T; N] {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] Eq, const N: usize> const Eq for [T; N] {}
 
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 trait SpecArrayEq<Other, const N: usize>: Sized {
     fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool;
     fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool;
 }
 
-impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] PartialEq<Other>, Other, const N: usize> const SpecArrayEq<Other, N> for T {
     default fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool {
         a[..] == b[..]
     }
@@ -138,7 +149,8 @@ impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T {
     }
 }
 
-impl<T: BytewiseEq<U>, U, const N: usize> SpecArrayEq<U, N> for T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] BytewiseEq<U>, U, const N: usize> const SpecArrayEq<U, N> for T {
     fn spec_eq(a: &[T; N], b: &[U; N]) -> bool {
         // SAFETY: Arrays are compared element-wise, and don't add any padding
         // between elements, so when the elements are `BytewiseEq`, we can
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 49d540314a2..178af2c0e3b 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -54,7 +54,8 @@ use crate::{assert_unsafe_precondition, fmt};
 /// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf
 /// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf
 /// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt
-#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[derive(Copy, Hash)]
+#[derive_const(Clone, Eq, PartialEq, Ord, PartialOrd)]
 #[unstable(feature = "ascii_char", issue = "110998")]
 #[repr(u8)]
 pub enum AsciiChar {
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 0812322f3fb..94536f25b41 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -29,7 +29,7 @@ mod bytewise;
 pub(crate) use bytewise::BytewiseEq;
 
 use self::Ordering::*;
-use crate::marker::PointeeSized;
+use crate::marker::{Destruct, PointeeSized};
 use crate::ops::ControlFlow;
 
 /// Trait for comparisons using the equality operator.
@@ -334,7 +334,9 @@ pub macro PartialEq($item:item) {
 #[doc(alias = "!=")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Eq"]
-pub trait Eq: PartialEq<Self> + PointeeSized {
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub trait Eq: [const] PartialEq<Self> + PointeeSized {
     // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a
     // type implements `Eq` itself. The current deriving infrastructure means doing this assertion
     // without using a method on this trait is nearly impossible.
@@ -380,8 +382,8 @@ pub struct AssertParamIsEq<T: Eq + PointeeSized> {
 ///
 /// assert_eq!(2.cmp(&1), Ordering::Greater);
 /// ```
-#[derive(Clone, Copy, Eq, PartialOrd, Ord, Debug, Hash)]
-#[derive_const(PartialEq)]
+#[derive(Copy, Debug, Hash)]
+#[derive_const(Clone, Eq, PartialOrd, Ord, PartialEq)]
 #[stable(feature = "rust1", since = "1.0.0")]
 // This is a lang item only so that `BinOp::Cmp` in MIR can return it.
 // It has no special behavior, but does require that the three variants
@@ -635,7 +637,11 @@ impl Ordering {
     #[inline]
     #[must_use]
     #[stable(feature = "ordering_chaining", since = "1.17.0")]
-    pub fn then_with<F: FnOnce() -> Ordering>(self, f: F) -> Ordering {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    pub const fn then_with<F>(self, f: F) -> Ordering
+    where
+        F: [const] FnOnce() -> Ordering + [const] Destruct,
+    {
         match self {
             Equal => f(),
             _ => self,
@@ -659,13 +665,15 @@ impl Ordering {
 /// v.sort_by_key(|&num| (num > 3, Reverse(num)));
 /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]);
 /// ```
-#[derive(PartialEq, Eq, Debug, Copy, Default, Hash)]
+#[derive(Copy, Debug, Hash)]
+#[derive_const(PartialEq, Eq, Default)]
 #[stable(feature = "reverse_cmp_key", since = "1.19.0")]
 #[repr(transparent)]
 pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
 
 #[stable(feature = "reverse_cmp_key", since = "1.19.0")]
-impl<T: PartialOrd> PartialOrd for Reverse<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] PartialOrd> const PartialOrd for Reverse<T> {
     #[inline]
     fn partial_cmp(&self, other: &Reverse<T>) -> Option<Ordering> {
         other.0.partial_cmp(&self.0)
@@ -690,7 +698,8 @@ impl<T: PartialOrd> PartialOrd for Reverse<T> {
 }
 
 #[stable(feature = "reverse_cmp_key", since = "1.19.0")]
-impl<T: Ord> Ord for Reverse<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] Ord> const Ord for Reverse<T> {
     #[inline]
     fn cmp(&self, other: &Reverse<T>) -> Ordering {
         other.0.cmp(&self.0)
@@ -957,7 +966,9 @@ impl<T: Clone> Clone for Reverse<T> {
 #[doc(alias = ">=")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Ord"]
-pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub trait Ord: [const] Eq + [const] PartialOrd<Self> + PointeeSized {
     /// This method returns an [`Ordering`] between `self` and `other`.
     ///
     /// By convention, `self.cmp(&other)` returns the ordering matching the expression
@@ -1011,7 +1022,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
     #[rustc_diagnostic_item = "cmp_ord_max"]
     fn max(self, other: Self) -> Self
     where
-        Self: Sized,
+        Self: Sized + [const] Destruct,
     {
         if other < self { self } else { other }
     }
@@ -1050,7 +1061,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
     #[rustc_diagnostic_item = "cmp_ord_min"]
     fn min(self, other: Self) -> Self
     where
-        Self: Sized,
+        Self: Sized + [const] Destruct,
     {
         if other < self { other } else { self }
     }
@@ -1076,7 +1087,7 @@ pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
     #[stable(feature = "clamp", since = "1.50.0")]
     fn clamp(self, min: Self, max: Self) -> Self
     where
-        Self: Sized,
+        Self: Sized + [const] Destruct,
     {
         assert!(min <= max);
         if self < min {
@@ -1341,6 +1352,8 @@ pub macro Ord($item:item) {
 )]
 #[rustc_diagnostic_item = "PartialOrd"]
 #[allow(multiple_supertrait_upcastable)] // FIXME(sized_hierarchy): remove this
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
     /// This method returns an ordering between `self` and `other` values if one exists.
     ///
@@ -1481,13 +1494,14 @@ pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
     }
 }
 
-fn default_chaining_impl<T, U>(
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+const fn default_chaining_impl<T, U>(
     lhs: &T,
     rhs: &U,
-    p: impl FnOnce(Ordering) -> bool,
+    p: impl [const] FnOnce(Ordering) -> bool + [const] Destruct,
 ) -> ControlFlow<bool>
 where
-    T: PartialOrd<U> + PointeeSized,
+    T: [const] PartialOrd<U> + PointeeSized,
     U: PointeeSized,
 {
     // It's important that this only call `partial_cmp` once, not call `eq` then
@@ -1545,7 +1559,8 @@ pub macro PartialOrd($item:item) {
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "cmp_min"]
-pub fn min<T: Ord>(v1: T, v2: T) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn min<T: [const] Ord + [const] Destruct>(v1: T, v2: T) -> T {
     v1.min(v2)
 }
 
@@ -1575,7 +1590,12 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn min_by<T: [const] Destruct, F: [const] FnOnce(&T, &T) -> Ordering>(
+    v1: T,
+    v2: T,
+    compare: F,
+) -> T {
     if compare(&v1, &v2).is_le() { v1 } else { v2 }
 }
 
@@ -1600,7 +1620,13 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn min_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> T
+where
+    T: [const] Destruct,
+    F: [const] FnMut(&T) -> K + [const] Destruct,
+    K: [const] Ord + [const] Destruct,
+{
     if f(&v2) < f(&v1) { v2 } else { v1 }
 }
 
@@ -1640,7 +1666,8 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "cmp_max"]
-pub fn max<T: Ord>(v1: T, v2: T) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn max<T: [const] Ord + [const] Destruct>(v1: T, v2: T) -> T {
     v1.max(v2)
 }
 
@@ -1670,7 +1697,12 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn max_by<T: [const] Destruct, F: [const] FnOnce(&T, &T) -> Ordering>(
+    v1: T,
+    v2: T,
+    compare: F,
+) -> T {
     if compare(&v1, &v2).is_gt() { v1 } else { v2 }
 }
 
@@ -1695,7 +1727,13 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
 #[inline]
 #[must_use]
 #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
-pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn max_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> T
+where
+    T: [const] Destruct,
+    F: [const] FnMut(&T) -> K + [const] Destruct,
+    K: [const] Ord + [const] Destruct,
+{
     if f(&v2) < f(&v1) { v1 } else { v2 }
 }
 
@@ -1739,9 +1777,10 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
 #[inline]
 #[must_use]
 #[unstable(feature = "cmp_minmax", issue = "115939")]
-pub fn minmax<T>(v1: T, v2: T) -> [T; 2]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn minmax<T>(v1: T, v2: T) -> [T; 2]
 where
-    T: Ord,
+    T: [const] Ord,
 {
     if v2 < v1 { [v2, v1] } else { [v1, v2] }
 }
@@ -1773,9 +1812,10 @@ where
 #[inline]
 #[must_use]
 #[unstable(feature = "cmp_minmax", issue = "115939")]
-pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
 where
-    F: FnOnce(&T, &T) -> Ordering,
+    F: [const] FnOnce(&T, &T) -> Ordering,
 {
     if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] }
 }
@@ -1801,10 +1841,11 @@ where
 #[inline]
 #[must_use]
 #[unstable(feature = "cmp_minmax", issue = "115939")]
-pub fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+pub const fn minmax_by_key<T, F, K>(v1: T, v2: T, mut f: F) -> [T; 2]
 where
-    F: FnMut(&T) -> K,
-    K: Ord,
+    F: [const] FnMut(&T) -> K + [const] Destruct,
+    K: [const] Ord + [const] Destruct,
 {
     if f(&v2) < f(&v1) { [v2, v1] } else { [v1, v2] }
 }
@@ -1830,7 +1871,8 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialEq for () {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const PartialEq for () {
         #[inline]
         fn eq(&self, _other: &()) -> bool {
             true
@@ -1848,7 +1890,8 @@ mod impls {
     macro_rules! eq_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl Eq for $t {}
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl const Eq for $t {}
         )*)
     }
 
@@ -1896,7 +1939,8 @@ mod impls {
     macro_rules! partial_ord_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialOrd for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl const PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
                     match (*self <= *other, *self >= *other) {
@@ -1913,7 +1957,8 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialOrd for () {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const PartialOrd for () {
         #[inline]
         fn partial_cmp(&self, _: &()) -> Option<Ordering> {
             Some(Equal)
@@ -1921,7 +1966,8 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl PartialOrd for bool {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const PartialOrd for bool {
         #[inline]
         fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
             Some(self.cmp(other))
@@ -1935,7 +1981,8 @@ mod impls {
     macro_rules! ord_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialOrd for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl const PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
                     Some(crate::intrinsics::three_way_compare(*self, *other))
@@ -1945,7 +1992,8 @@ mod impls {
             }
 
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl Ord for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl const Ord for $t {
                 #[inline]
                 fn cmp(&self, other: &Self) -> Ordering {
                     crate::intrinsics::three_way_compare(*self, *other)
@@ -1955,7 +2003,8 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl Ord for () {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const Ord for () {
         #[inline]
         fn cmp(&self, _other: &()) -> Ordering {
             Equal
@@ -1963,7 +2012,8 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl Ord for bool {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const Ord for bool {
         #[inline]
         fn cmp(&self, other: &bool) -> Ordering {
             // Casting to i8's and converting the difference to an Ordering generates
@@ -1998,7 +2048,8 @@ mod impls {
     ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl PartialEq for ! {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const PartialEq for ! {
         #[inline]
         fn eq(&self, _: &!) -> bool {
             *self
@@ -2006,10 +2057,12 @@ mod impls {
     }
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl Eq for ! {}
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const Eq for ! {}
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl PartialOrd for ! {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const PartialOrd for ! {
         #[inline]
         fn partial_cmp(&self, _: &!) -> Option<Ordering> {
             *self
@@ -2017,7 +2070,8 @@ mod impls {
     }
 
     #[unstable(feature = "never_type", issue = "35121")]
-    impl Ord for ! {
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl const Ord for ! {
         #[inline]
         fn cmp(&self, _: &!) -> Ordering {
             *self
@@ -2042,9 +2096,10 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: PointeeSized, B: PointeeSized> PartialOrd<&B> for &A
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl<A: PointeeSized, B: PointeeSized> const PartialOrd<&B> for &A
     where
-        A: PartialOrd<B>,
+        A: [const] PartialOrd<B>,
     {
         #[inline]
         fn partial_cmp(&self, other: &&B) -> Option<Ordering> {
@@ -2084,9 +2139,10 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: PointeeSized> Ord for &A
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl<A: PointeeSized> const Ord for &A
     where
-        A: Ord,
+        A: [const] Ord,
     {
         #[inline]
         fn cmp(&self, other: &Self) -> Ordering {
@@ -2094,7 +2150,8 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: PointeeSized> Eq for &A where A: Eq {}
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl<A: PointeeSized> const Eq for &A where A: [const] Eq {}
 
     // &mut pointers
 
@@ -2114,9 +2171,10 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: PointeeSized, B: PointeeSized> PartialOrd<&mut B> for &mut A
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl<A: PointeeSized, B: PointeeSized> const PartialOrd<&mut B> for &mut A
     where
-        A: PartialOrd<B>,
+        A: [const] PartialOrd<B>,
     {
         #[inline]
         fn partial_cmp(&self, other: &&mut B) -> Option<Ordering> {
@@ -2156,9 +2214,10 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: PointeeSized> Ord for &mut A
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl<A: PointeeSized> const Ord for &mut A
     where
-        A: Ord,
+        A: [const] Ord,
     {
         #[inline]
         fn cmp(&self, other: &Self) -> Ordering {
@@ -2166,7 +2225,8 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: PointeeSized> Eq for &mut A where A: Eq {}
+    #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+    impl<A: PointeeSized> const Eq for &mut A where A: [const] Eq {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index a3cfd85974a..89cda30c030 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -963,17 +963,20 @@ impl const PartialEq for Infallible {
 }
 
 #[stable(feature = "convert_infallible", since = "1.34.0")]
-impl Eq for Infallible {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl const Eq for Infallible {}
 
 #[stable(feature = "convert_infallible", since = "1.34.0")]
-impl PartialOrd for Infallible {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl const PartialOrd for Infallible {
     fn partial_cmp(&self, _other: &Self) -> Option<crate::cmp::Ordering> {
         match *self {}
     }
 }
 
 #[stable(feature = "convert_infallible", since = "1.34.0")]
-impl Ord for Infallible {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl const Ord for Infallible {
     fn cmp(&self, _other: &Self) -> crate::cmp::Ordering {
         match *self {}
     }
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 0f38081c355..1b7c28bb95a 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -4,7 +4,7 @@ use super::{IntErrorKind, ParseIntError};
 use crate::clone::UseCloned;
 use crate::cmp::Ordering;
 use crate::hash::{Hash, Hasher};
-use crate::marker::{Freeze, StructuralPartialEq};
+use crate::marker::{Destruct, Freeze, StructuralPartialEq};
 use crate::ops::{BitOr, BitOrAssign, Div, DivAssign, Neg, Rem, RemAssign};
 use crate::panic::{RefUnwindSafe, UnwindSafe};
 use crate::str::FromStr;
@@ -220,12 +220,14 @@ where
 impl<T> StructuralPartialEq for NonZero<T> where T: ZeroablePrimitive + StructuralPartialEq {}
 
 #[stable(feature = "nonzero", since = "1.28.0")]
-impl<T> Eq for NonZero<T> where T: ZeroablePrimitive + Eq {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T> const Eq for NonZero<T> where T: ZeroablePrimitive + [const] Eq {}
 
 #[stable(feature = "nonzero", since = "1.28.0")]
-impl<T> PartialOrd for NonZero<T>
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T> const PartialOrd for NonZero<T>
 where
-    T: ZeroablePrimitive + PartialOrd,
+    T: ZeroablePrimitive + [const] PartialOrd,
 {
     #[inline]
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -254,9 +256,12 @@ where
 }
 
 #[stable(feature = "nonzero", since = "1.28.0")]
-impl<T> Ord for NonZero<T>
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T> const Ord for NonZero<T>
 where
-    T: ZeroablePrimitive + Ord,
+    // FIXME(const_hack): the T: ~const Destruct should be inferred from the Self: ~const Destruct.
+    // See https://github.com/rust-lang/rust/issues/144207
+    T: ZeroablePrimitive + [const] Ord + [const] Destruct,
 {
     #[inline]
     fn cmp(&self, other: &Self) -> Ordering {
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index 73b74d53323..b760a7c4e21 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -83,7 +83,8 @@ use crate::{convert, ops};
 #[must_use]
 // ControlFlow should not implement PartialOrd or Ord, per RFC 3058:
 // https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Copy, Debug, Hash)]
+#[derive_const(Clone, PartialEq, Eq)]
 pub enum ControlFlow<B, C = ()> {
     /// Move on to the next phase of the operation as normal.
     #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 198636c67d0..886d581b0a6 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -585,7 +585,8 @@ use crate::{cmp, convert, hint, mem, slice};
 
 /// The `Option` type. See [the module level documentation](self) for more.
 #[doc(search_unbox)]
-#[derive(Copy, Eq, Debug, Hash)]
+#[derive(Copy, Debug, Hash)]
+#[derive_const(Eq)]
 #[rustc_diagnostic_item = "Option"]
 #[lang = "Option"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2363,7 +2364,8 @@ impl<T: [const] PartialEq> const PartialEq for Option<T> {
 // https://github.com/rust-lang/rust/issues/49892, although still
 // not optimal.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for Option<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] PartialOrd> const PartialOrd for Option<T> {
     #[inline]
     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
         match (self, other) {
@@ -2376,7 +2378,8 @@ impl<T: PartialOrd> PartialOrd for Option<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Ord for Option<T> {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] Ord> const Ord for Option<T> {
     #[inline]
     fn cmp(&self, other: &Self) -> cmp::Ordering {
         match (self, other) {
diff --git a/library/core/src/range.rs b/library/core/src/range.rs
index 8c49123fdaf..a096a8ceafc 100644
--- a/library/core/src/range.rs
+++ b/library/core/src/range.rs
@@ -49,7 +49,8 @@ pub use crate::ops::{Bound, IntoBounds, OneSidedRange, RangeBounds, RangeFull, R
 /// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum());
 /// ```
 #[lang = "RangeCopy"]
-#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
+#[derive(Copy, Hash)]
+#[derive_const(Clone, Default, PartialEq, Eq)]
 #[unstable(feature = "new_range_api", issue = "125687")]
 pub struct Range<Idx> {
     /// The lower bound of the range (inclusive).
@@ -424,7 +425,8 @@ impl<T> const From<legacy::RangeInclusive<T>> for RangeInclusive<T> {
 /// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum());
 /// ```
 #[lang = "RangeFromCopy"]
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[derive(Copy, Hash)]
+#[derive_const(Clone, PartialEq, Eq)]
 #[unstable(feature = "new_range_api", issue = "125687")]
 pub struct RangeFrom<Idx> {
     /// The lower bound of the range (inclusive).
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 7dffab9b316..5c1f64bfe14 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -542,7 +542,8 @@ use crate::{convert, fmt, hint};
 ///
 /// See the [module documentation](self) for details.
 #[doc(search_unbox)]
-#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[derive(Copy, Debug, Hash)]
+#[derive_const(PartialEq, PartialOrd, Eq, Ord)]
 #[must_use = "this `Result` may be an `Err` variant, which should be handled"]
 #[rustc_diagnostic_item = "Result"]
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 0d801306984..103630aba0f 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -23,7 +23,8 @@ where
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for [T] {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<T: [const] Eq> const Eq for [T] {}
 
 /// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -34,7 +35,7 @@ impl<T: Ord> Ord for [T] {
 }
 
 #[inline]
-fn as_underlying(x: ControlFlow<bool>) -> u8 {
+const fn as_underlying(x: ControlFlow<bool>) -> u8 {
     // SAFETY: This will only compile if `bool` and `ControlFlow<bool>` have the same
     // size (which isn't guaranteed but this is libcore). Because they have the same
     // size, it's a niched implementation, which in one byte means there can't be
@@ -154,12 +155,16 @@ where
 }
 
 #[doc(hidden)]
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 // intermediate trait for specialization of slice's PartialOrd
 trait SlicePartialOrd: Sized {
     fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
 }
 
 #[doc(hidden)]
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 // intermediate trait for specialization of slice's PartialOrd chaining methods
 trait SliceChain: Sized {
     fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
@@ -231,14 +236,17 @@ where
 }
 */
 
-impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<A: [const] AlwaysApplicableOrd> const SlicePartialOrd for A {
     fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
         Some(SliceOrd::compare(left, right))
     }
 }
 
 #[rustc_specialization_trait]
-trait AlwaysApplicableOrd: SliceOrd + Ord {}
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+trait AlwaysApplicableOrd: [const] SliceOrd + [const] Ord {}
 
 macro_rules! always_applicable_ord {
     ($([$($p:tt)*] $t:ty,)*) => {
@@ -257,6 +265,8 @@ always_applicable_ord! {
 }
 
 #[doc(hidden)]
+#[const_trait]
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
 // intermediate trait for specialization of slice's Ord
 trait SliceOrd: Sized {
     fn compare(left: &[Self], right: &[Self]) -> Ordering;
@@ -282,17 +292,24 @@ impl<A: Ord> SliceOrd for A {
 /// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
 ///   value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
 #[rustc_specialization_trait]
-unsafe trait UnsignedBytewiseOrd: Ord {}
+#[const_trait]
+unsafe trait UnsignedBytewiseOrd: [const] Ord {}
 
-unsafe impl UnsignedBytewiseOrd for bool {}
-unsafe impl UnsignedBytewiseOrd for u8 {}
-unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
-unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
-unsafe impl UnsignedBytewiseOrd for ascii::Char {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+unsafe impl const UnsignedBytewiseOrd for bool {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+unsafe impl const UnsignedBytewiseOrd for u8 {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+unsafe impl const UnsignedBytewiseOrd for NonZero<u8> {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+unsafe impl const UnsignedBytewiseOrd for Option<NonZero<u8>> {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+unsafe impl const UnsignedBytewiseOrd for ascii::Char {}
 
 // `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
 // use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
-impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<A: [const] Ord + [const] UnsignedBytewiseOrd> const SliceOrd for A {
     #[inline]
     fn compare(left: &[Self], right: &[Self]) -> Ordering {
         // Since the length of a slice is always less than or equal to
@@ -317,7 +334,9 @@ impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
 }
 
 // Don't generate our own chaining loops for `memcmp`-able things either.
-impl<A: PartialOrd + UnsignedBytewiseOrd> SliceChain for A {
+
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl<A: [const] PartialOrd + [const] UnsignedBytewiseOrd> const SliceChain for A {
     #[inline]
     fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
         match SliceOrd::compare(left, right) {
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 5adae62b7e6..a7cc943994c 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -32,7 +32,8 @@ impl const PartialEq for str {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl Eq for str {}
+#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+impl const Eq for str {}
 
 /// Implements comparison operations on strings.
 ///
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 2cdee1803a9..3892f831076 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -23,7 +23,8 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: PartialEq),+> PartialEq for ($($T,)+) {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl<$($T: [const] PartialEq),+> const PartialEq for ($($T,)+) {
                 #[inline]
                 fn eq(&self, other: &($($T,)+)) -> bool {
                     $( ${ignore($T)} self.${index()} == other.${index()} )&&+
@@ -38,7 +39,8 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: Eq),+> Eq for ($($T,)+)
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl<$($T: [const] Eq),+> const Eq for ($($T,)+)
             {}
         }
 
@@ -66,7 +68,8 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl<$($T: [const] PartialOrd),+> const PartialOrd for ($($T,)+)
             {
                 #[inline]
                 fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
@@ -110,7 +113,8 @@ macro_rules! tuple_impls {
         maybe_tuple_doc! {
             $($T)+ @
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: Ord),+> Ord for ($($T,)+)
+            #[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
+            impl<$($T: [const] Ord),+> const Ord for ($($T,)+)
             {
                 #[inline]
                 fn cmp(&self, other: &($($T,)+)) -> Ordering {
diff --git a/library/coretests/tests/cmp.rs b/library/coretests/tests/cmp.rs
index 6c4e2146f91..55e35a4a725 100644
--- a/library/coretests/tests/cmp.rs
+++ b/library/coretests/tests/cmp.rs
@@ -215,19 +215,18 @@ fn cmp_default() {
     assert_eq!(Fool(false), Fool(true));
 }
 
-/* FIXME(#110395)
 mod const_cmp {
     use super::*;
 
     struct S(i32);
 
-    impl PartialEq for S {
+    impl const PartialEq for S {
         fn eq(&self, other: &Self) -> bool {
             self.0 == other.0
         }
     }
 
-    impl PartialOrd for S {
+    impl const PartialOrd for S {
         fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
             let ret = match (self.0, other.0) {
                 (a, b) if a > b => Ordering::Greater,
@@ -247,4 +246,3 @@ mod const_cmp {
     const _: () = assert!(S(0) < S(1));
     const _: () = assert!(S(1) > S(0));
 }
-*/
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 1bdaa6965f6..04fa0aeba65 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -15,6 +15,7 @@
 #![feature(cfg_target_has_reliable_f16_f128)]
 #![feature(char_max_len)]
 #![feature(clone_to_uninit)]
+#![feature(const_cmp)]
 #![feature(const_convert)]
 #![feature(const_destruct)]
 #![feature(const_eval_select)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 97db0d6ab75..5725816c600 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -350,6 +350,7 @@
 #![feature(float_gamma)]
 #![feature(float_minimum_maximum)]
 #![feature(fmt_internals)]
+#![feature(fn_ptr_trait)]
 #![feature(generic_atomic)]
 #![feature(hasher_prefixfree_extras)]
 #![feature(hashmap_internals)]
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 8c115015580..2dbdc8a4e02 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -31,6 +31,7 @@ pub mod process;
 pub mod random;
 pub mod stdio;
 pub mod sync;
+pub mod thread;
 pub mod thread_local;
 
 // FIXME(117276): remove this, move feature implementations into individual
diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs
index f49821657d9..5200eaa5786 100644
--- a/library/std/src/sys/net/connection/socket/hermit.rs
+++ b/library/std/src/sys/net/connection/socket/hermit.rs
@@ -304,7 +304,8 @@ impl Socket {
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
-        unimplemented!()
+        let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
+        if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
     }
 
     // This is used by sys_common code to abstract over Windows and Unix.
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index fb8d69b7375..3ddf6e5acb0 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -25,7 +25,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 pub fn unsupported<T>() -> crate::io::Result<T> {
diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs
index 0fe713a503b..9681964ed9b 100644
--- a/library/std/src/sys/pal/hermit/os.rs
+++ b/library/std/src/sys/pal/hermit/os.rs
@@ -3,7 +3,7 @@ use crate::ffi::{OsStr, OsString};
 use crate::marker::PhantomData;
 use crate::path::{self, PathBuf};
 use crate::sys::unsupported;
-use crate::{fmt, io, str};
+use crate::{fmt, io};
 
 pub fn errno() -> i32 {
     unsafe { hermit_abi::get_errno() }
diff --git a/library/std/src/sys/pal/sgx/abi/mod.rs b/library/std/src/sys/pal/sgx/abi/mod.rs
index 57247cffad3..b8c4d7740c4 100644
--- a/library/std/src/sys/pal/sgx/abi/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/mod.rs
@@ -67,7 +67,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64
     let tls_guard = unsafe { tls.activate() };
 
     if secondary {
-        let join_notifier = super::thread::Thread::entry();
+        let join_notifier = crate::sys::thread::Thread::entry();
         drop(tls_guard);
         drop(join_notifier);
 
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 4a297b6823f..9a33873af58 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -13,7 +13,6 @@ mod libunwind_integration;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod thread_parking;
 pub mod time;
 pub mod waitqueue;
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 0011cf256df..9ca6dc58118 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -10,10 +10,8 @@ pub mod itron {
     pub mod error;
     pub mod spin;
     pub mod task;
-    pub mod thread;
     pub mod thread_parking;
     pub mod time;
-    use super::unsupported;
 }
 
 // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
@@ -22,7 +20,7 @@ pub(crate) mod error;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub use self::itron::{thread, thread_parking};
+pub use self::itron::thread_parking;
 pub mod time;
 
 // SAFETY: must be called only once during runtime initialization.
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index c7b17777258..dd0155265da 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -9,7 +9,6 @@
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 #[allow(non_upper_case_globals)]
 #[path = "../unix/time.rs"]
 pub mod time;
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 8911a2ee519..ebd311db1e1 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -17,7 +17,6 @@ pub mod helpers;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 #[cfg(test)]
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
deleted file mode 100644
index 47a48008c76..00000000000
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use super::unsupported;
-use crate::ffi::CStr;
-use crate::io;
-use crate::num::NonZero;
-use crate::ptr::NonNull;
-use crate::time::{Duration, Instant};
-
-pub struct Thread(!);
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024;
-
-impl Thread {
-    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(
-        _stack: usize,
-        _name: Option<&str>,
-        _p: Box<dyn FnOnce()>,
-    ) -> io::Result<Thread> {
-        unsupported()
-    }
-
-    pub fn yield_now() {
-        // do nothing
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        let boot_services: NonNull<r_efi::efi::BootServices> =
-            crate::os::uefi::env::boot_services().expect("can't sleep").cast();
-        let mut dur_ms = dur.as_micros();
-        // ceil up to the nearest microsecond
-        if dur.subsec_nanos() % 1000 > 0 {
-            dur_ms += 1;
-        }
-
-        while dur_ms > 0 {
-            let ms = crate::cmp::min(dur_ms, usize::MAX as u128);
-            let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) };
-            dur_ms -= ms;
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
-    pub fn join(self) {
-        self.0
-    }
-}
-
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    // UEFI is single threaded
-    Ok(NonZero::new(1).unwrap())
-}
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index ac5c823a1bf..dd1059fe04a 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -17,7 +17,6 @@ pub mod os;
 pub mod pipe;
 pub mod stack_overflow;
 pub mod sync;
-pub mod thread;
 pub mod thread_parking;
 pub mod time;
 
@@ -55,7 +54,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
     // thread-id for the main thread and so renaming the main thread will rename the
     // process and we only want to enable this on platforms we've tested.
     if cfg!(target_vendor = "apple") {
-        thread::Thread::set_name(&c"main");
+        crate::sys::thread::set_name(c"main");
     }
 
     unsafe fn sanitize_standard_fds() {
diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs
index c8cf75b876c..a3b980a3f3d 100644
--- a/library/std/src/sys/pal/unix/weak.rs
+++ b/library/std/src/sys/pal/unix/weak.rs
@@ -22,11 +22,24 @@
 #![allow(dead_code, unused_macros)]
 #![forbid(unsafe_op_in_unsafe_fn)]
 
-use crate::ffi::CStr;
-use crate::marker::PhantomData;
-use crate::sync::atomic::{self, Atomic, AtomicPtr, Ordering};
+use crate::ffi::{CStr, c_char, c_void};
+use crate::marker::{FnPtr, PhantomData};
+use crate::sync::atomic::{Atomic, AtomicPtr, Ordering};
 use crate::{mem, ptr};
 
+// We currently only test `dlsym!`, but that doesn't work on all platforms, so
+// we gate the tests to only the platforms where it is actually used.
+//
+// FIXME(joboet): add more tests, reorganise the whole module and get rid of
+//                `#[allow(dead_code, unused_macros)]`.
+#[cfg(any(
+    target_vendor = "apple",
+    all(target_os = "linux", target_env = "gnu"),
+    target_os = "freebsd",
+))]
+#[cfg(test)]
+mod tests;
+
 // We can use true weak linkage on ELF targets.
 #[cfg(all(unix, not(target_vendor = "apple")))]
 pub(crate) macro weak {
@@ -64,7 +77,7 @@ impl<F: Copy> ExternWeak<F> {
 
 pub(crate) macro dlsym {
     (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
-         dlsym!(
+        dlsym!(
             #[link_name = stringify!($name)]
             fn $name($($param : $t),*) -> $ret;
         );
@@ -73,21 +86,39 @@ pub(crate) macro dlsym {
         #[link_name = $sym:expr]
         fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;
     ) => (
-        static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
-            DlsymWeak::new(concat!($sym, '\0'));
+        static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
+            let Ok(name) = CStr::from_bytes_with_nul(concat!($sym, '\0').as_bytes()) else {
+                panic!("symbol name may not contain NUL")
+            };
+
+            // SAFETY: Whoever calls the function pointer returned by `get()`
+            // is responsible for ensuring that the signature is correct. Just
+            // like with extern blocks, this is syntactically enforced by making
+            // the function pointer be unsafe.
+            unsafe { DlsymWeak::new(name) }
+        };
+
         let $name = &DLSYM;
     )
 }
+
 pub(crate) struct DlsymWeak<F> {
-    name: &'static str,
+    /// A pointer to the nul-terminated name of the symbol.
+    // Use a pointer instead of `&'static CStr` to save space.
+    name: *const c_char,
     func: Atomic<*mut libc::c_void>,
     _marker: PhantomData<F>,
 }
 
-impl<F> DlsymWeak<F> {
-    pub(crate) const fn new(name: &'static str) -> Self {
+impl<F: FnPtr> DlsymWeak<F> {
+    /// # Safety
+    ///
+    /// If the signature of `F` does not match the signature of the symbol (if
+    /// it exists), calling the function pointer returned by `get()` is
+    /// undefined behaviour.
+    pub(crate) const unsafe fn new(name: &'static CStr) -> Self {
         DlsymWeak {
-            name,
+            name: name.as_ptr(),
             func: AtomicPtr::new(ptr::without_provenance_mut(1)),
             _marker: PhantomData,
         }
@@ -95,62 +126,59 @@ impl<F> DlsymWeak<F> {
 
     #[inline]
     pub(crate) fn get(&self) -> Option<F> {
-        unsafe {
-            // Relaxed is fine here because we fence before reading through the
-            // pointer (see the comment below).
-            match self.func.load(Ordering::Relaxed) {
-                func if func.addr() == 1 => self.initialize(),
-                func if func.is_null() => None,
-                func => {
-                    let func = mem::transmute_copy::<*mut libc::c_void, F>(&func);
-                    // The caller is presumably going to read through this value
-                    // (by calling the function we've dlsymed). This means we'd
-                    // need to have loaded it with at least C11's consume
-                    // ordering in order to be guaranteed that the data we read
-                    // from the pointer isn't from before the pointer was
-                    // stored. Rust has no equivalent to memory_order_consume,
-                    // so we use an acquire fence (sorry, ARM).
-                    //
-                    // Now, in practice this likely isn't needed even on CPUs
-                    // where relaxed and consume mean different things. The
-                    // symbols we're loading are probably present (or not) at
-                    // init, and even if they aren't the runtime dynamic loader
-                    // is extremely likely have sufficient barriers internally
-                    // (possibly implicitly, for example the ones provided by
-                    // invoking `mprotect`).
-                    //
-                    // That said, none of that's *guaranteed*, and so we fence.
-                    atomic::fence(Ordering::Acquire);
-                    Some(func)
-                }
-            }
+        // The caller is presumably going to read through this value
+        // (by calling the function we've dlsymed). This means we'd
+        // need to have loaded it with at least C11's consume
+        // ordering in order to be guaranteed that the data we read
+        // from the pointer isn't from before the pointer was
+        // stored. Rust has no equivalent to memory_order_consume,
+        // so we use an acquire load (sorry, ARM).
+        //
+        // Now, in practice this likely isn't needed even on CPUs
+        // where relaxed and consume mean different things. The
+        // symbols we're loading are probably present (or not) at
+        // init, and even if they aren't the runtime dynamic loader
+        // is extremely likely have sufficient barriers internally
+        // (possibly implicitly, for example the ones provided by
+        // invoking `mprotect`).
+        //
+        // That said, none of that's *guaranteed*, so we use acquire.
+        match self.func.load(Ordering::Acquire) {
+            func if func.addr() == 1 => self.initialize(),
+            func if func.is_null() => None,
+            // SAFETY:
+            // `func` is not null and `F` implements `FnPtr`, thus this
+            // transmutation is well-defined. It is the responsibility of the
+            // creator of this `DlsymWeak` to ensure that calling the resulting
+            // function pointer does not result in undefined behaviour (though
+            // the `dlsym!` macro delegates this responsibility to the caller
+            // of the function by using `unsafe` function pointers).
+            // FIXME: use `transmute` once it stops complaining about generics.
+            func => Some(unsafe { mem::transmute_copy::<*mut c_void, F>(&func) }),
         }
     }
 
     // Cold because it should only happen during first-time initialization.
     #[cold]
-    unsafe fn initialize(&self) -> Option<F> {
-        assert_eq!(size_of::<F>(), size_of::<*mut libc::c_void>());
-
-        let val = unsafe { fetch(self.name) };
-        // This synchronizes with the acquire fence in `get`.
+    fn initialize(&self) -> Option<F> {
+        // SAFETY: `self.name` was created from a `&'static CStr` and is
+        // therefore a valid C string pointer.
+        let val = unsafe { libc::dlsym(libc::RTLD_DEFAULT, self.name) };
+        // This synchronizes with the acquire load in `get`.
         self.func.store(val, Ordering::Release);
 
         if val.is_null() {
             None
         } else {
+            // SAFETY: see the comment in `get`.
+            // FIXME: use `transmute` once it stops complaining about generics.
             Some(unsafe { mem::transmute_copy::<*mut libc::c_void, F>(&val) })
         }
     }
 }
 
-unsafe fn fetch(name: &str) -> *mut libc::c_void {
-    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
-        Ok(cstr) => cstr,
-        Err(..) => return ptr::null_mut(),
-    };
-    unsafe { libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) }
-}
+unsafe impl<F> Send for DlsymWeak<F> {}
+unsafe impl<F> Sync for DlsymWeak<F> {}
 
 #[cfg(not(any(target_os = "linux", target_os = "android")))]
 pub(crate) macro syscall {
diff --git a/library/std/src/sys/pal/unix/weak/tests.rs b/library/std/src/sys/pal/unix/weak/tests.rs
new file mode 100644
index 00000000000..d807ba64e35
--- /dev/null
+++ b/library/std/src/sys/pal/unix/weak/tests.rs
@@ -0,0 +1,32 @@
+use super::*;
+
+#[test]
+fn dlsym_existing() {
+    const TEST_STRING: &'static CStr = c"Ferris!";
+
+    // Try to find a symbol that definitely exists.
+    dlsym! {
+        fn strlen(cs: *const c_char) -> usize;
+    }
+
+    dlsym! {
+        #[link_name = "strlen"]
+        fn custom_name(cs: *const c_char) -> usize;
+    }
+
+    let strlen = strlen.get().unwrap();
+    assert_eq!(unsafe { strlen(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes());
+
+    let custom_name = custom_name.get().unwrap();
+    assert_eq!(unsafe { custom_name(TEST_STRING.as_ptr()) }, TEST_STRING.count_bytes());
+}
+
+#[test]
+fn dlsym_missing() {
+    // Try to find a symbol that definitely does not exist.
+    dlsym! {
+        fn test_symbol_that_does_not_exist() -> i32;
+    }
+
+    assert!(test_symbol_that_does_not_exist.get().is_none());
+}
diff --git a/library/std/src/sys/pal/wasip1/mod.rs b/library/std/src/sys/pal/wasip1/mod.rs
index 61dd1c3f98b..ae5da3c1f77 100644
--- a/library/std/src/sys/pal/wasip1/mod.rs
+++ b/library/std/src/sys/pal/wasip1/mod.rs
@@ -20,7 +20,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
diff --git a/library/std/src/sys/pal/wasip1/thread.rs b/library/std/src/sys/pal/wasip1/thread.rs
deleted file mode 100644
index e062b49bd7a..00000000000
--- a/library/std/src/sys/pal/wasip1/thread.rs
+++ /dev/null
@@ -1,214 +0,0 @@
-#![forbid(unsafe_op_in_unsafe_fn)]
-
-use crate::ffi::CStr;
-use crate::num::NonZero;
-use crate::time::{Duration, Instant};
-use crate::{io, mem};
-
-cfg_select! {
-    target_feature = "atomics" => {
-        use crate::cmp;
-        use crate::ptr;
-        use crate::sys::os;
-        // Add a few symbols not in upstream `libc` just yet.
-        mod libc {
-            pub use crate::ffi;
-            pub use libc::*;
-
-            // defined in wasi-libc
-            // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
-            #[repr(C)]
-            union pthread_attr_union {
-                __i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
-                __vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
-                __s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
-            }
-
-            #[repr(C)]
-            pub struct pthread_attr_t {
-                __u: pthread_attr_union,
-            }
-
-            #[allow(non_camel_case_types)]
-            pub type pthread_t = *mut ffi::c_void;
-
-            pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84;
-
-            unsafe extern "C" {
-                pub fn pthread_create(
-                    native: *mut pthread_t,
-                    attr: *const pthread_attr_t,
-                    f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void,
-                    value: *mut ffi::c_void,
-                ) -> ffi::c_int;
-                pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int;
-                pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int;
-                pub fn pthread_attr_setstacksize(
-                    attr: *mut pthread_attr_t,
-                    stack_size: libc::size_t,
-                ) -> ffi::c_int;
-                pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int;
-                pub fn pthread_detach(thread: pthread_t) -> ffi::c_int;
-            }
-        }
-
-        pub struct Thread {
-            id: libc::pthread_t,
-        }
-
-        impl Drop for Thread {
-            fn drop(&mut self) {
-                let ret = unsafe { libc::pthread_detach(self.id) };
-                debug_assert_eq!(ret, 0);
-            }
-        }
-    }
-    _ => {
-        pub struct Thread(!);
-    }
-}
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
-
-impl Thread {
-    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    cfg_select! {
-        target_feature = "atomics" => {
-            pub unsafe fn new(stack: usize, _name: Option<&str>, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-                let p = Box::into_raw(Box::new(p));
-                let mut native: libc::pthread_t = unsafe { mem::zeroed() };
-                let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
-                assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
-
-                let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
-
-                match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } {
-                    0 => {}
-                    n => {
-                        assert_eq!(n, libc::EINVAL);
-                        // EINVAL means |stack_size| is either too small or not a
-                        // multiple of the system page size. Because it's definitely
-                        // >= PTHREAD_STACK_MIN, it must be an alignment issue.
-                        // Round up to the nearest page and try again.
-                        let page_size = os::page_size();
-                        let stack_size =
-                            (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
-                        assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0);
-                    }
-                };
-
-                let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
-                // Note: if the thread creation fails and this assert fails, then p will
-                // be leaked. However, an alternative design could cause double-free
-                // which is clearly worse.
-                assert_eq!(unsafe {libc::pthread_attr_destroy(&mut attr) }, 0);
-
-                return if ret != 0 {
-                    // The thread failed to start and as a result p was not consumed. Therefore, it is
-                    // safe to reconstruct the box so that it gets deallocated.
-                    unsafe { drop(Box::from_raw(p)); }
-                    Err(io::Error::from_raw_os_error(ret))
-                } else {
-                    Ok(Thread { id: native })
-                };
-
-                extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
-                    unsafe {
-                        // Finally, let's run some code.
-                        Box::from_raw(main as *mut Box<dyn FnOnce()>)();
-                    }
-                    ptr::null_mut()
-                }
-            }
-        }
-        _ => {
-            pub unsafe fn new(_stack: usize, _name: Option<&str>, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-                crate::sys::unsupported()
-            }
-        }
-    }
-
-    pub fn yield_now() {
-        let ret = unsafe { wasi::sched_yield() };
-        debug_assert_eq!(ret, Ok(()));
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        let mut nanos = dur.as_nanos();
-        while nanos > 0 {
-            const USERDATA: wasi::Userdata = 0x0123_45678;
-
-            let clock = wasi::SubscriptionClock {
-                id: wasi::CLOCKID_MONOTONIC,
-                timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
-                precision: 0,
-                flags: 0,
-            };
-            nanos -= u128::from(clock.timeout);
-
-            let in_ = wasi::Subscription {
-                userdata: USERDATA,
-                u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
-            };
-            unsafe {
-                let mut event: wasi::Event = mem::zeroed();
-                let res = wasi::poll_oneoff(&in_, &mut event, 1);
-                match (res, event) {
-                    (
-                        Ok(1),
-                        wasi::Event {
-                            userdata: USERDATA,
-                            error: wasi::ERRNO_SUCCESS,
-                            type_: wasi::EVENTTYPE_CLOCK,
-                            ..
-                        },
-                    ) => {}
-                    _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
-                }
-            }
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
-    pub fn join(self) {
-        cfg_select! {
-            target_feature = "atomics" => {
-                let id = mem::ManuallyDrop::new(self).id;
-                let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
-                if ret != 0 {
-                    rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
-                }
-            }
-            _ => {
-                self.0
-            }
-        }
-    }
-}
-
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    cfg_select! {
-        target_feature = "atomics" => {
-            match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-                -1 => Err(io::Error::last_os_error()),
-                cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT),
-            }
-        }
-        _ => crate::sys::unsupported(),
-    }
-}
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 5f3fb6d6ddf..c1d89da2677 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -14,7 +14,6 @@ pub mod futex;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
diff --git a/library/std/src/sys/pal/wasip2/thread.rs b/library/std/src/sys/pal/wasip2/thread.rs
deleted file mode 100644
index ad52918f15a..00000000000
--- a/library/std/src/sys/pal/wasip2/thread.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use crate::ffi::CStr;
-use crate::io;
-use crate::num::NonZero;
-use crate::time::{Duration, Instant};
-
-pub struct Thread(!);
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
-
-impl Thread {
-    pub unsafe fn new(
-        _stack: usize,
-        _name: Option<&str>,
-        _p: Box<dyn FnOnce()>,
-    ) -> io::Result<Thread> {
-        // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled
-        // there is no support for threads, not even experimentally, not even in
-        // wasi-libc. Thus this is unconditionally unsupported.
-        crate::sys::unsupported()
-    }
-
-    pub fn yield_now() {
-        // no API for this in WASIp2, but there's also no threads, so that's
-        // sort of expected.
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is
-        // entirely drained.
-        let mut remaining = dur.as_nanos();
-        while remaining > 0 {
-            let amt = u64::try_from(remaining).unwrap_or(u64::MAX);
-            wasip2::clocks::monotonic_clock::subscribe_duration(amt).block();
-            remaining -= u128::from(amt);
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        match u64::try_from(deadline.into_inner().as_duration().as_nanos()) {
-            // If the point in time we're sleeping to fits within a 64-bit
-            // number of nanoseconds then directly use `subscribe_instant`.
-            Ok(deadline) => {
-                wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block();
-            }
-            // ... otherwise we're sleeping for 500+ years relative to the
-            // "start" of what the system is using as a clock so speed/accuracy
-            // is not so much of a concern. Use `sleep` instead.
-            Err(_) => {
-                let now = Instant::now();
-
-                if let Some(delay) = deadline.checked_duration_since(now) {
-                    Self::sleep(delay);
-                }
-            }
-        }
-    }
-
-    pub fn join(self) {
-        self.0
-    }
-}
-
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    crate::sys::unsupported()
-}
diff --git a/library/std/src/sys/pal/wasip2/time.rs b/library/std/src/sys/pal/wasip2/time.rs
index f1f6839774b..980070e7b85 100644
--- a/library/std/src/sys/pal/wasip2/time.rs
+++ b/library/std/src/sys/pal/wasip2/time.rs
@@ -25,7 +25,7 @@ impl Instant {
         Some(Instant(self.0.checked_sub(*other)?))
     }
 
-    pub(super) fn as_duration(&self) -> &Duration {
+    pub(crate) fn as_duration(&self) -> &Duration {
         &self.0
     }
 }
diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs
deleted file mode 100644
index 42a7dbdf8b8..00000000000
--- a/library/std/src/sys/pal/wasm/atomics/thread.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use crate::ffi::CStr;
-use crate::io;
-use crate::num::NonZero;
-use crate::sys::unsupported;
-use crate::time::{Duration, Instant};
-
-pub struct Thread(!);
-
-pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
-
-impl Thread {
-    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(
-        _stack: usize,
-        _name: Option<&str>,
-        _p: Box<dyn FnOnce()>,
-    ) -> io::Result<Thread> {
-        unsupported()
-    }
-
-    pub fn yield_now() {}
-
-    pub fn set_name(_name: &CStr) {}
-
-    pub fn sleep(dur: Duration) {
-        #[cfg(target_arch = "wasm32")]
-        use core::arch::wasm32 as wasm;
-        #[cfg(target_arch = "wasm64")]
-        use core::arch::wasm64 as wasm;
-
-        use crate::cmp;
-
-        // Use an atomic wait to block the current thread artificially with a
-        // timeout listed. Note that we should never be notified (return value
-        // of 0) or our comparison should never fail (return value of 1) so we
-        // should always only resume execution through a timeout (return value
-        // 2).
-        let mut nanos = dur.as_nanos();
-        while nanos > 0 {
-            let amt = cmp::min(i64::MAX as u128, nanos);
-            let mut x = 0;
-            let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) };
-            debug_assert_eq!(val, 2);
-            nanos -= amt;
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
-    pub fn join(self) {}
-}
-
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsupported()
-}
-
-pub mod guard {
-    pub type Guard = !;
-    pub unsafe fn current() -> Option<Guard> {
-        None
-    }
-    pub unsafe fn init() -> Option<Guard> {
-        None
-    }
-}
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 346c9ff88c9..a20cd0e9ac7 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -23,18 +23,9 @@ pub mod pipe;
 #[path = "../unsupported/time.rs"]
 pub mod time;
 
-cfg_select! {
-    target_feature = "atomics" => {
-        #[path = "atomics/futex.rs"]
-        pub mod futex;
-        #[path = "atomics/thread.rs"]
-        pub mod thread;
-    }
-    _ => {
-        #[path = "../unsupported/thread.rs"]
-        pub mod thread;
-    }
-}
+#[cfg(target_feature = "atomics")]
+#[path = "atomics/futex.rs"]
+pub mod futex;
 
 #[path = "../unsupported/common.rs"]
 #[deny(unsafe_op_in_unsafe_fn)]
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index 3b6a86cbc8f..3357946b8f7 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -20,7 +20,6 @@ pub mod futex;
 pub mod handle;
 pub mod os;
 pub mod pipe;
-pub mod thread;
 pub mod time;
 cfg_select! {
     not(target_vendor = "uwp") => {
@@ -48,9 +47,9 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
     unsafe {
         stack_overflow::init();
 
-        // Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
+        // Normally, `thread::spawn` will call `set_name` but since this thread already
         // exists, we have to call it ourselves.
-        thread::Thread::set_name_wide(wide_str!("main"));
+        crate::sys::thread::set_name_wide(wide_str!("main"));
     }
 }
 
diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs
index a948c07e0a3..f8f9a9fd818 100644
--- a/library/std/src/sys/pal/windows/time.rs
+++ b/library/std/src/sys/pal/windows/time.rs
@@ -232,7 +232,7 @@ mod perf_counter {
 }
 
 /// A timer you can wait on.
-pub(super) struct WaitableTimer {
+pub(crate) struct WaitableTimer {
     handle: c::HANDLE,
 }
 impl WaitableTimer {
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index 042c4ff862f..e673157e0eb 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -5,7 +5,6 @@ use crate::os::xous::ffi::exit;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-pub mod thread;
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index 49e15d65f25..17d99cdb385 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -276,7 +276,9 @@ fn wait(
             // If the managing thread happens to signal and unpark us before we
             // can park ourselves, the result could be this thread never gets
             // unparked. Luckily `park` comes with the guarantee that if it got
-            // an `unpark` just before on an unparked thread it does not park.
+            // an `unpark` just before on an unparked thread it does not park. Crucially, we know
+            // the `unpark` must have happened between the `compare_exchange_weak` above and here,
+            // and there's no other `park` in that code that could steal our token.
             // SAFETY: we retrieved this handle on the current thread above.
             unsafe { node.thread.park() }
         }
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/thread/hermit.rs
index cc4734b6819..4d9f3b114c2 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/thread/hermit.rs
@@ -1,10 +1,5 @@
-#![allow(dead_code)]
-
-use super::hermit_abi;
-use crate::ffi::CStr;
-use crate::mem::ManuallyDrop;
 use crate::num::NonZero;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{io, ptr};
 
 pub type Tid = hermit_abi::Tid;
@@ -68,57 +63,30 @@ impl Thread {
         }
     }
 
-    #[inline]
-    pub fn yield_now() {
-        unsafe {
-            hermit_abi::yield_now();
-        }
-    }
-
-    #[inline]
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    #[inline]
-    pub fn sleep(dur: Duration) {
-        let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
-        let micros = u64::try_from(micros).unwrap_or(u64::MAX);
-
-        unsafe {
-            hermit_abi::usleep(micros);
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         unsafe {
             let _ = hermit_abi::join(self.tid);
         }
     }
+}
 
-    #[inline]
-    pub fn id(&self) -> Tid {
-        self.tid
-    }
-
-    #[inline]
-    pub fn into_id(self) -> Tid {
-        ManuallyDrop::new(self).tid
-    }
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
+#[inline]
+pub fn sleep(dur: Duration) {
+    let micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
+    let micros = u64::try_from(micros).unwrap_or(u64::MAX);
+
+    unsafe {
+        hermit_abi::usleep(micros);
+    }
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
+#[inline]
+pub fn yield_now() {
+    unsafe {
+        hermit_abi::yield_now();
+    }
 }
diff --git a/library/std/src/sys/thread/mod.rs b/library/std/src/sys/thread/mod.rs
new file mode 100644
index 00000000000..6bb7fc1a20e
--- /dev/null
+++ b/library/std/src/sys/thread/mod.rs
@@ -0,0 +1,152 @@
+cfg_select! {
+    target_os = "hermit" => {
+        mod hermit;
+        pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{current_os_id, set_name};
+    }
+    all(target_vendor = "fortanix", target_env = "sgx") => {
+        mod sgx;
+        pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+
+        // SGX should protect in-enclave data from outside attackers, so there
+        // must not be any data leakage to the OS, particularly no 1-1 mapping
+        // between SGX thread names and OS thread names. Hence `set_name` is
+        // intentionally a no-op.
+        //
+        // Note that the internally visible SGX thread name is already provided
+        // by the platform-agnostic Rust thread code. This can be observed in
+        // the [`std::thread::tests::test_named_thread`] test, which succeeds
+        // as-is with the SGX target.
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{available_parallelism, set_name};
+    }
+    target_os = "solid_asp3" => {
+        mod solid;
+        pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{available_parallelism, current_os_id, set_name};
+    }
+    target_os = "teeos" => {
+        mod teeos;
+        pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{available_parallelism, current_os_id, set_name};
+    }
+    target_os = "uefi" => {
+        mod uefi;
+        pub use uefi::{available_parallelism, sleep};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    target_family = "unix" => {
+        mod unix;
+        pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+        #[cfg(not(any(
+            target_env = "newlib",
+            target_os = "l4re",
+            target_os = "emscripten",
+            target_os = "redox",
+            target_os = "hurd",
+            target_os = "aix",
+        )))]
+        pub use unix::set_name;
+        #[cfg(any(
+            target_os = "freebsd",
+            target_os = "netbsd",
+            target_os = "linux",
+            target_os = "android",
+            target_os = "solaris",
+            target_os = "illumos",
+            target_os = "dragonfly",
+            target_os = "hurd",
+            target_os = "fuchsia",
+            target_os = "vxworks",
+        ))]
+        pub use unix::sleep_until;
+        #[expect(dead_code)]
+        mod unsupported;
+        #[cfg(any(
+            target_env = "newlib",
+            target_os = "l4re",
+            target_os = "emscripten",
+            target_os = "redox",
+            target_os = "hurd",
+            target_os = "aix",
+        ))]
+        pub use unsupported::set_name;
+    }
+    all(target_os = "wasi", target_env = "p1") => {
+        mod wasip1;
+        pub use wasip1::{DEFAULT_MIN_STACK_SIZE, sleep, yield_now};
+        #[cfg(target_feature = "atomics")]
+        pub use wasip1::{Thread, available_parallelism};
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{current_os_id, set_name};
+        #[cfg(not(target_feature = "atomics"))]
+        pub use unsupported::{Thread, available_parallelism};
+    }
+    all(target_os = "wasi", target_env = "p2") => {
+        mod wasip2;
+        pub use wasip2::{sleep, sleep_until};
+        #[expect(dead_code)]
+        mod unsupported;
+        // Note that unlike WASIp1 even if the wasm `atomics` feature is enabled
+        // there is no support for threads, not even experimentally, not even in
+        // wasi-libc. Thus this is unconditionally unsupported.
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    all(target_family = "wasm", target_feature = "atomics") => {
+        mod wasm;
+        pub use wasm::sleep;
+
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    target_os = "windows" => {
+        mod windows;
+        pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+    target_os = "xous" => {
+        mod xous;
+        pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+
+        #[expect(dead_code)]
+        mod unsupported;
+        pub use unsupported::{current_os_id, set_name};
+    }
+    _ => {
+        mod unsupported;
+        pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
+    }
+}
+
+#[cfg(not(any(
+    target_os = "freebsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "dragonfly",
+    target_os = "hurd",
+    target_os = "fuchsia",
+    target_os = "vxworks",
+    all(target_os = "wasi", target_env = "p2"),
+)))]
+pub fn sleep_until(deadline: crate::time::Instant) {
+    use crate::time::Instant;
+
+    let now = Instant::now();
+
+    if let Some(delay) = deadline.checked_duration_since(now) {
+        sleep(delay);
+    }
+}
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/thread/sgx.rs
index 1f613badcd7..f20ef7d86b9 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/thread/sgx.rs
@@ -1,11 +1,8 @@
 #![cfg_attr(test, allow(dead_code))] // why is this necessary?
 
-use super::abi::{thread, usercalls};
-use super::unsupported;
-use crate::ffi::CStr;
 use crate::io;
-use crate::num::NonZero;
-use crate::time::{Duration, Instant};
+use crate::sys::pal::abi::{thread, usercalls};
+use crate::time::Duration;
 
 pub struct Thread(task_queue::JoinHandle);
 
@@ -108,51 +105,27 @@ impl Thread {
         Ok(Thread(handle))
     }
 
-    pub(super) fn entry() -> JoinNotifier {
+    pub(crate) fn entry() -> JoinNotifier {
         let mut pending_tasks = task_queue::lock();
         let task = rtunwrap!(Some, pending_tasks.pop());
         drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
         task.run()
     }
 
-    pub fn yield_now() {
-        let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
-        rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
-    }
-
-    /// SGX should protect in-enclave data from the outside (attacker),
-    /// so there should be no data leakage to the OS,
-    /// and therefore also no 1-1 mapping between SGX thread names and OS thread names.
-    ///
-    /// This is why the method is intentionally No-Op.
-    pub fn set_name(_name: &CStr) {
-        // Note that the internally visible SGX thread name is already provided
-        // by the platform-agnostic (target-agnostic) Rust thread code.
-        // This can be observed in the [`std::thread::tests::test_named_thread`] test,
-        // which succeeds as-is with the SGX target.
-    }
-
-    pub fn sleep(dur: Duration) {
-        usercalls::wait_timeout(0, dur, || true);
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         self.0.wait();
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
+pub fn current_os_id() -> Option<u64> {
     Some(thread::current().addr().get() as u64)
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsupported()
+pub fn sleep(dur: Duration) {
+    usercalls::wait_timeout(0, dur, || true);
+}
+
+pub fn yield_now() {
+    let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
+    rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
 }
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/thread/solid.rs
index 4e14cb3cbca..46a84faa802 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/thread/solid.rs
@@ -1,16 +1,14 @@
 //! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
 //! `exd_tsk` are available.
 
-use super::error::{ItronError, expect_success, expect_success_aborting};
-use super::time::dur2reltims;
-use super::{abi, task};
 use crate::cell::UnsafeCell;
-use crate::ffi::CStr;
 use crate::mem::ManuallyDrop;
-use crate::num::NonZero;
 use crate::ptr::NonNull;
 use crate::sync::atomic::{Atomic, AtomicUsize, Ordering};
-use crate::time::{Duration, Instant};
+use crate::sys::pal::itron::error::{ItronError, expect_success, expect_success_aborting};
+use crate::sys::pal::itron::time::dur2reltims;
+use crate::sys::pal::itron::{abi, task};
+use crate::time::Duration;
 use crate::{hint, io};
 
 pub struct Thread {
@@ -195,28 +193,6 @@ impl Thread {
         Ok(Self { p_inner, task: new_task })
     }
 
-    pub fn yield_now() {
-        expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        for timeout in dur2reltims(dur) {
-            expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         // Safety: `ThreadInner` is alive at this point
         let inner = unsafe { self.p_inner.as_ref() };
@@ -361,10 +337,12 @@ unsafe fn terminate_and_delete_current_task() -> ! {
     unsafe { crate::hint::unreachable_unchecked() };
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
+pub fn yield_now() {
+    expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    super::unsupported()
+pub fn sleep(dur: Duration) {
+    for timeout in dur2reltims(dur) {
+        expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
+    }
 }
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/thread/teeos.rs
index 1812d11e692..cad100395c9 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/thread/teeos.rs
@@ -1,12 +1,18 @@
-use crate::ffi::CStr;
 use crate::mem::{self, ManuallyDrop};
-use crate::num::NonZero;
 use crate::sys::os;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{cmp, io, ptr};
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
 
+unsafe extern "C" {
+    safe fn TEE_Wait(timeout: u32) -> u32;
+}
+
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+    libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
+}
+
 pub struct Thread {
     id: libc::pthread_t,
 }
@@ -16,10 +22,6 @@ pub struct Thread {
 unsafe impl Send for Thread {}
 unsafe impl Sync for Thread {}
 
-unsafe extern "C" {
-    pub fn TEE_Wait(timeout: u32) -> u32;
-}
-
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(
@@ -74,7 +76,7 @@ impl Thread {
         } else {
             // The new thread will start running earliest after the next yield.
             // We add a yield here, so that the user does not have to.
-            Thread::yield_now();
+            yield_now();
             Ok(Thread { id: native })
         };
 
@@ -91,36 +93,6 @@ impl Thread {
         }
     }
 
-    pub fn yield_now() {
-        let ret = unsafe { libc::sched_yield() };
-        debug_assert_eq!(ret, 0);
-    }
-
-    /// This does not do anything on teeos
-    pub fn set_name(_name: &CStr) {
-        // Both pthread_setname_np and prctl are not available to the TA,
-        // so we can't implement this currently. If the need arises please
-        // contact the teeos rustzone team.
-    }
-
-    /// only main thread could wait for sometime in teeos
-    pub fn sleep(dur: Duration) {
-        let sleep_millis = dur.as_millis();
-        let final_sleep: u32 =
-            if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
-        unsafe {
-            let _ = TEE_Wait(final_sleep);
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     /// must join, because no pthread_detach supported
     pub fn join(self) {
         let id = self.into_id();
@@ -128,10 +100,6 @@ impl Thread {
         assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
     }
 
-    pub fn id(&self) -> libc::pthread_t {
-        self.id
-    }
-
     pub fn into_id(self) -> libc::pthread_t {
         ManuallyDrop::new(self).id
     }
@@ -144,16 +112,15 @@ impl Drop for Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
-// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
-// teeos, so this function always returns an Error!
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    Err(io::Error::UNKNOWN_THREAD_COUNT)
+pub fn yield_now() {
+    let ret = unsafe { libc::sched_yield() };
+    debug_assert_eq!(ret, 0);
 }
 
-fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
-    libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
+/// only main thread could wait for sometime in teeos
+pub fn sleep(dur: Duration) {
+    let sleep_millis = dur.as_millis();
+    let final_sleep: u32 =
+        if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
+    TEE_Wait(final_sleep);
 }
diff --git a/library/std/src/sys/thread/uefi.rs b/library/std/src/sys/thread/uefi.rs
new file mode 100644
index 00000000000..94f67d7ace2
--- /dev/null
+++ b/library/std/src/sys/thread/uefi.rs
@@ -0,0 +1,25 @@
+use crate::io;
+use crate::num::NonZero;
+use crate::ptr::NonNull;
+use crate::time::Duration;
+
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    // UEFI is single threaded
+    Ok(NonZero::new(1).unwrap())
+}
+
+pub fn sleep(dur: Duration) {
+    let boot_services: NonNull<r_efi::efi::BootServices> =
+        crate::os::uefi::env::boot_services().expect("can't sleep").cast();
+    let mut dur_ms = dur.as_micros();
+    // ceil up to the nearest microsecond
+    if dur.subsec_nanos() % 1000 > 0 {
+        dur_ms += 1;
+    }
+
+    while dur_ms > 0 {
+        let ms = crate::cmp::min(dur_ms, usize::MAX as u128);
+        let _ = unsafe { ((*boot_services.as_ptr()).stall)(ms as usize) };
+        dur_ms -= ms;
+    }
+}
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/thread/unix.rs
index 3389b8c0c8a..2d2c4f90212 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/thread/unix.rs
@@ -1,3 +1,11 @@
+#[cfg(not(any(
+    target_env = "newlib",
+    target_os = "l4re",
+    target_os = "emscripten",
+    target_os = "redox",
+    target_os = "hurd",
+    target_os = "aix",
+)))]
 use crate::ffi::CStr;
 use crate::mem::{self, ManuallyDrop};
 use crate::num::NonZero;
@@ -6,7 +14,7 @@ use crate::sys::weak::dlsym;
 #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto",))]
 use crate::sys::weak::weak;
 use crate::sys::{os, stack_overflow};
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{cmp, io, ptr};
 #[cfg(not(any(
     target_os = "l4re",
@@ -121,273 +129,6 @@ impl Thread {
         }
     }
 
-    pub fn yield_now() {
-        let ret = unsafe { libc::sched_yield() };
-        debug_assert_eq!(ret, 0);
-    }
-
-    #[cfg(target_os = "android")]
-    pub fn set_name(name: &CStr) {
-        const PR_SET_NAME: libc::c_int = 15;
-        unsafe {
-            let res = libc::prctl(
-                PR_SET_NAME,
-                name.as_ptr(),
-                0 as libc::c_ulong,
-                0 as libc::c_ulong,
-                0 as libc::c_ulong,
-            );
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(any(
-        target_os = "linux",
-        target_os = "freebsd",
-        target_os = "dragonfly",
-        target_os = "nuttx",
-        target_os = "cygwin"
-    ))]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            cfg_select! {
-                any(target_os = "linux", target_os = "cygwin") => {
-                    // Linux and Cygwin limits the allowed length of the name.
-                    const TASK_COMM_LEN: usize = 16;
-                    let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
-                }
-                _ => {
-                    // FreeBSD, DragonFly BSD and NuttX do not enforce length limits.
-                }
-            };
-            // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux,
-            // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0.
-            let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(target_os = "openbsd")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
-        }
-    }
-
-    #[cfg(target_vendor = "apple")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
-            let res = libc::pthread_setname_np(name.as_ptr());
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(target_os = "netbsd")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            let res = libc::pthread_setname_np(
-                libc::pthread_self(),
-                c"%s".as_ptr(),
-                name.as_ptr() as *mut libc::c_void,
-            );
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
-    pub fn set_name(name: &CStr) {
-        weak!(
-            fn pthread_setname_np(
-                thread: libc::pthread_t,
-                name: *const libc::c_char,
-            ) -> libc::c_int;
-        );
-
-        if let Some(f) = pthread_setname_np.get() {
-            #[cfg(target_os = "nto")]
-            const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
-            #[cfg(any(target_os = "solaris", target_os = "illumos"))]
-            const THREAD_NAME_MAX: usize = 32;
-
-            let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
-            let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
-            debug_assert_eq!(res, 0);
-        }
-    }
-
-    #[cfg(target_os = "fuchsia")]
-    pub fn set_name(name: &CStr) {
-        use super::fuchsia::*;
-        unsafe {
-            zx_object_set_property(
-                zx_thread_self(),
-                ZX_PROP_NAME,
-                name.as_ptr() as *const libc::c_void,
-                name.to_bytes().len(),
-            );
-        }
-    }
-
-    #[cfg(target_os = "haiku")]
-    pub fn set_name(name: &CStr) {
-        unsafe {
-            let thread_self = libc::find_thread(ptr::null_mut());
-            let res = libc::rename_thread(thread_self, name.as_ptr());
-            // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
-            debug_assert_eq!(res, libc::B_OK);
-        }
-    }
-
-    #[cfg(target_os = "vxworks")]
-    pub fn set_name(name: &CStr) {
-        let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name);
-        let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
-        debug_assert_eq!(res, libc::OK);
-    }
-
-    #[cfg(any(
-        target_env = "newlib",
-        target_os = "l4re",
-        target_os = "emscripten",
-        target_os = "redox",
-        target_os = "hurd",
-        target_os = "aix",
-    ))]
-    pub fn set_name(_name: &CStr) {
-        // Newlib and Emscripten have no way to set a thread name.
-    }
-
-    #[cfg(not(target_os = "espidf"))]
-    pub fn sleep(dur: Duration) {
-        let mut secs = dur.as_secs();
-        let mut nsecs = dur.subsec_nanos() as _;
-
-        // If we're awoken with a signal then the return value will be -1 and
-        // nanosleep will fill in `ts` with the remaining time.
-        unsafe {
-            while secs > 0 || nsecs > 0 {
-                let mut ts = libc::timespec {
-                    tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
-                    tv_nsec: nsecs,
-                };
-                secs -= ts.tv_sec as u64;
-                let ts_ptr = &raw mut ts;
-                if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
-                    assert_eq!(os::errno(), libc::EINTR);
-                    secs += ts.tv_sec as u64;
-                    nsecs = ts.tv_nsec;
-                } else {
-                    nsecs = 0;
-                }
-            }
-        }
-    }
-
-    #[cfg(target_os = "espidf")]
-    pub fn sleep(dur: Duration) {
-        // ESP-IDF does not have `nanosleep`, so we use `usleep` instead.
-        // As per the documentation of `usleep`, it is expected to support
-        // sleep times as big as at least up to 1 second.
-        //
-        // ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its
-        // `usleep` implementation
-        // (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210),
-        // we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow
-        // (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default).
-        const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1;
-
-        // Add any nanoseconds smaller than a microsecond as an extra microsecond
-        // so as to comply with the `std::thread::sleep` contract which mandates
-        // implementations to sleep for _at least_ the provided `dur`.
-        // We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of
-        // (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second
-        // (i.e. < 1_000_000_000)
-        let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
-
-        while micros > 0 {
-            let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 };
-            unsafe {
-                libc::usleep(st);
-            }
-
-            micros -= st as u128;
-        }
-    }
-
-    // Any unix that has clock_nanosleep
-    // If this list changes update the MIRI chock_nanosleep shim
-    #[cfg(any(
-        target_os = "freebsd",
-        target_os = "netbsd",
-        target_os = "linux",
-        target_os = "android",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "dragonfly",
-        target_os = "hurd",
-        target_os = "fuchsia",
-        target_os = "vxworks",
-    ))]
-    pub fn sleep_until(deadline: Instant) {
-        let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else {
-            // The deadline is further in the future then can be passed to
-            // clock_nanosleep. We have to use Self::sleep instead. This might
-            // happen on 32 bit platforms, especially closer to 2038.
-            let now = Instant::now();
-            if let Some(delay) = deadline.checked_duration_since(now) {
-                Self::sleep(delay);
-            }
-            return;
-        };
-
-        unsafe {
-            // When we get interrupted (res = EINTR) call clock_nanosleep again
-            loop {
-                let res = libc::clock_nanosleep(
-                    super::time::Instant::CLOCK_ID,
-                    libc::TIMER_ABSTIME,
-                    &ts,
-                    core::ptr::null_mut(), // not required with TIMER_ABSTIME
-                );
-
-                if res == 0 {
-                    break;
-                } else {
-                    assert_eq!(
-                        res,
-                        libc::EINTR,
-                        "timespec is in range,
-                         clockid is valid and kernel should support it"
-                    );
-                }
-            }
-        }
-    }
-
-    // Any unix that does not have clock_nanosleep
-    #[cfg(not(any(
-        target_os = "freebsd",
-        target_os = "netbsd",
-        target_os = "linux",
-        target_os = "android",
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "dragonfly",
-        target_os = "hurd",
-        target_os = "fuchsia",
-        target_os = "vxworks",
-    )))]
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         let id = self.into_id();
         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
@@ -410,84 +151,6 @@ impl Drop for Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    // Most Unix platforms have a way to query an integer ID of the current thread, all with
-    // slightly different spellings.
-    //
-    // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
-    // for process inspection (debuggers, trace, `top`, etc.).
-    cfg_select! {
-        // Most platforms have a function returning a `pid_t` or int, which is an `i32`.
-        any(target_os = "android", target_os = "linux") => {
-            use crate::sys::weak::syscall;
-
-            // `libc::gettid` is only available on glibc 2.30+, but the syscall is available
-            // since Linux 2.4.11.
-            syscall!(fn gettid() -> libc::pid_t;);
-
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pid_t = unsafe { gettid() };
-            Some(id as u64)
-        }
-        target_os = "nto" => {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pid_t = unsafe { libc::gettid() };
-            Some(id as u64)
-        }
-        target_os = "openbsd" => {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pid_t = unsafe { libc::getthrid() };
-            Some(id as u64)
-        }
-        target_os = "freebsd" => {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
-            Some(id as u64)
-        }
-        target_os = "netbsd" => {
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
-            Some(id as u64)
-        }
-        any(target_os = "illumos", target_os = "solaris") => {
-            // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
-            // SAFETY: FFI call with no preconditions.
-            let id: libc::pthread_t = unsafe { libc::pthread_self() };
-            Some(id as u64)
-        }
-        target_vendor = "apple" => {
-            // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
-            let mut id = 0u64;
-            // SAFETY: `thread_id` is a valid pointer, no other preconditions.
-            let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
-            if status == 0 {
-                Some(id)
-            } else {
-                None
-            }
-        }
-        // Other platforms don't have an OS thread ID or don't have a way to access it.
-        _ => None,
-    }
-}
-
-#[cfg(any(
-    target_os = "linux",
-    target_os = "nto",
-    target_os = "solaris",
-    target_os = "illumos",
-    target_os = "vxworks",
-    target_os = "cygwin",
-    target_vendor = "apple",
-))]
-fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
-    let mut result = [0; MAX_WITH_NUL];
-    for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
-        *dst = *src as libc::c_char;
-    }
-    result
-}
-
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     cfg_select! {
         any(
@@ -668,6 +331,318 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     }
 }
 
+pub fn current_os_id() -> Option<u64> {
+    // Most Unix platforms have a way to query an integer ID of the current thread, all with
+    // slightly different spellings.
+    //
+    // The OS thread ID is used rather than `pthread_self` so as to match what will be displayed
+    // for process inspection (debuggers, trace, `top`, etc.).
+    cfg_select! {
+        // Most platforms have a function returning a `pid_t` or int, which is an `i32`.
+        any(target_os = "android", target_os = "linux") => {
+            use crate::sys::pal::weak::syscall;
+
+            // `libc::gettid` is only available on glibc 2.30+, but the syscall is available
+            // since Linux 2.4.11.
+            syscall!(fn gettid() -> libc::pid_t;);
+
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { gettid() };
+            Some(id as u64)
+        }
+        target_os = "nto" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::gettid() };
+            Some(id as u64)
+        }
+        target_os = "openbsd" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::getthrid() };
+            Some(id as u64)
+        }
+        target_os = "freebsd" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
+            Some(id as u64)
+        }
+        target_os = "netbsd" => {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
+            Some(id as u64)
+        }
+        any(target_os = "illumos", target_os = "solaris") => {
+            // On Illumos and Solaris, the `pthread_t` is the same as the OS thread ID.
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pthread_t = unsafe { libc::pthread_self() };
+            Some(id as u64)
+        }
+        target_vendor = "apple" => {
+            // Apple allows querying arbitrary thread IDs, `thread=NULL` queries the current thread.
+            let mut id = 0u64;
+            // SAFETY: `thread_id` is a valid pointer, no other preconditions.
+            let status: libc::c_int = unsafe { libc::pthread_threadid_np(0, &mut id) };
+            if status == 0 {
+                Some(id)
+            } else {
+                None
+            }
+        }
+        // Other platforms don't have an OS thread ID or don't have a way to access it.
+        _ => None,
+    }
+}
+
+#[cfg(any(
+    target_os = "linux",
+    target_os = "nto",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "vxworks",
+    target_os = "cygwin",
+    target_vendor = "apple",
+))]
+fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
+    let mut result = [0; MAX_WITH_NUL];
+    for (src, dst) in cstr.to_bytes().iter().zip(&mut result[..MAX_WITH_NUL - 1]) {
+        *dst = *src as libc::c_char;
+    }
+    result
+}
+
+#[cfg(target_os = "android")]
+pub fn set_name(name: &CStr) {
+    const PR_SET_NAME: libc::c_int = 15;
+    unsafe {
+        let res = libc::prctl(
+            PR_SET_NAME,
+            name.as_ptr(),
+            0 as libc::c_ulong,
+            0 as libc::c_ulong,
+            0 as libc::c_ulong,
+        );
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(any(
+    target_os = "linux",
+    target_os = "freebsd",
+    target_os = "dragonfly",
+    target_os = "nuttx",
+    target_os = "cygwin"
+))]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        cfg_select! {
+            any(target_os = "linux", target_os = "cygwin") => {
+                // Linux and Cygwin limits the allowed length of the name.
+                const TASK_COMM_LEN: usize = 16;
+                let name = truncate_cstr::<{ TASK_COMM_LEN }>(name);
+            }
+            _ => {
+                // FreeBSD, DragonFly BSD and NuttX do not enforce length limits.
+            }
+        };
+        // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20 for Linux,
+        // FreeBSD 12.2 and 13.0, and DragonFly BSD 6.0.
+        let res = libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(target_os = "openbsd")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
+    }
+}
+
+#[cfg(target_vendor = "apple")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        let name = truncate_cstr::<{ libc::MAXTHREADNAMESIZE }>(name);
+        let res = libc::pthread_setname_np(name.as_ptr());
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(target_os = "netbsd")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        let res = libc::pthread_setname_np(
+            libc::pthread_self(),
+            c"%s".as_ptr(),
+            name.as_ptr() as *mut libc::c_void,
+        );
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
+pub fn set_name(name: &CStr) {
+    weak!(
+        fn pthread_setname_np(thread: libc::pthread_t, name: *const libc::c_char) -> libc::c_int;
+    );
+
+    if let Some(f) = pthread_setname_np.get() {
+        #[cfg(target_os = "nto")]
+        const THREAD_NAME_MAX: usize = libc::_NTO_THREAD_NAME_MAX as usize;
+        #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+        const THREAD_NAME_MAX: usize = 32;
+
+        let name = truncate_cstr::<{ THREAD_NAME_MAX }>(name);
+        let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
+        debug_assert_eq!(res, 0);
+    }
+}
+
+#[cfg(target_os = "fuchsia")]
+pub fn set_name(name: &CStr) {
+    use crate::sys::pal::fuchsia::*;
+    unsafe {
+        zx_object_set_property(
+            zx_thread_self(),
+            ZX_PROP_NAME,
+            name.as_ptr() as *const libc::c_void,
+            name.to_bytes().len(),
+        );
+    }
+}
+
+#[cfg(target_os = "haiku")]
+pub fn set_name(name: &CStr) {
+    unsafe {
+        let thread_self = libc::find_thread(ptr::null_mut());
+        let res = libc::rename_thread(thread_self, name.as_ptr());
+        // We have no good way of propagating errors here, but in debug-builds let's check that this actually worked.
+        debug_assert_eq!(res, libc::B_OK);
+    }
+}
+
+#[cfg(target_os = "vxworks")]
+pub fn set_name(name: &CStr) {
+    let mut name = truncate_cstr::<{ (libc::VX_TASK_RENAME_LENGTH - 1) as usize }>(name);
+    let res = unsafe { libc::taskNameSet(libc::taskIdSelf(), name.as_mut_ptr()) };
+    debug_assert_eq!(res, libc::OK);
+}
+
+#[cfg(not(target_os = "espidf"))]
+pub fn sleep(dur: Duration) {
+    let mut secs = dur.as_secs();
+    let mut nsecs = dur.subsec_nanos() as _;
+
+    // If we're awoken with a signal then the return value will be -1 and
+    // nanosleep will fill in `ts` with the remaining time.
+    unsafe {
+        while secs > 0 || nsecs > 0 {
+            let mut ts = libc::timespec {
+                tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t,
+                tv_nsec: nsecs,
+            };
+            secs -= ts.tv_sec as u64;
+            let ts_ptr = &raw mut ts;
+            if libc::nanosleep(ts_ptr, ts_ptr) == -1 {
+                assert_eq!(os::errno(), libc::EINTR);
+                secs += ts.tv_sec as u64;
+                nsecs = ts.tv_nsec;
+            } else {
+                nsecs = 0;
+            }
+        }
+    }
+}
+
+#[cfg(target_os = "espidf")]
+pub fn sleep(dur: Duration) {
+    // ESP-IDF does not have `nanosleep`, so we use `usleep` instead.
+    // As per the documentation of `usleep`, it is expected to support
+    // sleep times as big as at least up to 1 second.
+    //
+    // ESP-IDF does support almost up to `u32::MAX`, but due to a potential integer overflow in its
+    // `usleep` implementation
+    // (https://github.com/espressif/esp-idf/blob/d7ca8b94c852052e3bc33292287ef4dd62c9eeb1/components/newlib/time.c#L210),
+    // we limit the sleep time to the maximum one that would not cause the underlying `usleep` implementation to overflow
+    // (`portTICK_PERIOD_MS` can be anything between 1 to 1000, and is 10 by default).
+    const MAX_MICROS: u32 = u32::MAX - 1_000_000 - 1;
+
+    // Add any nanoseconds smaller than a microsecond as an extra microsecond
+    // so as to comply with the `std::thread::sleep` contract which mandates
+    // implementations to sleep for _at least_ the provided `dur`.
+    // We can't overflow `micros` as it is a `u128`, while `Duration` is a pair of
+    // (`u64` secs, `u32` nanos), where the nanos are strictly smaller than 1 second
+    // (i.e. < 1_000_000_000)
+    let mut micros = dur.as_micros() + if dur.subsec_nanos() % 1_000 > 0 { 1 } else { 0 };
+
+    while micros > 0 {
+        let st = if micros > MAX_MICROS as u128 { MAX_MICROS } else { micros as u32 };
+        unsafe {
+            libc::usleep(st);
+        }
+
+        micros -= st as u128;
+    }
+}
+
+// Any unix that has clock_nanosleep
+// If this list changes update the MIRI chock_nanosleep shim
+#[cfg(any(
+    target_os = "freebsd",
+    target_os = "netbsd",
+    target_os = "linux",
+    target_os = "android",
+    target_os = "solaris",
+    target_os = "illumos",
+    target_os = "dragonfly",
+    target_os = "hurd",
+    target_os = "fuchsia",
+    target_os = "vxworks",
+))]
+pub fn sleep_until(deadline: crate::time::Instant) {
+    use crate::time::Instant;
+
+    let Some(ts) = deadline.into_inner().into_timespec().to_timespec() else {
+        // The deadline is further in the future then can be passed to
+        // clock_nanosleep. We have to use Self::sleep instead. This might
+        // happen on 32 bit platforms, especially closer to 2038.
+        let now = Instant::now();
+        if let Some(delay) = deadline.checked_duration_since(now) {
+            sleep(delay);
+        }
+        return;
+    };
+
+    unsafe {
+        // When we get interrupted (res = EINTR) call clock_nanosleep again
+        loop {
+            let res = libc::clock_nanosleep(
+                crate::sys::time::Instant::CLOCK_ID,
+                libc::TIMER_ABSTIME,
+                &ts,
+                core::ptr::null_mut(), // not required with TIMER_ABSTIME
+            );
+
+            if res == 0 {
+                break;
+            } else {
+                assert_eq!(
+                    res,
+                    libc::EINTR,
+                    "timespec is in range,
+                         clockid is valid and kernel should support it"
+                );
+            }
+        }
+    }
+}
+
+pub fn yield_now() {
+    let ret = unsafe { libc::sched_yield() };
+    debug_assert_eq!(ret, 0);
+}
+
 #[cfg(any(target_os = "android", target_os = "linux"))]
 mod cgroups {
     //! Currently not covered
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/thread/unsupported.rs
index 34d9b5ec70c..a5001efa3b4 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/thread/unsupported.rs
@@ -1,8 +1,7 @@
-use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 
 pub struct Thread(!);
 
@@ -15,23 +14,7 @@ impl Thread {
         _name: Option<&str>,
         _p: Box<dyn FnOnce()>,
     ) -> io::Result<Thread> {
-        unsupported()
-    }
-
-    pub fn yield_now() {
-        // do nothing
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(_dur: Duration) {
-        panic!("can't sleep");
-    }
-
-    pub fn sleep_until(_deadline: Instant) {
-        panic!("can't sleep");
+        Err(io::Error::UNSUPPORTED_PLATFORM)
     }
 
     pub fn join(self) {
@@ -39,10 +22,22 @@ impl Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    Err(io::Error::UNKNOWN_THREAD_COUNT)
+}
+
+pub fn current_os_id() -> Option<u64> {
     None
 }
 
-pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsupported()
+pub fn yield_now() {
+    // do nothing
+}
+
+pub fn set_name(_name: &CStr) {
+    // nope
+}
+
+pub fn sleep(_dur: Duration) {
+    panic!("can't sleep");
 }
diff --git a/library/std/src/sys/thread/wasip1.rs b/library/std/src/sys/thread/wasip1.rs
new file mode 100644
index 00000000000..83001fad49c
--- /dev/null
+++ b/library/std/src/sys/thread/wasip1.rs
@@ -0,0 +1,185 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
+#[cfg(target_feature = "atomics")]
+use crate::io;
+use crate::mem;
+#[cfg(target_feature = "atomics")]
+use crate::num::NonZero;
+#[cfg(target_feature = "atomics")]
+use crate::sys::os;
+use crate::time::Duration;
+#[cfg(target_feature = "atomics")]
+use crate::{cmp, ptr};
+
+// Add a few symbols not in upstream `libc` just yet.
+#[cfg(target_feature = "atomics")]
+mod libc {
+    pub use libc::*;
+
+    pub use crate::ffi;
+
+    // defined in wasi-libc
+    // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108
+    #[repr(C)]
+    union pthread_attr_union {
+        __i: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
+        __vi: [ffi::c_int; if size_of::<ffi::c_long>() == 8 { 14 } else { 9 }],
+        __s: [ffi::c_ulong; if size_of::<ffi::c_long>() == 8 { 7 } else { 9 }],
+    }
+
+    #[repr(C)]
+    pub struct pthread_attr_t {
+        __u: pthread_attr_union,
+    }
+
+    #[allow(non_camel_case_types)]
+    pub type pthread_t = *mut ffi::c_void;
+
+    pub const _SC_NPROCESSORS_ONLN: ffi::c_int = 84;
+
+    unsafe extern "C" {
+        pub fn pthread_create(
+            native: *mut pthread_t,
+            attr: *const pthread_attr_t,
+            f: extern "C" fn(*mut ffi::c_void) -> *mut ffi::c_void,
+            value: *mut ffi::c_void,
+        ) -> ffi::c_int;
+        pub fn pthread_join(native: pthread_t, value: *mut *mut ffi::c_void) -> ffi::c_int;
+        pub fn pthread_attr_init(attrp: *mut pthread_attr_t) -> ffi::c_int;
+        pub fn pthread_attr_setstacksize(
+            attr: *mut pthread_attr_t,
+            stack_size: libc::size_t,
+        ) -> ffi::c_int;
+        pub fn pthread_attr_destroy(attr: *mut pthread_attr_t) -> ffi::c_int;
+        pub fn pthread_detach(thread: pthread_t) -> ffi::c_int;
+    }
+}
+
+#[cfg(target_feature = "atomics")]
+pub struct Thread {
+    id: libc::pthread_t,
+}
+
+#[cfg(target_feature = "atomics")]
+impl Drop for Thread {
+    fn drop(&mut self) {
+        let ret = unsafe { libc::pthread_detach(self.id) };
+        debug_assert_eq!(ret, 0);
+    }
+}
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
+
+#[cfg(target_feature = "atomics")]
+impl Thread {
+    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+    pub unsafe fn new(
+        stack: usize,
+        _name: Option<&str>,
+        p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
+        let p = Box::into_raw(Box::new(p));
+        let mut native: libc::pthread_t = unsafe { mem::zeroed() };
+        let mut attr: libc::pthread_attr_t = unsafe { mem::zeroed() };
+        assert_eq!(unsafe { libc::pthread_attr_init(&mut attr) }, 0);
+
+        let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
+
+        match unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) } {
+            0 => {}
+            n => {
+                assert_eq!(n, libc::EINVAL);
+                // EINVAL means |stack_size| is either too small or not a
+                // multiple of the system page size. Because it's definitely
+                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
+                // Round up to the nearest page and try again.
+                let page_size = os::page_size();
+                let stack_size =
+                    (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
+                assert_eq!(unsafe { libc::pthread_attr_setstacksize(&mut attr, stack_size) }, 0);
+            }
+        };
+
+        let ret = unsafe { libc::pthread_create(&mut native, &attr, thread_start, p as *mut _) };
+        // Note: if the thread creation fails and this assert fails, then p will
+        // be leaked. However, an alternative design could cause double-free
+        // which is clearly worse.
+        assert_eq!(unsafe { libc::pthread_attr_destroy(&mut attr) }, 0);
+
+        return if ret != 0 {
+            // The thread failed to start and as a result p was not consumed. Therefore, it is
+            // safe to reconstruct the box so that it gets deallocated.
+            unsafe {
+                drop(Box::from_raw(p));
+            }
+            Err(io::Error::from_raw_os_error(ret))
+        } else {
+            Ok(Thread { id: native })
+        };
+
+        extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+            unsafe {
+                // Finally, let's run some code.
+                Box::from_raw(main as *mut Box<dyn FnOnce()>)();
+            }
+            ptr::null_mut()
+        }
+    }
+
+    pub fn join(self) {
+        let id = mem::ManuallyDrop::new(self).id;
+        let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
+        if ret != 0 {
+            rtabort!("failed to join thread: {}", io::Error::from_raw_os_error(ret));
+        }
+    }
+}
+
+#[cfg(target_feature = "atomics")]
+pub fn available_parallelism() -> io::Result<NonZero<usize>> {
+    match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
+        -1 => Err(io::Error::last_os_error()),
+        cpus => NonZero::new(cpus as usize).ok_or(io::Error::UNKNOWN_THREAD_COUNT),
+    }
+}
+
+pub fn yield_now() {
+    let ret = unsafe { wasi::sched_yield() };
+    debug_assert_eq!(ret, Ok(()));
+}
+
+pub fn sleep(dur: Duration) {
+    let mut nanos = dur.as_nanos();
+    while nanos > 0 {
+        const USERDATA: wasi::Userdata = 0x0123_45678;
+
+        let clock = wasi::SubscriptionClock {
+            id: wasi::CLOCKID_MONOTONIC,
+            timeout: u64::try_from(nanos).unwrap_or(u64::MAX),
+            precision: 0,
+            flags: 0,
+        };
+        nanos -= u128::from(clock.timeout);
+
+        let in_ = wasi::Subscription {
+            userdata: USERDATA,
+            u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
+        };
+        unsafe {
+            let mut event: wasi::Event = mem::zeroed();
+            let res = wasi::poll_oneoff(&in_, &mut event, 1);
+            match (res, event) {
+                (
+                    Ok(1),
+                    wasi::Event {
+                        userdata: USERDATA,
+                        error: wasi::ERRNO_SUCCESS,
+                        type_: wasi::EVENTTYPE_CLOCK,
+                        ..
+                    },
+                ) => {}
+                _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/thread/wasip2.rs b/library/std/src/sys/thread/wasip2.rs
new file mode 100644
index 00000000000..420cad2a5e4
--- /dev/null
+++ b/library/std/src/sys/thread/wasip2.rs
@@ -0,0 +1,32 @@
+use crate::time::{Duration, Instant};
+
+pub fn sleep(dur: Duration) {
+    // Sleep in increments of `u64::MAX` nanoseconds until the `dur` is
+    // entirely drained.
+    let mut remaining = dur.as_nanos();
+    while remaining > 0 {
+        let amt = u64::try_from(remaining).unwrap_or(u64::MAX);
+        wasip2::clocks::monotonic_clock::subscribe_duration(amt).block();
+        remaining -= u128::from(amt);
+    }
+}
+
+pub fn sleep_until(deadline: Instant) {
+    match u64::try_from(deadline.into_inner().as_duration().as_nanos()) {
+        // If the point in time we're sleeping to fits within a 64-bit
+        // number of nanoseconds then directly use `subscribe_instant`.
+        Ok(deadline) => {
+            wasip2::clocks::monotonic_clock::subscribe_instant(deadline).block();
+        }
+        // ... otherwise we're sleeping for 500+ years relative to the
+        // "start" of what the system is using as a clock so speed/accuracy
+        // is not so much of a concern. Use `sleep` instead.
+        Err(_) => {
+            let now = Instant::now();
+
+            if let Some(delay) = deadline.checked_duration_since(now) {
+                sleep(delay);
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/thread/wasm.rs b/library/std/src/sys/thread/wasm.rs
new file mode 100644
index 00000000000..e843bc992ba
--- /dev/null
+++ b/library/std/src/sys/thread/wasm.rs
@@ -0,0 +1,23 @@
+use crate::cmp;
+use crate::time::Duration;
+
+pub fn sleep(dur: Duration) {
+    #[cfg(target_arch = "wasm32")]
+    use core::arch::wasm32 as wasm;
+    #[cfg(target_arch = "wasm64")]
+    use core::arch::wasm64 as wasm;
+
+    // Use an atomic wait to block the current thread artificially with a
+    // timeout listed. Note that we should never be notified (return value
+    // of 0) or our comparison should never fail (return value of 1) so we
+    // should always only resume execution through a timeout (return value
+    // 2).
+    let mut nanos = dur.as_nanos();
+    while nanos > 0 {
+        let amt = cmp::min(i64::MAX as u128, nanos);
+        let mut x = 0;
+        let val = unsafe { wasm::memory_atomic_wait32(&mut x, 0, amt as i64) };
+        debug_assert_eq!(val, 2);
+        nanos -= amt;
+    }
+}
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/thread/windows.rs
index b0e38220a2d..a5640c51c4a 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/thread/windows.rs
@@ -1,14 +1,14 @@
 use core::ffi::c_void;
 
-use super::time::WaitableTimer;
-use super::to_u16s;
 use crate::ffi::CStr;
 use crate::num::NonZero;
 use crate::os::windows::io::{AsRawHandle, HandleOrNull};
 use crate::sys::handle::Handle;
+use crate::sys::pal::time::WaitableTimer;
+use crate::sys::pal::{dur2timeout, to_u16s};
 use crate::sys::{c, stack_overflow};
 use crate::sys_common::FromInner;
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 use crate::{io, ptr};
 
 pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -62,24 +62,6 @@ impl Thread {
         }
     }
 
-    pub fn set_name(name: &CStr) {
-        if let Ok(utf8) = name.to_str() {
-            if let Ok(utf16) = to_u16s(utf8) {
-                unsafe {
-                    // SAFETY: the vec returned by `to_u16s` ends with a zero value
-                    Self::set_name_wide(&utf16)
-                }
-            };
-        };
-    }
-
-    /// # Safety
-    ///
-    /// `name` must end with a zero value
-    pub unsafe fn set_name_wide(name: &[u16]) {
-        unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) };
-    }
-
     pub fn join(self) {
         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
         if rc == c::WAIT_FAILED {
@@ -87,37 +69,6 @@ impl Thread {
         }
     }
 
-    pub fn yield_now() {
-        // This function will return 0 if there are no other threads to execute,
-        // but this also means that the yield was useless so this isn't really a
-        // case that needs to be worried about.
-        unsafe {
-            c::SwitchToThread();
-        }
-    }
-
-    pub fn sleep(dur: Duration) {
-        fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
-            let timer = WaitableTimer::high_resolution()?;
-            timer.set(dur)?;
-            timer.wait()
-        }
-        // Attempt to use high-precision sleep (Windows 10, version 1803+).
-        // On error fallback to the standard `Sleep` function.
-        // Also preserves the zero duration behavior of `Sleep`.
-        if dur.is_zero() || high_precision_sleep(dur).is_err() {
-            unsafe { c::Sleep(super::dur2timeout(dur)) }
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn handle(&self) -> &Handle {
         &self.handle
     }
@@ -127,14 +78,6 @@ impl Thread {
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    // SAFETY: FFI call with no preconditions.
-    let id: u32 = unsafe { c::GetCurrentThreadId() };
-
-    // A return value of 0 indicates failed lookup.
-    if id == 0 { None } else { Some(id.into()) }
-}
-
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     let res = unsafe {
         let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
@@ -146,3 +89,52 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
         cpus => Ok(unsafe { NonZero::new_unchecked(cpus) }),
     }
 }
+
+pub fn current_os_id() -> Option<u64> {
+    // SAFETY: FFI call with no preconditions.
+    let id: u32 = unsafe { c::GetCurrentThreadId() };
+
+    // A return value of 0 indicates failed lookup.
+    if id == 0 { None } else { Some(id.into()) }
+}
+
+pub fn set_name(name: &CStr) {
+    if let Ok(utf8) = name.to_str() {
+        if let Ok(utf16) = to_u16s(utf8) {
+            unsafe {
+                // SAFETY: the vec returned by `to_u16s` ends with a zero value
+                set_name_wide(&utf16)
+            }
+        };
+    };
+}
+
+/// # Safety
+///
+/// `name` must end with a zero value
+pub unsafe fn set_name_wide(name: &[u16]) {
+    unsafe { c::SetThreadDescription(c::GetCurrentThread(), name.as_ptr()) };
+}
+
+pub fn sleep(dur: Duration) {
+    fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
+        let timer = WaitableTimer::high_resolution()?;
+        timer.set(dur)?;
+        timer.wait()
+    }
+    // Attempt to use high-precision sleep (Windows 10, version 1803+).
+    // On error fallback to the standard `Sleep` function.
+    // Also preserves the zero duration behavior of `Sleep`.
+    if dur.is_zero() || high_precision_sleep(dur).is_err() {
+        unsafe { c::Sleep(dur2timeout(dur)) }
+    }
+}
+
+pub fn yield_now() {
+    // This function will return 0 if there are no other threads to execute,
+    // but this also means that the yield was useless so this isn't really a
+    // case that needs to be worried about.
+    unsafe {
+        c::SwitchToThread();
+    }
+}
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/thread/xous.rs
index 92803c94c6e..133e15a0928 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/thread/xous.rs
@@ -1,6 +1,5 @@
 use core::arch::asm;
 
-use crate::ffi::CStr;
 use crate::io;
 use crate::num::NonZero;
 use crate::os::xous::ffi::{
@@ -8,7 +7,7 @@ use crate::os::xous::ffi::{
     map_memory, update_memory_flags,
 };
 use crate::os::xous::services::{TicktimerScalar, ticktimer_server};
-use crate::time::{Duration, Instant};
+use crate::time::Duration;
 
 pub struct Thread {
     tid: ThreadId,
@@ -110,46 +109,29 @@ impl Thread {
         Ok(Thread { tid })
     }
 
-    pub fn yield_now() {
-        do_yield();
-    }
-
-    pub fn set_name(_name: &CStr) {
-        // nope
-    }
-
-    pub fn sleep(dur: Duration) {
-        // Because the sleep server works on units of `usized milliseconds`, split
-        // the messages up into these chunks. This means we may run into issues
-        // if you try to sleep a thread for more than 49 days on a 32-bit system.
-        let mut millis = dur.as_millis();
-        while millis > 0 {
-            let sleep_duration =
-                if millis > (usize::MAX as _) { usize::MAX } else { millis as usize };
-            blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into())
-                .expect("failed to send message to ticktimer server");
-            millis -= sleep_duration as u128;
-        }
-    }
-
-    pub fn sleep_until(deadline: Instant) {
-        let now = Instant::now();
-
-        if let Some(delay) = deadline.checked_duration_since(now) {
-            Self::sleep(delay);
-        }
-    }
-
     pub fn join(self) {
         join_thread(self.tid).unwrap();
     }
 }
 
-pub(crate) fn current_os_id() -> Option<u64> {
-    None
-}
-
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     // We're unicore right now.
     Ok(unsafe { NonZero::new_unchecked(1) })
 }
+
+pub fn yield_now() {
+    do_yield();
+}
+
+pub fn sleep(dur: Duration) {
+    // Because the sleep server works on units of `usized milliseconds`, split
+    // the messages up into these chunks. This means we may run into issues
+    // if you try to sleep a thread for more than 49 days on a 32-bit system.
+    let mut millis = dur.as_millis();
+    while millis > 0 {
+        let sleep_duration = if millis > (usize::MAX as _) { usize::MAX } else { millis as usize };
+        blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into())
+            .expect("failed to send message to ticktimer server");
+        millis -= sleep_duration as u128;
+    }
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index b6059c28cec..4d09b2b4e9d 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -550,7 +550,7 @@ impl Builder {
             }
 
             if let Some(name) = their_thread.cname() {
-                imp::Thread::set_name(name);
+                imp::set_name(name);
             }
 
             let f = f.into_inner();
@@ -763,7 +763,7 @@ where
 /// [`Mutex`]: crate::sync::Mutex
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn yield_now() {
-    imp::Thread::yield_now()
+    imp::yield_now()
 }
 
 /// Determines whether the current thread is unwinding because of panic.
@@ -884,7 +884,7 @@ pub fn sleep_ms(ms: u32) {
 /// ```
 #[stable(feature = "thread_sleep", since = "1.4.0")]
 pub fn sleep(dur: Duration) {
-    imp::Thread::sleep(dur)
+    imp::sleep(dur)
 }
 
 /// Puts the current thread to sleep until the specified deadline has passed.
@@ -983,7 +983,7 @@ pub fn sleep(dur: Duration) {
 /// ```
 #[unstable(feature = "thread_sleep_until", issue = "113752")]
 pub fn sleep_until(deadline: Instant) {
-    imp::Thread::sleep_until(deadline)
+    imp::sleep_until(deadline)
 }
 
 /// Used to ensure that `park` and `park_timeout` do not unwind, as that can
@@ -1021,13 +1021,23 @@ impl Drop for PanicGuard {
 ///   specifying a maximum time to block the thread for.
 ///
 /// * The [`unpark`] method on a [`Thread`] atomically makes the token available
-///   if it wasn't already. Because the token is initially absent, [`unpark`]
-///   followed by [`park`] will result in the second call returning immediately.
-///
-/// The API is typically used by acquiring a handle to the current thread,
-/// placing that handle in a shared data structure so that other threads can
-/// find it, and then `park`ing in a loop. When some desired condition is met, another
-/// thread calls [`unpark`] on the handle.
+///   if it wasn't already. Because the token can be held by a thread even if it is currently not
+///   parked, [`unpark`] followed by [`park`] will result in the second call returning immediately.
+///   However, note that to rely on this guarantee, you need to make sure that your `unpark` happens
+///   after all `park` that may be done by other data structures!
+///
+/// The API is typically used by acquiring a handle to the current thread, placing that handle in a
+/// shared data structure so that other threads can find it, and then `park`ing in a loop. When some
+/// desired condition is met, another thread calls [`unpark`] on the handle. The last bullet point
+/// above guarantees that even if the `unpark` occurs before the thread is finished `park`ing, it
+/// will be woken up properly.
+///
+/// Note that the coordination via the shared data structure is crucial: If you `unpark` a thread
+/// without first establishing that it is about to be `park`ing within your code, that `unpark` may
+/// get consumed by a *different* `park` in the same thread, leading to a deadlock. This also means
+/// you must not call unknown code between setting up for parking and calling `park`; for instance,
+/// if you invoke `println!`, that may itself call `park` and thus consume your `unpark` and cause a
+/// deadlock.
 ///
 /// The motivation for this design is twofold:
 ///
@@ -1058,21 +1068,24 @@ impl Drop for PanicGuard {
 ///
 /// ```
 /// use std::thread;
-/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
+/// use std::sync::atomic::{Ordering, AtomicBool};
 /// use std::time::Duration;
 ///
-/// let flag = Arc::new(AtomicBool::new(false));
-/// let flag2 = Arc::clone(&flag);
+/// static QUEUED: AtomicBool = AtomicBool::new(false);
+/// static FLAG: AtomicBool = AtomicBool::new(false);
 ///
 /// let parked_thread = thread::spawn(move || {
+///     println!("Thread spawned");
+///     // Signal that we are going to `park`. Between this store and our `park`, there may
+///     // be no other `park`, or else that `park` could consume our `unpark` token!
+///     QUEUED.store(true, Ordering::Release);
 ///     // We want to wait until the flag is set. We *could* just spin, but using
 ///     // park/unpark is more efficient.
-///     while !flag2.load(Ordering::Relaxed) {
-///         println!("Parking thread");
+///     while !FLAG.load(Ordering::Acquire) {
+///         // We can *not* use `println!` here since that could use thread parking internally.
 ///         thread::park();
 ///         // We *could* get here spuriously, i.e., way before the 10ms below are over!
 ///         // But that is no problem, we are in a loop until the flag is set anyway.
-///         println!("Thread unparked");
 ///     }
 ///     println!("Flag received");
 /// });
@@ -1080,11 +1093,22 @@ impl Drop for PanicGuard {
 /// // Let some time pass for the thread to be spawned.
 /// thread::sleep(Duration::from_millis(10));
 ///
+/// // Ensure the thread is about to park.
+/// // This is crucial! It guarantees that the `unpark` below is not consumed
+/// // by some other code in the parked thread (e.g. inside `println!`).
+/// while !QUEUED.load(Ordering::Acquire) {
+///     // Spinning is of course inefficient; in practice, this would more likely be
+///     // a dequeue where we have no work to do if there's nobody queued.
+///     std::hint::spin_loop();
+/// }
+///
 /// // Set the flag, and let the thread wake up.
-/// // There is no race condition here, if `unpark`
+/// // There is no race condition here: if `unpark`
 /// // happens first, `park` will return immediately.
+/// // There is also no other `park` that could consume this token,
+/// // since we waited until the other thread got queued.
 /// // Hence there is no risk of a deadlock.
-/// flag.store(true, Ordering::Relaxed);
+/// FLAG.store(true, Ordering::Release);
 /// println!("Unpark the thread");
 /// parked_thread.thread().unpark();
 ///
@@ -1494,10 +1518,14 @@ impl Thread {
     /// ```
     /// use std::thread;
     /// use std::time::Duration;
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    ///
+    /// static QUEUED: AtomicBool = AtomicBool::new(false);
     ///
     /// let parked_thread = thread::Builder::new()
     ///     .spawn(|| {
     ///         println!("Parking thread");
+    ///         QUEUED.store(true, Ordering::Release);
     ///         thread::park();
     ///         println!("Thread unparked");
     ///     })
@@ -1506,6 +1534,15 @@ impl Thread {
     /// // Let some time pass for the thread to be spawned.
     /// thread::sleep(Duration::from_millis(10));
     ///
+    /// // Wait until the other thread is queued.
+    /// // This is crucial! It guarantees that the `unpark` below is not consumed
+    /// // by some other code in the parked thread (e.g. inside `println!`).
+    /// while !QUEUED.load(Ordering::Acquire) {
+    ///     // Spinning is of course inefficient; in practice, this would more likely be
+    ///     // a dequeue where we have no work to do if there's nobody queued.
+    ///     std::hint::spin_loop();
+    /// }
+    ///
     /// println!("Unpark the thread");
     /// parked_thread.thread().unpark();
     ///
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index ae889f1e778..2117f5f93ce 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -287,6 +287,8 @@ fn test_park_unpark_called_other_thread() {
     for _ in 0..10 {
         let th = thread::current();
 
+        // Here we rely on `thread::spawn` (specifically the part that runs after spawning
+        // the thread) to not consume the parking token.
         let _guard = thread::spawn(move || {
             super::sleep(Duration::from_millis(50));
             th.unpark();
@@ -316,6 +318,8 @@ fn test_park_timeout_unpark_called_other_thread() {
     for _ in 0..10 {
         let th = thread::current();
 
+        // Here we rely on `thread::spawn` (specifically the part that runs after spawning
+        // the thread) to not consume the parking token.
         let _guard = thread::spawn(move || {
             super::sleep(Duration::from_millis(50));
             th.unpark();
diff --git a/library/std/tests/sync/condvar.rs b/library/std/tests/sync/condvar.rs
index 1d712a64300..1b1c33efad5 100644
--- a/library/std/tests/sync/condvar.rs
+++ b/library/std/tests/sync/condvar.rs
@@ -17,7 +17,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: notify_one,
     test_body: {
@@ -38,7 +38,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: notify_all,
     test_body: {
@@ -79,7 +79,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: test_mutex_arc_condvar,
     test_body: {
@@ -116,7 +116,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: wait_while,
     test_body: {
@@ -141,7 +141,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: wait_timeout_wait,
     test_body: {
@@ -164,7 +164,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: wait_timeout_while_wait,
     test_body: {
@@ -180,7 +180,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: wait_timeout_while_instant_satisfy,
     test_body: {
@@ -197,7 +197,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: wait_timeout_while_wake,
     test_body: {
@@ -226,7 +226,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
+#[cfg(not(any(target_os = "emscripten", target_os = "wasi")))] // No threads.
 nonpoison_and_poison_unwrap_test!(
     name: wait_timeout_wake,
     test_body: {
diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs
index ac1dbebcc5c..23112e10284 100644
--- a/library/std/tests/sync/lib.rs
+++ b/library/std/tests/sync/lib.rs
@@ -58,6 +58,9 @@ fn result_unwrap<T, E: std::fmt::Debug>(x: Result<T, E>) -> T {
 /// a no-op (the identity function).
 ///
 /// The test names will be prefiex with `poison_` or `nonpoison_`.
+///
+/// Important: most attributes (except `cfg`) will not work properly! (They are only applied to the first test.)
+/// See <https://github.com/rust-lang/rust/pull/146433> for more information.
 macro_rules! nonpoison_and_poison_unwrap_test {
     (
         name: $name:ident,
diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs
index 612c75c7aef..2445764001b 100644
--- a/library/std/tests/sync/mutex.rs
+++ b/library/std/tests/sync/mutex.rs
@@ -266,7 +266,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+#[cfg(panic = "unwind")] // Requires unwinding support.
 nonpoison_and_poison_unwrap_test!(
     name: test_panics,
     test_body: {
@@ -297,7 +297,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+#[cfg(panic = "unwind")] // Requires unwinding support.
 nonpoison_and_poison_unwrap_test!(
     name: test_mutex_arc_access_in_unwind,
     test_body: {
diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs
index eca15d2a4ad..65d8bac7194 100644
--- a/library/std/tests/sync/rwlock.rs
+++ b/library/std/tests/sync/rwlock.rs
@@ -50,7 +50,7 @@ nonpoison_and_poison_unwrap_test!(
 // FIXME: On macOS we use a provenance-incorrect implementation and Miri
 // catches that issue with a chance of around 1/1000.
 // See <https://github.com/rust-lang/rust/issues/121950> for details.
-#[cfg_attr(all(miri, target_os = "macos"), ignore)]
+#[cfg(not(all(miri, target_os = "macos")))]
 nonpoison_and_poison_unwrap_test!(
     name: frob,
     test_body: {
@@ -124,7 +124,7 @@ nonpoison_and_poison_unwrap_test!(
     }
 );
 
-#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+#[cfg(panic = "unwind")] // Requires unwinding support.
 nonpoison_and_poison_unwrap_test!(
     name: test_rw_arc_access_in_unwind,
     test_body: {
@@ -315,7 +315,7 @@ nonpoison_and_poison_unwrap_test!(
 
 // FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
 // See <https://github.com/rust-lang/rust/issues/121950> for details.
-#[cfg_attr(all(miri, target_os = "macos"), ignore)]
+#[cfg(not(all(miri, target_os = "macos")))]
 nonpoison_and_poison_unwrap_test!(
     name: test_downgrade_observe,
     test_body: {
@@ -362,7 +362,7 @@ nonpoison_and_poison_unwrap_test!(
 
 // FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue.
 // See <https://github.com/rust-lang/rust/issues/121950> for details.
-#[cfg_attr(all(miri, target_os = "macos"), ignore)]
+#[cfg(not(all(miri, target_os = "macos")))]
 nonpoison_and_poison_unwrap_test!(
     name: test_downgrade_atomic,
     test_body: {
diff --git a/library/std_detect/src/detect/os/linux/aarch64.rs b/library/std_detect/src/detect/os/linux/aarch64.rs
index 87a9d6ebb88..b733b8a9eb2 100644
--- a/library/std_detect/src/detect/os/linux/aarch64.rs
+++ b/library/std_detect/src/detect/os/linux/aarch64.rs
@@ -140,7 +140,7 @@ struct AtHwcap {
 impl From<auxvec::AuxVec> for AtHwcap {
     /// Reads AtHwcap from the auxiliary vector.
     fn from(auxv: auxvec::AuxVec) -> Self {
-        AtHwcap {
+        let mut cap = AtHwcap {
             fp: bit::test(auxv.hwcap, 0),
             asimd: bit::test(auxv.hwcap, 1),
             // evtstrm: bit::test(auxv.hwcap, 2),
@@ -207,39 +207,50 @@ impl From<auxvec::AuxVec> for AtHwcap {
             // smef32f32: bit::test(auxv.hwcap2, 29),
             smefa64: bit::test(auxv.hwcap2, 30),
             wfxt: bit::test(auxv.hwcap2, 31),
-            // ebf16: bit::test(auxv.hwcap2, 32),
-            // sveebf16: bit::test(auxv.hwcap2, 33),
-            cssc: bit::test(auxv.hwcap2, 34),
-            // rprfm: bit::test(auxv.hwcap2, 35),
-            sve2p1: bit::test(auxv.hwcap2, 36),
-            sme2: bit::test(auxv.hwcap2, 37),
-            sme2p1: bit::test(auxv.hwcap2, 38),
-            // smei16i32: bit::test(auxv.hwcap2, 39),
-            // smebi32i32: bit::test(auxv.hwcap2, 40),
-            smeb16b16: bit::test(auxv.hwcap2, 41),
-            smef16f16: bit::test(auxv.hwcap2, 42),
-            mops: bit::test(auxv.hwcap2, 43),
-            hbc: bit::test(auxv.hwcap2, 44),
-            sveb16b16: bit::test(auxv.hwcap2, 45),
-            lrcpc3: bit::test(auxv.hwcap2, 46),
-            lse128: bit::test(auxv.hwcap2, 47),
-            fpmr: bit::test(auxv.hwcap2, 48),
-            lut: bit::test(auxv.hwcap2, 49),
-            faminmax: bit::test(auxv.hwcap2, 50),
-            f8cvt: bit::test(auxv.hwcap2, 51),
-            f8fma: bit::test(auxv.hwcap2, 52),
-            f8dp4: bit::test(auxv.hwcap2, 53),
-            f8dp2: bit::test(auxv.hwcap2, 54),
-            f8e4m3: bit::test(auxv.hwcap2, 55),
-            f8e5m2: bit::test(auxv.hwcap2, 56),
-            smelutv2: bit::test(auxv.hwcap2, 57),
-            smef8f16: bit::test(auxv.hwcap2, 58),
-            smef8f32: bit::test(auxv.hwcap2, 59),
-            smesf8fma: bit::test(auxv.hwcap2, 60),
-            smesf8dp4: bit::test(auxv.hwcap2, 61),
-            smesf8dp2: bit::test(auxv.hwcap2, 62),
-            // pauthlr: bit::test(auxv.hwcap2, ??),
+            ..Default::default()
+        };
+
+        // Hardware capabilities from bits 32 to 63 should only
+        // be tested on LP64 targets with 64 bits `usize`.
+        // On ILP32 targets like `aarch64-unknown-linux-gnu_ilp32`,
+        // these hardware capabilities will default to `false`.
+        // https://github.com/rust-lang/rust/issues/146230
+        #[cfg(target_pointer_width = "64")]
+        {
+            // cap.ebf16: bit::test(auxv.hwcap2, 32);
+            // cap.sveebf16: bit::test(auxv.hwcap2, 33);
+            cap.cssc = bit::test(auxv.hwcap2, 34);
+            // cap.rprfm: bit::test(auxv.hwcap2, 35);
+            cap.sve2p1 = bit::test(auxv.hwcap2, 36);
+            cap.sme2 = bit::test(auxv.hwcap2, 37);
+            cap.sme2p1 = bit::test(auxv.hwcap2, 38);
+            // cap.smei16i32 = bit::test(auxv.hwcap2, 39);
+            // cap.smebi32i32 = bit::test(auxv.hwcap2, 40);
+            cap.smeb16b16 = bit::test(auxv.hwcap2, 41);
+            cap.smef16f16 = bit::test(auxv.hwcap2, 42);
+            cap.mops = bit::test(auxv.hwcap2, 43);
+            cap.hbc = bit::test(auxv.hwcap2, 44);
+            cap.sveb16b16 = bit::test(auxv.hwcap2, 45);
+            cap.lrcpc3 = bit::test(auxv.hwcap2, 46);
+            cap.lse128 = bit::test(auxv.hwcap2, 47);
+            cap.fpmr = bit::test(auxv.hwcap2, 48);
+            cap.lut = bit::test(auxv.hwcap2, 49);
+            cap.faminmax = bit::test(auxv.hwcap2, 50);
+            cap.f8cvt = bit::test(auxv.hwcap2, 51);
+            cap.f8fma = bit::test(auxv.hwcap2, 52);
+            cap.f8dp4 = bit::test(auxv.hwcap2, 53);
+            cap.f8dp2 = bit::test(auxv.hwcap2, 54);
+            cap.f8e4m3 = bit::test(auxv.hwcap2, 55);
+            cap.f8e5m2 = bit::test(auxv.hwcap2, 56);
+            cap.smelutv2 = bit::test(auxv.hwcap2, 57);
+            cap.smef8f16 = bit::test(auxv.hwcap2, 58);
+            cap.smef8f32 = bit::test(auxv.hwcap2, 59);
+            cap.smesf8fma = bit::test(auxv.hwcap2, 60);
+            cap.smesf8dp4 = bit::test(auxv.hwcap2, 61);
+            cap.smesf8dp2 = bit::test(auxv.hwcap2, 62);
+            // cap.pauthlr = bit::test(auxv.hwcap2, ??);
         }
+        cap
     }
 }
 
diff --git a/package-lock.json b/package-lock.json
index def0cfa86a5..d0297bf70b6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,7 +5,7 @@
   "packages": {
     "": {
       "dependencies": {
-        "browser-ui-test": "^0.22.0",
+        "browser-ui-test": "^0.22.2",
         "es-check": "^6.2.1",
         "eslint": "^8.57.1",
         "eslint-js": "github:eslint/js",
@@ -485,9 +485,9 @@
       }
     },
     "node_modules/browser-ui-test": {
-      "version": "0.22.0",
-      "resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.22.0.tgz",
-      "integrity": "sha512-p/C02TMybTDKsAjpGOdnyNC0Q25KDae/fKMnvHaqcJ0tXRqNKwndW2Ltq7HTmin5xqg8GGOmysEgWTZkXu6pfA==",
+      "version": "0.22.2",
+      "resolved": "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.22.2.tgz",
+      "integrity": "sha512-eNB/PN2yDGe5n5IwE3ld/N6A39jM1oRzJmT5nOVQqrvoZEtcd9JSggDQPNVUnMEyuGcD4OEOWMsEa4oJppAmDQ==",
       "license": "MIT",
       "dependencies": {
         "css-unit-converter": "^1.1.2",
diff --git a/package.json b/package.json
index 976d6303634..04e0f6af19a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "dependencies": {
-    "browser-ui-test": "^0.22.0",
+    "browser-ui-test": "^0.22.2",
     "es-check": "^6.2.1",
     "eslint": "^8.57.1",
     "eslint-js": "github:eslint/js",
diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml
index 9daf9faac14..b111a20f8d8 100644
--- a/src/bootstrap/defaults/bootstrap.dist.toml
+++ b/src/bootstrap/defaults/bootstrap.dist.toml
@@ -14,6 +14,10 @@ compiletest-use-stage0-libtest = false
 [llvm]
 download-ci-llvm = false
 
+# Most users installing from source want to build all parts of the project from source.
+[gcc]
+download-ci-gcc = false
+
 [rust]
 # We have several defaults in bootstrap that depend on whether the channel is `dev` (e.g. `omit-git-hash` and `download-ci-llvm`).
 # Make sure they don't get set when installing from source.
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index 77c9622a9bf..717dea37e9e 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -32,6 +32,10 @@ pub struct GccOutput {
 impl GccOutput {
     /// Install the required libgccjit library file(s) to the specified `path`.
     pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) {
+        if builder.config.dry_run() {
+            return;
+        }
+
         // At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol).
         // However, at runtime, it will by default look for libgccjit.so.0.
         // So when we install the built libgccjit.so file to the target `directory`, we add it there
@@ -39,8 +43,16 @@ impl GccOutput {
         let mut target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string();
         target_filename.push_str(".0");
 
+        // If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink.
+        // In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink,
+        // which wouldn't work.
+        let actual_libgccjit_path = t!(
+            self.libgccjit.canonicalize(),
+            format!("Cannot find libgccjit at {}", self.libgccjit.display())
+        );
+
         let dst = directory.join(target_filename);
-        builder.copy_link(&self.libgccjit, &dst, FileType::NativeLibrary);
+        builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
     }
 }
 
diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs
index 5999348a7fe..05a5dfc0bc5 100644
--- a/src/bootstrap/src/core/config/mod.rs
+++ b/src/bootstrap/src/core/config/mod.rs
@@ -422,10 +422,10 @@ impl std::str::FromStr for RustcLto {
 #[derive(Default, Clone)]
 pub enum GccCiMode {
     /// Build GCC from the local `src/gcc` submodule.
-    #[default]
     BuildLocally,
     /// Try to download GCC from CI.
     /// If it is not available on CI, it will be built locally instead.
+    #[default]
     DownloadFromCi,
 }
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 01309072927..03b39882e30 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -541,4 +541,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "Added a new option `rust.break-on-ice` to control if internal compiler errors cause a debug break on Windows.",
     },
+    ChangeInfo {
+        change_id: 146435,
+        severity: ChangeSeverity::Info,
+        summary: "The default value of the `gcc.download-ci-gcc` option has been changed to `true`.",
+    },
 ];
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index b01b596da68..3b84ae2bed0 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -3639,7 +3639,7 @@ class DocSearch {
             if (contains.length === 0) {
                 return 0;
             }
-            const maxPathEditDistance = Math.floor(
+            const maxPathEditDistance = parsedQuery.literalSearch ? 0 : Math.floor(
                 contains.reduce((acc, next) => acc + next.length, 0) / 3,
             );
             let ret_dist = maxPathEditDistance + 1;
@@ -3650,7 +3650,9 @@ class DocSearch {
                 let dist_total = 0;
                 for (let x = 0; x < clength; ++x) {
                     const [p, c] = [path[i + x], contains[x]];
-                    if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
+                    if (parsedQuery.literalSearch && p !== c) {
+                        continue pathiter;
+                    } else if (Math.floor((p.length - c.length) / 3) <= maxPathEditDistance &&
                         p.indexOf(c) !== -1
                     ) {
                         // discount distance on substring match
diff --git a/src/librustdoc/passes/lint/bare_urls.rs b/src/librustdoc/passes/lint/bare_urls.rs
index f70bdf4e4fe..06256d61151 100644
--- a/src/librustdoc/passes/lint/bare_urls.rs
+++ b/src/librustdoc/passes/lint/bare_urls.rs
@@ -17,7 +17,10 @@ use crate::core::DocContext;
 use crate::html::markdown::main_body_opts;
 
 pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) {
-    let report_diag = |cx: &DocContext<'_>, msg: &'static str, range: Range<usize>| {
+    let report_diag = |cx: &DocContext<'_>,
+                       msg: &'static str,
+                       range: Range<usize>,
+                       without_brackets: Option<&str>| {
         let maybe_sp = source_span_for_markdown_range(cx.tcx, dox, &range, &item.attrs.doc_strings)
             .map(|(sp, _)| sp);
         let sp = maybe_sp.unwrap_or_else(|| item.attr_span(cx.tcx));
@@ -27,14 +30,22 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
             // The fallback of using the attribute span is suitable for
             // highlighting where the error is, but not for placing the < and >
             if let Some(sp) = maybe_sp {
-                lint.multipart_suggestion(
-                    "use an automatic link instead",
-                    vec![
-                        (sp.shrink_to_lo(), "<".to_string()),
-                        (sp.shrink_to_hi(), ">".to_string()),
-                    ],
-                    Applicability::MachineApplicable,
-                );
+                if let Some(without_brackets) = without_brackets {
+                    lint.multipart_suggestion(
+                        "use an automatic link instead",
+                        vec![(sp, format!("<{without_brackets}>"))],
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    lint.multipart_suggestion(
+                        "use an automatic link instead",
+                        vec![
+                            (sp.shrink_to_lo(), "<".to_string()),
+                            (sp.shrink_to_hi(), ">".to_string()),
+                        ],
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
         });
     };
@@ -43,7 +54,7 @@ pub(super) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &
 
     while let Some((event, range)) = p.next() {
         match event {
-            Event::Text(s) => find_raw_urls(cx, &s, range, &report_diag),
+            Event::Text(s) => find_raw_urls(cx, dox, &s, range, &report_diag),
             // We don't want to check the text inside code blocks or links.
             Event::Start(tag @ (Tag::CodeBlock(_) | Tag::Link { .. })) => {
                 for (event, _) in p.by_ref() {
@@ -67,25 +78,35 @@ static URL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
         r"https?://",                          // url scheme
         r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
         r"[a-zA-Z]{2,63}",                     // root domain
-        r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
+        r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)",     // optional query or url fragments
     ))
     .expect("failed to build regex")
 });
 
 fn find_raw_urls(
     cx: &DocContext<'_>,
+    dox: &str,
     text: &str,
     range: Range<usize>,
-    f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>),
+    f: &impl Fn(&DocContext<'_>, &'static str, Range<usize>, Option<&str>),
 ) {
     trace!("looking for raw urls in {text}");
     // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
     for match_ in URL_REGEX.find_iter(text) {
-        let url_range = match_.range();
-        f(
-            cx,
-            "this URL is not a hyperlink",
-            Range { start: range.start + url_range.start, end: range.start + url_range.end },
-        );
+        let mut url_range = match_.range();
+        url_range.start += range.start;
+        url_range.end += range.start;
+        let mut without_brackets = None;
+        // If the link is contained inside `[]`, then we need to replace the brackets and
+        // not just add `<>`.
+        if dox[..url_range.start].ends_with('[')
+            && url_range.end <= dox.len()
+            && dox[url_range.end..].starts_with(']')
+        {
+            url_range.start -= 1;
+            url_range.end += 1;
+            without_brackets = Some(match_.as_str());
+        }
+        f(cx, "this URL is not a hyperlink", url_range, without_brackets);
     }
 }
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 761c4658d0079d607e6d33cf0c060e61a617cad
+Subproject 24bb93c388fb8c211a37986539f24a819dc669d
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 517aa343a6d..d433ee8daaa 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -606,6 +606,7 @@ Definite bugs found:
 * [A bug in the new `RwLock::downgrade` implementation](https://rust-lang.zulipchat.com/#narrow/channel/269128-miri/topic/Miri.20error.20library.20test) (caught by Miri before it landed in the Rust repo)
 * [Mockall reading uninitialized memory when mocking `std::io::Read::read`, even if all expectations are satisfied](https://github.com/asomers/mockall/issues/647) (caught by Miri running Tokio's test suite)
 * [`ReentrantLock` not correctly dealing with reuse of addresses for TLS storage of different threads](https://github.com/rust-lang/rust/pull/141248)
+* [Rare Deadlock in the thread (un)parking example code](https://github.com/rust-lang/rust/issues/145816)
 
 Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
index bcec5557a3f..c7c1a769cda 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
@@ -8,13 +8,13 @@ LL |             assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _
    = note: inside closure at tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs:LL:CC
 
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
index 51533cd17a8..ae8b2b936a7 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
@@ -8,13 +8,13 @@ LL |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
    = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC
 
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
index 63fc7ce346e..dfa9a6e2583 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
@@ -8,13 +8,13 @@ LL |             assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu
    = note: inside closure at tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC
 
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr
index d8a3e058da9..47a0ebdcfef 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_detached.stderr
@@ -1,5 +1,5 @@
 error: Undefined Behavior: trying to join a detached thread
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
@@ -7,7 +7,7 @@ LL |         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr
index 079f01c0e54..3b1181c92fd 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.stderr
@@ -9,13 +9,13 @@ LL |             assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), WAIT_OBJ
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
    |                                                                                          ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr
index 70de94f56ba..6eefa2da1d8 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr
+++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.stderr
@@ -8,13 +8,13 @@ LL |             assert_eq!(WaitForSingleObject(native, INFINITE), WAIT_OBJECT_0
    = note: inside closure at tests/fail-dep/concurrency/windows_join_self.rs:LL:CC
 
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) };
    |                                                                                          ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr
index 4f3a56fef82..6dd6c36ab65 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.stderr
@@ -1,11 +1,11 @@
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr
index 5045badaa87..3154197b95e 100644
--- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.stderr
@@ -1,11 +1,11 @@
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr
index 3713c8da392..1af44c107ff 100644
--- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.stderr
@@ -5,13 +5,13 @@ error: the evaluated program deadlocked
    = note: BACKTRACE on thread `unnamed-ID`:
 
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
index 47fc889b001..b85470225c6 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr
@@ -1,11 +1,11 @@
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
index 99d242ec7da..bbd2ab1c4d8 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.stderr
@@ -1,11 +1,11 @@
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
index f766500d331..c3cc2068173 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.stderr
@@ -1,11 +1,11 @@
 error: the evaluated program deadlocked
-  --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+  --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    |
 LL |         let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) };
    |                                                                  ^ this thread got stuck here
    |
    = note: BACKTRACE:
-   = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC
+   = note: inside `std::sys::thread::PLATFORM::Thread::join` at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC
    = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
    = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC
 note: inside `main`
diff --git a/src/tools/tidy/src/extra_checks/mod.rs b/src/tools/tidy/src/extra_checks/mod.rs
index 321ef65117e..a6b50b5ca47 100644
--- a/src/tools/tidy/src/extra_checks/mod.rs
+++ b/src/tools/tidy/src/extra_checks/mod.rs
@@ -124,6 +124,12 @@ fn check_impl(
         };
     }
 
+    let rerun_with_bless = |mode: &str, action: &str| {
+        if !bless {
+            eprintln!("rerun tidy with `--extra-checks={mode} --bless` to {action}");
+        }
+    };
+
     let python_lint = extra_check!(Py, Lint);
     let python_fmt = extra_check!(Py, Fmt);
     let shell_lint = extra_check!(Shell, Lint);
@@ -147,14 +153,21 @@ fn check_impl(
     }
 
     if python_lint {
-        eprintln!("linting python files");
         let py_path = py_path.as_ref().unwrap();
-        let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, &["check".as_ref()]);
+        let args: &[&OsStr] = if bless {
+            eprintln!("linting python files and applying suggestions");
+            &["check".as_ref(), "--fix".as_ref()]
+        } else {
+            eprintln!("linting python files");
+            &["check".as_ref()]
+        };
+
+        let res = run_ruff(root_path, outdir, py_path, &cfg_args, &file_args, args);
 
-        if res.is_err() && show_diff {
+        if res.is_err() && show_diff && !bless {
             eprintln!("\npython linting failed! Printing diff suggestions:");
 
-            let _ = run_ruff(
+            let diff_res = run_ruff(
                 root_path,
                 outdir,
                 py_path,
@@ -162,6 +175,10 @@ fn check_impl(
                 &file_args,
                 &["check".as_ref(), "--diff".as_ref()],
             );
+            // `ruff check --diff` will return status 0 if there are no suggestions.
+            if diff_res.is_err() {
+                rerun_with_bless("py:lint", "apply ruff suggestions");
+            }
         }
         // Rethrow error
         res?;
@@ -192,7 +209,7 @@ fn check_impl(
                     &["format".as_ref(), "--diff".as_ref()],
                 );
             }
-            eprintln!("rerun tidy with `--extra-checks=py:fmt --bless` to reformat Python code");
+            rerun_with_bless("py:fmt", "reformat Python code");
         }
 
         // Rethrow error
@@ -225,7 +242,7 @@ fn check_impl(
         let args = merge_args(&cfg_args_clang_format, &file_args_clang_format);
         let res = py_runner(py_path.as_ref().unwrap(), false, None, "clang-format", &args);
 
-        if res.is_err() && show_diff {
+        if res.is_err() && show_diff && !bless {
             eprintln!("\nclang-format linting failed! Printing diff suggestions:");
 
             let mut cfg_args_clang_format_diff = cfg_args.clone();
@@ -265,6 +282,7 @@ fn check_impl(
                     );
                 }
             }
+            rerun_with_bless("cpp:fmt", "reformat C++ code");
         }
         // Rethrow error
         res?;
@@ -290,12 +308,16 @@ fn check_impl(
         args.extend_from_slice(SPELLCHECK_DIRS);
 
         if bless {
-            eprintln!("spellcheck files and fix");
+            eprintln!("spellchecking files and fixing typos");
             args.push("--write-changes");
         } else {
-            eprintln!("spellcheck files");
+            eprintln!("spellchecking files");
         }
-        spellcheck_runner(root_path, &outdir, &cargo, &args)?;
+        let res = spellcheck_runner(root_path, &outdir, &cargo, &args);
+        if res.is_err() {
+            rerun_with_bless("spellcheck", "fix typos");
+        }
+        res?;
     }
 
     if js_lint || js_typecheck {
@@ -303,11 +325,21 @@ fn check_impl(
     }
 
     if js_lint {
-        rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless)?;
+        if bless {
+            eprintln!("linting javascript files");
+        } else {
+            eprintln!("linting javascript files and applying suggestions");
+        }
+        let res = rustdoc_js::lint(outdir, librustdoc_path, tools_path, bless);
+        if res.is_err() {
+            rerun_with_bless("js:lint", "apply eslint suggestions");
+        }
+        res?;
         rustdoc_js::es_check(outdir, librustdoc_path)?;
     }
 
     if js_typecheck {
+        eprintln!("typechecking javascript files");
         rustdoc_js::typecheck(outdir, librustdoc_path)?;
     }
 
diff --git a/src/tools/tidy/src/extra_checks/rustdoc_js.rs b/src/tools/tidy/src/extra_checks/rustdoc_js.rs
index a6c66b8be80..5137e618367 100644
--- a/src/tools/tidy/src/extra_checks/rustdoc_js.rs
+++ b/src/tools/tidy/src/extra_checks/rustdoc_js.rs
@@ -57,7 +57,7 @@ fn run_eslint(
             if exit_status.success() {
                 return Ok(());
             }
-            Err(super::Error::FailedCheck("eslint command failed"))
+            Err(super::Error::FailedCheck("eslint"))
         }
         Err(error) => Err(super::Error::Generic(format!("eslint command failed: {error:?}"))),
     }
@@ -94,7 +94,7 @@ pub(super) fn typecheck(outdir: &Path, librustdoc_path: &Path) -> Result<(), sup
             if exit_status.success() {
                 return Ok(());
             }
-            Err(super::Error::FailedCheck("tsc command failed"))
+            Err(super::Error::FailedCheck("tsc"))
         }
         Err(error) => Err(super::Error::Generic(format!("tsc command failed: {error:?}"))),
     }
@@ -112,7 +112,7 @@ pub(super) fn es_check(outdir: &Path, librustdoc_path: &Path) -> Result<(), supe
             if exit_status.success() {
                 return Ok(());
             }
-            Err(super::Error::FailedCheck("es-check command failed"))
+            Err(super::Error::FailedCheck("es-check"))
         }
         Err(error) => Err(super::Error::Generic(format!("es-check command failed: {error:?}"))),
     }
diff --git a/tests/assembly-llvm/c-variadic-arm.rs b/tests/assembly-llvm/c-variadic-arm.rs
new file mode 100644
index 00000000000..2ef307405e1
--- /dev/null
+++ b/tests/assembly-llvm/c-variadic-arm.rs
@@ -0,0 +1,26 @@
+//@ assembly-output: emit-asm
+//@ compile-flags: -Copt-level=3
+//@ only-arm
+//@ ignore-thumb
+//@ ignore-android
+#![no_std]
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+
+// Check that the assembly that rustc generates matches what clang emits.
+
+#[unsafe(no_mangle)]
+unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 {
+    // CHECK-LABEL: variadic
+    // CHECK: sub sp, sp
+
+    // CHECK: vldr
+    // CHECK: vadd.f64
+    // CHECK: vldr
+    // CHECK: vadd.f64
+    let b = args.arg::<f64>();
+    let c = args.arg::<f64>();
+    a + b + c
+
+    // CHECK: add sp, sp
+}
diff --git a/tests/codegen-llvm/c-variadic-lifetime.rs b/tests/codegen-llvm/c-variadic-lifetime.rs
new file mode 100644
index 00000000000..5b2f8af18c8
--- /dev/null
+++ b/tests/codegen-llvm/c-variadic-lifetime.rs
@@ -0,0 +1,21 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=3
+#![feature(c_variadic)]
+#![crate_type = "lib"]
+
+// Check that `%args` explicitly has its lifetime start and end. Being explicit can improve
+// instruction and register selection, see e.g. https://github.com/rust-lang/rust/pull/144549
+
+#[unsafe(no_mangle)]
+unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 {
+    // CHECK: call void @llvm.lifetime.start.p0(i64 {{[0-9]+}}, ptr nonnull %args)
+    // CHECK: call void @llvm.va_start.p0(ptr nonnull %args)
+
+    let b = args.arg::<f64>();
+    let c = args.arg::<f64>();
+
+    a + b + c
+
+    // CHECK: call void @llvm.va_end.p0(ptr nonnull %args)
+    // CHECK: call void @llvm.lifetime.end.p0(i64 {{[0-9]+}}, ptr nonnull %args)
+}
diff --git a/tests/rustdoc-js/literal-path.js b/tests/rustdoc-js/literal-path.js
new file mode 100644
index 00000000000..ea999ea1a6f
--- /dev/null
+++ b/tests/rustdoc-js/literal-path.js
@@ -0,0 +1,23 @@
+// exact-check
+
+// This test ensures that literal search is always applied on elements of the path.
+
+const EXPECTED = [
+    {
+        'query': '"some::path"',
+        'others': [
+            { 'path': 'literal_path::some', 'name': 'Path' },
+        ],
+    },
+    {
+        'query': '"somea::path"',
+        'others': [
+            { 'path': 'literal_path::somea', 'name': 'Path' },
+        ],
+    },
+    {
+        'query': '"soma::path"',
+        'others': [
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/literal-path.rs b/tests/rustdoc-js/literal-path.rs
new file mode 100644
index 00000000000..fa7685fd966
--- /dev/null
+++ b/tests/rustdoc-js/literal-path.rs
@@ -0,0 +1,7 @@
+pub mod some {
+    pub struct Path;
+}
+
+pub mod somea {
+    pub struct Path;
+}
diff --git a/tests/rustdoc-ui/lints/bare-urls.fixed b/tests/rustdoc-ui/lints/bare-urls.fixed
index a91573146b8..ac63e291c5b 100644
--- a/tests/rustdoc-ui/lints/bare-urls.fixed
+++ b/tests/rustdoc-ui/lints/bare-urls.fixed
@@ -68,3 +68,17 @@ pub mod foo {
     /// https://somewhere.com/a?hello=12&bye=11#xyz
     pub fn bar() {}
 }
+
+/// <https://bloob.blob>
+//~^ ERROR this URL is not a hyperlink
+/// [ <https://bloob.blob> ]
+//~^ ERROR this URL is not a hyperlink
+/// [ <https://bloob.blob>]
+//~^ ERROR this URL is not a hyperlink
+/// [<https://bloob.blob> ]
+//~^ ERROR this URL is not a hyperlink
+/// [<https://bloob.blob>
+//~^ ERROR this URL is not a hyperlink
+/// <https://bloob.blob>]
+//~^ ERROR this URL is not a hyperlink
+pub fn lint_with_brackets() {}
diff --git a/tests/rustdoc-ui/lints/bare-urls.rs b/tests/rustdoc-ui/lints/bare-urls.rs
index 5b008cdafa2..a70a3ec822e 100644
--- a/tests/rustdoc-ui/lints/bare-urls.rs
+++ b/tests/rustdoc-ui/lints/bare-urls.rs
@@ -68,3 +68,17 @@ pub mod foo {
     /// https://somewhere.com/a?hello=12&bye=11#xyz
     pub fn bar() {}
 }
+
+/// [https://bloob.blob]
+//~^ ERROR this URL is not a hyperlink
+/// [ https://bloob.blob ]
+//~^ ERROR this URL is not a hyperlink
+/// [ https://bloob.blob]
+//~^ ERROR this URL is not a hyperlink
+/// [https://bloob.blob ]
+//~^ ERROR this URL is not a hyperlink
+/// [https://bloob.blob
+//~^ ERROR this URL is not a hyperlink
+/// https://bloob.blob]
+//~^ ERROR this URL is not a hyperlink
+pub fn lint_with_brackets() {}
diff --git a/tests/rustdoc-ui/lints/bare-urls.stderr b/tests/rustdoc-ui/lints/bare-urls.stderr
index e1108c7e7f8..fc3c642f5aa 100644
--- a/tests/rustdoc-ui/lints/bare-urls.stderr
+++ b/tests/rustdoc-ui/lints/bare-urls.stderr
@@ -243,5 +243,73 @@ help: use an automatic link instead
 LL | #[doc = "<https://example.com/raw>"]
    |          +                       +
 
-error: aborting due to 20 previous errors
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:72:5
+   |
+LL | /// [https://bloob.blob]
+   |     ^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://bloob.blob>`
+   |
+   = note: bare URLs are not automatically turned into clickable links
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:74:7
+   |
+LL | /// [ https://bloob.blob ]
+   |       ^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// [ <https://bloob.blob> ]
+   |       +                  +
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:76:7
+   |
+LL | /// [ https://bloob.blob]
+   |       ^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// [ <https://bloob.blob>]
+   |       +                  +
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:78:6
+   |
+LL | /// [https://bloob.blob ]
+   |      ^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// [<https://bloob.blob> ]
+   |      +                  +
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:80:6
+   |
+LL | /// [https://bloob.blob
+   |      ^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// [<https://bloob.blob>
+   |      +                  +
+
+error: this URL is not a hyperlink
+  --> $DIR/bare-urls.rs:82:5
+   |
+LL | /// https://bloob.blob]
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: bare URLs are not automatically turned into clickable links
+help: use an automatic link instead
+   |
+LL | /// <https://bloob.blob>]
+   |     +                  +
+
+error: aborting due to 26 previous errors
 
diff --git a/tests/ui/consts/const_cmp_type_id.rs b/tests/ui/consts/const_cmp_type_id.rs
index ff44876c5c4..dc0701d3b1d 100644
--- a/tests/ui/consts/const_cmp_type_id.rs
+++ b/tests/ui/consts/const_cmp_type_id.rs
@@ -9,8 +9,7 @@ fn main() {
         assert!(TypeId::of::<u8>() == TypeId::of::<u8>());
         assert!(TypeId::of::<()>() != TypeId::of::<u8>());
         let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
-        //~^ ERROR: cannot call non-const operator in constants
-        // can't assert `_a` because it is not deterministic
-        // FIXME(const_trait_impl) make it pass
+        //~^ ERROR: the trait bound `TypeId: const PartialOrd` is not satisfied
+        // FIXME(const_trait_impl) make it pass; requires const comparison of pointers (#53020)
     }
 }
diff --git a/tests/ui/consts/const_cmp_type_id.stderr b/tests/ui/consts/const_cmp_type_id.stderr
index 05b94caef79..62a1677c0d9 100644
--- a/tests/ui/consts/const_cmp_type_id.stderr
+++ b/tests/ui/consts/const_cmp_type_id.stderr
@@ -1,13 +1,9 @@
-error[E0015]: cannot call non-const operator in constants
+error[E0277]: the trait bound `TypeId: const PartialOrd` is not satisfied
   --> $DIR/const_cmp_type_id.rs:11:18
    |
 LL |         let _a = TypeId::of::<u8>() < TypeId::of::<u16>();
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: impl defined here, but it is not `const`
-  --> $SRC_DIR/core/src/any.rs:LL:COL
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0015`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/fn_trait_refs.rs b/tests/ui/consts/fn_trait_refs.rs
index e475c0a1b6f..e4a62e18c7b 100644
--- a/tests/ui/consts/fn_trait_refs.rs
+++ b/tests/ui/consts/fn_trait_refs.rs
@@ -1,6 +1,5 @@
-//@ known-bug: #110395
+//@ check-pass
 
-#![feature(const_fn_trait_ref_impls)]
 #![feature(fn_traits)]
 #![feature(unboxed_closures)]
 #![feature(const_trait_impl)]
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
deleted file mode 100644
index bbe0714801c..00000000000
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0635]: unknown feature `const_fn_trait_ref_impls`
-  --> $DIR/fn_trait_refs.rs:3:12
-   |
-LL | #![feature(const_fn_trait_ref_impls)]
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `(i32, i32, i32): const PartialEq` is not satisfied
-  --> $DIR/fn_trait_refs.rs:71:17
-   |
-LL |         assert!(test_one == (1, 1, 1));
-   |                 ^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `(i32, i32): const PartialEq` is not satisfied
-  --> $DIR/fn_trait_refs.rs:74:17
-   |
-LL |         assert!(test_two == (2, 2));
-   |                 ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0277, E0635.
-For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/feature-gates/feature-gate-sanitize.rs b/tests/ui/feature-gates/feature-gate-sanitize.rs
index 40098d93272..768417cfae8 100644
--- a/tests/ui/feature-gates/feature-gate-sanitize.rs
+++ b/tests/ui/feature-gates/feature-gate-sanitize.rs
@@ -1,4 +1,3 @@
-//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
 #![feature(no_sanitize)] //~ ERROR feature has been removed
 
 #[sanitize(address = "on")]
diff --git a/tests/ui/feature-gates/feature-gate-sanitize.stderr b/tests/ui/feature-gates/feature-gate-sanitize.stderr
index 7c38b351916..513999636a9 100644
--- a/tests/ui/feature-gates/feature-gate-sanitize.stderr
+++ b/tests/ui/feature-gates/feature-gate-sanitize.stderr
@@ -1,5 +1,5 @@
 error[E0557]: feature has been removed
-  --> $DIR/feature-gate-sanitize.rs:2:12
+  --> $DIR/feature-gate-sanitize.rs:1:12
    |
 LL | #![feature(no_sanitize)]
    |            ^^^^^^^^^^^ feature has been removed
@@ -8,7 +8,7 @@ LL | #![feature(no_sanitize)]
    = note: renamed to sanitize(xyz = "on|off")
 
 error[E0658]: the `#[sanitize]` attribute is an experimental feature
-  --> $DIR/feature-gate-sanitize.rs:4:1
+  --> $DIR/feature-gate-sanitize.rs:3:1
    |
 LL | #[sanitize(address = "on")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.next.stderr b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.next.stderr
new file mode 100644
index 00000000000..86ac1bdad04
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.next.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/avoid-inference-constraints-from-blanket-2.rs:27:18
+   |
+LL |     let _: u32 = x;
+   |            ---   ^ expected `u32`, found `u64`
+   |            |
+   |            expected due to this
+   |
+help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit
+   |
+LL |     let _: u32 = x.try_into().unwrap();
+   |                   ++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.rs b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.rs
new file mode 100644
index 00000000000..b4f853de4aa
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-2.rs
@@ -0,0 +1,31 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[current] check-pass
+
+// Regression test for trait-system-refactor-initiative#205. Avoid
+// constraining other impl arguments when applying blanket impls.
+
+// FIXME(-Znext-solver): This currently incompletely constrains the
+// argument of `opaque: Trait<?x>` using the blanket impl of trait.
+// Ideally we don't do that.
+
+trait Trait<T> {}
+
+impl<T> Trait<u64> for T {}
+impl Trait<u32> for u64 {}
+
+fn impls_trait<T: Trait<U>, U>(_: U) -> T {
+    todo!()
+}
+
+fn foo() -> impl Sized {
+    let x = Default::default();
+    if false {
+        return impls_trait::<_, _>(x);
+    }
+    let _: u32 = x;
+    //[next]~^ ERROR mismatched types
+    1u64
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.rs b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.rs
new file mode 100644
index 00000000000..2f29cb4ee6b
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+#![allow(unconditional_recursion)]
+
+// Regression test for trait-system-refactor-initiative#205. Avoid
+// constraining other impl arguments when applying blanket impls,
+// especially if the nested where-bounds of the blanket impl don't
+// actually apply for the opaque.
+
+// FIXME(-Znext-solver): This currently incompletely constrains the
+// argument of `opaque: Trait<?x>` using the blanket impl of trait.
+// Ideally we don't do that.
+
+trait Trait<T> {}
+
+impl<T: Copy> Trait<u32> for T {}
+impl Trait<u64> for String {}
+fn impls_trait<T: Trait<U>, U>(_: T) {}
+
+fn test() -> impl Sized {
+    let x = test();
+    impls_trait(x); //~ ERROR the trait bound `String: Trait<u32>` is not satisfied
+    String::new()
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.stderr b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.stderr
new file mode 100644
index 00000000000..a5d19b48481
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket-3.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the trait bound `String: Trait<u32>` is not satisfied
+  --> $DIR/avoid-inference-constraints-from-blanket-3.rs:22:5
+   |
+LL |     impls_trait(x);
+   |     ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |
+   = help: the trait `Trait<u32>` is not implemented for `String`
+           but trait `Trait<u64>` is implemented for it
+   = help: for that trait implementation, expected `u64`, found `u32`
+note: required for `String` to implement `Trait<u32>`
+  --> $DIR/avoid-inference-constraints-from-blanket-3.rs:16:15
+   |
+LL | impl<T: Copy> Trait<u32> for T {}
+   |         ----  ^^^^^^^^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `impls_trait`
+  --> $DIR/avoid-inference-constraints-from-blanket-3.rs:18:19
+   |
+LL | fn impls_trait<T: Trait<U>, U>(_: T) {}
+   |                   ^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket.rs b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket.rs
new file mode 100644
index 00000000000..bb3acfde5bc
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/avoid-inference-constraints-from-blanket.rs
@@ -0,0 +1,25 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+
+// Regression test for trait-system-refactor-initiative#205. Avoid constraining
+// the opaque type when applying blanket impls.
+
+trait Trait<T> {}
+
+impl<T> Trait<T> for T {}
+impl Trait<u32> for u64 {}
+
+fn impls_trait<T: Trait<U>, U>() -> T {
+    todo!()
+}
+
+fn foo() -> impl Sized {
+    if false {
+        // `opaque: Trait<u32>` shouldn't constrain `opaque` to `u32` via the blanket impl
+        return impls_trait::<_, u32>();
+    }
+    1u64
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ambig.rs b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ambig.rs
new file mode 100644
index 00000000000..e7aaf6fa135
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ambig.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+#![allow(unconditional_recursion)]
+
+// Regression test for trait-system-refactor-initiative#182. If multiple
+// opaque types result in different item bounds, do not apply them.
+
+trait Trait<T> {}
+impl<T, U> Trait<T> for U {}
+
+fn impls_trait<T: Trait<U>, U>(_: T) -> U {
+    todo!()
+}
+
+fn overlap<T, U>() -> (impl Trait<T>, impl Trait<U>) {
+    let mut x = overlap::<T, U>().0;
+    x = overlap::<T, U>().1;
+    let u = impls_trait(x);
+    let _: u32 = u;
+    ((), ())
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ok.rs b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ok.rs
new file mode 100644
index 00000000000..d91efe181e3
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/multiple-opaques-ok.rs
@@ -0,0 +1,37 @@
+//@ compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+#![allow(unconditional_recursion)]
+
+// Regression test for trait-system-refactor-initiative#18, making sure
+// we support being sub unified with more than 1 opaque type.
+
+trait Id {
+    type This;
+}
+impl Id for &'static str {
+    type This = &'static str;
+}
+fn to_assoc<T: Id>(x: T) -> <T as Id>::This {
+    todo!()
+}
+
+fn mirror1() -> (impl Id<This = &'static str>, impl Sized) {
+    let mut opaque = mirror1().0;
+    opaque = mirror1().1;
+    let x = to_assoc(opaque);
+    // `?x` equals both opaques, make sure we still use the applicable
+    // item bound.
+    x.len();
+    (x, x)
+}
+fn mirror2() -> (impl Sized, impl Id<This = &'static str>) {
+    let mut opaque = mirror2().0;
+    opaque = mirror2().1;
+    let x = to_assoc(opaque);
+    // `?x` equals both opaques, make sure we still use the applicable
+    // item bound.
+    x.len();
+    (x, x)
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/no-rigid-alias.rs b/tests/ui/impl-trait/non-defining-uses/no-rigid-alias.rs
new file mode 100644
index 00000000000..fca5db3e20f
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/no-rigid-alias.rs
@@ -0,0 +1,27 @@
+//@ compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+#![allow(unconditional_recursion)]
+
+// Test for trait-system-refactor-initiative#182 making sure
+// that we don't incorrectly normalize to rigid aliases if the
+// opaque type only has a trait bound.
+
+trait Id {
+    type This;
+}
+impl<T> Id for Vec<T> {
+    type This = Vec<T>;
+}
+fn to_assoc<T: Id>(x: T) -> <T as Id>::This {
+    todo!()
+}
+
+fn mirror<T>(x: Vec<T>) -> impl Id {
+    let x = to_assoc(mirror(x));
+    // `?x` equals `<opaque::<T> as Id>::This`. We should not infer `?x`
+    // to be a rigid alias here.
+    let _: Vec<u32> = x;
+    x
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs b/tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs
new file mode 100644
index 00000000000..50bb3995b94
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/use-blanket-impl.rs
@@ -0,0 +1,19 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+
+// Regression test for trait-system-refactor-initiative#196.
+fn iterator(b: bool) -> impl Iterator<Item = String> {
+    if b {
+        // We need to eagerly figure out the type of `i` here by using
+        // the `<opaque as IntoIterator>::Item` obligation. This means
+        // we not only have to consider item bounds, but also blanket impls.
+        for i in iterator(false) {
+            i.len();
+        }
+    }
+
+    vec![].into_iter()
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/use-item-bound-over-blanket-impl.rs b/tests/ui/impl-trait/non-defining-uses/use-item-bound-over-blanket-impl.rs
new file mode 100644
index 00000000000..7c2766ade3f
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/use-item-bound-over-blanket-impl.rs
@@ -0,0 +1,30 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+#![allow(unconditional_recursion)]
+
+// Regression test for trait-system-refactor-initiative#182.
+
+trait Id {
+    type This;
+}
+impl<T> Id for T {
+    type This = T;
+}
+fn to_assoc<T>(x: T) -> <T as Id>::This {
+    x
+}
+
+fn mirror<T>(x: Vec<T>) -> impl Id<This = Vec<T>> {
+    let x = to_assoc(mirror(x));
+    // `?x` equals `<opaque::<T> as Id>::This`. We need to eagerly infer the
+    // type of `?x` to prevent this method call from resulting in an error.
+    //
+    // We could use both the item bound to normalize to `Vec<T>`, or the
+    // blanket impl to normalize to `opaque::<T>`. We have to go with the
+    // item bound.
+    x.len();
+    x
+}
+fn main() {}
diff --git a/tests/ui/impl-trait/non-defining-uses/use-item-bound.rs b/tests/ui/impl-trait/non-defining-uses/use-item-bound.rs
new file mode 100644
index 00000000000..36dcbacbe6f
--- /dev/null
+++ b/tests/ui/impl-trait/non-defining-uses/use-item-bound.rs
@@ -0,0 +1,25 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ check-pass
+#![allow(unconditional_recursion)]
+// Regression test for trait-system-refactor-initiative#182.
+
+trait Id {
+    type This;
+}
+impl<T> Id for Vec<T> {
+    type This = Vec<T>;
+}
+fn to_assoc<T: Id>(x: T) -> <T as Id>::This {
+    todo!()
+}
+
+fn mirror<T>(x: Vec<T>) -> impl Id<This = Vec<T>> {
+    let x = to_assoc(mirror(x));
+    // `?x` equals `<opaque::<T> as Id>::This`. We need to eagerly infer the
+    // type of `?x` to prevent this method call from resulting in an error.
+    x.len();
+    x
+}
+fn main() {}
diff --git a/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs b/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs
index 695a752fe17..5ac50c943d0 100644
--- a/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs
+++ b/tests/ui/macros/metavar-expressions/concat-allowed-operations.rs
@@ -92,6 +92,12 @@ macro_rules! combinations {
     }};
 }
 
+macro_rules! int_struct {
+    ($n: literal) => {
+        struct ${concat(E, $n)};
+    }
+}
+
 fn main() {
     create_things!(behold);
     behold_separated_idents_in_a_fn();
@@ -112,4 +118,16 @@ fn main() {
     assert_eq!(VAR_123, 2);
 
     combinations!(_hello, "a", b, "b");
+
+    int_struct!(1_0);
+    int_struct!(2);
+    int_struct!(3___0);
+    int_struct!(7_);
+    int_struct!(08);
+
+    let _ = E1_0;
+    let _ = E2;
+    let _ = E3___0;
+    let _ = E7_;
+    let _ = E08;
 }
diff --git a/tests/ui/macros/metavar-expressions/concat-usage-errors.rs b/tests/ui/macros/metavar-expressions/concat-usage-errors.rs
index 7d8756de9e2..277ad240b1b 100644
--- a/tests/ui/macros/metavar-expressions/concat-usage-errors.rs
+++ b/tests/ui/macros/metavar-expressions/concat-usage-errors.rs
@@ -140,7 +140,9 @@ macro_rules! bad_literal_non_string {
         //~| ERROR metavariables of `${concat(..)}` must be of type
         //~| ERROR metavariables of `${concat(..)}` must be of type
         //~| ERROR metavariables of `${concat(..)}` must be of type
-        //~| ERROR metavariables of `${concat(..)}` must be of type
+        //~| ERROR floats are not supported as metavariables of `${concat(..)}`
+        //~| ERROR integer metavariables of `${concat(..)}` must not be suffixed
+        //~| ERROR integer metavariables of `${concat(..)}` must not be suffixed
     }
 }
 
@@ -149,7 +151,6 @@ macro_rules! bad_tt_literal {
         const ${concat(_foo, $tt)}: () = ();
         //~^ ERROR metavariables of `${concat(..)}` must be of type
         //~| ERROR metavariables of `${concat(..)}` must be of type
-        //~| ERROR metavariables of `${concat(..)}` must be of type
     }
 }
 
@@ -178,13 +179,14 @@ fn main() {
     bad_literal_string!("1.0");
     bad_literal_string!("'1'");
 
-    bad_literal_non_string!(1);
     bad_literal_non_string!(-1);
     bad_literal_non_string!(1.0);
     bad_literal_non_string!('1');
     bad_literal_non_string!(false);
+    bad_literal_non_string!(4f64);
+    bad_literal_non_string!(5u8);
+    bad_literal_non_string!(6_u8);
 
-    bad_tt_literal!(1);
     bad_tt_literal!(1.0);
     bad_tt_literal!('1');
 }
diff --git a/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr b/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr
index 8be3e792ec3..c124b76cb78 100644
--- a/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr
+++ b/tests/ui/macros/metavar-expressions/concat-usage-errors.stderr
@@ -130,7 +130,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t
 LL |         ${concat($ex, aaaa)}
    |                   ^^
    |
-   = note: currently only string literals are supported
+   = note: currently only string and integer literals are supported
 
 error: variable `foo` is not recognized in meta-variable expression
   --> $DIR/concat-usage-errors.rs:37:30
@@ -276,7 +276,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t
 LL |         const ${concat(_foo, $literal)}: () = ();
    |                               ^^^^^^^
    |
-   = note: currently only string literals are supported
+   = note: currently only string and integer literals are supported
 
 error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
   --> $DIR/concat-usage-errors.rs:138:31
@@ -284,7 +284,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t
 LL |         const ${concat(_foo, $literal)}: () = ();
    |                               ^^^^^^^
    |
-   = note: currently only string literals are supported
+   = note: currently only string and integer literals are supported
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
@@ -293,7 +293,7 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t
 LL |         const ${concat(_foo, $literal)}: () = ();
    |                               ^^^^^^^
    |
-   = note: currently only string literals are supported
+   = note: currently only string and integer literals are supported
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
@@ -302,43 +302,45 @@ error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `t
 LL |         const ${concat(_foo, $literal)}: () = ();
    |                               ^^^^^^^
    |
-   = note: currently only string literals are supported
+   = note: currently only string and integer literals are supported
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
+error: floats are not supported as metavariables of `${concat(..)}`
   --> $DIR/concat-usage-errors.rs:138:31
    |
 LL |         const ${concat(_foo, $literal)}: () = ();
    |                               ^^^^^^^
+
+error: integer metavariables of `${concat(..)}` must not be suffixed
+  --> $DIR/concat-usage-errors.rs:138:31
    |
-   = note: currently only string literals are supported
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                               ^^^^^^^
 
-error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
-  --> $DIR/concat-usage-errors.rs:149:31
+error: integer metavariables of `${concat(..)}` must not be suffixed
+  --> $DIR/concat-usage-errors.rs:138:31
    |
-LL |         const ${concat(_foo, $tt)}: () = ();
-   |                               ^^
+LL |         const ${concat(_foo, $literal)}: () = ();
+   |                               ^^^^^^^
    |
-   = note: currently only string literals are supported
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
-  --> $DIR/concat-usage-errors.rs:149:31
+  --> $DIR/concat-usage-errors.rs:151:31
    |
 LL |         const ${concat(_foo, $tt)}: () = ();
    |                               ^^
    |
-   = note: currently only string literals are supported
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: currently only string and integer literals are supported
 
 error: metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`
-  --> $DIR/concat-usage-errors.rs:149:31
+  --> $DIR/concat-usage-errors.rs:151:31
    |
 LL |         const ${concat(_foo, $tt)}: () = ();
    |                               ^^
    |
-   = note: currently only string literals are supported
+   = note: currently only string and integer literals are supported
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 43 previous errors
+error: aborting due to 44 previous errors
 
diff --git a/tests/ui/traits/const-traits/const-impl-trait.rs b/tests/ui/traits/const-traits/const-impl-trait.rs
index da28d9a47c3..c89aaa62d99 100644
--- a/tests/ui/traits/const-traits/const-impl-trait.rs
+++ b/tests/ui/traits/const-traits/const-impl-trait.rs
@@ -1,7 +1,5 @@
+//@ check-pass
 //@ compile-flags: -Znext-solver
-//@ known-bug: #110395
-
-// Broken until `(): const PartialEq`
 
 #![allow(incomplete_features)]
 #![feature(const_trait_impl, const_cmp, const_destruct)]
diff --git a/tests/ui/traits/const-traits/const-impl-trait.stderr b/tests/ui/traits/const-traits/const-impl-trait.stderr
deleted file mode 100644
index cbb68d8c983..00000000000
--- a/tests/ui/traits/const-traits/const-impl-trait.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0277]: the trait bound `(): const PartialEq` is not satisfied
-  --> $DIR/const-impl-trait.rs:34:17
-   |
-LL |     assert!(cmp(&()));
-   |             --- ^^^
-   |             |
-   |             required by a bound introduced by this call
-   |
-note: required by a bound in `cmp`
-  --> $DIR/const-impl-trait.rs:11:23
-   |
-LL | const fn cmp(a: &impl [const] PartialEq) -> bool {
-   |                       ^^^^^^^^^^^^^^^^^ required by this bound in `cmp`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.rs b/tests/ui/traits/const-traits/const_derives/derive-const-use.rs
index 1a3012de06f..78c25ccd6e5 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-use.rs
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.rs
@@ -1,5 +1,4 @@
-//@ known-bug: #110395
-
+//@ check-pass
 #![feature(const_trait_impl, const_default, const_cmp, derive_const)]
 
 pub struct A;
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
deleted file mode 100644
index 4ea11a0c7ed..00000000000
--- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0277]: the trait bound `(): [const] PartialEq` is not satisfied
-  --> $DIR/derive-const-use.rs:16:14
-   |
-LL | #[derive_const(Default, PartialEq)]
-   |                         --------- in this derive macro expansion
-LL | pub struct S((), A);
-   |              ^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.