Skip to content

Commit b6bdb2c

Browse files
authored
Rollup merge of rust-lang#76484 - fusion-engineering-forks:maybe-uninit-drop, r=RalfJung
Add MaybeUninit::assume_init_drop. `ManuallyDrop`'s documentation tells the user to use `MaybeUninit` instead when handling uninitialized data. However, the main functionality of `ManuallyDrop` (`drop`) is not available directly on `MaybeUninit`. Adding it makes it easier to switch from one to the other. I re-used the `maybe_uninit_extra` feature and tracking issue number (rust-lang#63567), since it seems very related. (And to avoid creating too many features tracking issues for `MaybeUninit`.)
2 parents 5185c39 + 43c7a9b commit b6bdb2c

File tree

2 files changed

+42
-11
lines changed

2 files changed

+42
-11
lines changed

library/core/src/array/iter.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
103103
// dead now (i.e. do not touch). As `idx` was the start of the
104104
// alive-zone, the alive zone is now `data[alive]` again, restoring
105105
// all invariants.
106-
unsafe { self.data.get_unchecked(idx).read() }
106+
unsafe { self.data.get_unchecked(idx).assume_init_read() }
107107
})
108108
}
109109

@@ -136,7 +136,7 @@ impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
136136
// dead now (i.e. do not touch). As `idx` was the end of the
137137
// alive-zone, the alive zone is now `data[alive]` again, restoring
138138
// all invariants.
139-
unsafe { self.data.get_unchecked(idx).read() }
139+
unsafe { self.data.get_unchecked(idx).assume_init_read() }
140140
})
141141
}
142142
}

library/core/src/mem/maybe_uninit.rs

+40-9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::any::type_name;
22
use crate::fmt;
33
use crate::intrinsics;
44
use crate::mem::ManuallyDrop;
5+
use crate::ptr;
56

67
/// A wrapper type to construct uninitialized instances of `T`.
78
///
@@ -471,6 +472,8 @@ impl<T> MaybeUninit<T> {
471472
/// *immediate* undefined behavior, but will cause undefined behavior with most
472473
/// safe operations (including dropping it).
473474
///
475+
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
476+
///
474477
/// # Examples
475478
///
476479
/// Correct usage of this method:
@@ -519,8 +522,8 @@ impl<T> MaybeUninit<T> {
519522
/// this initialization invariant.
520523
///
521524
/// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
522-
/// multiple copies of the data (by calling `read` multiple times, or first
523-
/// calling `read` and then [`assume_init`]), it is your responsibility
525+
/// multiple copies of the data (by calling `assume_init_read` multiple times, or first
526+
/// calling `assume_init_read` and then [`assume_init`]), it is your responsibility
524527
/// to ensure that that data may indeed be duplicated.
525528
///
526529
/// [inv]: #initialization-invariant
@@ -536,16 +539,16 @@ impl<T> MaybeUninit<T> {
536539
///
537540
/// let mut x = MaybeUninit::<u32>::uninit();
538541
/// x.write(13);
539-
/// let x1 = unsafe { x.read() };
542+
/// let x1 = unsafe { x.assume_init_read() };
540543
/// // `u32` is `Copy`, so we may read multiple times.
541-
/// let x2 = unsafe { x.read() };
544+
/// let x2 = unsafe { x.assume_init_read() };
542545
/// assert_eq!(x1, x2);
543546
///
544547
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
545548
/// x.write(None);
546-
/// let x1 = unsafe { x.read() };
549+
/// let x1 = unsafe { x.assume_init_read() };
547550
/// // Duplicating a `None` value is okay, so we may read multiple times.
548-
/// let x2 = unsafe { x.read() };
551+
/// let x2 = unsafe { x.assume_init_read() };
549552
/// assert_eq!(x1, x2);
550553
/// ```
551554
///
@@ -557,14 +560,14 @@ impl<T> MaybeUninit<T> {
557560
///
558561
/// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
559562
/// x.write(Some(vec![0,1,2]));
560-
/// let x1 = unsafe { x.read() };
561-
/// let x2 = unsafe { x.read() };
563+
/// let x1 = unsafe { x.assume_init_read() };
564+
/// let x2 = unsafe { x.assume_init_read() };
562565
/// // We now created two copies of the same vector, leading to a double-free ⚠️ when
563566
/// // they both get dropped!
564567
/// ```
565568
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
566569
#[inline(always)]
567-
pub unsafe fn read(&self) -> T {
570+
pub unsafe fn assume_init_read(&self) -> T {
568571
// SAFETY: the caller must guarantee that `self` is initialized.
569572
// Reading from `self.as_ptr()` is safe since `self` should be initialized.
570573
unsafe {
@@ -573,6 +576,34 @@ impl<T> MaybeUninit<T> {
573576
}
574577
}
575578

579+
/// Drops the contained value in place.
580+
///
581+
/// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead.
582+
///
583+
/// # Safety
584+
///
585+
/// It is up to the caller to guarantee that the `MaybeUninit<T>` really is
586+
/// in an initialized state. Calling this when the content is not yet fully
587+
/// initialized causes undefined behavior.
588+
///
589+
/// On top of that, all additional invariants of the type `T` must be
590+
/// satisfied, as the `Drop` implementation of `T` (or its members) may
591+
/// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered
592+
/// initialized (under the current implementation; this does not constitute
593+
/// a stable guarantee) because the only requirement the compiler knows
594+
/// about it is that the data pointer must be non-null. Dropping such a
595+
/// `Vec<T>` however will cause undefined behaviour.
596+
///
597+
/// [`assume_init`]: MaybeUninit::assume_init
598+
/// [`Vec<T>`]: ../../std/vec/struct.Vec.html
599+
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
600+
pub unsafe fn assume_init_drop(&mut self) {
601+
// SAFETY: the caller must guarantee that `self` is initialized and
602+
// satisfies all invariants of `T`.
603+
// Dropping the value in place is safe if that is the case.
604+
unsafe { ptr::drop_in_place(self.as_mut_ptr()) }
605+
}
606+
576607
/// Gets a shared reference to the contained value.
577608
///
578609
/// This can be useful when we want to access a `MaybeUninit` that has been

0 commit comments

Comments
 (0)