Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit eead20a

Browse files
committedFeb 21, 2025·
Clarify MaybeUninit docs
Couldn't help myself while fixing #66845.
1 parent 5ff18d0 commit eead20a

File tree

1 file changed

+82
-84
lines changed

1 file changed

+82
-84
lines changed
 

‎library/core/src/mem/maybe_uninit.rs

+82-84
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ use crate::{fmt, intrinsics, ptr, slice};
44

55
/// A wrapper type to construct uninitialized instances of `T`.
66
///
7+
/// A `MaybeUninit<T>` is like a `T`, but without the requirement that it is properly initialized as a `T`.
8+
/// Dropping a `MaybeUninit<T>` does nothing, even if properly initialized as a `T`, because
9+
/// the compiler relies on the type system to decide how to drop variables. Thus, if a `MaybeUninit<T>`
10+
/// should be dropped like a `T`, it should be converted to a `T` with `assume_init` or similar.
11+
///
712
/// # Initialization invariant
813
///
9-
/// The compiler, in general, assumes that a variable is properly initialized
10-
/// according to the requirements of the variable's type. For example, a variable of
11-
/// reference type must be aligned and non-null. This is an invariant that must
14+
/// Every variable must be properly initialized according to the requirements of its type.
15+
/// For example, a variable of reference type must be aligned and non-null. This is an invariant that must
1216
/// *always* be upheld, even in unsafe code. As a consequence, zero-initializing a
1317
/// variable of reference type causes instantaneous [undefined behavior][ub],
1418
/// no matter whether that reference ever gets used to access memory:
@@ -25,7 +29,7 @@ use crate::{fmt, intrinsics, ptr, slice};
2529
/// This is exploited by the compiler for various optimizations, such as eliding
2630
/// run-time checks and optimizing `enum` layout.
2731
///
28-
/// Similarly, entirely uninitialized memory may have any content, while a `bool` must
32+
/// Similarly, entirely uninitialized memory may have any value, while a `bool` must
2933
/// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior:
3034
///
3135
/// ```rust,no_run
@@ -37,11 +41,11 @@ use crate::{fmt, intrinsics, ptr, slice};
3741
/// let b: bool = unsafe { MaybeUninit::uninit().assume_init() }; // undefined behavior! ⚠️
3842
/// ```
3943
///
40-
/// Moreover, uninitialized memory is special in that it does not have a fixed value ("fixed"
41-
/// meaning "it won't change without being written to"). Reading the same uninitialized byte
42-
/// multiple times can give different results. This makes it undefined behavior to have
43-
/// uninitialized data in a variable even if that variable has an integer type, which otherwise can
44-
/// hold any *fixed* bit pattern:
44+
/// Moreover, uninitialized memory is special in that it does not have a fixed
45+
/// (unchanged unless written to) value . Reading the same uninitialized byte
46+
/// multiple times can give different results. This even makes it undefined
47+
/// behavior to have uninitialized data in a variable of integer type,
48+
/// which otherwise could hold any *fixed* bit pattern:
4549
///
4650
/// ```rust,no_run
4751
/// # #![allow(invalid_value)]
@@ -308,7 +312,7 @@ impl<T> MaybeUninit<T> {
308312
MaybeUninit { value: ManuallyDrop::new(val) }
309313
}
310314

311-
/// Creates a new `MaybeUninit<T>` in an uninitialized state.
315+
/// Creates a new uninitialized `MaybeUninit<T>`.
312316
///
313317
/// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code.
314318
/// It is your responsibility to make sure `T` gets dropped if it got initialized.
@@ -331,7 +335,7 @@ impl<T> MaybeUninit<T> {
331335
MaybeUninit { uninit: () }
332336
}
333337

334-
/// Creates a new array of `MaybeUninit<T>` items, in an uninitialized state.
338+
/// Creates a new array of uninitialized `MaybeUninit<T>` elements.
335339
///
336340
/// Note: in a future Rust version this method may become unnecessary
337341
/// when Rust allows
@@ -367,8 +371,7 @@ impl<T> MaybeUninit<T> {
367371
[const { MaybeUninit::uninit() }; N]
368372
}
369373

