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

MaybeUninit: some docs, rename into_inner -> into_initialized, return &mut from set #58129

Merged
merged 10 commits into from
Feb 10, 2019
4 changes: 2 additions & 2 deletions src/libcore/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,12 +555,12 @@ macro_rules! unimplemented {
#[macro_export]
#[unstable(feature = "maybe_uninit", issue = "53491")]
macro_rules! uninitialized_array {
// This `into_inner` is safe because an array of `MaybeUninit` does not
// This `into_initialized` is safe because an array of `MaybeUninit` does not
// require initialization.
// FIXME(#49147): Could be replaced by an array initializer, once those can
// be any const expression.
($t:ty; $size:expr) => (unsafe {
MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_inner()
MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_initialized()
});
}

Expand Down
60 changes: 53 additions & 7 deletions src/libcore/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,42 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
}
}

/// A newtype to construct uninitialized instances of `T`
/// A newtype to construct uninitialized instances of `T`.
///
/// The compiler, in general, assumes that variables are properly initialized
/// at their respective type. For example, a variable of reference type must
/// be aligned and non-NULL. This is an invariant that must *always* be upheld,
/// even in unsafe code. As a consequence, 0-initializing a variable of reference
/// type causes instantaneous undefined behavior, no matter whether that reference
/// ever gets used to access memory:
/// ```rust,no_run
/// use std::mem;
///
/// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
/// ```
/// This is exploited by the compiler for various optimizations, such as eliding
/// run-time checks and optimizing `enum` layout.
///
/// Not initializing memory at all (instead of 0-initializing it) causes the same
/// issue: after all, the initial value of the variable might just happen to be
/// one that violates the invariant.
///
/// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data:
/// it is a signal to the compiler indicating that the data here might *not*
/// be initialized:
/// ```rust
/// #![feature(maybe_uninit)]
/// use std::mem::MaybeUninit;
///
/// // Create an explicitly uninitialized reference.
/// let mut x = MaybeUninit::<&i32>::uninitialized();
/// // Set it to a valid value.
/// x.set(&0);
/// // Extract the initialized data -- this is only allowed *after* properly
/// // initializing `x`!
/// let x = unsafe { x.into_initialized() };
/// ```
/// The compiler then knows to not optimize this code.
#[allow(missing_debug_implementations)]
#[unstable(feature = "maybe_uninit", issue = "53491")]
// NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::{uninitialized,zeroed}`
Expand Down Expand Up @@ -1083,11 +1118,14 @@ impl<T> MaybeUninit<T> {
}

/// Set the value of the `MaybeUninit`. This overwrites any previous value without dropping it.
/// For your convenience, this also returns a mutable reference to the (now
/// safely initialized) content of `self`.
#[unstable(feature = "maybe_uninit", issue = "53491")]
#[inline(always)]
pub fn set(&mut self, val: T) {
pub fn set(&mut self, val: T) -> &mut T {
unsafe {
self.value = ManuallyDrop::new(val);
self.get_mut()
}
}

Expand All @@ -1101,11 +1139,19 @@ impl<T> MaybeUninit<T> {
/// state, otherwise this will immediately cause undefined behavior.
#[unstable(feature = "maybe_uninit", issue = "53491")]
#[inline(always)]
pub unsafe fn into_inner(self) -> T {
pub unsafe fn into_initialized(self) -> T {
intrinsics::panic_if_uninhabited::<T>();
ManuallyDrop::into_inner(self.value)
}

/// Deprecated alternative to `into_initialized`. Will never get stabilized.
/// Exists only to transition stdsimd to `into_initialized`.
#[inline(always)]
#[allow(unused)]
pub(crate) unsafe fn into_inner(self) -> T {
self.into_initialized()
}

/// Get a reference to the contained value.
///
/// # Unsafety
Expand Down Expand Up @@ -1133,16 +1179,16 @@ impl<T> MaybeUninit<T> {
&mut *self.value
}

/// Get a pointer to the contained value. Reading from this pointer will be undefined
/// behavior unless the `MaybeUninit` is initialized.
/// Get a pointer to the contained value. Reading from this pointer or turning it
/// into a reference will be undefined behavior unless the `MaybeUninit` is initialized.
#[unstable(feature = "maybe_uninit", issue = "53491")]
#[inline(always)]
pub fn as_ptr(&self) -> *const T {
unsafe { &*self.value as *const T }
}

/// Get a mutable pointer to the contained value. Reading from this pointer will be undefined
/// behavior unless the `MaybeUninit` is initialized.
/// Get a mutable pointer to the contained value. Reading from this pointer or turning it
/// into a reference will be undefined behavior unless the `MaybeUninit` is initialized.
#[unstable(feature = "maybe_uninit", issue = "53491")]
#[inline(always)]
pub fn as_mut_ptr(&mut self) -> *mut T {
Expand Down
4 changes: 2 additions & 2 deletions src/libcore/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
pub unsafe fn read<T>(src: *const T) -> T {
let mut tmp = MaybeUninit::<T>::uninitialized();
copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
tmp.into_inner()
tmp.into_initialized()
}

/// Reads the value from `src` without moving it. This leaves the
Expand Down Expand Up @@ -642,7 +642,7 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
copy_nonoverlapping(src as *const u8,
tmp.as_mut_ptr() as *mut u8,
mem::size_of::<T>());
tmp.into_inner()
tmp.into_initialized()
}

/// Overwrites a memory location with the given value without reading or
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/sys/sgx/ext/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32>
);

match error {
0 => Ok(out.into_inner()),
0 => Ok(out.into_initialized()),
err => Err(err),
}
}
Expand Down Expand Up @@ -69,6 +69,6 @@ pub fn ereport(
"{rdx}"(report.as_mut_ptr())
);

report.into_inner()
report.into_initialized()
}
}
3 changes: 3 additions & 0 deletions src/test/codegen/box-maybe-uninit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ use std::mem::MaybeUninit;
pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
// CHECK-LABEL: @box_uninitialized
// CHECK-NOT: store
// CHECK-NOT: alloca
// CHECK-NOT: memcpy
// CHECK-NOT: memset
Box::new(MaybeUninit::uninitialized())
}
6 changes: 3 additions & 3 deletions src/test/run-pass/panic-uninitialized-zeroed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn main() {

assert_eq!(
panic::catch_unwind(|| {
mem::MaybeUninit::<!>::uninitialized().into_inner()
mem::MaybeUninit::<!>::uninitialized().into_initialized()
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
s == "Attempted to instantiate uninhabited type !"
})),
Expand All @@ -63,7 +63,7 @@ fn main() {

assert_eq!(
panic::catch_unwind(|| {
mem::MaybeUninit::<Foo>::uninitialized().into_inner()
mem::MaybeUninit::<Foo>::uninitialized().into_initialized()
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
s == "Attempted to instantiate uninhabited type Foo"
})),
Expand All @@ -90,7 +90,7 @@ fn main() {

assert_eq!(
panic::catch_unwind(|| {
mem::MaybeUninit::<Bar>::uninitialized().into_inner()
mem::MaybeUninit::<Bar>::uninitialized().into_initialized()
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
s == "Attempted to instantiate uninhabited type Bar"
})),
Expand Down