about summary refs log tree commit diff
diff options
context:
space:
mode:
-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--tests/ui/async-await/issue-64130-non-send-future-diags.stderr4
-rw-r--r--tests/ui/async-await/issue-71137.stderr4
-rw-r--r--tests/ui/async-await/issues/issue-67893.rs2
-rw-r--r--tests/ui/async-await/issues/issue-67893.stderr6
-rw-r--r--tests/ui/lint/must_not_suspend/mutex.rs2
-rw-r--r--tests/ui/lint/must_not_suspend/mutex.stderr2
-rw-r--r--tests/ui/privacy/private-field-access-in-mutex-54062.rs2
-rw-r--r--tests/ui/privacy/private-field-access-in-mutex-54062.stderr2
-rw-r--r--tests/ui/suggestions/inner_type.fixed2
-rw-r--r--tests/ui/suggestions/inner_type.rs2
-rw-r--r--tests/ui/suggestions/inner_type.stderr4
-rw-r--r--tests/ui/sync/mutexguard-sync.stderr2
-rw-r--r--tests/ui/traits/const-traits/span-bug-issue-121418.stderr6
-rw-r--r--tests/ui/typeck/assign-non-lval-derefmut.fixed4
-rw-r--r--tests/ui/typeck/assign-non-lval-derefmut.rs4
-rw-r--r--tests/ui/typeck/assign-non-lval-derefmut.stderr14
-rw-r--r--tests/ui/typeck/deref-multi.stderr2
20 files changed, 682 insertions, 32 deletions
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/tests/ui/async-await/issue-64130-non-send-future-diags.stderr b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
index d28807e223b..beaf8e9c96d 100644
--- a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
+++ b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
@@ -4,12 +4,12 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo());
    |             ^^^^^ future returned by `foo` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, u32>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/issue-64130-non-send-future-diags.rs:17:11
    |
 LL |     let g = x.lock().unwrap();
-   |         - has type `MutexGuard<'_, u32>` which is not `Send`
+   |         - has type `std::sync::MutexGuard<'_, u32>` which is not `Send`
 LL |     baz().await;
    |           ^^^^^ await occurs here, with `g` maybe used later
 note: required by a bound in `is_send`
diff --git a/tests/ui/async-await/issue-71137.stderr b/tests/ui/async-await/issue-71137.stderr
index 8739c22a310..d567e3f2063 100644
--- a/tests/ui/async-await/issue-71137.stderr
+++ b/tests/ui/async-await/issue-71137.stderr
@@ -4,12 +4,12 @@ error: future cannot be sent between threads safely
 LL |   fake_spawn(wrong_mutex());
    |              ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, i32>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/issue-71137.rs:14:26
    |
 LL |     let mut guard = m.lock().unwrap();
-   |         --------- has type `MutexGuard<'_, i32>` which is not `Send`
+   |         --------- has type `std::sync::MutexGuard<'_, i32>` which is not `Send`
 LL |     (async { "right"; }).await;
    |                          ^^^^^ await occurs here, with `mut guard` maybe used later
 note: required by a bound in `fake_spawn`
diff --git a/tests/ui/async-await/issues/issue-67893.rs b/tests/ui/async-await/issues/issue-67893.rs
index 73cce38c94a..2020abe7a5a 100644
--- a/tests/ui/async-await/issues/issue-67893.rs
+++ b/tests/ui/async-await/issues/issue-67893.rs
@@ -7,5 +7,5 @@ fn g(_: impl Send) {}
 
 fn main() {
     g(issue_67893::run())
-    //~^ ERROR `MutexGuard<'_, ()>` cannot be sent between threads safely
+    //~^ ERROR `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely
 }
diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr
index c01237255b8..34f28dd53c7 100644
--- a/tests/ui/async-await/issues/issue-67893.stderr
+++ b/tests/ui/async-await/issues/issue-67893.stderr
@@ -1,8 +1,8 @@
-error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely
+error[E0277]: `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely
   --> $DIR/issue-67893.rs:9:7
    |
 LL |     g(issue_67893::run())
-   |     - ^^^^^^^^^^^^^^^^^^ `MutexGuard<'_, ()>` cannot be sent between threads safely
+   |     - ^^^^^^^^^^^^^^^^^^ `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely
    |     |
    |     required by a bound introduced by this call
    |
@@ -11,7 +11,7 @@ LL |     g(issue_67893::run())
 LL | pub async fn run() {
    | ------------------ within this `impl Future<Output = ()>`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, ()>`
 note: required because it's used within this `async` fn body
   --> $DIR/auxiliary/issue_67893.rs:9:20
    |
diff --git a/tests/ui/lint/must_not_suspend/mutex.rs b/tests/ui/lint/must_not_suspend/mutex.rs
index d14f7130b4c..8dd4cc17615 100644
--- a/tests/ui/lint/must_not_suspend/mutex.rs
+++ b/tests/ui/lint/must_not_suspend/mutex.rs
@@ -5,7 +5,7 @@
 async fn other() {}
 
 pub async fn uhoh(m: std::sync::Mutex<()>) {
-    let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+    let _guard = m.lock().unwrap(); //~ ERROR `std::sync::MutexGuard` held across
     other().await;
 }
 
diff --git a/tests/ui/lint/must_not_suspend/mutex.stderr b/tests/ui/lint/must_not_suspend/mutex.stderr
index ca53a753150..0db1f2575b1 100644
--- a/tests/ui/lint/must_not_suspend/mutex.stderr
+++ b/tests/ui/lint/must_not_suspend/mutex.stderr
@@ -1,4 +1,4 @@
-error: `MutexGuard` held across a suspend point, but should not be
+error: `std::sync::MutexGuard` held across a suspend point, but should not be
   --> $DIR/mutex.rs:8:9
    |
 LL |     let _guard = m.lock().unwrap();
diff --git a/tests/ui/privacy/private-field-access-in-mutex-54062.rs b/tests/ui/privacy/private-field-access-in-mutex-54062.rs
index f145f9c3e52..c957e0bc7e8 100644
--- a/tests/ui/privacy/private-field-access-in-mutex-54062.rs
+++ b/tests/ui/privacy/private-field-access-in-mutex-54062.rs
@@ -8,7 +8,7 @@ fn main() {}
 
 fn testing(test: Test) {
     let _ = test.comps.inner.try_lock();
-    //~^ ERROR: field `inner` of struct `Mutex` is private
+    //~^ ERROR: field `inner` of struct `std::sync::Mutex` is private
 }
 
 // https://github.com/rust-lang/rust/issues/54062
diff --git a/tests/ui/privacy/private-field-access-in-mutex-54062.stderr b/tests/ui/privacy/private-field-access-in-mutex-54062.stderr
index 14244107597..f7f84640648 100644
--- a/tests/ui/privacy/private-field-access-in-mutex-54062.stderr
+++ b/tests/ui/privacy/private-field-access-in-mutex-54062.stderr
@@ -1,4 +1,4 @@
-error[E0616]: field `inner` of struct `Mutex` is private
+error[E0616]: field `inner` of struct `std::sync::Mutex` is private
   --> $DIR/private-field-access-in-mutex-54062.rs:10:24
    |
 LL |     let _ = test.comps.inner.try_lock();