370-
/// Creates a new `MaybeUninit<T>` in an uninitialized state, with the memory being
371-
/// filled with `0` bytes. It depends on `T` whether that already makes for
374+
/// Creates a new zero-filled `MaybeUninit<T>`. It depends on `T` whether that already makes for
372375
/// proper initialization. For example, `MaybeUninit<usize>::zeroed()` is initialized,
373376
/// but `MaybeUninit<&'static i32>::zeroed()` is not because references must not
374377
/// be null.
@@ -425,16 +428,13 @@ impl<T> MaybeUninit<T> {
425428
/// This overwrites any previous value without dropping it, so be careful
426429
/// not to use this twice unless you want to skip running the destructor.
427430
/// For your convenience, this also returns a mutable reference to the
428-
/// (now safely initialized) contents of `self`.
431+
/// (now safely initialized) value of `self`.
429432
///
430-
/// As the content is stored inside a `MaybeUninit`, the destructor is not
431-
/// run for the inner data if the MaybeUninit leaves scope without a call to
432-
/// [`assume_init`], [`assume_init_drop`], or similar. Code that receives
433-
/// the mutable reference returned by this function needs to keep this in
434-
/// mind. The safety model of Rust regards leaks as safe, but they are
435-
/// usually still undesirable. This being said, the mutable reference
436-
/// behaves like any other mutable reference would, so assigning a new value
437-
/// to it will drop the old content.
433+
/// Keep in mind, that the value, as it is wrapped in a `MaybeUninit`,
434+
/// will not be dropped when its wrapper is. You can make sure the value is dropped by unwrapping
435+
/// it with a call to [`assume_init`], or by dropping it directly with [`assume_init_drop`].
436+
/// While the value is also dropped when the returned mutable reference is assigned a new value,
437+
/// the new value is then subject to the same rules, as now the new value is wrapped in a `MaybeUninit`.
438438
///
439439
/// [`assume_init`]: Self::assume_init
440440
/// [`assume_init_drop`]: Self::assume_init_drop
@@ -470,7 +470,7 @@ impl<T> MaybeUninit<T> {
470470
/// # // FIXME(https://github.com/rust-lang/miri/issues/3670):
471471
/// # // use -Zmiri-disable-leak-check instead of unleaking in tests meant to leak.
472472
/// # unsafe { MaybeUninit::assume_init_drop(&mut x); }
473-
/// // This leaks the contained string:
473+
/// // This leaks the initialized string:
474474
/// x.write("hello".to_string());
475475
/// // x is initialized now:
476476
/// let s = unsafe { x.assume_init() };
@@ -513,7 +513,7 @@ impl<T> MaybeUninit<T> {
513513
unsafe { self.assume_init_mut() }
514514
}
515515

516-
/// Gets a pointer to the contained value. Reading from this pointer or turning it
516+
/// Gets a pointer to the `T` value of the `MaybeUninit<T>`. Reading from this pointer or turning it
517517
/// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized.
518518
/// Writing to memory that this pointer (non-transitively) points to is undefined behavior
519519
/// (except inside an `UnsafeCell<T>`).
@@ -545,7 +545,7 @@ impl<T> MaybeUninit<T> {
545545
/// ```
546546
///
547547
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
548-
/// until they are, it is advisable to avoid them.)
548+
/// until they are, it is advisable to avoid references to uninitialized data.)
549549
#[stable(feature = "maybe_uninit", since = "1.36.0")]
550550
#[rustc_const_stable(feature = "const_maybe_uninit_as_ptr", since = "1.59.0")]
551551
#[rustc_as_ptr]
@@ -555,7 +555,7 @@ impl<T> MaybeUninit<T> {
555555
self as *const _ as *const T
556556
}
557557

558-
/// Gets a mutable pointer to the contained value. Reading from this pointer or turning it
558+
/// Gets a mutable pointer to the `T` value of the `MaybeUninit<T>`. Reading from this pointer or turning it
559559
/// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized.
560560
///
561561
/// # Examples
@@ -597,16 +597,17 @@ impl<T> MaybeUninit<T> {
597597
self as *mut _ as *mut T
598598
}
599599

600-
/// Extracts the value from the `MaybeUninit<T>` container. This is a great way
600+
/// Converts an initialized `MaybeUninit<T>` into a `T`. This is a great way
601601
/// to ensure that the data will get dropped, because the resulting `T` is
602602
/// subject to the usual drop handling.
603603
///
604604
/// # Safety
605605
///
606-
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
607-
/// state. Calling this when the content is not yet fully initialized causes immediate undefined
608-
/// behavior. The [type-level documentation][inv] contains more information about
609-
/// this initialization invariant.
606+
/// It is up to the caller to ensure that the `MaybeUninit<T>` has been fully initialized,
607+
/// before converting it into a `T`. Calling this when the `T` value of the `MaybeUninit<T>`
608+
/// is not yet fully initialized causes immediate undefined behavior.
609+
///
610+
/// The [type-level documentation][inv] contains more information about this initialization invariant.
610611
///
611612
/// [inv]: #initialization-invariant
612613
///
@@ -656,21 +657,23 @@ impl<T> MaybeUninit<T> {
656657
}
657658
}
658659

659-
/// Reads the value from the `MaybeUninit<T>` container. The resulting `T` is subject
660-
/// to the usual drop handling.
660+
/// Reads the `T` value of the `MaybeUninit<T>`. The result is an ordinary `T` which,
661+
/// just like all `T` values, is subject to the usual drop handling.
661662
///
662663
/// Whenever possible, it is preferable to use [`assume_init`] instead, which
663-
/// prevents duplicating the content of the `MaybeUninit<T>`.
664+
/// prevents duplicating the value of the `MaybeUninit<T>`.
664665
///
665666
/// # Safety
666667
///
667-
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized
668-
/// state. Calling this when the content is not yet fully initialized causes undefined
669-
/// behavior. The [type-level documentation][inv] contains more information about
668+
/// It is up to the caller to ensure that the `MaybeUninit<T>` has been fully initialized,
669+
/// before reading the `T` value of the `MaybeUninit<T>`. Calling this when the `T` value
670+
/// of the `MaybeUninit<T>` is not yet fully initialized causes immediate undefined behavior.
671+
///
672+
/// The [type-level documentation][inv] contains more information about
670673
/// this initialization invariant.
671674
///
672675
/// Moreover, similar to the [`ptr::read`] function, this function creates a
673-
/// bitwise copy of the contents, regardless whether the contained type
676+
/// bitwise copy of the value, regardless of whether its type
674677
/// implements the [`Copy`] trait or not. When using multiple copies of the
675678
/// data (by calling `assume_init_read` multiple times, or first calling
676679
/// `assume_init_read` and then [`assume_init`]), it is your responsibility
@@ -726,16 +729,16 @@ impl<T> MaybeUninit<T> {
726729
}
727730
}
728731

729-
/// Drops the contained value in place.
732+
/// Drops the `T` value of the `MaybeUninit<T>` in place.
730733
///
731734
/// If you have ownership of the `MaybeUninit`, you can also use
732735
/// [`assume_init`] as an alternative.
733736
///
734737
/// # Safety
735738
///
736-
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is
737-
/// in an initialized state. Calling this when the content is not yet fully
738-
/// initialized causes undefined behavior.
739+
/// It is up to the caller to ensure that the `MaybeUninit<T>` has been fully initialized,
740+
/// before dropping the `T` value of the `MaybeUninit<T>`. Calling this when the `T` value
741+
/// of the `MaybeUninit<T>` is not yet fully initialized causes immediate undefined behavior.
739742
///
740743
/// On top of that, all additional invariants of the type `T` must be
741744
/// satisfied, as the `Drop` implementation of `T` (or its members) may
@@ -755,17 +758,17 @@ impl<T> MaybeUninit<T> {
755758
unsafe { ptr::drop_in_place(self.as_mut_ptr()) }
756759
}
757760

758-
/// Gets a shared reference to the contained value.
761+
/// Gets a shared reference to the `T` value of the `MaybeUninit<T>`.
759762
///
760763
/// This can be useful when we want to access a `MaybeUninit` that has been
761764
/// initialized but don't have ownership of the `MaybeUninit` (preventing the use
762765
/// of `.assume_init()`).
763766
///
764767
/// # Safety
765768
///
766-
/// Calling this when the content is not yet fully initialized causes undefined
767-
/// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
768-
/// is in an initialized state.
769+
/// It is up to the caller to ensure that the `MaybeUninit<T>` has been fully initialized,
770+
/// before getting a reference to the `T` value of the `MaybeUninit<T>`. Calling this when the `T` value
771+
/// of the `MaybeUninit<T>` is not yet fully initialized causes immediate undefined behavior.
769772
///
770773
/// # Examples
771774
///
@@ -823,18 +826,17 @@ impl<T> MaybeUninit<T> {
823826
}
824827
}
825828

