Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions library/core/src/mem/maybe_uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,15 +726,30 @@ impl<T> MaybeUninit<T> {
/// `assume_init_read` and then [`assume_init`]), it is your responsibility
/// to ensure that data may indeed be duplicated.
///
/// Additionally, if you call this function from a different thread than the one
/// that holds the `MaybeUninit<T>`, it logically constitutes a cross-thread ownership
/// transfer of the contained value `T`. You are responsible for guaranteeing
/// the thread safety of the transfer. Note that `MaybeUninit<T>` is [`Sync`] if `T`
/// is merely [`Sync`]; therefore, safely obtaining `&MaybeUninit<T>` does *not* ensure
/// the said thread safety. If `T` is [`Send`], the thread safety is
/// guaranteed; otherwise, you will need to provide type-specific reasoning to
/// prove that the transfer and your usage of the value `T` are actually thread-safe.
/// If your type's safe API relies on this function, you may need to manually
/// implement `!Send`, `!Sync`, [`Send`], and/or [`Sync`] to *tighten* the conditions
/// for the type to be [`Send`] and/or [`Sync`].
///
/// [inv]: #initialization-invariant
/// [`assume_init`]: MaybeUninit::assume_init
/// [`Send`]: crate::marker::Send
/// [`Sync`]: crate::marker::Sync
///
/// # Examples
///
/// Correct usage of this method:
///
/// ```rust
/// use std::mem::MaybeUninit;
/// use std::thread;
///
/// let mut x = MaybeUninit::<u32>::uninit();
/// x.write(13);
Expand All @@ -749,19 +764,43 @@ impl<T> MaybeUninit<T> {
/// // Duplicating a `None` value is okay, so we may read multiple times.
/// let x2 = unsafe { x.assume_init_read() };
/// assert_eq!(x1, x2);
///
/// let mut x = MaybeUninit::<Vec<u32>>::uninit();
/// x.write(vec![0, 1, 2]);
/// // Moving the vector to another thread. We may read only once.
/// // `Vec<u32>` is `Send`, so this is thread-safe.
/// thread::scope(|s| {
/// s.spawn(|| {
/// let v = unsafe { x.assume_init_read() };
/// assert_eq!(v, vec![0, 1, 2]);
/// });
/// });
/// ```
///
/// *Incorrect* usage of this method:
///
/// ```rust,no_run
/// use std::mem::MaybeUninit;
/// use std::thread;
/// use std::sync::Mutex;
///
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
/// x.write(Some(vec![0, 1, 2]));
/// let x1 = unsafe { x.assume_init_read() };
/// let x2 = unsafe { x.assume_init_read() };
/// // We now created two copies of the same vector, leading to a double-free ⚠️ when
/// // they both get dropped!
///
/// let mtx = Mutex::new(0u32);
/// let x = MaybeUninit::new(mtx.lock().unwrap());
/// // Moving the `MutexGuard<'_, u32>: !Send + Sync` to another thread.
/// // ⚠️ Thread safety is not guaranteed here!
/// thread::scope(|s| {
/// // This compiles because `MaybeUninit<MutexGuard<'_, u32>>` is `Sync`.
/// s.spawn(|| {
/// let _unused = unsafe { x.assume_init_read() };
/// });
/// });
/// ```
#[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
#[rustc_const_stable(feature = "const_maybe_uninit_assume_init_read", since = "1.75.0")]
Expand Down
Loading