diff --git a/tests/ui/suggestions/inner_type.fixed b/tests/ui/suggestions/inner_type.fixed
index 3dc939d6b5c..175a2a02acd 100644
--- a/tests/ui/suggestions/inner_type.fixed
+++ b/tests/ui/suggestions/inner_type.fixed
@@ -25,7 +25,7 @@ fn main() {
     let another_item = std::sync::Mutex::new(Struct { p: 42_u32 });
 
     another_item.lock().unwrap().method();
-    //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599]
+    //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599]
     //~| HELP use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
 
     let another_item = std::sync::RwLock::new(Struct { p: 42_u32 });
diff --git a/tests/ui/suggestions/inner_type.rs b/tests/ui/suggestions/inner_type.rs
index 81a05c25311..ab021414f56 100644
--- a/tests/ui/suggestions/inner_type.rs
+++ b/tests/ui/suggestions/inner_type.rs
@@ -25,7 +25,7 @@ fn main() {
     let another_item = std::sync::Mutex::new(Struct { p: 42_u32 });
 
     another_item.method();
-    //~^ ERROR no method named `method` found for struct `Mutex` in the current scope [E0599]
+    //~^ ERROR no method named `method` found for struct `std::sync::Mutex` in the current scope [E0599]
     //~| HELP use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired
 
     let another_item = std::sync::RwLock::new(Struct { p: 42_u32 });
diff --git a/tests/ui/suggestions/inner_type.stderr b/tests/ui/suggestions/inner_type.stderr
index 5ac3d04f104..67ebb5789b7 100644
--- a/tests/ui/suggestions/inner_type.stderr
+++ b/tests/ui/suggestions/inner_type.stderr
@@ -30,11 +30,11 @@ help: use `.borrow_mut()` to mutably borrow the `Struct<u32>`, panicking if any
 LL |     other_item.borrow_mut().some_mutable_method();
    |               +++++++++++++
 
-error[E0599]: no method named `method` found for struct `Mutex` in the current scope
+error[E0599]: no method named `method` found for struct `std::sync::Mutex` in the current scope
   --> $DIR/inner_type.rs:27:18
    |
 LL |     another_item.method();
-   |                  ^^^^^^ method not found in `Mutex<Struct<u32>>`
+   |                  ^^^^^^ method not found in `std::sync::Mutex<Struct<u32>>`
    |
 note: the method `method` exists on the type `Struct<u32>`
   --> $DIR/inner_type.rs:9:5
diff --git a/tests/ui/sync/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr
index 1501a793d5e..ab9983c1f2c 100644
--- a/tests/ui/sync/mutexguard-sync.stderr
+++ b/tests/ui/sync/mutexguard-sync.stderr
@@ -8,7 +8,7 @@ LL |     test_sync(guard);
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
-   = note: required for `MutexGuard<'_, Cell<i32>>` to implement `Sync`
+   = note: required for `std::sync::MutexGuard<'_, Cell<i32>>` to implement `Sync`
 note: required by a bound in `test_sync`
   --> $DIR/mutexguard-sync.rs:5:17
    |
diff --git a/tests/ui/traits/const-traits/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
index 92cfecd0540..f31129d9cb7 100644
--- a/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
+++ b/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
@@ -14,8 +14,8 @@ error[E0277]: the size for values of type `(dyn T + 'static)` cannot be known at
 LL |     pub const fn new() -> std::sync::Mutex<dyn T> {}
    |                           ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`
-note: required because it appears within the type `Mutex<(dyn T + 'static)>`
+   = help: within `std::sync::Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`
+note: required because it appears within the type `std::sync::Mutex<(dyn T + 'static)>`
   --> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
    = note: the return type of a function must have a statically known size
 
@@ -27,7 +27,7 @@ LL |     pub const fn new() -> std::sync::Mutex<dyn T> {}
    |                  |
    |                  implicitly returns `()` as its body has no tail or `return` expression
    |
-   = note: expected struct `Mutex<(dyn T + 'static)>`
+   = note: expected struct `std::sync::Mutex<(dyn T + 'static)>`
            found unit type `()`
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/typeck/assign-non-lval-derefmut.fixed b/tests/ui/typeck/assign-non-lval-derefmut.fixed
index 6ecec574f2e..e6f97a9e86c 100644
--- a/tests/ui/typeck/assign-non-lval-derefmut.fixed
+++ b/tests/ui/typeck/assign-non-lval-derefmut.fixed
@@ -5,11 +5,11 @@ fn main() {
     *x.lock().unwrap() = 2;
     //~^ ERROR invalid left-hand side of assignment
     *x.lock().unwrap() += 1;
-    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
 
     let mut y = x.lock().unwrap();
     *y = 2;
     //~^ ERROR mismatched types
     *y += 1;
-    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
 }
diff --git a/tests/ui/typeck/assign-non-lval-derefmut.rs b/tests/ui/typeck/assign-non-lval-derefmut.rs
index ac1be913e2a..a53a52c7e4d 100644
--- a/tests/ui/typeck/assign-non-lval-derefmut.rs
+++ b/tests/ui/typeck/assign-non-lval-derefmut.rs
@@ -5,11 +5,11 @@ fn main() {
     x.lock().unwrap() = 2;
     //~^ ERROR invalid left-hand side of assignment
     x.lock().unwrap() += 1;
-    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
 
     let mut y = x.lock().unwrap();
     y = 2;
     //~^ ERROR mismatched types
     y += 1;
-    //~^ ERROR binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+    //~^ ERROR binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
 }
diff --git a/tests/ui/typeck/assign-non-lval-derefmut.stderr b/tests/ui/typeck/assign-non-lval-derefmut.stderr
index 16fb1e9c5c3..f57b5abe2ee 100644
--- a/tests/ui/typeck/assign-non-lval-derefmut.stderr
+++ b/tests/ui/typeck/assign-non-lval-derefmut.stderr
@@ -11,15 +11,15 @@ help: consider dereferencing here to assign to the mutably borrowed value
 LL |     *x.lock().unwrap() = 2;
    |     +
 
-error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+error[E0368]: binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
   --> $DIR/assign-non-lval-derefmut.rs:7:5
    |
 LL |     x.lock().unwrap() += 1;
    |     -----------------^^^^^
    |     |
-   |     cannot use `+=` on type `MutexGuard<'_, usize>`
+   |     cannot use `+=` on type `std::sync::MutexGuard<'_, usize>`
    |
-note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
+note: the foreign item type `std::sync::MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
   --> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
    |
    = note: not implement `AddAssign<{integer}>`
@@ -36,22 +36,22 @@ LL |     let mut y = x.lock().unwrap();
 LL |     y = 2;
    |         ^ expected `MutexGuard<'_, usize>`, found integer
    |
-   = note: expected struct `MutexGuard<'_, usize>`
+   = note: expected struct `std::sync::MutexGuard<'_, usize>`
                 found type `{integer}`
 help: consider dereferencing here to assign to the mutably borrowed value
    |
 LL |     *y = 2;
    |     +
 
-error[E0368]: binary assignment operation `+=` cannot be applied to type `MutexGuard<'_, usize>`
+error[E0368]: binary assignment operation `+=` cannot be applied to type `std::sync::MutexGuard<'_, usize>`
   --> $DIR/assign-non-lval-derefmut.rs:13:5
    |
 LL |     y += 1;
    |     -^^^^^
    |     |
-   |     cannot use `+=` on type `MutexGuard<'_, usize>`
+   |     cannot use `+=` on type `std::sync::MutexGuard<'_, usize>`
    |
-note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
+note: the foreign item type `std::sync::MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>`
   --> $SRC_DIR/std/src/sync/poison/mutex.rs:LL:COL
    |
    = note: not implement `AddAssign<{integer}>`
diff --git a/tests/ui/typeck/deref-multi.stderr b/tests/ui/typeck/deref-multi.stderr
index 02513853c48..c4fa49e43ef 100644
--- a/tests/ui/typeck/deref-multi.stderr
+++ b/tests/ui/typeck/deref-multi.stderr
@@ -63,7 +63,7 @@ LL |     x.lock().unwrap()
    |     ^^^^^^^^^^^^^^^^^ expected `i32`, found `MutexGuard<'_, &i32>`
    |
    = note: expected type `i32`
-            found struct `MutexGuard<'_, &i32>`
+            found struct `std::sync::MutexGuard<'_, &i32>`
 help: consider dereferencing the type
    |
 LL |     **x.lock().unwrap()