826-
/// Gets a mutable (unique) reference to the contained value.
829+
/// Gets a mutable (unique) reference to the `T` value of the `MaybeUninit<T>`.
827830
///
828831
/// This can be useful when we want to access a `MaybeUninit` that has been
829832
/// initialized but don't have ownership of the `MaybeUninit` (preventing the use
830833
/// of `.assume_init()`).
831834
///
832835
/// # Safety
833836
///
834-
/// Calling this when the content is not yet fully initialized causes undefined
835-
/// behavior: it is up to the caller to guarantee that the `MaybeUninit<T>` really
836-
/// is in an initialized state. For instance, `.assume_init_mut()` cannot be used to
837-
/// initialize a `MaybeUninit`.
837+
/// It is up to the caller to ensure that the `MaybeUninit<T>` has been fully initialized,
838+
/// before getting a mutable reference to the `T` value of the `MaybeUninit<T>`. Calling this when the `T` value
839+
/// of the `MaybeUninit<T>` is not yet fully initialized causes immediate undefined behavior.
838840
///
839841
/// # Examples
840842
///
@@ -940,12 +942,12 @@ impl<T> MaybeUninit<T> {
940942
}
941943
}
942944

943-
/// Extracts the values from an array of `MaybeUninit` containers.
945+
/// Extracts the values from an array of `MaybeUninit` wrappers.
944946
///
945947
/// # Safety
946948
///
947949
/// It is up to the caller to guarantee that all elements of the array are
948-
/// in an initialized state.
950+
/// properly initialized.
949951
///
950952
/// # Examples
951953
///
@@ -980,10 +982,9 @@ impl<T> MaybeUninit<T> {
980982
}
981983
}
982984

