Skip to content

Commit c75e6f5

Browse files
authored
Rollup merge of rust-lang#103394 - Pointerbender:unsafecell-docs, r=Amanieu
Clarify documentation about the memory layout of `UnsafeCell` This PR addresses a [comment](rust-lang#101717 (comment)) by `@RalfJung` in PR rust-lang#101717 to further clarify the documentation of `UnsafeCell<T>`. The previous PR was merged already before we had a chance to correct this, hence this second PR :) To goal of this PR is: 1. Split the paragraph about the memory layout of `UnsafeCell<T>` and the usage of `UnsafeCell::(raw_)get()` into two paragraphs, so that it is easier to digest for the reader. 2. Slightly simplify the previously added examples in order to reduce redundancy between the new examples and the examples that already [existed](https://github.com/rust-lang/rust/blob/ddd119b2fed57eb6b19c44c18108de95c564a48d/library/core/src/cell.rs#L1858-L1908) before these 2 PRs (which remained untouched by both PRs).
2 parents 16e74c7 + 166d8b8 commit c75e6f5

File tree

1 file changed

+36
-25
lines changed

1 file changed

+36
-25
lines changed

library/core/src/cell.rs

+36-25
Original file line numberDiff line numberDiff line change
@@ -1816,6 +1816,8 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
18161816
///
18171817
/// [`.get_mut()`]: `UnsafeCell::get_mut`
18181818
///
1819+
/// # Memory layout
1820+
///
18191821
/// `UnsafeCell<T>` has the same in-memory representation as its inner type `T`. A consequence
18201822
/// of this guarantee is that it is possible to convert between `T` and `UnsafeCell<T>`.
18211823
/// Special care has to be taken when converting a nested `T` inside of an `Outer<T>` type
@@ -1825,35 +1827,44 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
18251827
/// Therefore this is not a valid conversion, despite `NonNull<u8>` and `UnsafeCell<NonNull<u8>>>`
18261828
/// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in
18271829
/// order to avoid its interior mutability property from spreading from `T` into the `Outer` type,
1828-
/// thus this can cause distortions in the type size in these cases. Furthermore, it is only valid
1829-
/// to obtain a `*mut T` pointer to the contents of a _shared_ `UnsafeCell<T>` through [`.get()`]
1830-
/// or [`.raw_get()`]. A `&mut T` reference can be obtained by either dereferencing this pointer or
1831-
/// by calling [`.get_mut()`] on an _exclusive_ `UnsafeCell<T>`, e.g.:
1830+
/// thus this can cause distortions in the type size in these cases.
1831+
///
1832+
/// Note that the only valid way to obtain a `*mut T` pointer to the contents of a
1833+
/// _shared_ `UnsafeCell<T>` is through [`.get()`] or [`.raw_get()`]. A `&mut T` reference
1834+
/// can be obtained by either dereferencing this pointer or by calling [`.get_mut()`]
1835+
/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
1836+
/// same memory layout, the following is not allowed and undefined behavior:
1837+
///
1838+
/// ```rust,no_run
1839+
/// # use std::cell::UnsafeCell;
1840+
/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
1841+
/// let t = ptr as *const UnsafeCell<T> as *mut T;
1842+
/// // This is undefined behavior, because the `*mut T` pointer
1843+
/// // was not obtained through `.get()` nor `.raw_get()`:
1844+
/// unsafe { &mut *t }
1845+
/// }
1846+
/// ```
1847+
///
1848+
/// Instead, do this:
18321849
///
18331850
/// ```rust
1834-
/// use std::cell::UnsafeCell;
1851+
/// # use std::cell::UnsafeCell;
1852+
/// // Safety: the caller must ensure that there are no references that
1853+
/// // point to the *contents* of the `UnsafeCell`.
1854+
/// unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
1855+
/// unsafe { &mut *ptr.get() }
1856+
/// }
1857+
/// ```
18351858
///
1836-
/// let mut x: UnsafeCell<u32> = UnsafeCell::new(5);
1837-
/// let shared: &UnsafeCell<u32> = &x;
1838-
/// // using `.get()` is okay:
1839-
/// unsafe {
1840-
/// // SAFETY: there exist no other references to the contents of `x`
1841-
/// let exclusive: &mut u32 = &mut *shared.get();
1842-
/// };
1843-
/// // using `.raw_get()` is also okay:
1844-
/// unsafe {
1845-
/// // SAFETY: there exist no other references to the contents of `x` in this scope
1846-
/// let exclusive: &mut u32 = &mut *UnsafeCell::raw_get(shared as *const _);
1847-
/// };
1848-
/// // using `.get_mut()` is always safe:
1849-
/// let exclusive: &mut u32 = x.get_mut();
1859+
/// Coverting in the other direction from a `&mut T`
1860+
/// to an `&UnsafeCell<T>` is allowed:
18501861
///
1851-
/// // when we have exclusive access, we can convert it to a shared `&UnsafeCell`:
1852-
/// unsafe {
1853-
/// // SAFETY: `u32` has no niche, therefore it has the same layout as `UnsafeCell<u32>`
1854-
/// let shared: &UnsafeCell<u32> = &*(exclusive as *mut _ as *const UnsafeCell<u32>);
1855-
/// // SAFETY: there exist no other *active* references to the contents of `x` in this scope
1856-
/// let exclusive: &mut u32 = &mut *shared.get();
1862+
/// ```rust
1863+
/// # use std::cell::UnsafeCell;
1864+
/// fn get_shared<T>(ptr: &mut T) -> &UnsafeCell<T> {
1865+
/// let t = ptr as *mut T as *const UnsafeCell<T>;
1866+
/// // SAFETY: `T` and `UnsafeCell<T>` have the same memory layout
1867+
/// unsafe { &*t }
18571868
/// }
18581869
/// ```
18591870
///

0 commit comments

Comments
 (0)