]> git.lizzy.rs Git - rust.git/blobdiff - src/libcore/mem.rs
Auto merge of #58129 - RalfJung:maybe-uninit, r=cramertj
[rust.git] / src / libcore / mem.rs
index 9e100d0a58d1762757c2a7527b107b6c36df2d08..2f86e13b938166fd719228c3951323028d7b1300 100644 (file)
@@ -15,6 +15,7 @@
 use ops::{Deref, DerefMut};
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[doc(inline)]
 pub use intrinsics::transmute;
 
 /// Takes ownership and "forgets" about the value **without running its destructor**.
@@ -491,7 +492,6 @@ pub const fn needs_drop<T>() -> bool {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn zeroed<T>() -> T {
-    #[cfg(not(stage0))]
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::init()
 }
@@ -625,7 +625,6 @@ pub unsafe fn zeroed<T>() -> T {
 #[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn uninitialized<T>() -> T {
-    #[cfg(not(stage0))]
     intrinsics::panic_if_uninhabited::<T>();
     intrinsics::uninit()
 }
@@ -713,8 +712,7 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
 
 /// Disposes of a value.
 ///
-/// While this does call the argument's implementation of [`Drop`][drop],
-/// it will not release any borrows, as borrows are based on lexical scope.
+/// This does call the argument's implementation of [`Drop`][drop].
 ///
 /// This effectively does nothing for types which implement `Copy`, e.g.
 /// integers. Such values are copied and _then_ moved into the function, so the
@@ -741,32 +739,6 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
 /// drop(v); // explicitly drop the vector
 /// ```
 ///
-/// Borrows are based on lexical scope, so this produces an error:
-///
-/// ```compile_fail,E0502
-/// let mut v = vec![1, 2, 3];
-/// let x = &v[0];
-///
-/// drop(x); // explicitly drop the reference, but the borrow still exists
-///
-/// v.push(4); // error: cannot borrow `v` as mutable because it is also
-///            // borrowed as immutable
-/// ```
-///
-/// An inner scope is needed to fix this:
-///
-/// ```
-/// let mut v = vec![1, 2, 3];
-///
-/// {
-///     let x = &v[0];
-///
-///     drop(x); // this is now redundant, as `x` is going out of scope anyway
-/// }
-///
-/// v.push(4); // no problems
-/// ```
-///
 /// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can
 /// release a [`RefCell`] borrow:
 ///
@@ -1063,7 +1035,42 @@ fn deref_mut(&mut self) -> &mut 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}`
@@ -1112,11 +1119,14 @@ pub fn zeroed() -> 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()
         }
     }
 
@@ -1130,12 +1140,19 @@ pub fn set(&mut self, val: T) {
     /// state, otherwise this will immediately cause undefined behavior.
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline(always)]
-    pub unsafe fn into_inner(self) -> T {
-        #[cfg(not(stage0))]
+    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
@@ -1163,19 +1180,33 @@ pub unsafe fn get_mut(&mut self) -> &mut 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 {
         unsafe { &mut *self.value as *mut T }
     }
+
+    /// Get a pointer to the first element of the array.
+    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[inline(always)]
+    pub fn first_ptr(this: &[MaybeUninit<T>]) -> *const T {
+        this as *const [MaybeUninit<T>] as *const T
+    }
+
+    /// Get a mutable pointer to the first element of the array.
+    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[inline(always)]
+    pub fn first_ptr_mut(this: &mut [MaybeUninit<T>]) -> *mut T {
+        this as *mut [MaybeUninit<T>] as *mut T
+    }
 }