diff options
| author | Ralf Jung <post@ralfj.de> | 2019-02-03 22:10:39 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2019-02-03 22:10:39 +0100 |
| commit | 9a460aac37e91f66f9ba79824dbf62105733efee (patch) | |
| tree | ead66a857b27b8ea116a30023a1ffcdb9273019c | |
| parent | 2966fbc10d0fd4fe15a25608b9eca3e52ba24995 (diff) | |
| download | rust-9a460aac37e91f66f9ba79824dbf62105733efee.tar.gz rust-9a460aac37e91f66f9ba79824dbf62105733efee.zip | |
some type-level docs for MaybeUninit; rename into_inner -> into_initialized
| -rw-r--r-- | src/libcore/macros.rs | 4 | ||||
| -rw-r--r-- | src/libcore/mem.rs | 45 | ||||
| -rw-r--r-- | src/libcore/ptr.rs | 4 |
3 files changed, 47 insertions, 6 deletions
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 12b7adb8a9d..664490c1997 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -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() }); } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 8b6d9d882b5..998e892bffb 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1034,7 +1034,41 @@ 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,ignore +/// use std::mem; +/// +/// let x: &i32 = mem::zeroed(); // undefined behavior! +/// ``` +/// This is exploitet 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 may *not* +/// be initialized: +/// ```rust +/// 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}` @@ -1101,11 +1135,18 @@ 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)] + pub(crate) unsafe fn into_inner(self) -> T { + self.into_initialized() + } + /// Get a reference to the contained value. /// /// # Unsafety diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 02eef07afd7..537aa92c2cf 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -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 @@ -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 |
