diff options
| author | kennytm <kennytm@gmail.com> | 2019-02-16 00:56:00 +0800 |
|---|---|---|
| committer | kennytm <kennytm@gmail.com> | 2019-02-16 14:11:55 +0800 |
| commit | 9a2437c0dc1f88eac3ca4c57ca005b2386a30a29 (patch) | |
| tree | 161f1a449cc0ca20c675d4318798f9b5f505c57c | |
| parent | 762b988a0a7740d6a9b5f99932036a4ae03dd6cb (diff) | |
| parent | 95ef9b4fc28ad2f5db078eb1ae233fd5be76806b (diff) | |
| download | rust-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.rs | 4 | ||||
| -rw-r--r-- | src/liballoc/lib.rs | 2 | ||||
| -rw-r--r-- | src/libcore/lib.rs | 2 | ||||
| -rw-r--r-- | src/libcore/macros.rs | 4 | ||||
| -rw-r--r-- | 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 @@ 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 |
