@@ -1811,35 +1811,43 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
1811
1811
///
1812
1812
/// [`.get_mut()`]: `UnsafeCell::get_mut`
1813
1813
///
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.:
1818
1822
///
1819
1823
/// ```rust
1820
1824
/// use std::cell::UnsafeCell;
1821
1825
///
1822
1826
/// let mut x: UnsafeCell<u32> = UnsafeCell::new(5);
1823
- /// let p1 : &UnsafeCell<u32> = &x;
1827
+ /// let shared : &UnsafeCell<u32> = &x;
1824
1828
/// // using `.get()` is okay:
1825
1829
/// unsafe {
1826
1830
/// // 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();
1828
1832
/// };
1829
1833
/// // using `.raw_get()` is also okay:
1830
1834
/// unsafe {
1831
1835
/// // 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 _);
1833
1837
/// };
1834
1838
/// // 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
+ /// }
1841
1848
/// ```
1842
1849
///
1850
+ /// [niche]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#niche
1843
1851
/// [`.raw_get()`]: `UnsafeCell::raw_get`
1844
1852
///
1845
1853
/// # Examples
0 commit comments