Skip to content

Commit 9c37c80

Browse files
committed
expand documentation on type conversion w.r.t. UnsafeCell
1 parent 13bc099 commit 9c37c80

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

library/core/src/cell.rs

+21-13
Original file line numberDiff line numberDiff line change
@@ -1811,35 +1811,43 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
18111811
///
18121812
/// [`.get_mut()`]: `UnsafeCell::get_mut`
18131813
///
1814-
/// `UnsafeCell<T>` has the same in-memory representation as its inner type `T`. A consequence
1815-
/// of this guarantee is that it is possible to convert between `T` and `UnsafeCell<T>`.
1816-
/// However, it is only valid to obtain a `*mut T` pointer or `&mut T` reference to the
1817-
/// contents of an `UnsafeCell<T>` through [`.get()`], [`.raw_get()`] or [`.get_mut()`], e.g.:
1814+
/// `UnsafeCell<T>` has the same in-memory representation as its inner type `T` if and only if
1815+
/// the type `T` does not contain a [niche] (e.g. the type `Option<NonNull<u8>>` is typically
1816+
/// 8 bytes large on 64-bit platforms, but the type `Option<UnsafeCell<NonNull<u8>>>` takes
1817+
/// up 16 bytes of space). A consequence of this guarantee is that it is possible to convert
1818+
/// between `T` and `UnsafeCell<T>` when `T` has no niches. However, it is only valid to obtain
1819+
/// a `*mut T` pointer to the contents of a _shared_ `UnsafeCell<T>` through [`.get()`] or
1820+
/// [`.raw_get()`]. A `&mut T` reference can be obtained by either dereferencing this pointer
1821+
/// or by calling [`.get_mut()`] on an _exclusive_ `UnsafeCell<T>`, e.g.:
18181822
///
18191823
/// ```rust
18201824
/// use std::cell::UnsafeCell;
18211825
///
18221826
/// let mut x: UnsafeCell<u32> = UnsafeCell::new(5);
1823-
/// let p1: &UnsafeCell<u32> = &x;
1827+
/// let shared: &UnsafeCell<u32> = &x;
18241828
/// // using `.get()` is okay:
18251829
/// unsafe {
18261830
/// // SAFETY: there exist no other references to the contents of `x`
1827-
/// let p2: &mut u32 = &mut *p1.get();
1831+
/// let exclusive: &mut u32 = &mut *shared.get();
18281832
/// };
18291833
/// // using `.raw_get()` is also okay:
18301834
/// unsafe {
18311835
/// // SAFETY: there exist no other references to the contents of `x` in this scope
1832-
/// let p2: &mut u32 = &mut *UnsafeCell::raw_get(p1 as *const _);
1836+
/// let exclusive: &mut u32 = &mut *UnsafeCell::raw_get(shared as *const _);
18331837
/// };
18341838
/// // using `.get_mut()` is always safe:
1835-
/// let p2: &mut u32 = x.get_mut();
1836-
/// // but the following is not allowed!
1837-
/// // let p2: &mut u32 = unsafe {
1838-
/// // let t: *mut u32 = &x as *const _ as *mut u32;
1839-
/// // &mut *t
1840-
/// // };
1839+
/// let exclusive: &mut u32 = x.get_mut();
1840+
///
1841+
/// // when we have exclusive access, we can convert it to a shared `&UnsafeCell`:
1842+
/// unsafe {
1843+
/// // SAFETY: `u32` has no niche, therefore it has the same layout as `UnsafeCell<u32>`
1844+
/// let shared: &UnsafeCell<u32> = &*(exclusive as *mut _ as *const UnsafeCell<u32>);
1845+
/// // SAFETY: there exist no other *active* references to the contents of `x` in this scope
1846+
/// let exclusive: &mut u32 = &mut *shared.get();
1847+
/// }
18411848
/// ```
18421849
///
1850+
/// [niche]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#niche
18431851
/// [`.raw_get()`]: `UnsafeCell::raw_get`
18441852
///
18451853
/// # Examples

0 commit comments

Comments
 (0)