diff options
Diffstat (limited to '')
-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/ptr/alignment.rs (renamed from library/core/src/mem/valid_align.rs) | 175 |
4 files changed, 227 insertions, 81 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/ptr/alignment.rs index 32b2afb72..1390e09dd 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,4 +1,4 @@ -use crate::convert::TryFrom; +use crate::convert::{TryFrom, TryInto}; use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -8,16 +8,62 @@ use crate::{cmp, fmt, hash, mem, num}; /// /// Note that particularly large alignments, while representable in this type, /// are likely not to be supported by actual allocators and linkers. -#[derive(Copy, Clone)] +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +#[derive(Copy, Clone, Eq, PartialEq)] #[repr(transparent)] -pub(crate) struct ValidAlign(ValidAlignEnum); +pub struct Alignment(AlignmentEnum); -// 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>()); +// Alignment is `repr(usize)`, but via extra steps. +const _: () = assert!(mem::size_of::<Alignment>() == mem::size_of::<usize>()); +const _: () = assert!(mem::align_of::<Alignment>() == mem::align_of::<usize>()); -impl ValidAlign { - /// Creates a `ValidAlign` from a power-of-two `usize`. +fn _alignment_can_be_structurally_matched(a: Alignment) -> bool { + matches!(a, Alignment::MIN) +} + +impl Alignment { + /// The smallest possible alignment, 1. + /// + /// All addresses are always aligned at least this much. + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_alignment_type)] + /// use std::ptr::Alignment; + /// + /// assert_eq!(Alignment::MIN.as_usize(), 1); + /// ``` + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + pub const MIN: Self = Self(AlignmentEnum::_Align1Shl0); + + /// Returns the alignment for a type. + /// + /// This provides the same numerical value as [`mem::align_of`], + /// but in an `Alignment` instead of a `usize. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[inline] + pub const fn of<T>() -> Self { + // SAFETY: rustc ensures that type alignment is always a power of two. + unsafe { Alignment::new_unchecked(mem::align_of::<T>()) } + } + + /// Creates an `Alignment` from a `usize`, or returns `None` if it's + /// not a power of two. + /// + /// Note that `0` is not a power of two, nor a valid alignment. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[inline] + pub const fn new(align: usize) -> Option<Self> { + if align.is_power_of_two() { + // SAFETY: Just checked it only has one bit set + Some(unsafe { Self::new_unchecked(align) }) + } else { + None + } + } + + /// Creates an `Alignment` from a power-of-two `usize`. /// /// # Safety /// @@ -25,101 +71,120 @@ impl ValidAlign { /// /// Equivalently, it must be `1 << exp` for some `exp` in `0..usize::BITS`. /// It must *not* be zero. + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] - pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { + pub 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()) }; + unsafe { + assert_unsafe_precondition!( + "Alignment::new_unchecked requires a power of two", + (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) } + unsafe { mem::transmute::<usize, Alignment>(align) } } + /// Returns the alignment as a [`usize`] + #[unstable(feature = "ptr_alignment_type", issue = "102070")] + #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] - pub(crate) const fn as_usize(self) -> usize { + pub const fn as_usize(self) -> usize { self.0 as usize } + /// Returns the alignment as a [`NonZeroUsize`] + #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] - pub(crate) const fn as_nonzero(self) -> NonZeroUsize { + pub 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. + /// Returns the base-2 logarithm of the alignment. /// /// This is always exact, as `self` represents a power of two. + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_alignment_type)] + /// use std::ptr::Alignment; + /// + /// assert_eq!(Alignment::of::<u8>().log2(), 0); + /// assert_eq!(Alignment::new(1024).unwrap().log2(), 10); + /// ``` + #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] - pub(crate) fn log2(self) -> u32 { + pub 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 { +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl fmt::Debug for Alignment { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2()) } } -impl TryFrom<NonZeroUsize> for ValidAlign { +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl TryFrom<NonZeroUsize> for Alignment { 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(())) - } + fn try_from(align: NonZeroUsize) -> Result<Alignment, Self::Error> { + align.get().try_into() } } -impl TryFrom<usize> for ValidAlign { +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl TryFrom<usize> for Alignment { 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(())) - } + fn try_from(align: usize) -> Result<Alignment, Self::Error> { + Self::new(align).ok_or(num::TryFromIntError(())) } } -impl cmp::Eq for ValidAlign {} +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl From<Alignment> for NonZeroUsize { + #[inline] + fn from(align: Alignment) -> NonZeroUsize { + align.as_nonzero() + } +} -impl cmp::PartialEq for ValidAlign { +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl From<Alignment> for usize { #[inline] - fn eq(&self, other: &Self) -> bool { - self.as_nonzero() == other.as_nonzero() + fn from(align: Alignment) -> usize { + align.as_usize() } } -impl cmp::Ord for ValidAlign { +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl cmp::Ord for Alignment { #[inline] fn cmp(&self, other: &Self) -> cmp::Ordering { self.as_nonzero().cmp(&other.as_nonzero()) } } -impl cmp::PartialOrd for ValidAlign { +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl cmp::PartialOrd for Alignment { #[inline] fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { Some(self.cmp(other)) } } -impl hash::Hash for ValidAlign { +#[unstable(feature = "ptr_alignment_type", issue = "102070")] +impl hash::Hash for Alignment { #[inline] fn hash<H: hash::Hasher>(&self, state: &mut H) { self.as_nonzero().hash(state) @@ -127,15 +192,15 @@ impl hash::Hash for ValidAlign { } #[cfg(target_pointer_width = "16")] -type ValidAlignEnum = ValidAlignEnum16; +type AlignmentEnum = AlignmentEnum16; #[cfg(target_pointer_width = "32")] -type ValidAlignEnum = ValidAlignEnum32; +type AlignmentEnum = AlignmentEnum32; #[cfg(target_pointer_width = "64")] -type ValidAlignEnum = ValidAlignEnum64; +type AlignmentEnum = AlignmentEnum64; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq)] #[repr(u16)] -enum ValidAlignEnum16 { +enum AlignmentEnum16 { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, _Align1Shl2 = 1 << 2, @@ -154,9 +219,9 @@ enum ValidAlignEnum16 { _Align1Shl15 = 1 << 15, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq)] #[repr(u32)] -enum ValidAlignEnum32 { +enum AlignmentEnum32 { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, _Align1Shl2 = 1 << 2, @@ -191,9 +256,9 @@ enum ValidAlignEnum32 { _Align1Shl31 = 1 << 31, } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq)] #[repr(u64)] -enum ValidAlignEnum64 { +enum AlignmentEnum64 { _Align1Shl0 = 1 << 0, _Align1Shl1 = 1 << 1, _Align1Shl2 = 1 << 2, |