diff options
Diffstat (limited to 'library/core/src/mem')
-rw-r--r-- | library/core/src/mem/maybe_uninit.rs | 44 | ||||
-rw-r--r-- | library/core/src/mem/mod.rs | 85 | ||||
-rw-r--r-- | library/core/src/mem/transmutability.rs | 4 | ||||
-rw-r--r-- | library/core/src/mem/valid_align.rs | 261 |
4 files changed, 107 insertions, 287 deletions
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 2490c0767..7757c95de 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -146,7 +146,6 @@ use crate::slice; /// /// ``` /// use std::mem::MaybeUninit; -/// use std::ptr; /// /// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is /// // safe because the type we are claiming to have initialized here is a @@ -162,7 +161,7 @@ use crate::slice; /// /// // For each item in the array, drop if we allocated it. /// for elem in &mut data[0..data_len] { -/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); } +/// unsafe { elem.assume_init_drop(); } /// } /// ``` /// @@ -647,7 +646,7 @@ impl<T> MaybeUninit<T> { /// implements the [`Copy`] trait or not. When using multiple copies of the /// data (by calling `assume_init_read` multiple times, or first calling /// `assume_init_read` and then [`assume_init`]), it is your responsibility - /// to ensure that that data may indeed be duplicated. + /// to ensure that data may indeed be duplicated. /// /// [inv]: #initialization-invariant /// [`assume_init`]: MaybeUninit::assume_init @@ -1284,3 +1283,42 @@ impl<T> MaybeUninit<T> { } } } + +impl<T, const N: usize> MaybeUninit<[T; N]> { + /// Transposes a `MaybeUninit<[T; N]>` into a `[MaybeUninit<T>; N]`. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_uninit_array_transpose)] + /// # use std::mem::MaybeUninit; + /// + /// let data: [MaybeUninit<u8>; 1000] = MaybeUninit::uninit().transpose(); + /// ``` + #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")] + #[inline] + pub const fn transpose(self) -> [MaybeUninit<T>; N] { + // SAFETY: T and MaybeUninit<T> have the same layout + unsafe { super::transmute_copy(&ManuallyDrop::new(self)) } + } +} + +impl<T, const N: usize> [MaybeUninit<T>; N] { + /// Transposes a `[MaybeUninit<T>; N]` into a `MaybeUninit<[T; N]>`. + /// + /// # Examples + /// + /// ``` + /// #![feature(maybe_uninit_uninit_array_transpose)] + /// # use std::mem::MaybeUninit; + /// + /// let data = [MaybeUninit::<u8>::uninit(); 1000]; + /// let data: MaybeUninit<[u8; 1000]> = data.transpose(); + /// ``` + #[unstable(feature = "maybe_uninit_uninit_array_transpose", issue = "96097")] + #[inline] + pub const fn transpose(self) -> MaybeUninit<[T; N]> { + // SAFETY: T and MaybeUninit<T> have the same layout + unsafe { super::transmute_copy(&ManuallyDrop::new(self)) } + } +} diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index d2dd2941d..9195da5a4 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -21,11 +21,10 @@ mod maybe_uninit; #[stable(feature = "maybe_uninit", since = "1.36.0")] pub use maybe_uninit::MaybeUninit; -mod valid_align; -// For now this type is left crate-local. It could potentially make sense to expose -// it publicly, as it would be a nice parameter type for methods which need to take -// alignment as a parameter, such as `Layout::padding_needed_for`. -pub(crate) use valid_align::ValidAlign; +// FIXME: This is left here for now to avoid complications around pending reverts. +// Once <https://github.com/rust-lang/rust/issues/101899> is fully resolved, +// this should be removed and the references in `alloc::Layout` updated. +pub(crate) use ptr::Alignment as ValidAlign; mod transmutability; #[unstable(feature = "transmutability", issue = "99571")] @@ -1009,18 +1008,18 @@ pub fn copy<T: Copy>(x: &T) -> T { *x } -/// Interprets `src` as having type `&U`, and then reads `src` without moving +/// Interprets `src` as having type `&Dst`, and then reads `src` without moving /// the contained value. /// -/// This function will unsafely assume the pointer `src` is valid for [`size_of::<U>`][size_of] -/// bytes by transmuting `&T` to `&U` and then reading the `&U` (except that this is done in a way -/// that is correct even when `&U` has stricter alignment requirements than `&T`). It will also -/// unsafely create a copy of the contained value instead of moving out of `src`. +/// This function will unsafely assume the pointer `src` is valid for [`size_of::<Dst>`][size_of] +/// bytes by transmuting `&Src` to `&Dst` and then reading the `&Dst` (except that this is done +/// in a way that is correct even when `&Dst` has stricter alignment requirements than `&Src`). +/// It will also unsafely create a copy of the contained value instead of moving out of `src`. /// -/// It is not a compile-time error if `T` and `U` have different sizes, but it -/// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers [undefined behavior][ub] if `U` is larger than -/// `T`. +/// It is not a compile-time error if `Src` and `Dst` have different sizes, but it +/// is highly encouraged to only invoke this function where `Src` and `Dst` have the +/// same size. This function triggers [undefined behavior][ub] if `Dst` is larger than +/// `Src`. /// /// [ub]: ../../reference/behavior-considered-undefined.html /// @@ -1053,19 +1052,22 @@ pub fn copy<T: Copy>(x: &T) -> T { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] -pub const unsafe fn transmute_copy<T, U>(src: &T) -> U { - assert!(size_of::<T>() >= size_of::<U>(), "cannot transmute_copy if U is larger than T"); +pub const unsafe fn transmute_copy<Src, Dst>(src: &Src) -> Dst { + assert!( + size_of::<Src>() >= size_of::<Dst>(), + "cannot transmute_copy if Dst is larger than Src" + ); - // If U has a higher alignment requirement, src might not be suitably aligned. - if align_of::<U>() > align_of::<T>() { + // If Dst has a higher alignment requirement, src might not be suitably aligned. + if align_of::<Dst>() > align_of::<Src>() { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. // The caller must guarantee that the actual transmutation is safe. - unsafe { ptr::read_unaligned(src as *const T as *const U) } + unsafe { ptr::read_unaligned(src as *const Src as *const Dst) } } else { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. - // We just checked that `src as *const U` was properly aligned. + // We just checked that `src as *const Dst` was properly aligned. // The caller must guarantee that the actual transmutation is safe. - unsafe { ptr::read(src as *const T as *const U) } + unsafe { ptr::read(src as *const Src as *const Dst) } } } @@ -1178,3 +1180,44 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> { pub const fn variant_count<T>() -> usize { intrinsics::variant_count::<T>() } + +/// Provides associated constants for various useful properties of types, +/// to give them a canonical form in our code and make them easier to read. +/// +/// This is here only to simplify all the ZST checks we need in the library. +/// It's not on a stabilization track right now. +#[doc(hidden)] +#[unstable(feature = "sized_type_properties", issue = "none")] +pub trait SizedTypeProperties: Sized { + /// `true` if this type requires no storage. + /// `false` if its [size](size_of) is greater than zero. + /// + /// # Examples + /// + /// ``` + /// #![feature(sized_type_properties)] + /// use core::mem::SizedTypeProperties; + /// + /// fn do_something_with<T>() { + /// if T::IS_ZST { + /// // ... special approach ... + /// } else { + /// // ... the normal thing ... + /// } + /// } + /// + /// struct MyUnit; + /// assert!(MyUnit::IS_ZST); + /// + /// // For negative checks, consider using UFCS to emphasize the negation + /// assert!(!<i32>::IS_ZST); + /// // As it can sometimes hide in the type otherwise + /// assert!(!String::IS_ZST); + /// ``` + #[doc(hidden)] + #[unstable(feature = "sized_type_properties", issue = "none")] + const IS_ZST: bool = size_of::<Self>() == 0; +} +#[doc(hidden)] +#[unstable(feature = "sized_type_properties", issue = "none")] +impl<T> SizedTypeProperties for T {} diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 87a378631..3b98efff2 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -4,7 +4,7 @@ /// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`, /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] -#[cfg_attr(not(bootstrap), lang = "transmute_trait")] +#[lang = "transmute_trait"] #[rustc_on_unimplemented( message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`." @@ -17,7 +17,7 @@ where /// What transmutation safety conditions shall the compiler assume that *you* are checking? #[unstable(feature = "transmutability", issue = "99571")] -#[cfg_attr(not(bootstrap), lang = "transmute_opts")] +#[lang = "transmute_opts"] #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Assume { /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs deleted file mode 100644 index 32b2afb72..000000000 --- a/library/core/src/mem/valid_align.rs +++ /dev/null @@ -1,261 +0,0 @@ -use crate::convert::TryFrom; -use crate::intrinsics::assert_unsafe_precondition; -use crate::num::NonZeroUsize; -use crate::{cmp, fmt, hash, mem, num}; - -/// A type storing a `usize` which is a power of two, and thus -/// represents a possible alignment in the rust abstract machine. -/// -/// Note that particularly large alignments, while representable in this type, -/// are likely not to be supported by actual allocators and linkers. -#[derive(Copy, Clone)] -#[repr(transparent)] -pub(crate) struct ValidAlign(ValidAlignEnum); - -// ValidAlign is `repr(usize)`, but via extra steps. -const _: () = assert!(mem::size_of::<ValidAlign>() == mem::size_of::<usize>()); -const _: () = assert!(mem::align_of::<ValidAlign>() == mem::align_of::<usize>()); - -impl ValidAlign { - /// Creates a `ValidAlign` from a power-of-two `usize`. - /// - /// # Safety - /// - /// `align` must be a power of two. - /// - /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`. - /// It must *not* be zero. - #[inline] - pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { - // SAFETY: Precondition passed to the caller. - unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) }; - - // SAFETY: By precondition, this must be a power of two, and - // our variants encompass all possible powers of two. - unsafe { mem::transmute::<usize, ValidAlign>(align) } - } - - #[inline] - pub(crate) const fn as_usize(self) -> usize { - self.0 as usize - } - - #[inline] - pub(crate) const fn as_nonzero(self) -> NonZeroUsize { - // SAFETY: All the discriminants are non-zero. - unsafe { NonZeroUsize::new_unchecked(self.as_usize()) } - } - - /// Returns the base 2 logarithm of the alignment. - /// - /// This is always exact, as `self` represents a power of two. - #[inline] - pub(crate) fn log2(self) -> u32 { - self.as_nonzero().trailing_zeros() - } - - /// Returns the alignment for a type. - #[inline] - pub(crate) fn of<T>() -> Self { - // SAFETY: rustc ensures that type alignment is always a power of two. - unsafe { ValidAlign::new_unchecked(mem::align_of::<T>()) } - } -} - -impl fmt::Debug for ValidAlign { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2()) - } -} - -impl TryFrom<NonZeroUsize> for ValidAlign { - type Error = num::TryFromIntError; - - #[inline] - fn try_from(align: NonZeroUsize) -> Result<ValidAlign, Self::Error> { - if align.is_power_of_two() { - // SAFETY: Just checked for power-of-two - unsafe { Ok(ValidAlign::new_unchecked(align.get())) } - } else { - Err(num::TryFromIntError(())) - } - } -} - -impl TryFrom<usize> for ValidAlign { - type Error = num::TryFromIntError; - - #[inline] - fn try_from(align: usize) -> Result<ValidAlign, Self::Error> { - if align.is_power_of_two() { - // SAFETY: Just checked for power-of-two - unsafe { Ok(ValidAlign::new_unchecked(align)) } - } else { - Err(num::TryFromIntError(())) - } - } -} - -impl cmp::Eq for ValidAlign {} - -impl cmp::PartialEq for ValidAlign { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.as_nonzero() == other.as_nonzero() - } -} - -impl cmp::Ord for ValidAlign { - #[inline] - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.as_nonzero().cmp(&other.as_nonzero()) - } -} - -impl cmp::PartialOrd for ValidAlign { - #[inline] - fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl hash::Hash for ValidAlign { - #[inline] - fn hash<H: hash::Hasher>(&self, state: &mut H) { - self.as_nonzero().hash(state) - } -} - -#[cfg(target_pointer_width = "16")] -type ValidAlignEnum = ValidAlignEnum16; -#[cfg(target_pointer_width = "32")] -type ValidAlignEnum = ValidAlignEnum32; -#[cfg(target_pointer_width = "64")] -type ValidAlignEnum = ValidAlignEnum64; - -#[derive(Copy, Clone)] -#[repr(u16)] -enum ValidAlignEnum16 { - _Align1Shl0 = 1 << 0, - _Align1Shl1 = 1 << 1, - _Align1Shl2 = 1 << 2, - _Align1Shl3 = 1 << 3, - _Align1Shl4 = 1 << 4, - _Align1Shl5 = 1 << 5, - _Align1Shl6 = 1 << 6, - _Align1Shl7 = 1 << 7, - _Align1Shl8 = 1 << 8, - _Align1Shl9 = 1 << 9, - _Align1Shl10 = 1 << 10, - _Align1Shl11 = 1 << 11, - _Align1Shl12 = 1 << 12, - _Align1Shl13 = 1 << 13, - _Align1Shl14 = 1 << 14, - _Align1Shl15 = 1 << 15, -} - -#[derive(Copy, Clone)] -#[repr(u32)] -enum ValidAlignEnum32 { - _Align1Shl0 = 1 << 0, - _Align1Shl1 = 1 << 1, - _Align1Shl2 = 1 << 2, - _Align1Shl3 = 1 << 3, - _Align1Shl4 = 1 << 4, - _Align1Shl5 = 1 << 5, - _Align1Shl6 = 1 << 6, - _Align1Shl7 = 1 << 7, - _Align1Shl8 = 1 << 8, - _Align1Shl9 = 1 << 9, - _Align1Shl10 = 1 << 10, - _Align1Shl11 = 1 << 11, - _Align1Shl12 = 1 << 12, - _Align1Shl13 = 1 << 13, - _Align1Shl14 = 1 << 14, - _Align1Shl15 = 1 << 15, - _Align1Shl16 = 1 << 16, - _Align1Shl17 = 1 << 17, - _Align1Shl18 = 1 << 18, - _Align1Shl19 = 1 << 19, - _Align1Shl20 = 1 << 20, - _Align1Shl21 = 1 << 21, - _Align1Shl22 = 1 << 22, - _Align1Shl23 = 1 << 23, - _Align1Shl24 = 1 << 24, - _Align1Shl25 = 1 << 25, - _Align1Shl26 = 1 << 26, - _Align1Shl27 = 1 << 27, - _Align1Shl28 = 1 << 28, - _Align1Shl29 = 1 << 29, - _Align1Shl30 = 1 << 30, - _Align1Shl31 = 1 << 31, -} - -#[derive(Copy, Clone)] -#[repr(u64)] -enum ValidAlignEnum64 { - _Align1Shl0 = 1 << 0, - _Align1Shl1 = 1 << 1, - _Align1Shl2 = 1 << 2, - _Align1Shl3 = 1 << 3, - _Align1Shl4 = 1 << 4, - _Align1Shl5 = 1 << 5, - _Align1Shl6 = 1 << 6, - _Align1Shl7 = 1 << 7, - _Align1Shl8 = 1 << 8, - _Align1Shl9 = 1 << 9, - _Align1Shl10 = 1 << 10, - _Align1Shl11 = 1 << 11, - _Align1Shl12 = 1 << 12, - _Align1Shl13 = 1 << 13, - _Align1Shl14 = 1 << 14, - _Align1Shl15 = 1 << 15, - _Align1Shl16 = 1 << 16, - _Align1Shl17 = 1 << 17, - _Align1Shl18 = 1 << 18, - _Align1Shl19 = 1 << 19, - _Align1Shl20 = 1 << 20, - _Align1Shl21 = 1 << 21, - _Align1Shl22 = 1 << 22, - _Align1Shl23 = 1 << 23, - _Align1Shl24 = 1 << 24, - _Align1Shl25 = 1 << 25, - _Align1Shl26 = 1 << 26, - _Align1Shl27 = 1 << 27, - _Align1Shl28 = 1 << 28, - _Align1Shl29 = 1 << 29, - _Align1Shl30 = 1 << 30, - _Align1Shl31 = 1 << 31, - _Align1Shl32 = 1 << 32, - _Align1Shl33 = 1 << 33, - _Align1Shl34 = 1 << 34, - _Align1Shl35 = 1 << 35, - _Align1Shl36 = 1 << 36, - _Align1Shl37 = 1 << 37, - _Align1Shl38 = 1 << 38, - _Align1Shl39 = 1 << 39, - _Align1Shl40 = 1 << 40, - _Align1Shl41 = 1 << 41, - _Align1Shl42 = 1 << 42, - _Align1Shl43 = 1 << 43, - _Align1Shl44 = 1 << 44, - _Align1Shl45 = 1 << 45, - _Align1Shl46 = 1 << 46, - _Align1Shl47 = 1 << 47, - _Align1Shl48 = 1 << 48, - _Align1Shl49 = 1 << 49, - _Align1Shl50 = 1 << 50, - _Align1Shl51 = 1 << 51, - _Align1Shl52 = 1 << 52, - _Align1Shl53 = 1 << 53, - _Align1Shl54 = 1 << 54, - _Align1Shl55 = 1 << 55, - _Align1Shl56 = 1 << 56, - _Align1Shl57 = 1 << 57, - _Align1Shl58 = 1 << 58, - _Align1Shl59 = 1 << 59, - _Align1Shl60 = 1 << 60, - _Align1Shl61 = 1 << 61, - _Align1Shl62 = 1 << 62, - _Align1Shl63 = 1 << 63, -} |