983-
/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
985+
/// Returns a slice of potentially uninitialized bytes to the value of this `MaybeUninit`.
984986
///
985-
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
986-
/// contain padding bytes which are left uninitialized.
987+
/// Note that a value may still contain uninitialized padding bytes even if it has been fully initialized.
987988
///
988989
/// # Examples
989990
///
@@ -1005,11 +1006,9 @@ impl<T> MaybeUninit<T> {
10051006
}
10061007
}
10071008

1008-
/// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized
1009-
/// bytes.
1009+
/// Returns a mutable slice of potentially uninitialized bytes to the value of this `MaybeUninit`.
10101010
///
1011-
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
1012-
/// contain padding bytes which are left uninitialized.
1011+
/// Note that a value may still contain uninitialized padding bytes even if it has been fully initialized.
10131012
///
10141013
/// # Examples
10151014
///
@@ -1103,8 +1102,9 @@ impl<T> MaybeUninit<T> {
11031102
this.write_clone_of_slice(src)
11041103
}
11051104

1106-
/// Fills a slice with elements by cloning `value`, returning a mutable reference to the now
1107-
/// initialized contents of the slice.
1105+
/// Fills a `&mut [MaybeUninit<T>]` with clones of the given value of type `T`.
1106+
/// Returns a `&mut [T]` to the so initialized slice.
1107+
///
11081108
/// Any previously initialized elements will not be dropped.
11091109
///
11101110
/// This is similar to [`slice::fill`].
@@ -1282,8 +1282,8 @@ impl<T> MaybeUninit<T> {
12821282
}
12831283

