diff options
| author | Ralf Jung <post@ralfj.de> | 2019-05-01 19:39:52 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2019-05-20 10:44:02 +0200 |
| commit | b7afe777f79462c9023a30b31785b81e8346c96c (patch) | |
| tree | 924a5e3a2dcef35692863d4606834c00cdb1aa3b | |
| parent | caef1e833fbd9de740d521114d716a11a29b71cb (diff) | |
| download | rust-b7afe777f79462c9023a30b31785b81e8346c96c.tar.gz rust-b7afe777f79462c9023a30b31785b81e8346c96c.zip | |
stabilize core parts of MaybeUninit and deprecate mem::uninitialized in the future
Also expand the documentation a bit
| -rw-r--r-- | src/liballoc/lib.rs | 2 | ||||
| -rw-r--r-- | src/libcore/lib.rs | 2 | ||||
| -rw-r--r-- | src/libcore/mem.rs | 300 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 1 | ||||
| -rw-r--r-- | src/test/codegen/box-maybe-uninit.rs | 1 | ||||
| -rw-r--r-- | src/test/run-pass/panic-uninitialized-zeroed.rs | 2 |
6 files changed, 138 insertions, 170 deletions
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2edd946ff11..d90036eaf49 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -109,7 +109,7 @@ #![feature(rustc_const_unstable)] #![feature(const_vec_new)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)] #![feature(alloc_layout_extra)] #![feature(try_trait)] #![feature(iter_nth_back)] diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 28db55578c3..4a70329b64b 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -125,7 +125,7 @@ #![feature(structural_match)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] -#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_slice, maybe_uninit_array)] #![feature(external_doc)] #[prelude_import] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 9fb071d2952..9e23a5e61e4 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -465,29 +465,39 @@ pub const fn needs_drop<T>() -> bool { /// Creates a value whose bytes are all zero. /// -/// This has the same effect as allocating space with -/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for -/// FFI sometimes, but should generally be avoided. +/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. +/// It is useful for FFI sometimes, but should generally be avoided. /// /// There is no guarantee that an all-zero byte-pattern represents a valid value of -/// some type `T`. If `T` has a destructor and the value is destroyed (due to -/// a panic or the end of a scope) before being initialized, then the destructor -/// will run on zeroed data, likely leading to [undefined behavior][ub]. +/// some type `T`. For example, the all-zero byte-pattern is not a valid value +/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types +/// causes immediate [undefined behavior][ub]. /// -/// See also the documentation for [`mem::uninitialized`][uninit], which has -/// many of the same caveats. +/// See the documentation of [`MaybeUninit<T>`] and [`MaybeUninit::zeroed()`][zeroed] +/// for more discussion on how to initialize values. /// -/// [uninit]: fn.uninitialized.html +/// [zeroed]: union.MaybeUninit.html#method.zeroed +/// [`MaybeUninit<T>`]: union.MaybeUninit.html /// [ub]: ../../reference/behavior-considered-undefined.html /// /// # Examples /// +/// Correct usage of this function: initializing an integer with zero. +/// /// ``` /// use std::mem; /// /// let x: i32 = unsafe { mem::zeroed() }; /// assert_eq!(0, x); /// ``` +/// +/// *Incorrect* usage of this function: initializing a reference with zero. +/// +/// ```no_run +/// use std::mem; +/// +/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn zeroed<T>() -> T { @@ -498,130 +508,13 @@ pub unsafe fn zeroed<T>() -> T { /// Bypasses Rust's normal memory-initialization checks by pretending to /// produce a value of type `T`, while doing nothing at all. /// -/// **This is incredibly dangerous and should not be done lightly. Deeply -/// consider initializing your memory with a default value instead.** -/// -/// This is useful for FFI functions and initializing arrays sometimes, -/// but should generally be avoided. -/// -/// # Undefined behavior -/// -/// It is [undefined behavior][ub] to read uninitialized memory, even just an -/// uninitialized boolean. For instance, if you branch on the value of such -/// a boolean, your program may take one, both, or neither of the branches. -/// -/// Writing to the uninitialized value is similarly dangerous. Rust believes the -/// value is initialized, and will therefore try to [`Drop`] the uninitialized -/// value and its fields if you try to overwrite it in a normal manner. The only way -/// to safely initialize an uninitialized value is with [`ptr::write`][write], -/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no]. -/// -/// If the value does implement [`Drop`], it must be initialized before -/// it goes out of scope (and therefore would be dropped). Note that this -/// includes a `panic` occurring and unwinding the stack suddenly. -/// -/// If you partially initialize an array, you may need to use -/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully -/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running -/// on the array. If a partially allocated array is dropped this will lead to -/// undefined behaviour. +/// **This functon is deprecated because it basically cannot be used correctly.** /// -/// # Examples -/// -/// Here's how to safely initialize an array of [`Vec`]s. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// // Only declare the array. This safely leaves it -/// // uninitialized in a way that Rust will track for us. -/// // However we can't initialize it element-by-element -/// // safely, and we can't use the `[value; 1000]` -/// // constructor because it only works with `Copy` data. -/// let mut data: [Vec<u32>; 1000]; -/// -/// unsafe { -/// // So we need to do this to initialize it. -/// data = mem::uninitialized(); -/// -/// // DANGER ZONE: if anything panics or otherwise -/// // incorrectly reads the array here, we will have -/// // Undefined Behavior. -/// -/// // It's ok to mutably iterate the data, since this -/// // doesn't involve reading it at all. -/// // (ptr and len are statically known for arrays) -/// for elem in &mut data[..] { -/// // *elem = Vec::new() would try to drop the -/// // uninitialized memory at `elem` -- bad! -/// // -/// // Vec::new doesn't allocate or do really -/// // anything. It's only safe to call here -/// // because we know it won't panic. -/// ptr::write(elem, Vec::new()); -/// } +/// Use [`MaybeUninit<T>`] instead. /// -/// // SAFE ZONE: everything is initialized. -/// } -/// -/// println!("{:?}", &data[0]); -/// ``` -/// -/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized` -/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a -/// value that is only [`Clone`], so the following is semantically equivalent and -/// vastly less dangerous, as long as you can live with an extra heap -/// allocation: -/// -/// ``` -/// let data: Vec<Vec<u32>> = vec![Vec::new(); 1000]; -/// println!("{:?}", &data[0]); -/// ``` -/// -/// This example shows how to handle partially initialized arrays, which could -/// be found in low-level datastructures. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// // Count the number of elements we have assigned. -/// let mut data_len: usize = 0; -/// let mut data: [String; 1000]; -/// -/// unsafe { -/// data = mem::uninitialized(); -/// -/// for elem in &mut data[0..500] { -/// ptr::write(elem, String::from("hello")); -/// data_len += 1; -/// } -/// -/// // For each item in the array, drop if we allocated it. -/// for i in &mut data[0..data_len] { -/// ptr::drop_in_place(i); -/// } -/// } -/// // Forget the data. If this is allowed to drop, you may see a crash such as: -/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object -/// // 0x7ff3b8402920: pointer being freed was not allocated' -/// mem::forget(data); -/// ``` -/// -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// [`vec!`]: ../../std/macro.vec.html -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [ub]: ../../reference/behavior-considered-undefined.html -/// [write]: ../ptr/fn.write.html -/// [drop_in_place]: ../ptr/fn.drop_in_place.html -/// [mem_zeroed]: fn.zeroed.html -/// [mem_forget]: fn.forget.html -/// [copy]: ../intrinsics/fn.copy.html -/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html -/// [`Drop`]: ../ops/trait.Drop.html +/// [`MaybeUninit<T>`]: union.MaybeUninit.html #[inline] -#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninit` instead")] +#[rustc_deprecated(since = "1.40.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn uninitialized<T>() -> T { intrinsics::panic_if_uninhabited::<T>(); @@ -899,7 +792,6 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> { } } -// FIXME: Reference `MaybeUninit` from these docs, once that is stable. /// A wrapper to inhibit compiler from automatically calling `T`’s destructor. /// /// This wrapper is 0-cost. @@ -908,6 +800,7 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> { /// As a consequence, it has *no effect* on the assumptions that the compiler makes /// about all values being initialized at their type. In particular, initializing /// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior. +/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead. /// /// # Examples /// @@ -942,6 +835,7 @@ pub fn discriminant<T>(v: &T) -> Discriminant<T> { /// ``` /// /// [`mem::zeroed`]: fn.zeroed.html +/// [`MaybeUninit<T>`]: union.MaybeUninit.html #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1042,17 +936,18 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { } } -/// A wrapper to construct uninitialized instances of `T`. +/// A wrapper type to construct uninitialized instances of `T`. +/// +/// # Initialization invariant /// /// 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, zero-initializing a variable of reference -/// type causes instantaneous undefined behavior, no matter whether that reference +/// type causes instantaneous [undefined behavior][ub], no matter whether that reference /// ever gets used to access memory: /// /// ```rust,no_run -/// #![feature(maybe_uninit)] /// use std::mem::{self, MaybeUninit}; /// /// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! @@ -1067,7 +962,6 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { /// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior: /// /// ```rust,no_run -/// #![feature(maybe_uninit)] /// use std::mem::{self, MaybeUninit}; /// /// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! @@ -1078,10 +972,9 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { /// 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 an integer type, -/// which otherwise can hold any bit pattern: +/// which otherwise can hold any *fixed* bit pattern: /// /// ```rust,no_run -/// #![feature(maybe_uninit)] /// use std::mem::{self, MaybeUninit}; /// /// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! @@ -1091,37 +984,108 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) /// +/// On top of that, remember that most types have additional invariants beyond merely +/// being considered initialized at the type level. For example, a `1`-initialized [`Vec<T>`] +/// is considered initialized because the only requirement the compiler knows about it +/// is that the data pointer must be non-null. Creating such a `Vec<T>` does not cause +/// *immediate* undefined behavior, but will cause undefined behavior with most +/// safe operations (including dropping it). +/// +/// [`Vec<T>`]: ../../std/vec/struct.Vec.html +/// +/// # Examples +/// /// `MaybeUninit<T>` 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. The compiler knows that data inside /// // a `MaybeUninit<T>` may be invalid, and hence this is not UB: /// let mut x = MaybeUninit::<&i32>::uninit(); /// // Set it to a valid value. -/// x.write(&0); +/// unsafe { x.as_mut_ptr().write(&0); } /// // Extract the initialized data -- this is only allowed *after* properly /// // initializing `x`! /// let x = unsafe { x.assume_init() }; /// ``` /// /// The compiler then knows to not make any incorrect assumptions or optimizations on this code. -// -// FIXME before stabilizing, explain how to initialize a struct field-by-field. +/// +/// ## Initializing an array element-by-element +/// +/// `MaybeUninit<T>` can be used to initialize a large array element-by-element: +/// +/// ``` +/// use std::mem::{self, MaybeUninit}; +/// use std::ptr; +/// +/// let data = unsafe { +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit<Vec<u32>>; 1000] = MaybeUninit::uninit().assume_init(); +/// +/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, +/// // we have a memory leak, but there is no memory safety issue. +/// for elem in &mut data[..] { +/// ptr::write(elem.as_mut_ptr(), vec![42]); +/// } +/// +/// // Everything is initialized. Transmute the array to the +/// // initialized type. +/// mem::transmute::<_, [Vec<u32>; 1000]>(data) +/// }; +/// +/// println!("{:?}", &data[0]); +/// ``` +/// +/// You can also work with partially initialized arrays, which could +/// be found in low-level datastructures. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// use std::ptr; +/// +/// unsafe { +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit<String>; 1000] = MaybeUninit::uninit().assume_init(); +/// // Count the number of elements we have assigned. +/// let mut data_len: usize = 0; +/// +/// for elem in &mut data[0..500] { +/// ptr::write(elem.as_mut_ptr(), String::from("hello")); +/// data_len += 1; +/// } +/// +/// // For each item in the array, drop if we allocated it. +/// for elem in &mut data[0..data_len] { +/// ptr::drop_in_place(elem.as_mut_ptr()); +/// } +/// } +/// ``` +/// +/// ## Initializing a struct field-by-field +/// +/// There is unfortunately currently no supported way to create a raw pointer or reference +/// to a field of a struct inside `MaybeUninit<Struct>`. That means it is not possible +/// to create a struct by calling `MaybeUninit::uninit::<Struct>()` and then writing +/// to its fields. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html #[allow(missing_debug_implementations)] -#[unstable(feature = "maybe_uninit", issue = "53491")] +#[stable(feature = "maybe_uninit", since = "1.36.0")] #[derive(Copy)] -// NOTE: after stabilizing `MaybeUninit`, proceed to deprecate `mem::uninitialized`. pub union MaybeUninit<T> { uninit: (), value: ManuallyDrop<T>, } -#[unstable(feature = "maybe_uninit", issue = "53491")] +#[stable(feature = "maybe_uninit", since = "1.36.0")] impl<T: Copy> Clone for MaybeUninit<T> { #[inline(always)] fn clone(&self) -> Self { @@ -1132,10 +1096,13 @@ impl<T: Copy> Clone for MaybeUninit<T> { impl<T> MaybeUninit<T> { /// Creates a new `MaybeUninit<T>` initialized with the given value. + /// It is safe to call [`assume_init`] on the return value of this function. /// /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code. /// It is your responsibility to make sure `T` gets dropped if it got initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] + /// + /// [`assume_init`]: #method.assume_init + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub const fn new(val: T) -> MaybeUninit<T> { MaybeUninit { value: ManuallyDrop::new(val) } @@ -1145,7 +1112,11 @@ impl<T> MaybeUninit<T> { /// /// Note that dropping a `MaybeUninit<T>` will never call `T`'s drop code. /// It is your responsibility to make sure `T` gets dropped if it got initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] + /// + /// See the [type-level documentation][type] for some examples. + /// + /// [type]: union.MaybeUninit.html + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub const fn uninit() -> MaybeUninit<T> { MaybeUninit { uninit: () } @@ -1166,7 +1137,6 @@ impl<T> MaybeUninit<T> { /// fields of the struct can hold the bit-pattern 0 as a valid value. /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::<(u8, bool)>::zeroed(); @@ -1178,7 +1148,6 @@ impl<T> MaybeUninit<T> { /// cannot hold 0 as a valid value. /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// enum NotZero { One = 1, Two = 2 }; @@ -1188,7 +1157,7 @@ impl<T> MaybeUninit<T> { /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. /// // This is undefined behavior. /// ``` - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline] pub fn zeroed() -> MaybeUninit<T> { let mut u = MaybeUninit::<T>::uninit(); @@ -1202,7 +1171,7 @@ impl<T> MaybeUninit<T> { /// without dropping it, so be careful not to use this twice unless you want to /// skip running the destructor. For your convenience, this also returns a mutable /// reference to the (now safely initialized) contents of `self`. - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] #[inline(always)] pub fn write(&mut self, val: T) -> &mut T { unsafe { @@ -1213,13 +1182,14 @@ impl<T> MaybeUninit<T> { /// Gets a pointer to the contained value. Reading from this pointer or turning it /// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized. + /// Writing to memory that this pointer (non-transitively) points to is undefined behavior + /// (except inside an `UnsafeCell`). /// /// # Examples /// /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); @@ -1232,7 +1202,6 @@ impl<T> MaybeUninit<T> { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::<Vec<u32>>::uninit(); @@ -1242,7 +1211,7 @@ impl<T> MaybeUninit<T> { /// /// (Notice that the rules around references to uninitialized data are not finalized yet, but /// until they are, it is advisable to avoid them.) - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub fn as_ptr(&self) -> *const T { unsafe { &*self.value as *const T } @@ -1256,7 +1225,6 @@ impl<T> MaybeUninit<T> { /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); @@ -1271,7 +1239,6 @@ impl<T> MaybeUninit<T> { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Vec<u32>>::uninit(); @@ -1281,7 +1248,7 @@ impl<T> MaybeUninit<T> { /// /// (Notice that the rules around references to uninitialized data are not finalized yet, but /// until they are, it is advisable to avoid them.) - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub fn as_mut_ptr(&mut self) -> *mut T { unsafe { &mut *self.value as *mut T } @@ -1294,15 +1261,17 @@ impl<T> MaybeUninit<T> { /// # Safety /// /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// state. Calling this when the content is not yet fully initialized causes immediate undefined + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. + /// + /// [inv]: #initialization-invariant /// /// # Examples /// /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<bool>::uninit(); @@ -1314,14 +1283,13 @@ impl<T> MaybeUninit<T> { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::<Vec<u32>>::uninit(); /// let x_init = unsafe { x.assume_init() }; /// // `x` had not been initialized yet, so this last line caused undefined behavior. /// ``` - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub unsafe fn assume_init(self) -> T { intrinsics::panic_if_uninhabited::<T>(); @@ -1338,13 +1306,15 @@ impl<T> MaybeUninit<T> { /// /// It is up to the caller to guarantee that the `MaybeUninit<T>` really is in an initialized /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using /// multiple copies of the data (by calling `read` multiple times, or first /// calling `read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// + /// [inv]: #initialization-invariant /// [`assume_init`]: #method.assume_init /// /// # Examples @@ -1352,7 +1322,7 @@ impl<T> MaybeUninit<T> { /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] + /// #![feature(maybe_uninit_extra)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<u32>::uninit(); @@ -1373,7 +1343,7 @@ impl<T> MaybeUninit<T> { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] + /// #![feature(maybe_uninit_extra)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit(); @@ -1383,7 +1353,7 @@ impl<T> MaybeUninit<T> { /// // We now created two copies of the same vector, leading to a double-free when /// // they both get dropped! /// ``` - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] #[inline(always)] pub unsafe fn read(&self) -> T { intrinsics::panic_if_uninhabited::<T>(); diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 2401946536f..e044b46e0d0 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -272,7 +272,6 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![feature(maybe_uninit)] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] diff --git a/src/test/codegen/box-maybe-uninit.rs b/src/test/codegen/box-maybe-uninit.rs index 0dd67bb95cc..5004f787cde 100644 --- a/src/test/codegen/box-maybe-uninit.rs +++ b/src/test/codegen/box-maybe-uninit.rs @@ -1,6 +1,5 @@ // compile-flags: -O #![crate_type="lib"] -#![feature(maybe_uninit)] use std::mem::MaybeUninit; diff --git a/src/test/run-pass/panic-uninitialized-zeroed.rs b/src/test/run-pass/panic-uninitialized-zeroed.rs index 3f6e489bb83..4ca4b407bd4 100644 --- a/src/test/run-pass/panic-uninitialized-zeroed.rs +++ b/src/test/run-pass/panic-uninitialized-zeroed.rs @@ -2,7 +2,7 @@ // This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results // in a runtime panic. -#![feature(never_type, maybe_uninit)] +#![feature(never_type)] use std::{mem, panic}; |
