Skip to content

Commit 8169989

Browse files
Add non-unsafe .get_mut() for UnsafeCell
Update the tracking issue number Updated the documentation for `UnsafeCell` Address review comments Address more review comments + minor changes
1 parent b3aae05 commit 8169989

File tree

1 file changed

+84
-9
lines changed

1 file changed

+84
-9
lines changed

library/core/src/cell.rs

+84-9
Original file line numberDiff line numberDiff line change
@@ -1543,8 +1543,11 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
15431543
/// allow internal mutability, such as `Cell<T>` and `RefCell<T>`, use `UnsafeCell` to wrap their
15441544
/// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell<T>`.
15451545
///
1546-
/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to
1547-
/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly.
1546+
/// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer
1547+
/// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer
1548+
/// correctly.
1549+
///
1550+
/// [`.get()`]: `UnsafeCell::get`
15481551
///
15491552
/// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious:
15501553
///
@@ -1571,21 +1574,70 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
15711574
/// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T`
15721575
/// co-exist with it. A `&mut T` must always be unique.
15731576
///
1574-
/// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell<T>` is
1575-
/// ok (provided you enforce the invariants some other way), it is still undefined behavior
1576-
/// to have multiple `&mut UnsafeCell<T>` aliases.
1577+
/// Note that whilst mutating the contents of an `&UnsafeCell<T>` (even while other
1578+
/// `&UnsafeCell<T>` references alias the cell) is
1579+
/// ok (provided you enforce the above invariants some other way), it is still undefined behavior
1580+
/// to have multiple `&mut UnsafeCell<T>` aliases. That is, `UnsafeCell` is a wrapper
1581+
/// designed to have a special interaction with _shared_ accesses (_i.e._, through an
1582+
/// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_
1583+
/// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value
1584+
/// may be aliased for the duration of that `&mut` borrow.
1585+
/// This is showcased by the [`.get_mut()`] accessor, which is a non-`unsafe` getter that yields
1586+
/// a `&mut T`.
1587+
///
1588+
/// [`.get_mut()`]: `UnsafeCell::get_mut`
15771589
///
15781590
/// # Examples
15791591
///
1592+
/// Here is an example showcasing how to soundly mutate the contents of an `UnsafeCell<_>` despite
1593+
/// there being multiple references aliasing the cell:
1594+
///
15801595
/// ```
15811596
/// use std::cell::UnsafeCell;
15821597
///
1583-
/// # #[allow(dead_code)]
1584-
/// struct NotThreadSafe<T> {
1585-
/// value: UnsafeCell<T>,
1598+
/// let x: UnsafeCell<i32> = 42.into();
1599+
/// // Get multiple / concurrent / shared references to the same `x`.
1600+
/// let (p1, p2): (&UnsafeCell<i32>, &UnsafeCell<i32>) = (&x, &x);
1601+
///
1602+
/// unsafe {
1603+
/// // SAFETY: within this scope there are no other references to `x`'s contents,
1604+
/// // so ours is effectively unique.
1605+
/// let p1_exclusive: &mut i32 = &mut *p1.get(); // -- borrow --+
1606+
/// *p1_exclusive += 27; // |
1607+
/// } // <---------- cannot go beyond this point -------------------+
1608+
///
1609+
/// unsafe {
1610+
/// // SAFETY: within this scope nobody expects to have exclusive access to `x`'s contents,
1611+
/// // so we can have multiple shared accesses concurrently.
1612+
/// let p2_shared: &i32 = &*p2.get();
1613+
/// assert_eq!(*p2_shared, 42 + 27);
1614+
/// let p1_shared: &i32 = &*p1.get();
1615+
/// assert_eq!(*p1_shared, *p2_shared);
15861616
/// }
1617+
/// ```
1618+
///
1619+
/// The following example showcases the fact that exclusive access to an `UnsafeCell<T>`
1620+
/// implies exclusive access to its `T`:
15871621
///
1588-
/// unsafe impl<T> Sync for NotThreadSafe<T> {}
1622+
/// ```rust
1623+
/// #![feature(unsafe_cell_get_mut)]
1624+
/// #![forbid(unsafe_code)] // with exclusive accesses,
1625+
/// // `UnsafeCell` is a transparent no-op wrapper,
1626+
/// // so no need for `unsafe` here.
1627+
/// use std::cell::UnsafeCell;
1628+
///
1629+
/// let mut x: UnsafeCell<i32> = 42.into();
1630+
///
1631+
/// // Get a compile-time-checked unique reference to `x`.
1632+
/// let p_unique: &mut UnsafeCell<i32> = &mut x;
1633+
/// // With an exclusive reference, we can mutate the contents for free.
1634+
/// *p_unique.get_mut() = 0;
1635+
/// // Or, equivalently:
1636+
/// x = UnsafeCell::new(0);
1637+
///
1638+
/// // When we own the value, we can extract the contents for free.
1639+
/// let contents: i32 = x.into_inner();
1640+
/// assert_eq!(contents, 0);
15891641
/// ```
15901642
#[lang = "unsafe_cell"]
15911643
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1663,6 +1715,29 @@ impl<T: ?Sized> UnsafeCell<T> {
16631715
self as *const UnsafeCell<T> as *const T as *mut T
16641716
}
16651717

1718+
/// Returns a mutable reference to the underlying data.
1719+
///
1720+
/// This call borrows the `UnsafeCell` mutably (at compile-time) which
1721+
/// guarantees that we possess the only reference.
1722+
///
1723+
/// # Examples
1724+
///
1725+
/// ```
1726+
/// #![feature(unsafe_cell_get_mut)]
1727+
/// use std::cell::UnsafeCell;
1728+
///
1729+
/// let mut c = UnsafeCell::new(5);
1730+
/// *c.get_mut() += 1;
1731+
///
1732+
/// assert_eq!(*c.get_mut(), 6);
1733+
/// ```
1734+
#[inline]
1735+
#[unstable(feature = "unsafe_cell_get_mut", issue = "76943")]
1736+
pub fn get_mut(&mut self) -> &mut T {
1737+
// SAFETY: (outer) `&mut` guarantees unique access.
1738+
unsafe { &mut *self.get() }
1739+
}
1740+
16661741
/// Gets a mutable pointer to the wrapped value.
16671742
/// The difference to [`get`] is that this function accepts a raw pointer,
16681743
/// which is useful to avoid the creation of temporary references.

0 commit comments

Comments
 (0)