12841284
impl<T> [MaybeUninit<T>] {
1285-
/// Copies the elements from `src` to `self`,
1286-
/// returning a mutable reference to the now initialized contents of `self`.
1285+
/// Copies all elements from a `&[T]` to this `[MaybeUninit<T>]`.
1286+
/// Returns a `&mut [T]` to the so initialized array.
12871287
///
12881288
/// If `T` does not implement `Copy`, use [`write_clone_of_slice`] instead.
12891289
///
@@ -1340,13 +1340,14 @@ impl<T> [MaybeUninit<T>] {
13401340
unsafe { self.assume_init_mut() }
13411341
}
13421342

1343-
/// Clones the elements from `src` to `self`,
1344-
/// returning a mutable reference to the now initialized contents of `self`.
1343+
/// Clones all elements from a `&[T]` to this `[MaybeUninit<T>]`.
1344+
/// Returns a `&mut [T]` to the so initialized array.
13451345
/// Any already initialized elements will not be dropped.
13461346
///
13471347
/// If `T` implements `Copy`, use [`write_copy_of_slice`] instead.
13481348
///
1349-
/// This is similar to [`slice::clone_from_slice`] but does not drop existing elements.
1349+
/// This is similar to [`slice::clone_from_slice`] but cannot drop existing `MaybeUninit<T>`,
1350+
/// as it cannot know if any of them was initialized.
13501351
///
13511352
/// # Panics
13521353
///
@@ -1419,10 +1420,9 @@ impl<T> [MaybeUninit<T>] {
14191420
unsafe { self.assume_init_mut() }
14201421
}
14211422

1422-
/// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
1423+
/// Returns a slice of potentially uninitialized bytes to the value of this `[MaybeUninit<T>]`.
14231424
///
1424-
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
1425-
/// contain padding bytes which are left uninitialized.
1425+
/// Note that a value may still contain uninitialized padding bytes even if it has been fully initialized.
14261426
///
14271427
/// # Examples
14281428
///
@@ -1445,11 +1445,9 @@ impl<T> [MaybeUninit<T>] {
14451445
}
14461446
}
14471447

1448-
/// Returns the contents of this `MaybeUninit` slice as a mutable slice of potentially
1449-
/// uninitialized bytes.
1448+
/// Returns a mutable slice of potentially uninitialized bytes to the value of this `[MaybeUninit<T>]`.
14501449
///
1451-
/// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
1452-
/// contain padding bytes which are left uninitialized.
1450+
/// Note that a value may still contain uninitialized padding bytes even if it has been fully initialized.
14531451
///
14541452
/// # Examples
14551453
///
@@ -1478,13 +1476,13 @@ impl<T> [MaybeUninit<T>] {
14781476
}
14791477
}
14801478

1481-
/// Drops the contained values in place.
1479+
/// Assumes all elements have been fully initialized and drops them in place.
14821480
///
14831481
/// # Safety
14841482
///
1485-
/// It is up to the caller to guarantee that every `MaybeUninit<T>` in the slice
1486-
/// really is in an initialized state. Calling this when the content is not yet
1487-
/// fully initialized causes undefined behavior.
1483+
/// It is up to the caller to ensure that the `MaybeUninit<T>` has been fully initialized,
1484+
/// before calling. Calling this when any of the `T` elements of the `[MaybeUninit<T>]`
1485+
/// has not yet been fully initialized causes immediate undefined behavior.
14881486
///
14891487
/// On top of that, all additional invariants of the type `T` must be
14901488
/// satisfied, as the `Drop` implementation of `T` (or its members) may
@@ -1505,13 +1503,13 @@ impl<T> [MaybeUninit<T>] {
15051503
}
15061504
}
15071505

1508-
/// Gets a shared reference to the contained value.
1506+
/// Gets a `&[T]` to the values in the `&[MaybeUninit<T>]`.
15091507
///
15101508
/// # Safety
15111509
///
1512-
/// Calling this when the content is not yet fully initialized causes undefined
1510+
/// Calling this when the elements have not been fully initialized causes undefined
15131511
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` in
1514-
/// the slice really is in an initialized state.
1512+
/// the slice really is properly initialized.
15151513
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
15161514
#[inline(always)]
15171515
pub const unsafe fn assume_init_ref(&self) -> &[T] {
@@ -1522,13 +1520,13 @@ impl<T> [MaybeUninit<T>] {
15221520
unsafe { &*(self as *const Self as *const [T]) }
15231521
}
15241522

1525-
/// Gets a mutable (unique) reference to the contained value.
1523+
/// Gets a `&mut [T]` to the values in the `&mut [MaybeUninit<T>]`.
15261524
///
15271525
/// # Safety
15281526
///
1529-
/// Calling this when the content is not yet fully initialized causes undefined
1527+
/// Calling this when the elements have not been fully initialized causes undefined
15301528
/// behavior: it is up to the caller to guarantee that every `MaybeUninit<T>` in the
1531-
/// slice really is in an initialized state. For instance, `.assume_init_mut()` cannot
1529+
/// slice really is properly initialized. For instance, `.assume_init_mut()` cannot
15321530
/// be used to initialize a `MaybeUninit` slice.
15331531
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
15341532
#[inline(always)]

0 commit comments

Comments
 (0)
Please sign in to comment.