Skip to content

Commit e84ee52

Browse files
authored
Rollup merge of #86220 - est31:maybe-uninit-extra, r=RalfJung
Improve maybe_uninit_extra docs For reasoning, see #63567 (comment)
2 parents 3f4d6d7 + 8710258 commit e84ee52

File tree

1 file changed

+67
-13
lines changed

1 file changed

+67
-13
lines changed

library/core/src/mem/maybe_uninit.rs

+67-13
Original file line numberDiff line numberDiff line change
@@ -402,10 +402,60 @@ impl<T> MaybeUninit<T> {
402402
u
403403
}
404404

405-
/// Sets the value of the `MaybeUninit<T>`. This overwrites any previous value
406-
/// without dropping it, so be careful not to use this twice unless you want to
407-
/// skip running the destructor. For your convenience, this also returns a mutable
408-
/// reference to the (now safely initialized) contents of `self`.
405+
/// Sets the value of the `MaybeUninit<T>`.
406+
///
407+
/// This overwrites any previous value without dropping it, so be careful
408+
/// not to use this twice unless you want to skip running the destructor.
409+
/// For your convenience, this also returns a mutable reference to the
410+
/// (now safely initialized) contents of `self`.
411+
///
412+
/// As the content is stored inside a `MaybeUninit`, the destructor is not
413+
/// ran for the inner data if the MaybeUninit leaves scope without a call to
414+
/// [`assume_init`], [`assume_init_drop`], or similar. Code that receives
415+
/// the mutable reference returned by this function needs to keep this in
416+
/// mind. The safety model of Rust regards leaks as safe, but they are
417+
/// usually still undesirable. This being said, the mutable reference
418+
/// behaves like any other mutable reference would, so assigning a new value
419+
/// to it will drop the old content.
420+
///
421+
/// [`assume_init`]: Self::assume_init
422+
/// [`assume_init_drop`]: Self::assume_init_drop
423+
///
424+
/// # Examples
425+
///
426+
/// Correct usage of this method:
427+
///
428+
/// ```rust
429+
/// #![feature(maybe_uninit_extra)]
430+
/// use std::mem::MaybeUninit;
431+
///
432+
/// let mut x = MaybeUninit::<Vec<u8>>::uninit();
433+
///
434+
/// {
435+
/// let hello = x.write((&b"Hello, world!").to_vec());
436+
/// // Setting hello does not leak prior allocations, but drops them
437+
/// *hello = (&b"Hello").to_vec();
438+
/// hello[0] = 'h' as u8;
439+
/// }
440+
/// // x is initialized now:
441+
/// let s = unsafe { x.assume_init() };
442+
/// assert_eq!(b"hello", s.as_slice());
443+
/// ```
444+
///
445+
/// This usage of the method causes a leak:
446+
///
447+
/// ```rust
448+
/// #![feature(maybe_uninit_extra)]
449+
/// use std::mem::MaybeUninit;
450+
///
451+
/// let mut x = MaybeUninit::<String>::uninit();
452+
///
453+
/// x.write("Hello".to_string());
454+
/// // This leaks the contained string:
455+
/// x.write("hello".to_string());
456+
/// // x is initialized now:
457+
/// let s = unsafe { x.assume_init() };
458+
/// ```
409459
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
410460
#[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
411461
#[inline(always)]
@@ -564,9 +614,11 @@ impl<T> MaybeUninit<T> {
564614
/// behavior. The [type-level documentation][inv] contains more information about
565615
/// this initialization invariant.
566616
///
567-
/// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
568-
/// multiple copies of the data (by calling `assume_init_read` multiple times, or first
569-
/// calling `assume_init_read` and then [`assume_init`]), it is your responsibility
617+
/// Moreover, similar to the [`ptr::read`] function, this function creates a
618+
/// bitwise copy of the contents, regardless whether the contained type
619+
/// implements the [`Copy`] trait or not. When using multiple copies of the
620+
/// data (by calling `assume_init_read` multiple times, or first calling
621+
/// `assume_init_read` and then [`assume_init`]), it is your responsibility
570622
/// to ensure that that data may indeed be duplicated.
571623
///
572624
/// [inv]: #initialization-invariant
@@ -622,7 +674,8 @@ impl<T> MaybeUninit<T> {
622674

623675
/// Drops the contained value in place.
624676
///
625-
/// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead.
677+
/// If you have ownership of the `MaybeUninit`, you can also use
678+
/// [`assume_init`] as an alternative.
626679
///
627680
/// # Safety
628681
///
@@ -632,11 +685,12 @@ impl<T> MaybeUninit<T> {
632685
///
633686
/// On top of that, all additional invariants of the type `T` must be
634687
/// satisfied, as the `Drop` implementation of `T` (or its members) may
635-
/// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered
636-
/// initialized (under the current implementation; this does not constitute
637-
/// a stable guarantee) because the only requirement the compiler knows
638-
/// about it is that the data pointer must be non-null. Dropping such a
639-
/// `Vec<T>` however will cause undefined behaviour.
688+
/// rely on this. For example, setting a [`Vec<T>`] to an invalid but
689+
/// non-null address makes it initialized (under the current implementation;
690+
/// this does not constitute a stable guarantee), because the only
691+
/// requirement the compiler knows about it is that the data pointer must be
692+
/// non-null. Dropping such a `Vec<T>` however will cause undefined
693+
/// behaviour.
640694
///
641695
/// [`assume_init`]: MaybeUninit::assume_init
642696
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html

0 commit comments

Comments
 (0)