Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add comment about UnsafeCell in MaybeUninit #66051

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 40 additions & 5 deletions src/libcore/cell.rs
Expand Up @@ -1426,8 +1426,9 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
/// allow internal mutability, such as `Cell<T>` and `RefCell<T>`, use `UnsafeCell` to wrap their
/// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell<T>`.
///
/// 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:
///
Expand Down Expand Up @@ -1458,17 +1459,51 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
/// ok (provided you enforce the invariants some other way), it is still undefined behavior
/// to have multiple `&mut UnsafeCell<T>` 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<T> {
/// value: UnsafeCell<T>,
/// struct MyCell<T> {
/// value: UnsafeCell<T>
/// }
///
/// # #[allow(dead_code)]
/// impl<T: Copy> MyCell<T> {
/// 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`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should bless this pattern yet, while the memory model is still so much in flux.

I like your other improvements, but for the interaction with UnsafeCell I'm afraid just changing docs won't cut it at this point.

///
/// ```
/// use std::cell::UnsafeCell;
/// use std::mem::MaybeUninit;
///
/// unsafe impl<T> Sync for NotThreadSafe<T> {}
/// let cell: MaybeUninit<UnsafeCell<bool>> = 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")]
Expand Down
4 changes: 3 additions & 1 deletion src/libcore/mem/maybe_uninit.rs
Expand Up @@ -324,7 +324,7 @@ impl<T> MaybeUninit<T> {
/// Gets a pointer to the contained value. Reading from this pointer or turning it
/// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized.
/// Writing to memory that this pointer (non-transitively) points to is undefined behavior
/// (except inside an `UnsafeCell<T>`).
/// (except inside an `UnsafeCell<T>`, [see `UnsafeCell`]).
///
/// # Examples
///
Expand Down Expand Up @@ -352,6 +352,8 @@ impl<T> MaybeUninit<T> {
///
/// (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 {
Expand Down