about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/macros.rs4
-rw-r--r--src/libcore/mem.rs60
-rw-r--r--src/libcore/ptr.rs4
-rw-r--r--src/libstd/sys/sgx/ext/arch.rs4
-rw-r--r--src/test/codegen/box-maybe-uninit.rs3
-rw-r--r--src/test/run-pass/panic-uninitialized-zeroed.rs6
6 files changed, 65 insertions, 16 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 6dad32f399b..2f86e13b938 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -1035,7 +1035,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}`
@@ -1084,11 +1119,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()
         }
     }
 
@@ -1102,11 +1140,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
@@ -1134,16 +1180,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 {
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
diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs
index 3bd87b5d265..97f7d9181a5 100644
--- a/src/libstd/sys/sgx/ext/arch.rs
+++ b/src/libstd/sys/sgx/ext/arch.rs
@@ -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),
         }
     }
@@ -69,6 +69,6 @@ pub fn ereport(
               "{rdx}"(report.as_mut_ptr())
         );
 
-        report.into_inner()
+        report.into_initialized()
     }
 }
diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs
index a7fb74c0473..ad1d259a0da 100644
--- a/src/test/codegen/box-maybe-uninit.rs
+++ b/src/test/codegen/box-maybe-uninit.rs
@@ -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())
 }
diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs
index d47ff6c630d..31c0d2994d4 100644
--- a/src/test/run-pass/panic-uninitialized-zeroed.rs
+++ b/src/test/run-pass/panic-uninitialized-zeroed.rs
@@ -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 !"
             })),
@@ -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"
             })),
@@ -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"
             })),