From b5ab2c7f1cf31a642c826047ed1025f4fc13d879 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Feb 2019 20:00:16 +0100 Subject: [PATCH] split MaybeUninit into several features, expand docs a bit --- src/liballoc/collections/btree/node.rs | 4 +- src/liballoc/lib.rs | 2 +- src/libcore/lib.rs | 2 +- src/libcore/macros.rs | 4 +- src/libcore/mem.rs | 76 +++++++++++++++++--------- 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 @@ pub fn ascend(self) -> Result< 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 @@ pub fn descend(self) -> NodeRef { 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 d4ee428a3b5..2f23a697a58 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)] #![feature(alloc_layout_extra)] #![feature(try_trait)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 227fb22bc7d..2c0d0dd1490 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)] #![feature(unrestricted_attribute_tokens)] #[prelude_import] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index b9b235969da..02f8065eb21 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; N]`. +/// This macro constructs an uninitialized array of the type `[MaybeUninit; N]`. /// /// [`MaybeUninit`]: mem/union.MaybeUninit.html #[macro_export] -#[unstable(feature = "maybe_uninit", issue = "53491")] +#[unstable(feature = "maybe_uninit_slice", 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 2a493e88fe8..c4443a25d8c 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1045,17 +1045,34 @@ fn deref_mut(&mut self) -> &mut 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 @@ fn deref_mut(&mut self) -> &mut 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 @@ fn deref_mut(&mut self) -> &mut 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 @@ pub fn set(&mut self, val: T) -> &mut 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 @@ pub fn set(&mut self, val: T) -> &mut 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 @@ pub(crate) unsafe fn into_inner(self) -> 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 @@ pub unsafe fn get_ref(&self) -> &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]) -> *const T { this as *const [MaybeUninit] 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]) -> *mut T { this as *mut [MaybeUninit] as *mut T