about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2019-02-16 00:56:00 +0800
committerkennytm <kennytm@gmail.com>2019-02-16 14:11:55 +0800
commit9a2437c0dc1f88eac3ca4c57ca005b2386a30a29 (patch)
tree161f1a449cc0ca20c675d4318798f9b5f505c57c
parent762b988a0a7740d6a9b5f99932036a4ae03dd6cb (diff)
parent95ef9b4fc28ad2f5db078eb1ae233fd5be76806b (diff)
downloadrust-9a2437c0dc1f88eac3ca4c57ca005b2386a30a29.tar.gz
rust-9a2437c0dc1f88eac3ca4c57ca005b2386a30a29.zip
Rollup merge of #58468 - RalfJung:maybe-uninit-split, r=Centril
split MaybeUninit into several features, expand docs a bit

This splits the `maybe_uninit` feature gate into several:

* `maybe_uninit` for what we will hopefully stabilize soon-ish.
* `maybe_uninit_ref` for creating references into `MaybeUninit`, for which the rules are not yet clear.
* `maybe_uninit_slice` for handling slices of `MaybeUninit`, which needs more API design work.
* `maybe_uninit_array` for creating arrays of `MaybeUninit` using a macro (because we don't have https://github.com/rust-lang/rust/issues/49147 yet).

Is that an okay thing to do? The goal is to help people avoid APIs we do not want to stabilize yet. I used this to make sure rustc itself does not use `get_ref` and `get_mut`.

I also extended the docs to advise against uninitialized integers -- again this is something for which the rules are still being discussed.
-rw-r--r--src/liballoc/collections/btree/node.rs4
-rw-r--r--src/liballoc/lib.rs2
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/libcore/macros.rs4
-rw-r--r--src/libcore/mem.rs76
5 files changed, 55 insertions, 33 deletions
diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs
index eb0667228d1..fc1c1878924 100644
--- a/src/liballoc/collections/btree/node.rs
+++ b/src/liballoc/collections/btree/node.rs
@@ -453,7 +453,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
                     root: self.root,
                     _marker: PhantomData
                 },
