diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 3451a25504e..12c6f211725 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1825,35 +1825,44 @@ impl fmt::Display for RefMut<'_, T> { /// Therefore this is not a valid conversion, despite `NonNull` and `UnsafeCell>>` /// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in /// order to avoid its interior mutability property from spreading from `T` into the `Outer` type, -/// thus this can cause distortions in the type size in these cases. Furthermore, it is only valid -/// to obtain a `*mut T` pointer to the contents of a _shared_ `UnsafeCell` through [`.get()`] -/// or [`.raw_get()`]. A `&mut T` reference can be obtained by either dereferencing this pointer or -/// by calling [`.get_mut()`] on an _exclusive_ `UnsafeCell`, e.g.: +/// thus this can cause distortions in the type size in these cases. +/// +/// Note that it is still only valid to obtain a `*mut T` pointer to the contents of a +/// _shared_ `UnsafeCell` through [`.get()`] or [`.raw_get()`]. A `&mut T` reference +/// can be obtained by either dereferencing this pointer or by calling [`.get_mut()`] +/// on an _exclusive_ `UnsafeCell`. Even though `T` and `UnsafeCell` have the +/// same memory layout, the following is not allowed and undefined behavior: +/// +/// ```rust,no_run +/// # use std::cell::UnsafeCell; +/// unsafe fn not_allowed(ptr: &UnsafeCell) -> &mut T { +/// let t = ptr as *const UnsafeCell as *mut T; +/// // This is undefined behavior, because the `*mut T` pointer +/// // was not obtained through `.get()` nor `.raw_get()`: +/// unsafe { &mut *t } +/// } +/// ``` +/// +/// Instead, do this: /// /// ```rust -/// use std::cell::UnsafeCell; +/// # use std::cell::UnsafeCell; +/// // Safety: the caller must ensure that there are no references that +/// // point to the *contents* of the `UnsafeCell`. +/// unsafe fn get_mut(ptr: &UnsafeCell) -> &mut T { +/// unsafe { &mut *ptr.get() } +/// } +/// ``` /// -/// let mut x: UnsafeCell = UnsafeCell::new(5); -/// let shared: &UnsafeCell = &x; -/// // using `.get()` is okay: -/// unsafe { -/// // SAFETY: there exist no other references to the contents of `x` -/// let exclusive: &mut u32 = &mut *shared.get(); -/// }; -/// // using `.raw_get()` is also okay: -/// unsafe { -/// // SAFETY: there exist no other references to the contents of `x` in this scope -/// let exclusive: &mut u32 = &mut *UnsafeCell::raw_get(shared as *const _); -/// }; -/// // using `.get_mut()` is always safe: -/// let exclusive: &mut u32 = x.get_mut(); +/// Coverting in the other direction from a `&mut T` +/// to an `&UnsafeCell` is allowed: /// -/// // when we have exclusive access, we can convert it to a shared `&UnsafeCell`: -/// unsafe { -/// // SAFETY: `u32` has no niche, therefore it has the same layout as `UnsafeCell` -/// let shared: &UnsafeCell = &*(exclusive as *mut _ as *const UnsafeCell); -/// // SAFETY: there exist no other *active* references to the contents of `x` in this scope -/// let exclusive: &mut u32 = &mut *shared.get(); +/// ```rust +/// # use std::cell::UnsafeCell; +/// fn get_shared(ptr: &mut T) -> &UnsafeCell { +/// let t = ptr as *mut T as *const UnsafeCell; +/// // SAFETY: `T` and `UnsafeCell` have the same memory layout +/// unsafe { &*t } /// } /// ``` ///