diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index fda103a52d8bc..e0d1e35858a2a 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -1426,8 +1426,9 @@ impl fmt::Display for RefMut<'_, T> { /// allow internal mutability, such as `Cell` and `RefCell`, use `UnsafeCell` to wrap their /// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell`. /// -/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to -/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. +/// The `UnsafeCell` API itself is technically very simple: `get` gives you a raw pointer `*mut T` +/// to its contents. It is up to _you_ as the abstraction designer to use that raw pointer +/// correctly. /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// @@ -1458,17 +1459,51 @@ impl fmt::Display for RefMut<'_, T> { /// ok (provided you enforce the invariants some other way), it is still undefined behavior /// to have multiple `&mut UnsafeCell` aliases. /// +/// /// # Examples /// +/// ## Wrapper not handing out references +/// +/// A tiny wrapper similar to `Cell`, safe because it never creates an `&T` or `&mut T` reference: +/// /// ``` /// use std::cell::UnsafeCell; /// /// # #[allow(dead_code)] -/// struct NotThreadSafe { -/// value: UnsafeCell, +/// struct MyCell { +/// value: UnsafeCell +/// } +/// +/// # #[allow(dead_code)] +/// impl MyCell { +/// fn get(&self) -> T { +/// unsafe { *self.value.get() } +/// } +/// +/// fn set(&self, val: T) { +/// unsafe { *self.value.get() = val} +/// } /// } +/// ``` +/// +/// Wrappers that hand out references get to complex for an example, where you somehow have to +/// ensure there are no live references when modifying the wrapped value. +/// +/// ## Using UnsafeCell through a raw reference +/// +/// If you have a raw reference to an `UnsafeCell` that can't be turned into a shared reference +/// (because for example the wrapped value may be uninitialized), use a pointer cast instead of +/// `get`: +/// +/// ``` +/// use std::cell::UnsafeCell; +/// use std::mem::MaybeUninit; /// -/// unsafe impl Sync for NotThreadSafe {} +/// let cell: MaybeUninit> = MaybeUninit::uninit(); +/// let inner: *const UnsafeCell = cell.as_ptr(); +/// // Do a raw pointer cast instead of `get`: +/// let val = cell as *mut bool; +/// unsafe { val.write(true) }; /// ``` #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs index 792ce9dfad419..425c519a4ef35 100644 --- a/src/libcore/mem/maybe_uninit.rs +++ b/src/libcore/mem/maybe_uninit.rs @@ -324,7 +324,7 @@ impl MaybeUninit { /// Gets a pointer to the contained value. Reading from this pointer or turning it /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. /// Writing to memory that this pointer (non-transitively) points to is undefined behavior - /// (except inside an `UnsafeCell`). + /// (except inside an `UnsafeCell`, [see `UnsafeCell`]). /// /// # Examples /// @@ -352,6 +352,8 @@ impl MaybeUninit { /// /// (Notice that the rules around references to uninitialized data are not finalized yet, but /// until they are, it is advisable to avoid them.) + /// + /// [see `UnsafeCell`]: ../cell/struct.UnsafeCell.html#using-unsafecell-through-a-raw-reference #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub fn as_ptr(&self) -> *const T {