-                idx: unsafe { usize::from(*self.as_header().parent_idx.get_ref()) },
+                idx: unsafe { usize::from(*self.as_header().parent_idx.as_ptr()) },
                 _marker: PhantomData
             })
         } else {
@@ -1143,7 +1143,7 @@ impl<BorrowType, K, V>
         NodeRef {
             height: self.node.height - 1,
             node: unsafe {
-                self.node.as_internal().edges.get_unchecked(self.idx).get_ref().as_ptr()
+                (&*self.node.as_internal().edges.get_unchecked(self.idx).as_ptr()).as_ptr()
             },
             root: self.node.root,
             _marker: PhantomData
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 95b9dacf856..440ce8ac5e8 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -112,7 +112,7 @@
 #![feature(rustc_const_unstable)]
 #![feature(const_vec_new)]
 #![feature(slice_partition_dedup)]
-#![feature(maybe_uninit)]
+#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)]
 #![feature(alloc_layout_extra)]
 #![feature(try_trait)]
 
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 227fb22bc7d..d046236b535 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -122,7 +122,7 @@
 #![feature(structural_match)]
 #![feature(abi_unadjusted)]
 #![feature(adx_target_feature)]
-#![feature(maybe_uninit)]
+#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)]
 #![feature(unrestricted_attribute_tokens)]
 
 #[prelude_import]
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index b9b235969da..fdbfa56000b 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -563,11 +563,11 @@ macro_rules! unimplemented {
 
 /// A macro to create an array of [`MaybeUninit`]
 ///
-/// This macro constructs and uninitialized array of the type `[MaybeUninit<K>; N]`.
+/// This macro constructs an uninitialized array of the type `[MaybeUninit<K>; N]`.
 ///
 /// [`MaybeUninit`]: mem/union.MaybeUninit.html
 #[macro_export]
-#[unstable(feature = "maybe_uninit", issue = "53491")]
+#[unstable(feature = "maybe_uninit_array", issue = "53491")]
 macro_rules! uninitialized_array {
     // This `into_initialized` is safe because an array of `MaybeUninit` does not
     // require initialization.
diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs
index 3f7455aeb59..e0b0e72ff9b 100644
--- a/src/libcore/mem.rs
+++ b/src/libcore/mem.rs
@@ -1045,17 +1045,34 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 /// ever gets used to access memory:
 ///
 /// ```rust,no_run
-/// use std::mem;
+/// #![feature(maybe_uninit)]
+/// use std::mem::{self, MaybeUninit};
 ///
 /// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior!
+/// // equivalent code with `MaybeUninit`
+/// let x: &i32 = unsafe { MaybeUninit::zeroed().into_initialized() }; // 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 zero--initializing it) causes the same
+/// Not initializing memory at all (instead of zero-initializing it) causes the same
 /// issue: after all, the initial value of the variable might just happen to be
-/// one that violates the invariant.
+/// one that violates the invariant. Moreover, uninitialized memory is special
+/// in that the compiler knows that it does not have a fixed value. This makes
+/// it undefined behavior to have uninitialized data in a variable even if that
+/// variable has otherwise no restrictions about which values are valid:
+///
+/// ```rust,no_run
+/// #![feature(maybe_uninit)]
+/// use std::mem::{self, MaybeUninit};
+///
+/// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior!
+/// // equivalent code with `MaybeUninit`
+/// let x: i32 = unsafe { MaybeUninit::uninitialized().into_initialized() }; // undefined behavior!
+/// ```
+/// (Notice that the rules around uninitialized integers are not finalized yet, but
+/// until they are, it is advisable to avoid them.)
 ///
 /// `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*
@@ -1065,7 +1082,8 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 /// #![feature(maybe_uninit)]
 /// use std::mem::MaybeUninit;
 ///
-/// // Create an explicitly uninitialized reference.
+/// // Create an explicitly uninitialized reference. The compiler knows that data inside
+/// // a `MaybeUninit` may be invalid, and hence this is not UB:
 /// let mut x = MaybeUninit::<&i32>::uninitialized();
 /// // Set it to a valid value.
 /// x.set(&0);
@@ -1075,6 +1093,7 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
 /// ```
 ///
 /// The compiler then knows to not optimize this code.
+// FIXME before stabilizing, explain how to initialize a struct field-by-field.
 #[allow(missing_debug_implementations)]
 #[unstable(feature = "maybe_uninit", issue = "53491")]
 // NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::{uninitialized,zeroed}`
@@ -1134,6 +1153,22 @@ impl<T> MaybeUninit<T> {
         }
     }
 
+    /// Gets 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 }
+    }
+
+    /// Gets 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 }
+    }
+
     /// Extracts the value from the `MaybeUninit` container. This is a great way
     /// to ensure that the data will get dropped, because the resulting `T` is
     /// subject to the usual drop handling.
@@ -1141,7 +1176,8 @@ impl<T> MaybeUninit<T> {
     /// # Unsafety
     ///
     /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized
-    /// state, otherwise this will immediately cause undefined behavior.
+    /// state. Calling this when the content is not yet fully initialized causes undefined
+    /// behavior.
     #[unstable(feature = "maybe_uninit", issue = "53491")]
     #[inline(always)]
     pub unsafe fn into_initialized(self) -> T {
@@ -1162,8 +1198,9 @@ impl<T> MaybeUninit<T> {
     /// # Unsafety
     ///
     /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized
-    /// state, otherwise this will immediately cause undefined behavior.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    /// state. Calling this when the content is not yet fully initialized causes undefined
+    /// behavior.
+    #[unstable(feature = "maybe_uninit_ref", issue = "53491")]
     #[inline(always)]
     pub unsafe fn get_ref(&self) -> &T {
         &*self.value
@@ -1174,41 +1211,26 @@ impl<T> MaybeUninit<T> {
     /// # Unsafety
     ///
     /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized
-    /// state, otherwise this will immediately cause undefined behavior.
+    /// state. Calling this when the content is not yet fully initialized causes undefined
+    /// behavior.
     // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references
     // to uninitialized data (e.g., in `libcore/fmt/float.rs`).  We should make
     // a final decision about the rules before stabilization.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[unstable(feature = "maybe_uninit_ref", issue = "53491")]
     #[inline(always)]
     pub unsafe fn get_mut(&mut self) -> &mut T {
         &mut *self.value
     }
 
-    /// Gets 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 sa 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 }
-    }
-
     /// Gets a pointer to the first element of the array.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[unstable(feature = "maybe_uninit_slice", issue = "53491")]
     #[inline(always)]
     pub fn first_ptr(this: &[MaybeUninit<T>]) -> *const T {
         this as *const [MaybeUninit<T>] as *const T
     }
 
     /// Gets a mutable pointer to the first element of the array.
-    #[unstable(feature = "maybe_uninit", issue = "53491")]
+    #[unstable(feature = "maybe_uninit_slice", issue = "53491")]
     #[inline(always)]
     pub fn first_ptr_mut(this: &mut [MaybeUninit<T>]) -> *mut T {
         this as *mut [MaybeUninit<T>] as *mut T