@@ -1825,35 +1825,44 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
1825
1825
/// Therefore this is not a valid conversion, despite `NonNull<u8>` and `UnsafeCell<NonNull<u8>>>`
1826
1826
/// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in
1827
1827
/// 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.:
1828
+ /// thus this can cause distortions in the type size in these cases.
1829
+ ///
1830
+ /// Note that it is still only valid to obtain a `*mut T` pointer to the contents of a
1831
+ /// _shared_ `UnsafeCell<T>` through [`.get()`] or [`.raw_get()`]. A `&mut T` reference
1832
+ /// can be obtained by either dereferencing this pointer or by calling [`.get_mut()`]
1833
+ /// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
1834
+ /// same memory layout, the following is not allowed and undefined behavior:
1835
+ ///
1836
+ /// ```rust,no_run
1837
+ /// # use std::cell::UnsafeCell;
1838
+ /// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
1839
+ /// let t = ptr as *const UnsafeCell<T> as *mut T;
1840
+ /// // This is undefined behavior, because the `*mut T` pointer
1841
+ /// // was not obtained through `.get()` nor `.raw_get()`:
1842
+ /// unsafe { &mut *t }
1843
+ /// }
1844
+ /// ```
1845
+ ///
1846
+ /// Instead, do this:
1832
1847
///
1833
1848
/// ```rust
1834
- /// use std::cell::UnsafeCell;
1849
+ /// # use std::cell::UnsafeCell;
1850
+ /// // Safety: the caller must ensure that there are no references that
1851
+ /// // point to the *contents* of the `UnsafeCell`.
1852
+ /// unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
1853
+ /// unsafe { &mut *ptr.get() }
1854
+ /// }
1855
+ /// ```
1835
1856
///
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();
1857
+ /// Coverting in the other direction from a `&mut T`
1858
+ /// to an `&UnsafeCell<T>` is allowed:
1850
1859
///
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();
1860
+ /// ```rust
1861
+ /// # use std::cell::UnsafeCell;
1862
+ /// fn get_shared<T>(ptr: &mut T) -> & UnsafeCell<T> {
1863
+ /// let t = ptr as *mut T as *const UnsafeCell<T> ;
1864
+ /// // SAFETY: `T` and `UnsafeCell<T>` have the same memory layout
1865
+ /// unsafe { &*t }
1857
1866
/// }
1858
1867
/// ```
1859
1868
///
0 commit comments