about summary refs log tree commit diff
path: root/library/std
diff options
context:
space:
mode:
Diffstat (limited to 'library/std')
-rw-r--r--library/std/Cargo.toml1
-rw-r--r--library/std/src/fs.rs11
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--library/std/src/macros.rs74
-rw-r--r--library/std/src/num/f32.rs12
-rw-r--r--library/std/src/num/f64.rs12
-rw-r--r--library/std/src/panic.rs6
-rw-r--r--library/std/src/panicking.rs19
-rw-r--r--library/std/src/path.rs7
-rw-r--r--library/std/src/sync/lazy_lock.rs60
-rw-r--r--library/std/src/sync/mod.rs2
-rw-r--r--library/std/src/sync/nonpoison.rs37
-rw-r--r--library/std/src/sync/nonpoison/mutex.rs611
-rw-r--r--library/std/src/sync/once_lock.rs2
-rw-r--r--library/std/src/sync/poison.rs30
-rw-r--r--library/std/src/sync/poison/condvar.rs2
-rw-r--r--library/std/src/sync/poison/mutex.rs72
-rw-r--r--library/std/src/sync/poison/once.rs6
-rw-r--r--library/std/src/sync/poison/rwlock.rs10
-rw-r--r--library/std/src/sys/args/common.rs2
-rw-r--r--library/std/src/sys/configure_builtins.rs22
-rw-r--r--library/std/src/sys/mod.rs5
-rw-r--r--library/std/src/sys/pal/hermit/thread.rs10
-rw-r--r--library/std/src/sys/pal/itron/thread.rs10
-rw-r--r--library/std/src/sys/pal/sgx/thread.rs12
-rw-r--r--library/std/src/sys/pal/teeos/thread.rs10
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs22
-rw-r--r--library/std/src/sys/pal/uefi/thread.rs10
-rw-r--r--library/std/src/sys/pal/unix/stack_overflow.rs29
-rw-r--r--library/std/src/sys/pal/unix/thread.rs80
-rw-r--r--library/std/src/sys/pal/unsupported/thread.rs10
-rw-r--r--library/std/src/sys/pal/wasi/thread.rs8
-rw-r--r--library/std/src/sys/pal/wasm/atomics/thread.rs10
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt1
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs1
-rw-r--r--library/std/src/sys/pal/windows/stack_overflow.rs3
-rw-r--r--library/std/src/sys/pal/windows/thread.rs14
-rw-r--r--library/std/src/sys/pal/xous/thread.rs10
-rw-r--r--library/std/src/sys/random/sgx.rs14
-rw-r--r--library/std/src/sys/random/uefi.rs5
-rw-r--r--library/std/src/thread/current.rs13
-rw-r--r--library/std/src/thread/mod.rs7
-rw-r--r--library/std/src/thread/tests.rs7
-rw-r--r--library/std/tests/sync/lib.rs55
-rw-r--r--library/std/tests/sync/mutex.rs525
45 files changed, 1555 insertions, 319 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 29ab9be0e69..7bc52976500 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -18,7 +18,6 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core", public = true }
-compiler_builtins = { path = "../compiler-builtins/compiler-builtins" }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.15", default-features = false, features = [
     'rustc-dep-of-std',
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 72ad7c244ee..a220a3f56e9 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -814,7 +814,7 @@ impl File {
     ///
     /// If this file handle/descriptor, or a clone of it, already holds a lock, the exact behavior
     /// is unspecified and platform dependent, including the possibility that it will deadlock.
-    /// However, if this method returns `Ok(true)`, then it has acquired an exclusive lock.
+    /// However, if this method returns `Ok(())`, then it has acquired an exclusive lock.
     ///
     /// If the file is not open for writing, it is unspecified whether this function returns an error.
     ///
@@ -879,7 +879,7 @@ impl File {
     ///
     /// If this file handle, or a clone of it, already holds a lock, the exact behavior is
     /// unspecified and platform dependent, including the possibility that it will deadlock.
-    /// However, if this method returns `Ok(true)`, then it has acquired a shared lock.
+    /// However, if this method returns `Ok(())`, then it has acquired a shared lock.
     ///
     /// The lock will be released when this file (along with any other file descriptors/handles
     /// duplicated or inherited from it) is closed, or if the [`unlock`] method is called.
@@ -1111,6 +1111,11 @@ impl File {
     /// `futimes` on macOS before 10.13) and the `SetFileTime` function on Windows. Note that this
     /// [may change in the future][changes].
     ///
+    /// On most platforms, including UNIX and Windows platforms, this function can also change the
+    /// timestamps of a directory. To get a `File` representing a directory in order to call
+    /// `set_times`, open the directory with `File::open` without attempting to obtain write
+    /// permission.
+    ///
     /// [changes]: io#platform-specific-behavior
     ///
     /// # Errors
@@ -1128,7 +1133,7 @@ impl File {
     ///     use std::fs::{self, File, FileTimes};
     ///
     ///     let src = fs::metadata("src")?;
-    ///     let dest = File::options().write(true).open("dest")?;
+    ///     let dest = File::open("dest")?;
     ///     let times = FileTimes::new()
     ///         .set_accessed(src.accessed()?)
     ///         .set_modified(src.modified()?);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 323742a75b0..0c537530647 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -294,6 +294,8 @@
 #![feature(f128)]
 #![feature(ffi_const)]
 #![feature(formatting_options)]
+#![feature(hash_map_internals)]
+#![feature(hash_map_macro)]
 #![feature(if_let_guard)]
 #![feature(intra_doc_pointers)]
 #![feature(iter_advance_by)]
@@ -319,18 +321,17 @@
 #![feature(try_blocks)]
 #![feature(try_trait_v2)]
 #![feature(type_alias_impl_trait)]
-#![feature(unsigned_signed_diff)]
 // tidy-alphabetical-end
 //
 // Library features (core):
 // tidy-alphabetical-start
-#![feature(array_chunks)]
 #![feature(bstr)]
 #![feature(bstr_internals)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
+#![feature(drop_guard)]
 #![feature(duration_constants)]
 #![feature(error_generic_member_access)]
 #![feature(error_iter)]
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 25e2b7ea137..254570ae9c8 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -379,3 +379,77 @@ macro_rules! dbg {
         ($($crate::dbg!($val)),+,)
     };
 }
+
+#[doc(hidden)]
+#[macro_export]
+#[allow_internal_unstable(hash_map_internals)]
+#[unstable(feature = "hash_map_internals", issue = "none")]
+macro_rules! repetition_utils {
+    (@count $($tokens:tt),*) => {{
+        [$($crate::repetition_utils!(@replace $tokens => ())),*].len()
+    }};
+
+    (@replace $x:tt => $y:tt) => { $y }
+}
+
+/// Creates a [`HashMap`] containing the arguments.
+///
+/// `hash_map!` allows specifying the entries that make
+/// up the [`HashMap`] where the key and value are separated by a `=>`.
+///
+/// The entries are separated by commas with a trailing comma being allowed.
+///
+/// It is semantically equivalent to using repeated [`HashMap::insert`]
+/// on a newly created hashmap.
+///
+/// `hash_map!` will attempt to avoid repeated reallocations by
+/// using [`HashMap::with_capacity`].
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(hash_map_macro)]
+///
+/// let map = hash_map! {
+///     "key" => "value",
+///     "key1" => "value1"
+/// };
+///
+/// assert_eq!(map.get("key"), Some(&"value"));
+/// assert_eq!(map.get("key1"), Some(&"value1"));
+/// assert!(map.get("brrrrrrooooommm").is_none());
+/// ```
+///
+/// And with a trailing comma
+///
+///```rust
+/// #![feature(hash_map_macro)]
+///
+/// let map = hash_map! {
+///     "key" => "value", // notice the ,
+/// };
+///
+/// assert_eq!(map.get("key"), Some(&"value"));
+/// ```
+///
+/// The key and value are moved into the HashMap.
+///
+/// [`HashMap`]: crate::collections::HashMap
+/// [`HashMap::insert`]: crate::collections::HashMap::insert
+/// [`HashMap::with_capacity`]: crate::collections::HashMap::with_capacity
+#[macro_export]
+#[allow_internal_unstable(hash_map_internals)]
+#[unstable(feature = "hash_map_macro", issue = "144032")]
+macro_rules! hash_map {
+    () => {{
+        $crate::collections::HashMap::new()
+    }};
+
+    ( $( $key:expr => $value:expr ),* $(,)? ) => {{
+        let mut map = $crate::collections::HashMap::with_capacity(
+            const { $crate::repetition_utils!(@count $($key),*) }
+        );
+        $( map.insert($key, $value); )*
+        map
+    }}
+}
diff --git a/library/std/src/num/f32.rs b/library/std/src/num/f32.rs
index 2bff73add33..5dee68ad909 100644
--- a/library/std/src/num/f32.rs
+++ b/library/std/src/num/f32.rs
@@ -44,7 +44,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn floor(self) -> f32 {
         core::f32::math::floor(self)
@@ -67,7 +67,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn ceil(self) -> f32 {
         core::f32::math::ceil(self)
@@ -96,7 +96,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn round(self) -> f32 {
         core::f32::math::round(self)
@@ -123,7 +123,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "round_ties_even", since = "1.77.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn round_ties_even(self) -> f32 {
         core::f32::math::round_ties_even(self)
@@ -149,7 +149,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn trunc(self) -> f32 {
         core::f32::math::trunc(self)
@@ -173,7 +173,7 @@ impl f32 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn fract(self) -> f32 {
         core::f32::math::fract(self)
diff --git a/library/std/src/num/f64.rs b/library/std/src/num/f64.rs
index b71e319f407..3ec80f68bdb 100644
--- a/library/std/src/num/f64.rs
+++ b/library/std/src/num/f64.rs
@@ -44,7 +44,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn floor(self) -> f64 {
         core::f64::math::floor(self)
@@ -67,7 +67,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn ceil(self) -> f64 {
         core::f64::math::ceil(self)
@@ -96,7 +96,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn round(self) -> f64 {
         core::f64::math::round(self)
@@ -123,7 +123,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "round_ties_even", since = "1.77.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn round_ties_even(self) -> f64 {
         core::f64::math::round_ties_even(self)
@@ -149,7 +149,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn trunc(self) -> f64 {
         core::f64::math::trunc(self)
@@ -173,7 +173,7 @@ impl f64 {
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_stable(feature = "const_float_round_methods", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "const_float_round_methods", since = "1.90.0")]
     #[inline]
     pub const fn fract(self) -> f64 {
         core::f64::math::fract(self)
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index 234fb284a59..cff4f20b5a8 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -108,8 +108,6 @@ impl<'a> PanicHookInfo<'a> {
     /// # Example
     ///
     /// ```should_panic
-    /// #![feature(panic_payload_as_str)]
-    ///
     /// std::panic::set_hook(Box::new(|panic_info| {
     ///     if let Some(s) = panic_info.payload_as_str() {
     ///         println!("panic occurred: {s:?}");
@@ -122,7 +120,7 @@ impl<'a> PanicHookInfo<'a> {
     /// ```
     #[must_use]
     #[inline]
-    #[unstable(feature = "panic_payload_as_str", issue = "125175")]
+    #[stable(feature = "panic_payload_as_str", since = "CURRENT_RUSTC_VERSION")]
     pub fn payload_as_str(&self) -> Option<&str> {
         if let Some(s) = self.payload.downcast_ref::<&str>() {
             Some(s)
@@ -388,7 +386,7 @@ pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
 /// ```
 #[stable(feature = "resume_unwind", since = "1.9.0")]
 pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
-    panicking::rust_panic_without_hook(payload)
+    panicking::resume_unwind(payload)
 }
 
 /// Makes all future panics abort directly without running the panic hook or unwinding.
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 7873049d20b..87a3fc80dfa 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -269,6 +269,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
 
         thread::with_current_name(|name| {
             let name = name.unwrap_or("<unnamed>");
+            let tid = thread::current_os_id();
 
             // Try to write the panic message to a buffer first to prevent other concurrent outputs
             // interleaving with it.
@@ -277,7 +278,7 @@ fn default_hook(info: &PanicHookInfo<'_>) {
 
             let write_msg = |dst: &mut dyn crate::io::Write| {
                 // We add a newline to ensure the panic message appears at the start of a line.
-                writeln!(dst, "\nthread '{name}' panicked at {location}:\n{msg}")
+                writeln!(dst, "\nthread '{name}' ({tid}) panicked at {location}:\n{msg}")
             };
 
             if write_msg(&mut cursor).is_ok() {
@@ -627,7 +628,7 @@ pub fn panicking() -> bool {
 /// Entry point of panics from the core crate (`panic_impl` lang item).
 #[cfg(not(any(test, doctest)))]
 #[panic_handler]
-pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
+pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
     struct FormatStringPayload<'a> {
         inner: &'a core::panic::PanicMessage<'a>,
         string: Option<String>,
@@ -696,14 +697,14 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
     let msg = info.message();
     crate::sys::backtrace::__rust_end_short_backtrace(move || {
         if let Some(s) = msg.as_str() {
-            rust_panic_with_hook(
+            panic_with_hook(
                 &mut StaticStrPayload(s),
                 loc,
                 info.can_unwind(),
                 info.force_no_backtrace(),
             );
         } else {
-            rust_panic_with_hook(
+            panic_with_hook(
                 &mut FormatStringPayload { inner: &msg, string: None },
                 loc,
                 info.can_unwind(),
@@ -767,7 +768,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
 
     let loc = Location::caller();
     crate::sys::backtrace::__rust_end_short_backtrace(move || {
-        rust_panic_with_hook(
+        panic_with_hook(
             &mut Payload { inner: Some(msg) },
             loc,
             /* can_unwind */ true,
@@ -792,7 +793,7 @@ fn payload_as_str(payload: &dyn Any) -> &str {
 /// panics, panic hooks, and finally dispatching to the panic runtime to either
 /// abort or unwind.
 #[optimize(size)]
-fn rust_panic_with_hook(
+fn panic_with_hook(
     payload: &mut dyn PanicPayload,
     location: &Location<'_>,
     can_unwind: bool,
@@ -861,7 +862,7 @@ fn rust_panic_with_hook(
 /// This is the entry point for `resume_unwind`.
 /// It just forwards the payload to the panic runtime.
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
-pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
+pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! {
     panic_count::increase(false);
 
     struct RewrapBox(Box<dyn Any + Send>);
@@ -885,8 +886,8 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
     rust_panic(&mut RewrapBox(payload))
 }
 
-/// An unmangled function (through `rustc_std_internal_symbol`) on which to slap
-/// yer breakpoints.
+/// A function with a fixed suffix (through `rustc_std_internal_symbol`)
+/// on which to slap yer breakpoints.
 #[inline(never)]
 #[cfg_attr(not(test), rustc_std_internal_symbol)]
 #[cfg(not(feature = "panic_immediate_abort"))]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index d9c34d4fa04..e7ba6936435 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2683,6 +2683,8 @@ impl Path {
     ///
     /// assert_eq!("foo", Path::new("foo.rs").file_prefix().unwrap());
     /// assert_eq!("foo", Path::new("foo.tar.gz").file_prefix().unwrap());
+    /// assert_eq!(".config", Path::new(".config").file_prefix().unwrap());
+    /// assert_eq!(".config", Path::new(".config.toml").file_prefix().unwrap());
     /// ```
     ///
     /// # See Also
@@ -3259,8 +3261,8 @@ impl Path {
     ///
     /// # Examples
     ///
-    #[cfg_attr(unix, doc = "```no_run")]
-    #[cfg_attr(not(unix), doc = "```ignore")]
+    /// ```rust,no_run
+    /// # #[cfg(unix)] {
     /// use std::path::Path;
     /// use std::os::unix::fs::symlink;
     ///
@@ -3268,6 +3270,7 @@ impl Path {
     /// symlink("/origin_does_not_exist/", link_path).unwrap();
     /// assert_eq!(link_path.is_symlink(), true);
     /// assert_eq!(link_path.exists(), false);
+    /// # }
     /// ```
     ///
     /// # See Also
diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs
index eba849d16da..a40e29a772a 100644
--- a/library/std/src/sync/lazy_lock.rs
+++ b/library/std/src/sync/lazy_lock.rs
@@ -25,6 +25,22 @@ union Data<T, F> {
 ///
 /// [`LazyCell`]: crate::cell::LazyCell
 ///
+/// # Poisoning
+///
+/// If the initialization closure passed to [`LazyLock::new`] panics, the lock will be poisoned.
+/// Once the lock is poisoned, any threads that attempt to access this lock (via a dereference
+/// or via an explicit call to [`force()`]) will panic.
+///
+/// This concept is similar to that of poisoning in the [`std::sync::poison`] module. A key
+/// difference, however, is that poisoning in `LazyLock` is _unrecoverable_. All future accesses of
+/// the lock from other threads will panic, whereas a type in [`std::sync::poison`] like
+/// [`std::sync::poison::Mutex`] allows recovery via [`PoisonError::into_inner()`].
+///
+/// [`force()`]: LazyLock::force
+/// [`std::sync::poison`]: crate::sync::poison
+/// [`std::sync::poison::Mutex`]: crate::sync::poison::Mutex
+/// [`PoisonError::into_inner()`]: crate::sync::poison::PoisonError::into_inner
+///
 /// # Examples
 ///
 /// Initialize static variables with `LazyLock`.
@@ -102,6 +118,10 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     ///
     /// Returns `Ok(value)` if `Lazy` is initialized and `Err(f)` otherwise.
     ///
+    /// # Panics
+    ///
+    /// Panics if the lock is poisoned.
+    ///
     /// # Examples
     ///
     /// ```
@@ -136,6 +156,15 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// Forces the evaluation of this lazy value and returns a mutable reference to
     /// the result.
     ///
+    /// # Panics
+    ///
+    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
+    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
+    /// accesses of the lock (via [`force()`] or a dereference) to panic.
+    ///
+    /// [`new()`]: LazyLock::new
+    /// [`force()`]: LazyLock::force
+    ///
     /// # Examples
     ///
     /// ```
@@ -193,6 +222,15 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
     /// This method will block the calling thread if another initialization
     /// routine is currently running.
     ///
+    /// # Panics
+    ///
+    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
+    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
+    /// accesses of the lock (via [`force()`] or a dereference) to panic.
+    ///
+    /// [`new()`]: LazyLock::new
+    /// [`force()`]: LazyLock::force
+    ///
     /// # Examples
     ///
     /// ```
@@ -227,7 +265,8 @@ impl<T, F: FnOnce() -> T> LazyLock<T, F> {
 }
 
 impl<T, F> LazyLock<T, F> {
-    /// Returns a mutable reference to the value if initialized, or `None` if not.
+    /// Returns a mutable reference to the value if initialized. Otherwise (if uninitialized or
+    /// poisoned), returns `None`.
     ///
     /// # Examples
     ///
@@ -256,7 +295,8 @@ impl<T, F> LazyLock<T, F> {
         }
     }
 
-    /// Returns a reference to the value if initialized, or `None` if not.
+    /// Returns a reference to the value if initialized. Otherwise (if uninitialized or poisoned),
+    /// returns `None`.
     ///
     /// # Examples
     ///
@@ -307,6 +347,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
     /// This method will block the calling thread if another initialization
     /// routine is currently running.
     ///
+    /// # Panics
+    ///
+    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
+    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
+    /// accesses of the lock (via [`force()`] or a dereference) to panic.
+    ///
+    /// [`new()`]: LazyLock::new
+    /// [`force()`]: LazyLock::force
     #[inline]
     fn deref(&self) -> &T {
         LazyLock::force(self)
@@ -315,6 +363,14 @@ impl<T, F: FnOnce() -> T> Deref for LazyLock<T, F> {
 
 #[stable(feature = "lazy_deref_mut", since = "1.89.0")]
 impl<T, F: FnOnce() -> T> DerefMut for LazyLock<T, F> {
+    /// # Panics
+    ///
+    /// If the initialization closure panics (the one that is passed to the [`new()`] method), the
+    /// panic is propagated to the caller, and the lock becomes poisoned. This will cause all future
+    /// accesses of the lock (via [`force()`] or a dereference) to panic.
+    ///
+    /// [`new()`]: LazyLock::new
+    /// [`force()`]: LazyLock::force
     #[inline]
     fn deref_mut(&mut self) -> &mut T {
         LazyLock::force_mut(self)
diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs
index e67b4f6f22f..6ef3bf25cf6 100644
--- a/library/std/src/sync/mod.rs
+++ b/library/std/src/sync/mod.rs
@@ -225,6 +225,8 @@ pub use self::poison::{MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWrit
 pub mod mpmc;
 pub mod mpsc;
 
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+pub mod nonpoison;
 #[unstable(feature = "sync_poison_mod", issue = "134646")]
 pub mod poison;
 
diff --git a/library/std/src/sync/nonpoison.rs b/library/std/src/sync/nonpoison.rs
new file mode 100644
index 00000000000..2bbf226dc2c
--- /dev/null
+++ b/library/std/src/sync/nonpoison.rs
@@ -0,0 +1,37 @@
+//! Non-poisoning synchronous locks.
+//!
+//! The difference from the locks in the [`poison`] module is that the locks in this module will not
+//! become poisoned when a thread panics while holding a guard.
+//!
+//! [`poison`]: super::poison
+
+use crate::fmt;
+
+/// A type alias for the result of a nonblocking locking method.
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+pub type TryLockResult<Guard> = Result<Guard, WouldBlock>;
+
+/// A lock could not be acquired at this time because the operation would otherwise block.
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+pub struct WouldBlock;
+
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+impl fmt::Debug for WouldBlock {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "WouldBlock".fmt(f)
+    }
+}
+
+#[unstable(feature = "sync_nonpoison", issue = "134645")]
+impl fmt::Display for WouldBlock {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "try_lock failed because the operation would block".fmt(f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+pub use self::mutex::MappedMutexGuard;
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+pub use self::mutex::{Mutex, MutexGuard};
+
+mod mutex;
diff --git a/library/std/src/sync/nonpoison/mutex.rs b/library/std/src/sync/nonpoison/mutex.rs
new file mode 100644
index 00000000000..b6861c78f00
--- /dev/null
+++ b/library/std/src/sync/nonpoison/mutex.rs
@@ -0,0 +1,611 @@
+use crate::cell::UnsafeCell;
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::{self, ManuallyDrop};
+use crate::ops::{Deref, DerefMut};
+use crate::ptr::NonNull;
+use crate::sync::nonpoison::{TryLockResult, WouldBlock};
+use crate::sys::sync as sys;
+
+/// A mutual exclusion primitive useful for protecting shared data that does not keep track of
+/// lock poisoning.
+///
+/// For more information about mutexes, check out the documentation for the poisoning variant of
+/// this lock at [`poison::Mutex`].
+///
+/// [`poison::Mutex`]: crate::sync::poison::Mutex
+///
+/// # Examples
+///
+/// Note that this `Mutex` does **not** propagate threads that panic while holding the lock via
+/// poisoning. If you need this functionality, see [`poison::Mutex`].
+///
+/// ```
+/// #![feature(nonpoison_mutex)]
+///
+/// use std::thread;
+/// use std::sync::{Arc, nonpoison::Mutex};
+///
+/// let mutex = Arc::new(Mutex::new(0u32));
+/// let mut handles = Vec::new();
+///
+/// for n in 0..10 {
+///     let m = Arc::clone(&mutex);
+///     let handle = thread::spawn(move || {
+///         let mut guard = m.lock();
+///         *guard += 1;
+///         panic!("panic from thread {n} {guard}")
+///     });
+///     handles.push(handle);
+/// }
+///
+/// for h in handles {
+///     let _ = h.join();
+/// }
+///
+/// println!("Finished, locked {} times", mutex.lock());
+/// ```
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonMutex")]
+pub struct Mutex<T: ?Sized> {
+    inner: sys::Mutex,
+    data: UnsafeCell<T>,
+}
+
+/// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
+/// the owned `T` from the `Mutex` via [`into_inner`].
+///
+/// [`into_inner`]: Mutex::into_inner
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
+
+/// `T` must be `Send` for [`Mutex`] to be `Sync`.
+/// This ensures that the protected data can be accessed safely from multiple threads
+/// without causing data races or other unsafe behavior.
+///
+/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
+/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
+/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer,
+/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
+/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
+/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
+/// to potential data races.
+///
+/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
+/// to one thread at a time if `T` is not `Sync`.
+///
+/// [`Rc`]: crate::rc::Rc
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
+
+/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
+/// dropped (falls out of scope), the lock will be unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`lock`] and [`try_lock`] methods on
+/// [`Mutex`].
+///
+/// [`lock`]: Mutex::lock
+/// [`try_lock`]: Mutex::try_lock
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MutexGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+#[clippy::has_significant_drop]
+#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonMutexGuard")]
+pub struct MutexGuard<'a, T: ?Sized + 'a> {
+    lock: &'a Mutex<T>,
+}
+
+/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
+///
+/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
+/// release mutex locks on the same thread they were acquired.
+/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
+/// another thread.
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
+
+/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
+/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}
+
+// FIXME(nonpoison_condvar): Use this link instead: [`Condvar`]: crate::sync::nonpoison::Condvar
+/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
+/// subfield of the protected data. When this structure is dropped (falls out
+/// of scope), the lock will be unlocked.
+///
+/// The main difference between `MappedMutexGuard` and [`MutexGuard`] is that the
+/// former cannot be used with [`Condvar`], since that could introduce soundness issues if the
+/// locked object is modified by another thread while the `Mutex` is unlocked.
+///
+/// The data protected by the mutex can be accessed through this guard via its
+/// [`Deref`] and [`DerefMut`] implementations.
+///
+/// This structure is created by the [`map`] and [`filter_map`] methods on
+/// [`MutexGuard`].
+///
+/// [`map`]: MutexGuard::map
+/// [`filter_map`]: MutexGuard::filter_map
+/// [`Condvar`]: crate::sync::Condvar
+#[must_use = "if unused the Mutex will immediately unlock"]
+#[must_not_suspend = "holding a MappedMutexGuard across suspend \
+                      points can cause deadlocks, delays, \
+                      and cause Futures to not implement `Send`"]
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+#[clippy::has_significant_drop]
+pub struct MappedMutexGuard<'a, T: ?Sized + 'a> {
+    // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a
+    // `MappedMutexGuard` argument doesn't hold uniqueness for its whole scope, only until it drops.
+    // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field
+    // below for the correct variance over `T` (invariance).
+    data: NonNull<T>,
+    inner: &'a sys::Mutex,
+    _variance: PhantomData<&'a mut T>,
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> !Send for MappedMutexGuard<'_, T> {}
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+unsafe impl<T: ?Sized + Sync> Sync for MappedMutexGuard<'_, T> {}
+
+impl<T> Mutex<T> {
+    /// Creates a new mutex in an unlocked state ready for use.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(nonpoison_mutex)]
+    ///
+    /// use std::sync::nonpoison::Mutex;
+    ///
+    /// let mutex = Mutex::new(0);
+    /// ```
+    #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    #[inline]
+    pub const fn new(t: T) -> Mutex<T> {
+        Mutex { inner: sys::Mutex::new(), data: UnsafeCell::new(t) }
+    }
+
+    /// Returns the contained value by cloning it.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(nonpoison_mutex)]
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::nonpoison::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.get_cloned(), 7);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn get_cloned(&self) -> T
+    where
+        T: Clone,
+    {
+        self.lock().clone()
+    }
+
+    /// Sets the contained value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(nonpoison_mutex)]
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::nonpoison::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.get_cloned(), 7);
+    /// mutex.set(11);
+    /// assert_eq!(mutex.get_cloned(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn set(&self, value: T) {
+        if mem::needs_drop::<T>() {
+            // If the contained value has a non-trivial destructor, we
+            // call that destructor after the lock has been released.
+            drop(self.replace(value))
+        } else {
+            *self.lock() = value;
+        }
+    }
+
+    /// Replaces the contained value with `value`, and returns the old contained value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(nonpoison_mutex)]
+    /// #![feature(lock_value_accessors)]
+    ///
+    /// use std::sync::nonpoison::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(7);
+    ///
+    /// assert_eq!(mutex.replace(11), 7);
+    /// assert_eq!(mutex.get_cloned(), 11);
+    /// ```
+    #[unstable(feature = "lock_value_accessors", issue = "133407")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn replace(&self, value: T) -> T {
+        let mut guard = self.lock();
+        mem::replace(&mut *guard, value)
+    }
+}
+
+impl<T: ?Sized> Mutex<T> {
+    /// Acquires a mutex, blocking the current thread until it is able to do so.
+    ///
+    /// This function will block the local thread until it is available to acquire
+    /// the mutex. Upon returning, the thread is the only thread with the lock
+    /// held. An RAII guard is returned to allow scoped unlock of the lock. When
+    /// the guard goes out of scope, the mutex will be unlocked.
+    ///
+    /// The exact behavior on locking a mutex in the thread which already holds
+    /// the lock is left unspecified. However, this function will not return on
+    /// the second call (it might panic or deadlock, for example).
+    ///
+    /// # Panics
+    ///
+    /// This function might panic when called if the lock is already held by
+    /// the current thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(nonpoison_mutex)]
+    ///
+    /// use std::sync::{Arc, nonpoison::Mutex};
+    /// use std::thread;
+    ///
+    /// let mutex = Arc::new(Mutex::new(0));
+    /// let c_mutex = Arc::clone(&mutex);
+    ///
+    /// thread::spawn(move || {
+    ///     *c_mutex.lock() = 10;
+    /// }).join().expect("thread::spawn failed");
+    /// assert_eq!(*mutex.lock(), 10);
+    /// ```
+    #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn lock(&self) -> MutexGuard<'_, T> {
+        unsafe {
+            self.inner.lock();
+            MutexGuard::new(self)
+        }
+    }
+
+    /// Attempts to acquire this lock.
+    ///
+    /// This function does not block. If the lock could not be acquired at this time, then
+    /// [`WouldBlock`] is returned. Otherwise, an RAII guard is returned.
+    ///
+    /// The lock will be unlocked when the guard is dropped.
+    ///
+    /// # Errors
+    ///
+    /// If the mutex could not be acquired because it is already locked, then this call will return
+    /// the [`WouldBlock`] error.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::sync::{Arc, Mutex};
+    /// use std::thread;
+    ///
+    /// let mutex = Arc::new(Mutex::new(0));
+    /// let c_mutex = Arc::clone(&mutex);
+    ///
+    /// thread::spawn(move || {
+    ///     let mut lock = c_mutex.try_lock();
+    ///     if let Ok(ref mut mutex) = lock {
+    ///         **mutex = 10;
+    ///     } else {
+    ///         println!("try_lock failed");
+    ///     }
+    /// }).join().expect("thread::spawn failed");
+    /// assert_eq!(*mutex.lock().unwrap(), 10);
+    /// ```
+    #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
+        unsafe { if self.inner.try_lock() { Ok(MutexGuard::new(self)) } else { Err(WouldBlock) } }
+    }
+
+    /// Consumes this mutex, returning the underlying data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(nonpoison_mutex)]
+    ///
+    /// use std::sync::nonpoison::Mutex;
+    ///
+    /// let mutex = Mutex::new(0);
+    /// assert_eq!(mutex.into_inner(), 0);
+    /// ```
+    #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn into_inner(self) -> T
+    where
+        T: Sized,
+    {
+        self.data.into_inner()
+    }
+
+    /// Returns a mutable reference to the underlying data.
+    ///
+    /// Since this call borrows the `Mutex` mutably, no actual locking needs to
+    /// take place -- the mutable borrow statically guarantees no locks exist.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(nonpoison_mutex)]
+    ///
+    /// use std::sync::nonpoison::Mutex;
+    ///
+    /// let mut mutex = Mutex::new(0);
+    /// *mutex.get_mut() = 10;
+    /// assert_eq!(*mutex.lock(), 10);
+    /// ```
+    #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn get_mut(&mut self) -> &mut T {
+        self.data.get_mut()
+    }
+
+    /// Returns a raw pointer to the underlying data.
+    ///
+    /// The returned pointer is always non-null and properly aligned, but it is
+    /// the user's responsibility to ensure that any reads and writes through it
+    /// are properly synchronized to avoid data races, and that it is not read
+    /// or written through after the mutex is dropped.
+    #[unstable(feature = "mutex_data_ptr", issue = "140368")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn data_ptr(&self) -> *mut T {
+        self.data.get()
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T> From<T> for Mutex<T> {
+    /// Creates a new mutex in an unlocked state ready for use.
+    /// This is equivalent to [`Mutex::new`].
+    fn from(t: T) -> Self {
+        Mutex::new(t)
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + Default> Default for Mutex<T> {
+    /// Creates a `Mutex<T>`, with the `Default` value for T.
+    fn default() -> Mutex<T> {
+        Mutex::new(Default::default())
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut d = f.debug_struct("Mutex");
+        match self.try_lock() {
+            Ok(guard) => {
+                d.field("data", &&*guard);
+            }
+            Err(WouldBlock) => {
+                d.field("data", &"<locked>");
+            }
+        }
+        d.finish_non_exhaustive()
+    }
+}
+
+impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> {
+    unsafe fn new(lock: &'mutex Mutex<T>) -> MutexGuard<'mutex, T> {
+        return MutexGuard { lock };
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> Deref for MutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { &*self.lock.data.get() }
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { &mut *self.lock.data.get() }
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized> Drop for MutexGuard<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.lock.inner.unlock();
+        }
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[unstable(feature = "nonpoison_mutex", issue = "134645")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+impl<'a, T: ?Sized> MutexGuard<'a, T> {
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MutexGuard::map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `filter_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedMutexGuard { data, inner: &orig.lock.inner, _variance: PhantomData }
+    }
+
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MutexGuard::filter_map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `filter_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { &mut *orig.lock.data.get() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedMutexGuard { data, inner: &orig.lock.inner, _variance: PhantomData })
+            }
+            None => Err(orig),
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Deref for MappedMutexGuard<'_, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        unsafe { self.data.as_ref() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> DerefMut for MappedMutexGuard<'_, T> {
+    fn deref_mut(&mut self) -> &mut T {
+        unsafe { self.data.as_mut() }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized> Drop for MappedMutexGuard<'_, T> {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe {
+            self.inner.unlock();
+        }
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedMutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&**self, f)
+    }
+}
+
+#[unstable(feature = "mapped_lock_guards", issue = "117108")]
+impl<T: ?Sized + fmt::Display> fmt::Display for MappedMutexGuard<'_, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        (**self).fmt(f)
+    }
+}
+
+impl<'a, T: ?Sized> MappedMutexGuard<'a, T> {
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data, e.g.
+    /// an enum variant.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedMutexGuard::map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U>
+    where
+        F: FnOnce(&mut T) -> &mut U,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `filter_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
+        let orig = ManuallyDrop::new(orig);
+        MappedMutexGuard { data, inner: orig.inner, _variance: PhantomData }
+    }
+
+    /// Makes a [`MappedMutexGuard`] for a component of the borrowed data. The
+    /// original guard is returned as an `Err(...)` if the closure returns
+    /// `None`.
+    ///
+    /// The `Mutex` is already locked, so this cannot fail.
+    ///
+    /// This is an associated function that needs to be used as
+    /// `MappedMutexGuard::filter_map(...)`. A method would interfere with methods of the
+    /// same name on the contents of the `MutexGuard` used through `Deref`.
+    #[unstable(feature = "mapped_lock_guards", issue = "117108")]
+    // #[unstable(feature = "nonpoison_mutex", issue = "134645")]
+    pub fn filter_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U>, Self>
+    where
+        F: FnOnce(&mut T) -> Option<&mut U>,
+        U: ?Sized,
+    {
+        // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard
+        // was created, and have been upheld throughout `map` and/or `filter_map`.
+        // The signature of the closure guarantees that it will not "leak" the lifetime of the reference
+        // passed to it. If the closure panics, the guard will be dropped.
+        match f(unsafe { orig.data.as_mut() }) {
+            Some(data) => {
+                let data = NonNull::from(data);
+                let orig = ManuallyDrop::new(orig);
+                Ok(MappedMutexGuard { data, inner: orig.inner, _variance: PhantomData })
+            }
+            None => Err(orig),
+        }
+    }
+}
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index a5c3a6c46a4..b224044cbe0 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -16,6 +16,8 @@ use crate::sync::Once;
 /// A `OnceLock` can be thought of as a safe abstraction over uninitialized data that becomes
 /// initialized once written.
 ///
+/// Unlike [`Mutex`](crate::sync::Mutex), `OnceLock` is never poisoned on panic.
+///
 /// [`OnceCell`]: crate::cell::OnceCell
 /// [`LazyLock<T, F>`]: crate::sync::LazyLock
 /// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new
diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs
index 0c05f152ef8..31889dcc10f 100644
--- a/library/std/src/sync/poison.rs
+++ b/library/std/src/sync/poison.rs
@@ -2,18 +2,21 @@
 //!
 //! # Poisoning
 //!
-//! All synchronization objects in this module implement a strategy called "poisoning"
-//! where if a thread panics while holding the exclusive access granted by the primitive,
-//! the state of the primitive is set to "poisoned".
-//! This information is then propagated to all other threads
+//! All synchronization objects in this module implement a strategy called
+//! "poisoning" where a primitive becomes poisoned if it recognizes that some
+//! thread has panicked while holding the exclusive access granted by the
+//! primitive. This information is then propagated to all other threads
 //! to signify that the data protected by this primitive is likely tainted
 //! (some invariant is not being upheld).
 //!
-//! The specifics of how this "poisoned" state affects other threads
-//! depend on the primitive. See [#Overview] below.
+//! The specifics of how this "poisoned" state affects other threads and whether
+//! the panics are recognized reliably or on a best-effort basis depend on the
+//! primitive. See [Overview](#overview) below.
 //!
 //! For the alternative implementations that do not employ poisoning,
-//! see `std::sync::nonpoisoning`.
+//! see [`std::sync::nonpoison`].
+//!
+//! [`std::sync::nonpoison`]: crate::sync::nonpoison
 //!
 //! # Overview
 //!
@@ -34,14 +37,15 @@
 //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at
 //!   most one thread at a time is able to access some data.
 //!
-//!   [`Mutex::lock()`] returns a [`LockResult`],
-//!   providing a way to deal with the poisoned state.
-//!   See [`Mutex`'s documentation](Mutex#poisoning) for more.
+//!   Panicking while holding the lock typically poisons the mutex, but it is
+//!   not guaranteed to detect this condition in all circumstances.
+//!   [`Mutex::lock()`] returns a [`LockResult`], providing a way to deal with
+//!   the poisoned state. See [`Mutex`'s documentation](Mutex#poisoning) for more.
 //!
 //! - [`Once`]: A thread-safe way to run a piece of code only once.
 //!   Mostly useful for implementing one-time global initialization.
 //!
-//!   [`Once`] is poisoned if the piece of code passed to
+//!   [`Once`] is reliably poisoned if the piece of code passed to
 //!   [`Once::call_once()`] or [`Once::call_once_force()`] panics.
 //!   When in poisoned state, subsequent calls to [`Once::call_once()`] will panic too.
 //!   [`Once::call_once_force()`] can be used to clear the poisoned state.
@@ -51,13 +55,11 @@
 //!   writer at a time. In some cases, this can be more efficient than
 //!   a mutex.
 //!
-//!   This implementation, like [`Mutex`], will become poisoned on a panic.
+//!   This implementation, like [`Mutex`], usually becomes poisoned on a panic.
 //!   Note, however, that an `RwLock` may only be poisoned if a panic occurs
 //!   while it is locked exclusively (write mode). If a panic occurs in any reader,
 //!   then the lock will not be poisoned.
 
-// FIXME(sync_nonpoison) add links to sync::nonpoison to the doc comment above.
-
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::condvar::{Condvar, WaitTimeoutResult};
 #[unstable(feature = "mapped_lock_guards", issue = "117108")]
diff --git a/library/std/src/sync/poison/condvar.rs b/library/std/src/sync/poison/condvar.rs
index 7f0f3f652bc..0e9d4233c65 100644
--- a/library/std/src/sync/poison/condvar.rs
+++ b/library/std/src/sync/poison/condvar.rs
@@ -13,7 +13,7 @@ use crate::time::{Duration, Instant};
 #[stable(feature = "wait_timeout", since = "1.5.0")]
 pub struct WaitTimeoutResult(bool);
 
-// FIXME(sync_nonpoison): `WaitTimeoutResult` is actually poisoning-agnostic, it seems.
+// FIXME(nonpoison_condvar): `WaitTimeoutResult` is actually poisoning-agnostic, it seems.
 // Should we take advantage of this fact?
 impl WaitTimeoutResult {
     /// Returns `true` if the wait was known to have timed out.
diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs
index 30325be685c..6205c4fa4ca 100644
--- a/library/std/src/sync/poison/mutex.rs
+++ b/library/std/src/sync/poison/mutex.rs
@@ -18,20 +18,69 @@ use crate::sys::sync as sys;
 /// # Poisoning
 ///
 /// The mutexes in this module implement a strategy called "poisoning" where a
-/// mutex is considered poisoned whenever a thread panics while holding the
-/// mutex. Once a mutex is poisoned, all other threads are unable to access the
-/// data by default as it is likely tainted (some invariant is not being
-/// upheld).
+/// mutex becomes poisoned if it recognizes that the thread holding it has
+/// panicked.
 ///
-/// For a mutex, this means that the [`lock`] and [`try_lock`] methods return a
+/// Once a mutex is poisoned, all other threads are unable to access the data by
+/// default as it is likely tainted (some invariant is not being upheld). For a
+/// mutex, this means that the [`lock`] and [`try_lock`] methods return a
 /// [`Result`] which indicates whether a mutex has been poisoned or not. Most
 /// usage of a mutex will simply [`unwrap()`] these results, propagating panics
 /// among threads to ensure that a possibly invalid invariant is not witnessed.
 ///
-/// A poisoned mutex, however, does not prevent all access to the underlying
-/// data. The [`PoisonError`] type has an [`into_inner`] method which will return
-/// the guard that would have otherwise been returned on a successful lock. This
-/// allows access to the data, despite the lock being poisoned.
+/// Poisoning is only advisory: the [`PoisonError`] type has an [`into_inner`]
+/// method which will return the guard that would have otherwise been returned
+/// on a successful lock. This allows access to the data, despite the lock being
+/// poisoned.
+///
+/// In addition, the panic detection is not ideal, so even unpoisoned mutexes
+/// need to be handled with care, since certain panics may have been skipped.
+/// Here is a non-exhaustive list of situations where this might occur:
+///
+/// - If a mutex is locked while a panic is underway, e.g. within a [`Drop`]
+///   implementation or a [panic hook], panicking for the second time while the
+///   lock is held will leave the mutex unpoisoned. Note that while double panic
+///   usually aborts the program, [`catch_unwind`] can prevent this.
+///
+/// - Locking and unlocking the mutex across different panic contexts, e.g. by
+///   storing the guard to a [`Cell`] within [`Drop::drop`] and accessing it
+///   outside, or vice versa, can affect poisoning status in an unexpected way.
+///
+/// - Foreign exceptions do not currently trigger poisoning even in absence of
+///   other panics.
+///
+/// While this rarely happens in realistic code, `unsafe` code cannot rely on
+/// poisoning for soundness, since the behavior of poisoning can depend on
+/// outside context. Here's an example of **incorrect** use of poisoning:
+///
+/// ```rust
+/// use std::sync::Mutex;
+///
+/// struct MutexBox<T> {
+///     data: Mutex<*mut T>,
+/// }
+///
+/// impl<T> MutexBox<T> {
+///     pub fn new(value: T) -> Self {
+///         Self {
+///             data: Mutex::new(Box::into_raw(Box::new(value))),
+///         }
+///     }
+///
+///     pub fn replace_with(&self, f: impl FnOnce(T) -> T) {
+///         let ptr = self.data.lock().expect("poisoned");
+///         // While `f` is running, the data is moved out of `*ptr`. If `f`
+///         // panics, `*ptr` keeps pointing at a dropped value. The intention
+///         // is that this will poison the mutex, so the following calls to
+///         // `replace_with` will panic without reading `*ptr`. But since
+///         // poisoning is not guaranteed to occur if this is run from a panic
+///         // hook, this can lead to use-after-free.
+///         unsafe {
+///             (*ptr).write(f((*ptr).read()));
+///         }
+///     }
+/// }
+/// ```
 ///
 /// [`new`]: Self::new
 /// [`lock`]: Self::lock
@@ -39,6 +88,9 @@ use crate::sys::sync as sys;
 /// [`unwrap()`]: Result::unwrap
 /// [`PoisonError`]: super::PoisonError
 /// [`into_inner`]: super::PoisonError::into_inner
+/// [panic hook]: crate::panic::set_hook
+/// [`catch_unwind`]: crate::panic::catch_unwind
+/// [`Cell`]: crate::cell::Cell
 ///
 /// # Examples
 ///
@@ -650,7 +702,7 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
                 d.field("data", &&**err.get_ref());
             }
             Err(TryLockError::WouldBlock) => {
-                d.field("data", &format_args!("<locked>"));
+                d.field("data", &"<locked>");
             }
         }
         d.field("poisoned", &self.poison.get());
diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs
index 103e5195407..faf2913c547 100644
--- a/library/std/src/sync/poison/once.rs
+++ b/library/std/src/sync/poison/once.rs
@@ -136,7 +136,8 @@ impl Once {
     /// it will *poison* this [`Once`] instance, causing all future invocations of
     /// `call_once` to also panic.
     ///
-    /// This is similar to [poisoning with mutexes][poison].
+    /// This is similar to [poisoning with mutexes][poison], but this mechanism
+    /// is guaranteed to never skip panics within `f`.
     ///
     /// [poison]: struct.Mutex.html#poisoning
     #[inline]
@@ -293,6 +294,9 @@ impl Once {
 
     /// Blocks the current thread until initialization has completed, ignoring
     /// poisoning.
+    ///
+    /// If this [`Once`] has been poisoned, this function blocks until it
+    /// becomes completed, unlike [`Once::wait()`], which panics in this case.
     #[stable(feature = "once_wait", since = "1.86.0")]
     pub fn wait_force(&self) {
         if !self.inner.is_completed() {
diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs
index 934a173425a..2c92602bc87 100644
--- a/library/std/src/sync/poison/rwlock.rs
+++ b/library/std/src/sync/poison/rwlock.rs
@@ -46,10 +46,12 @@ use crate::sys::sync as sys;
 ///
 /// # Poisoning
 ///
-/// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however,
-/// that an `RwLock` may only be poisoned if a panic occurs while it is locked
-/// exclusively (write mode). If a panic occurs in any reader, then the lock
-/// will not be poisoned.
+/// An `RwLock`, like [`Mutex`], will [usually] become poisoned on a panic. Note,
+/// however, that an `RwLock` may only be poisoned if a panic occurs while it is
+/// locked exclusively (write mode). If a panic occurs in any reader, then the
+/// lock will not be poisoned.
+///
+/// [usually]: super::Mutex#poisoning
 ///
 /// # Examples
 ///
diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs
index e787105a05a..33f3794ee63 100644
--- a/library/std/src/sys/args/common.rs
+++ b/library/std/src/sys/args/common.rs
@@ -12,7 +12,7 @@ impl !Sync for Args {}
 
 impl Args {
     #[inline]
-    pub(super) fn new(args: Vec<OsString>) -> Self {
+    pub fn new(args: Vec<OsString>) -> Self {
         Args { iter: args.into_iter() }
     }
 }
diff --git a/library/std/src/sys/configure_builtins.rs b/library/std/src/sys/configure_builtins.rs
new file mode 100644
index 00000000000..9d776b778dc
--- /dev/null
+++ b/library/std/src/sys/configure_builtins.rs
@@ -0,0 +1,22 @@
+/// Hook into .init_array to enable LSE atomic operations at startup, if
+/// supported.
+#[cfg(all(target_arch = "aarch64", target_os = "linux", not(feature = "compiler-builtins-c")))]
+#[used]
+#[unsafe(link_section = ".init_array.90")]
+static RUST_LSE_INIT: extern "C" fn() = {
+    extern "C" fn init_lse() {
+        use crate::arch;
+
+        // This is provided by compiler-builtins::aarch64_linux.
+        unsafe extern "C" {
+            fn __rust_enable_lse();
+        }
+
+        if arch::is_aarch64_feature_detected!("lse") {
+            unsafe {
+                __rust_enable_lse();
+            }
+        }
+    }
+    init_lse
+};
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index f9a02b522e5..8ec0a0e3302 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -1,5 +1,10 @@
 #![allow(unsafe_op_in_unsafe_fn)]
 
+/// The configure builtins provides runtime support compiler-builtin features
+/// which require dynamic intialization to work as expected, e.g. aarch64
+/// outline-atomics.
+mod configure_builtins;
+
 /// The PAL (platform abstraction layer) contains platform-specific abstractions
 /// for implementing the features in the other submodules, e.g. UNIX file
 /// descriptors.
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 9bc5a16b800..cc4734b6819 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -58,7 +58,11 @@ impl Thread {
         }
     }
 
-    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    pub unsafe fn new(
+        stack: usize,
+        _name: Option<&str>,
+        p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
         unsafe {
             Thread::new_with_coreid(stack, p, -1 /* = no specific core */)
         }
@@ -111,6 +115,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsafe { Ok(NonZero::new_unchecked(hermit_abi::available_parallelism())) }
 }
diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs
index 813e1cbcd58..4e14cb3cbca 100644
--- a/library/std/src/sys/pal/itron/thread.rs
+++ b/library/std/src/sys/pal/itron/thread.rs
@@ -86,7 +86,11 @@ impl Thread {
     /// # Safety
     ///
     /// See `thread::Builder::spawn_unchecked` for safety requirements.
-    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    pub unsafe fn new(
+        stack: usize,
+        _name: Option<&str>,
+        p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
         let inner = Box::new(ThreadInner {
             start: UnsafeCell::new(ManuallyDrop::new(p)),
             lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
@@ -357,6 +361,10 @@ unsafe fn terminate_and_delete_current_task() -> ! {
     unsafe { crate::hint::unreachable_unchecked() };
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     super::unsupported()
 }
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index 85f6dcd96b4..1f613badcd7 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -1,6 +1,6 @@
 #![cfg_attr(test, allow(dead_code))] // why is this necessary?
 
-use super::abi::usercalls;
+use super::abi::{thread, usercalls};
 use super::unsupported;
 use crate::ffi::CStr;
 use crate::io;
@@ -96,7 +96,11 @@ pub mod wait_notify {
 
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce() + Send>) -> io::Result<Thread> {
+    pub unsafe fn new(
+        _stack: usize,
+        _name: Option<&str>,
+        p: Box<dyn FnOnce() + Send>,
+    ) -> io::Result<Thread> {
         let mut queue_lock = task_queue::lock();
         unsafe { usercalls::launch_thread()? };
         let (task, handle) = task_queue::Task::new(p);
@@ -145,6 +149,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    Some(thread::current().addr().get() as u64)
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
diff --git a/library/std/src/sys/pal/teeos/thread.rs b/library/std/src/sys/pal/teeos/thread.rs
index b9cdc7a2a58..1812d11e692 100644
--- a/library/std/src/sys/pal/teeos/thread.rs
+++ b/library/std/src/sys/pal/teeos/thread.rs
@@ -22,7 +22,11 @@ unsafe extern "C" {
 
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    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() };
@@ -140,6 +144,10 @@ 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>> {
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 271dc4d11de..b50574de937 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -444,17 +444,17 @@ impl<'a> DevicePathNode<'a> {
 
 impl<'a> PartialEq for DevicePathNode<'a> {
     fn eq(&self, other: &Self) -> bool {
-        let self_len = self.length();
-        let other_len = other.length();
-
-        self_len == other_len
-            && unsafe {
-                compiler_builtins::mem::memcmp(
-                    self.protocol.as_ptr().cast(),
-                    other.protocol.as_ptr().cast(),
-                    usize::from(self_len),
-                ) == 0
-            }
+        // Compare as a single buffer rather than by field since it optimizes better.
+        //
+        // SAFETY: `Protocol` is followed by a buffer of `length - sizeof::<Protocol>()`. `Protocol`
+        // has no padding so it is sound to interpret as a slice.
+        unsafe {
+            let s1 =
+                slice::from_raw_parts(self.protocol.as_ptr().cast::<u8>(), self.length().into());
+            let s2 =
+                slice::from_raw_parts(other.protocol.as_ptr().cast::<u8>(), other.length().into());
+            s1 == s2
+        }
     }
 }
 
diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs
index e4776ec42fb..47a48008c76 100644
--- a/library/std/src/sys/pal/uefi/thread.rs
+++ b/library/std/src/sys/pal/uefi/thread.rs
@@ -11,7 +11,11 @@ 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, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    pub unsafe fn new(
+        _stack: usize,
+        _name: Option<&str>,
+        _p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
         unsupported()
     }
 
@@ -52,6 +56,10 @@ impl Thread {
     }
 }
 
+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/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs
index a3be2cdf738..0d2100d66bc 100644
--- a/library/std/src/sys/pal/unix/stack_overflow.rs
+++ b/library/std/src/sys/pal/unix/stack_overflow.rs
@@ -8,8 +8,8 @@ pub struct Handler {
 }
 
 impl Handler {
-    pub unsafe fn new() -> Handler {
-        make_handler(false)
+    pub unsafe fn new(thread_name: Option<Box<str>>) -> Handler {
+        make_handler(false, thread_name)
     }
 
     fn null() -> Handler {
@@ -72,7 +72,6 @@ mod imp {
     use crate::sync::OnceLock;
     use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, AtomicUsize, Ordering};
     use crate::sys::pal::unix::os;
-    use crate::thread::with_current_name;
     use crate::{io, mem, panic, ptr};
 
     // Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
@@ -120,7 +119,8 @@ mod imp {
                     && thread_info.guard_page_range.contains(&fault_addr)
                 {
                     let name = thread_info.thread_name.as_deref().unwrap_or("<unknown>");
-                    rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
+                    let tid = crate::thread::current_os_id();
+                    rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n");
                     rtabort!("stack overflow");
                 }
             })
@@ -158,13 +158,12 @@ mod imp {
                 if !NEED_ALTSTACK.load(Ordering::Relaxed) {
                     // haven't set up our sigaltstack yet
                     NEED_ALTSTACK.store(true, Ordering::Release);
-                    let handler = unsafe { make_handler(true) };
+                    let handler = unsafe { make_handler(true, None) };
                     MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
                     mem::forget(handler);
 
                     if let Some(guard_page_range) = guard_page_range.take() {
-                        let thread_name = with_current_name(|name| name.map(Box::from));
-                        set_current_info(guard_page_range, thread_name);
+                        set_current_info(guard_page_range, Some(Box::from("main")));
                     }
                 }
 
@@ -230,14 +229,13 @@ mod imp {
     /// # Safety
     /// Mutates the alternate signal stack
     #[forbid(unsafe_op_in_unsafe_fn)]
-    pub unsafe fn make_handler(main_thread: bool) -> Handler {
+    pub unsafe fn make_handler(main_thread: bool, thread_name: Option<Box<str>>) -> Handler {
         if !NEED_ALTSTACK.load(Ordering::Acquire) {
             return Handler::null();
         }
 
         if !main_thread {
             if let Some(guard_page_range) = unsafe { current_guard() } {
-                let thread_name = with_current_name(|name| name.map(Box::from));
                 set_current_info(guard_page_range, thread_name);
             }
         }
@@ -634,7 +632,10 @@ mod imp {
 
     pub unsafe fn cleanup() {}
 
-    pub unsafe fn make_handler(_main_thread: bool) -> super::Handler {
+    pub unsafe fn make_handler(
+        _main_thread: bool,
+        _thread_name: Option<Box<str>>,
+    ) -> super::Handler {
         super::Handler::null()
     }
 
@@ -696,7 +697,8 @@ mod imp {
             if code == c::EXCEPTION_STACK_OVERFLOW {
                 crate::thread::with_current_name(|name| {
                     let name = name.unwrap_or("<unknown>");
-                    rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
+                    let tid = crate::thread::current_os_id();
+                    rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n");
                 });
             }
             c::EXCEPTION_CONTINUE_SEARCH
@@ -717,7 +719,10 @@ mod imp {
 
     pub unsafe fn cleanup() {}
 
-    pub unsafe fn make_handler(main_thread: bool) -> super::Handler {
+    pub unsafe fn make_handler(
+        main_thread: bool,
+        _thread_name: Option<Box<str>>,
+    ) -> super::Handler {
         if !main_thread {
             reserve_stack();
         }
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index e4f5520d8a3..36e53e7cadc 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -22,6 +22,11 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
 #[cfg(any(target_os = "espidf", target_os = "nuttx"))]
 pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used
 
+struct ThreadData {
+    name: Option<Box<str>>,
+    f: Box<dyn FnOnce()>,
+}
+
 pub struct Thread {
     id: libc::pthread_t,
 }
@@ -34,8 +39,12 @@ unsafe impl Sync for Thread {}
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
-        let p = Box::into_raw(Box::new(p));
+    pub unsafe fn new(
+        stack: usize,
+        name: Option<&str>,
+        f: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
+        let data = Box::into_raw(Box::new(ThreadData { name: name.map(Box::from), f }));
         let mut native: libc::pthread_t = mem::zeroed();
         let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
         assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
@@ -73,7 +82,7 @@ impl Thread {
             };
         }
 
-        let ret = libc::pthread_create(&mut native, attr.as_ptr(), thread_start, p as *mut _);
+        let ret = libc::pthread_create(&mut native, attr.as_ptr(), thread_start, data 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.
@@ -82,19 +91,20 @@ impl Thread {
         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.
-            drop(Box::from_raw(p));
+            drop(Box::from_raw(data));
             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 {
+        extern "C" fn thread_start(data: *mut libc::c_void) -> *mut libc::c_void {
             unsafe {
+                let data = Box::from_raw(data as *mut ThreadData);
                 // Next, set up our stack overflow handler which may get triggered if we run
                 // out of stack.
-                let _handler = stack_overflow::Handler::new();
+                let _handler = stack_overflow::Handler::new(data.name);
                 // Finally, let's run some code.
-                Box::from_raw(main as *mut Box<dyn FnOnce()>)();
+                (data.f)();
             }
             ptr::null_mut()
         }
@@ -388,6 +398,62 @@ 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_if::cfg_if! {
+        // Most platforms have a function returning a `pid_t` or int, which is an `i32`.
+        if #[cfg(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)
+        } else if #[cfg(target_os = "nto")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::gettid() };
+            Some(id as u64)
+        } else if #[cfg(target_os = "openbsd")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::pid_t = unsafe { libc::getthrid() };
+            Some(id as u64)
+        } else if #[cfg(target_os = "freebsd")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::c_int = unsafe { libc::pthread_getthreadid_np() };
+            Some(id as u64)
+        } else if #[cfg(target_os = "netbsd")] {
+            // SAFETY: FFI call with no preconditions.
+            let id: libc::lwpid_t = unsafe { libc::_lwp_self() };
+            Some(id as u64)
+        } else if #[cfg(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)
+        } else if #[cfg(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
+            }
+        } else {
+            // 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",
diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs
index 8a3119fa292..34d9b5ec70c 100644
--- a/library/std/src/sys/pal/unsupported/thread.rs
+++ b/library/std/src/sys/pal/unsupported/thread.rs
@@ -10,7 +10,11 @@ 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, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    pub unsafe fn new(
+        _stack: usize,
+        _name: Option<&str>,
+        _p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
         unsupported()
     }
 
@@ -35,6 +39,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs
index 5f21a553673..4755e2ef5da 100644
--- a/library/std/src/sys/pal/wasi/thread.rs
+++ b/library/std/src/sys/pal/wasi/thread.rs
@@ -73,7 +73,7 @@ impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     cfg_if::cfg_if! {
         if #[cfg(target_feature = "atomics")] {
-            pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+            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() };
@@ -120,7 +120,7 @@ impl Thread {
                 }
             }
         } else {
-            pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+            pub unsafe fn new(_stack: usize, _name: Option<&str>, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
                 crate::sys::unsupported()
             }
         }
@@ -194,6 +194,10 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     cfg_if::cfg_if! {
         if #[cfg(target_feature = "atomics")] {
diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs
index 44ce3eab109..42a7dbdf8b8 100644
--- a/library/std/src/sys/pal/wasm/atomics/thread.rs
+++ b/library/std/src/sys/pal/wasm/atomics/thread.rs
@@ -10,7 +10,11 @@ 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, _p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    pub unsafe fn new(
+        _stack: usize,
+        _name: Option<&str>,
+        _p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
         unsupported()
     }
 
@@ -52,6 +56,10 @@ impl Thread {
     pub fn join(self) {}
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    None
+}
+
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
     unsupported()
 }
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index 827d96e73db..c8e4dca4781 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2185,6 +2185,7 @@ GetSystemInfo
 GetSystemTimeAsFileTime
 GetSystemTimePreciseAsFileTime
 GetTempPathW
+GetThreadId
 GetUserProfileDirectoryW
 GetWindowsDirectoryW
 HANDLE
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index b2e3aabc633..45a273d241a 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -61,6 +61,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *
 windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
 windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
 windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
+windows_targets::link!("kernel32.dll" "system" fn GetThreadId(thread : HANDLE) -> u32);
 windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
 windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
 windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
diff --git a/library/std/src/sys/pal/windows/stack_overflow.rs b/library/std/src/sys/pal/windows/stack_overflow.rs
index 734cd30bed0..9a40551b985 100644
--- a/library/std/src/sys/pal/windows/stack_overflow.rs
+++ b/library/std/src/sys/pal/windows/stack_overflow.rs
@@ -20,7 +20,8 @@ unsafe extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POIN
         if code == c::EXCEPTION_STACK_OVERFLOW {
             thread::with_current_name(|name| {
                 let name = name.unwrap_or("<unknown>");
-                rtprintpanic!("\nthread '{name}' has overflowed its stack\n");
+                let tid = thread::current_os_id();
+                rtprintpanic!("\nthread '{name}' ({tid}) has overflowed its stack\n");
             });
         }
         c::EXCEPTION_CONTINUE_SEARCH
diff --git a/library/std/src/sys/pal/windows/thread.rs b/library/std/src/sys/pal/windows/thread.rs
index 14785171755..c708da5af12 100644
--- a/library/std/src/sys/pal/windows/thread.rs
+++ b/library/std/src/sys/pal/windows/thread.rs
@@ -20,7 +20,11 @@ pub struct Thread {
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
-    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    pub unsafe fn new(
+        stack: usize,
+        _name: Option<&str>,
+        p: Box<dyn FnOnce()>,
+    ) -> io::Result<Thread> {
         let p = Box::into_raw(Box::new(p));
 
         // CreateThread rounds up values for the stack size to the nearest page size (at least 4kb).
@@ -123,6 +127,14 @@ impl Thread {
     }
 }
 
+pub(crate) fn current_os_id() -> Option<u64> {
+    // SAFETY: FFI call with no preconditions.
+    let id: u32 = unsafe { c::GetThreadId(c::GetCurrentThread()) };
+
+    // 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();
diff --git a/library/std/src/sys/pal/xous/thread.rs b/library/std/src/sys/pal/xous/thread.rs
index 1b344e984dc..92803c94c6e 100644
--- a/library/std/src/sys/pal/xous/thread.rs
+++ b/library/std/src/sys/pal/xous/thread.rs
@@ -20,7 +20,11 @@ pub const GUARD_PAGE_SIZE: usize = 4096;
 
 impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
-    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+    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 stack_size = crate::cmp::max(stack, MIN_STACK_SIZE);
 
@@ -141,6 +145,10 @@ impl Thread {
     }
 }
 
+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) })
diff --git a/library/std/src/sys/random/sgx.rs b/library/std/src/sys/random/sgx.rs
index c3647a8df22..462b19003fa 100644
--- a/library/std/src/sys/random/sgx.rs
+++ b/library/std/src/sys/random/sgx.rs
@@ -46,22 +46,22 @@ fn rdrand16() -> u16 {
 }
 
 pub fn fill_bytes(bytes: &mut [u8]) {
-    let mut chunks = bytes.array_chunks_mut();
-    for chunk in &mut chunks {
+    let (chunks, remainder) = bytes.as_chunks_mut();
+    for chunk in chunks {
         *chunk = rdrand64().to_ne_bytes();
     }
 
-    let mut chunks = chunks.into_remainder().array_chunks_mut();
-    for chunk in &mut chunks {
+    let (chunks, remainder) = remainder.as_chunks_mut();
+    for chunk in chunks {
         *chunk = rdrand32().to_ne_bytes();
     }
 
-    let mut chunks = chunks.into_remainder().array_chunks_mut();
-    for chunk in &mut chunks {
+    let (chunks, remainder) = remainder.as_chunks_mut();
+    for chunk in chunks {
         *chunk = rdrand16().to_ne_bytes();
     }
 
-    if let [byte] = chunks.into_remainder() {
+    if let [byte] = remainder {
         *byte = rdrand16() as u8;
     }
 }
diff --git a/library/std/src/sys/random/uefi.rs b/library/std/src/sys/random/uefi.rs
index 5f001f0f532..4a71d32fffe 100644
--- a/library/std/src/sys/random/uefi.rs
+++ b/library/std/src/sys/random/uefi.rs
@@ -138,12 +138,11 @@ mod rdrand {
     }
 
     unsafe fn rdrand_exact(dest: &mut [u8]) -> Option<()> {
-        let mut chunks = dest.array_chunks_mut();
-        for chunk in &mut chunks {
+        let (chunks, tail) = dest.as_chunks_mut();
+        for chunk in chunks {
             *chunk = unsafe { rdrand() }?.to_ne_bytes();
         }
 
-        let tail = chunks.into_remainder();
         let n = tail.len();
         if n > 0 {
             let src = unsafe { rdrand() }?.to_ne_bytes();
diff --git a/library/std/src/thread/current.rs b/library/std/src/thread/current.rs
index 414711298f0..5c879903526 100644
--- a/library/std/src/thread/current.rs
+++ b/library/std/src/thread/current.rs
@@ -1,4 +1,4 @@
-use super::{Thread, ThreadId};
+use super::{Thread, ThreadId, imp};
 use crate::mem::ManuallyDrop;
 use crate::ptr;
 use crate::sys::thread_local::local_pointer;
@@ -148,6 +148,17 @@ pub(crate) fn current_id() -> ThreadId {
     id::get_or_init()
 }
 
+/// Gets the OS thread ID of the thread that invokes it, if available. If not, return the Rust
+/// thread ID.
+///
+/// We use a `u64` to all possible platform IDs without excess `cfg`; most use `int`, some use a
+/// pointer, and Apple uses `uint64_t`. This is a "best effort" approach for diagnostics and is
+/// allowed to fall back to a non-OS ID (such as the Rust thread ID) or a non-unique ID (such as a
+/// PID) if the thread ID cannot be retrieved.
+pub(crate) fn current_os_id() -> u64 {
+    imp::current_os_id().unwrap_or_else(|| current_id().as_u64().get())
+}
+
 /// Gets a reference to the handle of the thread that invokes it, if the handle
 /// has been initialized.
 pub(super) fn try_with_current<F, R>(f: F) -> R
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 8cd1e0163a1..292323d0118 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -183,7 +183,7 @@ mod current;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use current::current;
-pub(crate) use current::{current_id, current_or_unnamed, drop_current};
+pub(crate) use current::{current_id, current_or_unnamed, current_os_id, drop_current};
 use current::{set_current, try_with_current};
 
 mod spawnhook;
@@ -595,7 +595,7 @@ impl Builder {
             // Similarly, the `sys` implementation must guarantee that no references to the closure
             // exist after the thread has terminated, which is signaled by `Thread::join`
             // returning.
-            native: unsafe { imp::Thread::new(stack_size, main)? },
+            native: unsafe { imp::Thread::new(stack_size, my_thread.name(), main)? },
             thread: my_thread,
             packet: my_packet,
         })
@@ -2018,6 +2018,9 @@ fn _assert_sync_and_send() {
 ///   which may take time on systems with large numbers of mountpoints.
 ///   (This does not apply to cgroup v2, or to processes not in a
 ///   cgroup.)
+/// - It does not attempt to take `ulimit` into account. If there is a limit set on the number of
+///   threads, `available_parallelism` cannot know how much of that limit a Rust program should
+///   take, or know in a reliable and race-free way how much of that limit is already taken.
 ///
 /// On all targets:
 /// - It may overcount the amount of parallelism available when running in a VM
diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs
index 59ec48a57d1..ae889f1e778 100644
--- a/library/std/src/thread/tests.rs
+++ b/library/std/src/thread/tests.rs
@@ -347,6 +347,13 @@ fn test_thread_id_not_equal() {
 }
 
 #[test]
+fn test_thread_os_id_not_equal() {
+    let spawned_id = thread::spawn(|| thread::current_os_id()).join().unwrap();
+    let current_id = thread::current_os_id();
+    assert!(current_id != spawned_id);
+}
+
+#[test]
 fn test_scoped_threads_drop_result_before_join() {
     let actually_finished = &AtomicBool::new(false);
     struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool);
diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs
index 51190f0894f..94f1fe96b6a 100644
--- a/library/std/tests/sync/lib.rs
+++ b/library/std/tests/sync/lib.rs
@@ -6,7 +6,10 @@
 #![feature(reentrant_lock)]
 #![feature(rwlock_downgrade)]
 #![feature(std_internals)]
+#![feature(sync_nonpoison)]
+#![feature(nonpoison_mutex)]
 #![allow(internal_features)]
+#![feature(macro_metavar_expr_concat)] // For concatenating identifiers in macros.
 
 mod barrier;
 mod condvar;
@@ -29,3 +32,55 @@ mod rwlock;
 
 #[path = "../common/mod.rs"]
 mod common;
+
+#[track_caller]
+fn result_unwrap<T, E: std::fmt::Debug>(x: Result<T, E>) -> T {
+    x.unwrap()
+}
+
+/// A macro that generates two test cases for both the poison and nonpoison locks.
+///
+/// To write a test that tests both `poison` and `nonpoison` locks, import any of the types
+/// under both `poison` and `nonpoison` using the module name `locks` instead. For example, write
+/// `use locks::Mutex;` instead of `use std::sync::poiosn::Mutex`. This will import the correct type
+/// for each test variant.
+///
+/// Write a test as normal in the `test_body`, but instead of calling `unwrap` on `poison` methods
+/// that return a `LockResult` or similar, call the function `maybe_unwrap(...)` on the result.
+///
+/// For example, call `maybe_unwrap(mutex.lock())` instead of `mutex.lock().unwrap()` or
+/// `maybe_unwrap(rwlock.read())` instead of `rwlock.read().unwrap()`.
+///
+/// For the `poison` types, `maybe_unwrap` will simply unwrap the `Result` (usually this is a form
+/// of `LockResult`, but it could also be other kinds of results). For the `nonpoison` types, it is
+/// a no-op (the identity function).
+///
+/// The test names will be prefiex with `poison_` or `nonpoison_`.
+macro_rules! nonpoison_and_poison_unwrap_test {
+    (
+        name: $name:ident,
+        test_body: {$($test_body:tt)*}
+    ) => {
+        // Creates the nonpoison test.
+        #[test]
+        fn ${concat(nonpoison_, $name)}() {
+            #[allow(unused_imports)]
+            use ::std::convert::identity as maybe_unwrap;
+            use ::std::sync::nonpoison as locks;
+
+            $($test_body)*
+        }
+
+        // Creates the poison test with the suffix `_unwrap_poisoned`.
+        #[test]
+        fn ${concat(poison_, $name)}() {
+            #[allow(unused_imports)]
+            use super::result_unwrap as maybe_unwrap;
+            use ::std::sync::poison as locks;
+
+            $($test_body)*
+        }
+    }
+}
+
+use nonpoison_and_poison_unwrap_test;
diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs
index ac82914d6de..90cefc0d594 100644
--- a/library/std/tests/sync/mutex.rs
+++ b/library/std/tests/sync/mutex.rs
@@ -6,7 +6,71 @@ use std::sync::mpsc::channel;
 use std::sync::{Arc, Condvar, MappedMutexGuard, Mutex, MutexGuard, TryLockError};
 use std::{hint, mem, thread};
 
-struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Nonpoison & Poison Tests
+////////////////////////////////////////////////////////////////////////////////////////////////////
+use super::nonpoison_and_poison_unwrap_test;
+
+nonpoison_and_poison_unwrap_test!(
+    name: smoke,
+    test_body: {
+        use locks::Mutex;
+
+        let m = Mutex::new(());
+        drop(maybe_unwrap(m.lock()));
+        drop(maybe_unwrap(m.lock()));
+    }
+);
+
+nonpoison_and_poison_unwrap_test!(
+    name: lots_and_lots,
+    test_body: {
+        use locks::Mutex;
+
+        const J: u32 = 1000;
+        const K: u32 = 3;
+
+        let m = Arc::new(Mutex::new(0));
+
+        fn inc(m: &Mutex<u32>) {
+            for _ in 0..J {
+                *maybe_unwrap(m.lock()) += 1;
+            }
+        }
+
+        let (tx, rx) = channel();
+        for _ in 0..K {
+            let tx2 = tx.clone();
+            let m2 = m.clone();
+            thread::spawn(move || {
+                inc(&m2);
+                tx2.send(()).unwrap();
+            });
+            let tx2 = tx.clone();
+            let m2 = m.clone();
+            thread::spawn(move || {
+                inc(&m2);
+                tx2.send(()).unwrap();
+            });
+        }
+
+        drop(tx);
+        for _ in 0..2 * K {
+            rx.recv().unwrap();
+        }
+        assert_eq!(*maybe_unwrap(m.lock()), J * K * 2);
+    }
+);
+
+nonpoison_and_poison_unwrap_test!(
+    name: try_lock,
+    test_body: {
+        use locks::Mutex;
+
+        let m = Mutex::new(());
+        *m.try_lock().unwrap() = ();
+    }
+);
 
 #[derive(Eq, PartialEq, Debug)]
 struct NonCopy(i32);
@@ -26,58 +90,278 @@ fn test_needs_drop() {
     assert!(mem::needs_drop::<NonCopyNeedsDrop>());
 }
 
-#[derive(Clone, Eq, PartialEq, Debug)]
-struct Cloneable(i32);
+nonpoison_and_poison_unwrap_test!(
+    name: test_into_inner,
+    test_body: {
+        use locks::Mutex;
 
-#[test]
-fn smoke() {
-    let m = Mutex::new(());
-    drop(m.lock().unwrap());
-    drop(m.lock().unwrap());
-}
+        let m = Mutex::new(NonCopy(10));
+        assert_eq!(maybe_unwrap(m.into_inner()), NonCopy(10));
+    }
+);
 
-#[test]
-fn lots_and_lots() {
-    const J: u32 = 1000;
-    const K: u32 = 3;
+nonpoison_and_poison_unwrap_test!(
+    name: test_into_inner_drop,
+    test_body: {
+        use locks::Mutex;
 
-    let m = Arc::new(Mutex::new(0));
+        struct Foo(Arc<AtomicUsize>);
+        impl Drop for Foo {
+            fn drop(&mut self) {
+                self.0.fetch_add(1, Ordering::SeqCst);
+            }
+        }
 
-    fn inc(m: &Mutex<u32>) {
-        for _ in 0..J {
-            *m.lock().unwrap() += 1;
+        let num_drops = Arc::new(AtomicUsize::new(0));
+        let m = Mutex::new(Foo(num_drops.clone()));
+        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+        {
+            let _inner = maybe_unwrap(m.into_inner());
+            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
         }
+        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
     }
+);
 
-    let (tx, rx) = channel();
-    for _ in 0..K {
-        let tx2 = tx.clone();
-        let m2 = m.clone();
-        thread::spawn(move || {
-            inc(&m2);
-            tx2.send(()).unwrap();
-        });
-        let tx2 = tx.clone();
-        let m2 = m.clone();
-        thread::spawn(move || {
-            inc(&m2);
-            tx2.send(()).unwrap();
-        });
+nonpoison_and_poison_unwrap_test!(
+    name: test_get_mut,
+    test_body: {
+        use locks::Mutex;
+
+        let mut m = Mutex::new(NonCopy(10));
+        *maybe_unwrap(m.get_mut()) = NonCopy(20);
+        assert_eq!(maybe_unwrap(m.into_inner()), NonCopy(20));
     }
+);
 
-    drop(tx);
-    for _ in 0..2 * K {
-        rx.recv().unwrap();
+nonpoison_and_poison_unwrap_test!(
+    name: test_get_cloned,
+    test_body: {
+        use locks::Mutex;
+
+        #[derive(Clone, Eq, PartialEq, Debug)]
+        struct Cloneable(i32);
+
+        let m = Mutex::new(Cloneable(10));
+
+        assert_eq!(maybe_unwrap(m.get_cloned()), Cloneable(10));
     }
-    assert_eq!(*m.lock().unwrap(), J * K * 2);
-}
+);
+
+nonpoison_and_poison_unwrap_test!(
+    name: test_set,
+    test_body: {
+        use locks::Mutex;
+
+        fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+        where
+            T: Debug + Eq,
+        {
+            let m = Mutex::new(init());
+
+            assert_eq!(*maybe_unwrap(m.lock()), init());
+            maybe_unwrap(m.set(value()));
+            assert_eq!(*maybe_unwrap(m.lock()), value());
+        }
+
+        inner(|| NonCopy(10), || NonCopy(20));
+        inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+    }
+);
+
+// Ensure that old values that are replaced by `set` are correctly dropped.
+nonpoison_and_poison_unwrap_test!(
+    name: test_set_drop,
+    test_body: {
+        use locks::Mutex;
+
+        struct Foo(Arc<AtomicUsize>);
+        impl Drop for Foo {
+            fn drop(&mut self) {
+                self.0.fetch_add(1, Ordering::SeqCst);
+            }
+        }
+
+        let num_drops = Arc::new(AtomicUsize::new(0));
+        let m = Mutex::new(Foo(num_drops.clone()));
+        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+
+        let different = Foo(Arc::new(AtomicUsize::new(42)));
+        maybe_unwrap(m.set(different));
+        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+    }
+);
+
+nonpoison_and_poison_unwrap_test!(
+    name: test_replace,
+    test_body: {
+        use locks::Mutex;
+
+        fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
+        where
+            T: Debug + Eq,
+        {
+            let m = Mutex::new(init());
+
+            assert_eq!(*maybe_unwrap(m.lock()), init());
+            assert_eq!(maybe_unwrap(m.replace(value())), init());
+            assert_eq!(*maybe_unwrap(m.lock()), value());
+        }
 
+        inner(|| NonCopy(10), || NonCopy(20));
+        inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
+    }
+);
+
+// FIXME(nonpoison_condvar): Move this to the `condvar.rs` test file once `nonpoison::condvar` gets
+// implemented.
 #[test]
-fn try_lock() {
-    let m = Mutex::new(());
-    *m.try_lock().unwrap() = ();
+fn test_mutex_arc_condvar() {
+    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
+    let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
+    let packet2 = Packet(packet.0.clone());
+
+    let (tx, rx) = channel();
+
+    let _t = thread::spawn(move || {
+        // Wait until our parent has taken the lock.
+        rx.recv().unwrap();
+        let &(ref lock, ref cvar) = &*packet2.0;
+
+        // Set the data to `true` and wake up our parent.
+        let mut guard = lock.lock().unwrap();
+        *guard = true;
+        cvar.notify_one();
+    });
+
+    let &(ref lock, ref cvar) = &*packet.0;
+    let mut guard = lock.lock().unwrap();
+    // Wake up our child.
+    tx.send(()).unwrap();
+
+    // Wait until our child has set the data to `true`.
+    assert!(!*guard);
+    while !*guard {
+        guard = cvar.wait(guard).unwrap();
+    }
 }
 
+nonpoison_and_poison_unwrap_test!(
+    name: test_mutex_arc_nested,
+    test_body: {
+        use locks::Mutex;
+
+        // Tests nested mutexes and access
+        // to underlying data.
+        let arc = Arc::new(Mutex::new(1));
+        let arc2 = Arc::new(Mutex::new(arc));
+        let (tx, rx) = channel();
+        let _t = thread::spawn(move || {
+            let lock = maybe_unwrap(arc2.lock());
+            let lock2 = maybe_unwrap(lock.lock());
+            assert_eq!(*lock2, 1);
+            tx.send(()).unwrap();
+        });
+        rx.recv().unwrap();
+    }
+);
+
+nonpoison_and_poison_unwrap_test!(
+    name: test_mutex_unsized,
+    test_body: {
+        use locks::Mutex;
+
+        let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
+        {
+            let b = &mut *maybe_unwrap(mutex.lock());
+            b[0] = 4;
+            b[2] = 5;
+        }
+        let comp: &[i32] = &[4, 2, 5];
+        assert_eq!(&*maybe_unwrap(mutex.lock()), comp);
+    }
+);
+
+nonpoison_and_poison_unwrap_test!(
+    name: test_mapping_mapped_guard,
+    test_body: {
+        use locks::{Mutex, MutexGuard, MappedMutexGuard};
+
+        let arr = [0; 4];
+        let lock = Mutex::new(arr);
+        let guard = maybe_unwrap(lock.lock());
+        let guard = MutexGuard::map(guard, |arr| &mut arr[..2]);
+        let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]);
+        assert_eq!(guard.len(), 1);
+        guard[0] = 42;
+        drop(guard);
+        assert_eq!(*maybe_unwrap(lock.lock()), [0, 42, 0, 0]);
+    }
+);
+
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+nonpoison_and_poison_unwrap_test!(
+    name: test_panics,
+    test_body: {
+        use locks::Mutex;
+
+        let mutex = Mutex::new(42);
+
+        let catch_unwind_result1 = panic::catch_unwind(AssertUnwindSafe(|| {
+            let _guard1 = maybe_unwrap(mutex.lock());
+
+            panic!("test panic with mutex once");
+        }));
+        assert!(catch_unwind_result1.is_err());
+
+        let catch_unwind_result2 = panic::catch_unwind(AssertUnwindSafe(|| {
+            let _guard2 = maybe_unwrap(mutex.lock());
+
+            panic!("test panic with mutex twice");
+        }));
+        assert!(catch_unwind_result2.is_err());
+
+        let catch_unwind_result3 = panic::catch_unwind(AssertUnwindSafe(|| {
+            let _guard3 = maybe_unwrap(mutex.lock());
+
+            panic!("test panic with mutex thrice");
+        }));
+        assert!(catch_unwind_result3.is_err());
+    }
+);
+
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+nonpoison_and_poison_unwrap_test!(
+    name: test_mutex_arc_access_in_unwind,
+    test_body: {
+        use locks::Mutex;
+
+        let arc = Arc::new(Mutex::new(1));
+        let arc2 = arc.clone();
+        let _ = thread::spawn(move || -> () {
+            struct Unwinder {
+                i: Arc<Mutex<i32>>,
+            }
+            impl Drop for Unwinder {
+                fn drop(&mut self) {
+                    *maybe_unwrap(self.i.lock()) += 1;
+                }
+            }
+            let _u = Unwinder { i: arc2 };
+            panic!();
+        })
+        .join();
+        let lock = maybe_unwrap(arc.lock());
+        assert_eq!(*lock, 2);
+    }
+);
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Poison Tests
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Creates a mutex that is immediately poisoned.
 fn new_poisoned_mutex<T>(value: T) -> Mutex<T> {
     let mutex = Mutex::new(value);
 
@@ -94,30 +378,6 @@ fn new_poisoned_mutex<T>(value: T) -> Mutex<T> {
 }
 
 #[test]
-fn test_into_inner() {
-    let m = Mutex::new(NonCopy(10));
-    assert_eq!(m.into_inner().unwrap(), NonCopy(10));
-}
-
-#[test]
-fn test_into_inner_drop() {
-    struct Foo(Arc<AtomicUsize>);
-    impl Drop for Foo {
-        fn drop(&mut self) {
-            self.0.fetch_add(1, Ordering::SeqCst);
-        }
-    }
-    let num_drops = Arc::new(AtomicUsize::new(0));
-    let m = Mutex::new(Foo(num_drops.clone()));
-    assert_eq!(num_drops.load(Ordering::SeqCst), 0);
-    {
-        let _inner = m.into_inner().unwrap();
-        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
-    }
-    assert_eq!(num_drops.load(Ordering::SeqCst), 1);
-}
-
-#[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_into_inner_poison() {
     let m = new_poisoned_mutex(NonCopy(10));
@@ -129,15 +389,11 @@ fn test_into_inner_poison() {
 }
 
 #[test]
-fn test_get_cloned() {
-    let m = Mutex::new(Cloneable(10));
-
-    assert_eq!(m.get_cloned().unwrap(), Cloneable(10));
-}
-
-#[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_get_cloned_poison() {
+    #[derive(Clone, Eq, PartialEq, Debug)]
+    struct Cloneable(i32);
+
     let m = new_poisoned_mutex(Cloneable(10));
 
     match m.get_cloned() {
@@ -147,13 +403,6 @@ fn test_get_cloned_poison() {
 }
 
 #[test]
-fn test_get_mut() {
-    let mut m = Mutex::new(NonCopy(10));
-    *m.get_mut().unwrap() = NonCopy(20);
-    assert_eq!(m.into_inner().unwrap(), NonCopy(20));
-}
-
-#[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_get_mut_poison() {
     let mut m = new_poisoned_mutex(NonCopy(10));
@@ -165,23 +414,6 @@ fn test_get_mut_poison() {
 }
 
 #[test]
-fn test_set() {
-    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
-    where
-        T: Debug + Eq,
-    {
-        let m = Mutex::new(init());
-
-        assert_eq!(*m.lock().unwrap(), init());
-        m.set(value()).unwrap();
-        assert_eq!(*m.lock().unwrap(), value());
-    }
-
-    inner(|| NonCopy(10), || NonCopy(20));
-    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
-}
-
-#[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_set_poison() {
     fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
@@ -204,23 +436,6 @@ fn test_set_poison() {
 }
 
 #[test]
-fn test_replace() {
-    fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
-    where
-        T: Debug + Eq,
-    {
-        let m = Mutex::new(init());
-
-        assert_eq!(*m.lock().unwrap(), init());
-        assert_eq!(m.replace(value()).unwrap(), init());
-        assert_eq!(*m.lock().unwrap(), value());
-    }
-
-    inner(|| NonCopy(10), || NonCopy(20));
-    inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20));
-}
-
-#[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_replace_poison() {
     fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T)
@@ -243,31 +458,10 @@ fn test_replace_poison() {
 }
 
 #[test]
-fn test_mutex_arc_condvar() {
-    let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
-    let packet2 = Packet(packet.0.clone());
-    let (tx, rx) = channel();
-    let _t = thread::spawn(move || {
-        // wait until parent gets in
-        rx.recv().unwrap();
-        let &(ref lock, ref cvar) = &*packet2.0;
-        let mut lock = lock.lock().unwrap();
-        *lock = true;
-        cvar.notify_one();
-    });
-
-    let &(ref lock, ref cvar) = &*packet.0;
-    let mut lock = lock.lock().unwrap();
-    tx.send(()).unwrap();
-    assert!(!*lock);
-    while !*lock {
-        lock = cvar.wait(lock).unwrap();
-    }
-}
-
-#[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_arc_condvar_poison() {
+    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+
     let packet = Packet(Arc::new((Mutex::new(1), Condvar::new())));
     let packet2 = Packet(packet.0.clone());
     let (tx, rx) = channel();
@@ -327,69 +521,6 @@ fn test_mutex_arc_poison_mapped() {
 }
 
 #[test]
-fn test_mutex_arc_nested() {
-    // Tests nested mutexes and access
-    // to underlying data.
-    let arc = Arc::new(Mutex::new(1));
-    let arc2 = Arc::new(Mutex::new(arc));
-    let (tx, rx) = channel();
-    let _t = thread::spawn(move || {
-        let lock = arc2.lock().unwrap();
-        let lock2 = lock.lock().unwrap();
-        assert_eq!(*lock2, 1);
-        tx.send(()).unwrap();
-    });
-    rx.recv().unwrap();
-}
-
-#[test]
-#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
-fn test_mutex_arc_access_in_unwind() {
-    let arc = Arc::new(Mutex::new(1));
-    let arc2 = arc.clone();
-    let _ = thread::spawn(move || -> () {
-        struct Unwinder {
-            i: Arc<Mutex<i32>>,
-        }
-        impl Drop for Unwinder {
-            fn drop(&mut self) {
-                *self.i.lock().unwrap() += 1;
-            }
-        }
-        let _u = Unwinder { i: arc2 };
-        panic!();
-    })
-    .join();
-    let lock = arc.lock().unwrap();
-    assert_eq!(*lock, 2);
-}
-
-#[test]
-fn test_mutex_unsized() {
-    let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
-    {
-        let b = &mut *mutex.lock().unwrap();
-        b[0] = 4;
-        b[2] = 5;
-    }
-    let comp: &[i32] = &[4, 2, 5];
-    assert_eq!(&*mutex.lock().unwrap(), comp);
-}
-
-#[test]
-fn test_mapping_mapped_guard() {
-    let arr = [0; 4];
-    let mut lock = Mutex::new(arr);
-    let guard = lock.lock().unwrap();
-    let guard = MutexGuard::map(guard, |arr| &mut arr[..2]);
-    let mut guard = MappedMutexGuard::map(guard, |slice| &mut slice[1..]);
-    assert_eq!(guard.len(), 1);
-    guard[0] = 42;
-    drop(guard);
-    assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]);
-}
-
-#[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn panic_while_mapping_unlocked_poison() {
     let lock = Mutex::new(());