Auto merge of #58129 - RalfJung:maybe-uninit, r=cramertj
MaybeUninit: some docs, rename into_inner -> into_initialized, return &mut from set
This commit is contained in:
commit
0b7af2668a
6 changed files with 65 additions and 16 deletions
|
@ -555,12 +555,12 @@ macro_rules! unimplemented {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||||
macro_rules! uninitialized_array {
|
macro_rules! uninitialized_array {
|
||||||
// This `into_inner` is safe because an array of `MaybeUninit` does not
|
// This `into_initialized` is safe because an array of `MaybeUninit` does not
|
||||||
// require initialization.
|
// require initialization.
|
||||||
// FIXME(#49147): Could be replaced by an array initializer, once those can
|
// FIXME(#49147): Could be replaced by an array initializer, once those can
|
||||||
// be any const expression.
|
// be any const expression.
|
||||||
($t:ty; $size:expr) => (unsafe {
|
($t:ty; $size:expr) => (unsafe {
|
||||||
MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_inner()
|
MaybeUninit::<[MaybeUninit<$t>; $size]>::uninitialized().into_initialized()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1035,7 +1035,42 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<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)]
|
#[allow(missing_debug_implementations)]
|
||||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||||
// NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::{uninitialized,zeroed}`
|
// NOTE after stabilizing `MaybeUninit` proceed to deprecate `mem::{uninitialized,zeroed}`
|
||||||
|
@ -1084,11 +1119,14 @@ impl<T> MaybeUninit<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the value of the `MaybeUninit`. This overwrites any previous value without dropping it.
|
/// 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")]
|
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set(&mut self, val: T) {
|
pub fn set(&mut self, val: T) -> &mut T {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.value = ManuallyDrop::new(val);
|
self.value = ManuallyDrop::new(val);
|
||||||
|
self.get_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,11 +1140,19 @@ impl<T> MaybeUninit<T> {
|
||||||
/// state, otherwise this will immediately cause undefined behavior.
|
/// state, otherwise this will immediately cause undefined behavior.
|
||||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn into_inner(self) -> T {
|
pub unsafe fn into_initialized(self) -> T {
|
||||||
intrinsics::panic_if_uninhabited::<T>();
|
intrinsics::panic_if_uninhabited::<T>();
|
||||||
ManuallyDrop::into_inner(self.value)
|
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.
|
/// Get a reference to the contained value.
|
||||||
///
|
///
|
||||||
/// # Unsafety
|
/// # Unsafety
|
||||||
|
@ -1134,16 +1180,16 @@ impl<T> MaybeUninit<T> {
|
||||||
&mut *self.value
|
&mut *self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a pointer to the contained value. Reading from this pointer will be undefined
|
/// Get a pointer to the contained value. Reading from this pointer or turning it
|
||||||
/// behavior unless the `MaybeUninit` is initialized.
|
/// into a reference will be undefined behavior unless the `MaybeUninit` is initialized.
|
||||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn as_ptr(&self) -> *const T {
|
pub fn as_ptr(&self) -> *const T {
|
||||||
unsafe { &*self.value as *const T }
|
unsafe { &*self.value as *const T }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable pointer to the contained value. Reading from this pointer will be undefined
|
/// Get a mutable pointer to the contained value. Reading from this pointer or turning it
|
||||||
/// behavior unless the `MaybeUninit` is initialized.
|
/// into a reference will be undefined behavior unless the `MaybeUninit` is initialized.
|
||||||
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
#[unstable(feature = "maybe_uninit", issue = "53491")]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn as_mut_ptr(&mut self) -> *mut T {
|
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||||
|
|
|
@ -573,7 +573,7 @@ pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
|
||||||
pub unsafe fn read<T>(src: *const T) -> T {
|
pub unsafe fn read<T>(src: *const T) -> T {
|
||||||
let mut tmp = MaybeUninit::<T>::uninitialized();
|
let mut tmp = MaybeUninit::<T>::uninitialized();
|
||||||
copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
|
copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
|
||||||
tmp.into_inner()
|
tmp.into_initialized()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the value from `src` without moving it. This leaves the
|
/// Reads the value from `src` without moving it. This leaves the
|
||||||
|
@ -642,7 +642,7 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
|
||||||
copy_nonoverlapping(src as *const u8,
|
copy_nonoverlapping(src as *const u8,
|
||||||
tmp.as_mut_ptr() as *mut u8,
|
tmp.as_mut_ptr() as *mut u8,
|
||||||
mem::size_of::<T>());
|
mem::size_of::<T>());
|
||||||
tmp.into_inner()
|
tmp.into_initialized()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overwrites a memory location with the given value without reading or
|
/// Overwrites a memory location with the given value without reading or
|
||||||
|
|
|
@ -41,7 +41,7 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32>
|
||||||
);
|
);
|
||||||
|
|
||||||
match error {
|
match error {
|
||||||
0 => Ok(out.into_inner()),
|
0 => Ok(out.into_initialized()),
|
||||||
err => Err(err),
|
err => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,6 @@ pub fn ereport(
|
||||||
"{rdx}"(report.as_mut_ptr())
|
"{rdx}"(report.as_mut_ptr())
|
||||||
);
|
);
|
||||||
|
|
||||||
report.into_inner()
|
report.into_initialized()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,8 @@ use std::mem::MaybeUninit;
|
||||||
pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
|
pub fn box_uninitialized() -> Box<MaybeUninit<usize>> {
|
||||||
// CHECK-LABEL: @box_uninitialized
|
// CHECK-LABEL: @box_uninitialized
|
||||||
// CHECK-NOT: store
|
// CHECK-NOT: store
|
||||||
|
// CHECK-NOT: alloca
|
||||||
|
// CHECK-NOT: memcpy
|
||||||
|
// CHECK-NOT: memset
|
||||||
Box::new(MaybeUninit::uninitialized())
|
Box::new(MaybeUninit::uninitialized())
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ fn main() {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
panic::catch_unwind(|| {
|
panic::catch_unwind(|| {
|
||||||
mem::MaybeUninit::<!>::uninitialized().into_inner()
|
mem::MaybeUninit::<!>::uninitialized().into_initialized()
|
||||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||||
s == "Attempted to instantiate uninhabited type !"
|
s == "Attempted to instantiate uninhabited type !"
|
||||||
})),
|
})),
|
||||||
|
@ -63,7 +63,7 @@ fn main() {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
panic::catch_unwind(|| {
|
panic::catch_unwind(|| {
|
||||||
mem::MaybeUninit::<Foo>::uninitialized().into_inner()
|
mem::MaybeUninit::<Foo>::uninitialized().into_initialized()
|
||||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||||
s == "Attempted to instantiate uninhabited type Foo"
|
s == "Attempted to instantiate uninhabited type Foo"
|
||||||
})),
|
})),
|
||||||
|
@ -90,7 +90,7 @@ fn main() {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
panic::catch_unwind(|| {
|
panic::catch_unwind(|| {
|
||||||
mem::MaybeUninit::<Bar>::uninitialized().into_inner()
|
mem::MaybeUninit::<Bar>::uninitialized().into_initialized()
|
||||||
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
}).err().and_then(|a| a.downcast_ref::<String>().map(|s| {
|
||||||
s == "Attempted to instantiate uninhabited type Bar"
|
s == "Attempted to instantiate uninhabited type Bar"
|
||||||
})),
|
})),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue