@@ -354,7 +354,7 @@ use core::{
354354 fmt:: { self , Debug , Display , Formatter } ,
355355 hash:: Hasher ,
356356 marker:: PhantomData ,
357- mem:: { self , ManuallyDrop , MaybeUninit } ,
357+ mem:: { self , ManuallyDrop , MaybeUninit as CoreMaybeUninit } ,
358358 num:: {
359359 NonZeroI128 , NonZeroI16 , NonZeroI32 , NonZeroI64 , NonZeroI8 , NonZeroIsize , NonZeroU128 ,
360360 NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
@@ -711,6 +711,15 @@ pub unsafe trait KnownLayout {
711711 /// This is `()` for sized types and `usize` for slice DSTs.
712712 type PointerMetadata : PointerMetadata ;
713713
714+ /// A maybe-uninitialized analog of `Self`
715+ ///
716+ /// # Safety
717+ ///
718+ /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical.
719+ /// `Self::MaybeUninit` admits uninitialized bytes in all positions.
720+ #[ doc( hidden) ]
721+ type MaybeUninit : ?Sized + KnownLayout < PointerMetadata = Self :: PointerMetadata > ;
722+
714723 /// The layout of `Self`.
715724 ///
716725 /// # Safety
@@ -843,6 +852,35 @@ unsafe impl<T> KnownLayout for [T] {
843852
844853 type PointerMetadata = usize ;
845854
855+ // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are identical
856+ // because `CoreMaybeUninit<T>` has the same size and alignment as `T` [1].
857+ // Consequently, `[CoreMaybeUninit<T>]::LAYOUT` and `[T]::LAYOUT` are
858+ // identical, because they both lack a fixed-sized prefix and because they
859+ // inherit the alignments of their inner element type (which are identical)
860+ // [2][3].
861+ //
862+ // `[CoreMaybeUninit<T>]` admits uninitialized bytes at all positions
863+ // because `CoreMaybeUninit<T>` admits uninitialized bytes at all positions
864+ // and because the inner elements of `[CoreMaybeUninit<T>]` are laid out
865+ // back-to-back [2][3].
866+ //
867+ // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
868+ //
869+ // `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
870+ // `T`
871+ //
872+ // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout:
873+ //
874+ // Slices have the same layout as the section of the array they slice.
875+ //
876+ // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout:
877+ //
878+ // An array of `[T; N]` has a size of `size_of::<T>() * N` and the same
879+ // alignment of `T`. Arrays are laid out so that the zero-based `nth`
880+ // element of the array is offset from the start of the array by `n *
881+ // size_of::<T>()` bytes.
882+ type MaybeUninit = [ CoreMaybeUninit < T > ] ;
883+
846884 const LAYOUT : DstLayout = DstLayout :: for_slice :: < T > ( ) ;
847885
848886 // SAFETY: `.cast` preserves address and provenance. The returned pointer
@@ -895,9 +933,11 @@ impl_known_layout!(
895933 T => Option <T >,
896934 T : ?Sized => PhantomData <T >,
897935 T => Wrapping <T >,
898- T => MaybeUninit <T >,
936+ T => CoreMaybeUninit <T >,
899937 T : ?Sized => * const T ,
900- T : ?Sized => * mut T
938+ T : ?Sized => * mut T ,
939+ T : ?Sized => & ' _ T ,
940+ T : ?Sized => & ' _ mut T ,
901941) ;
902942impl_known_layout ! ( const N : usize , T => [ T ; N ] ) ;
903943
@@ -928,6 +968,21 @@ safety_comment! {
928968 unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T ) ] UnsafeCell <T >) ;
929969}
930970
971+ safety_comment ! {
972+ /// SAFETY:
973+ /// - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT`
974+ /// and `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit`
975+ /// have the same:
976+ /// - Fixed prefix size
977+ /// - Alignment
978+ /// - (For DSTs) trailing slice element size
979+ /// - By consequence of the above, referents `T::MaybeUninit` and `T` have
980+ /// the require the same kind of pointer metadata, and thus it is valid to
981+ /// perform an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this
982+ /// operation preserves referent size (ie, `size_of_val_raw`).
983+ unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T :: MaybeUninit ) ] MaybeUninit <T >) ;
984+ }
985+
931986/// Analyzes whether a type is [`FromZeros`].
932987///
933988/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -2547,7 +2602,7 @@ pub unsafe trait TryFromBytes {
25472602 where
25482603 Self : Sized ,
25492604 {
2550- let candidate = match MaybeUninit :: < Self > :: read_from_bytes ( source) {
2605+ let candidate = match CoreMaybeUninit :: < Self > :: read_from_bytes ( source) {
25512606 Ok ( candidate) => candidate,
25522607 Err ( e) => {
25532608 return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2608,7 +2663,7 @@ pub unsafe trait TryFromBytes {
26082663 where
26092664 Self : Sized ,
26102665 {
2611- let ( candidate, suffix) = match MaybeUninit :: < Self > :: read_from_prefix ( source) {
2666+ let ( candidate, suffix) = match CoreMaybeUninit :: < Self > :: read_from_prefix ( source) {
26122667 Ok ( candidate) => candidate,
26132668 Err ( e) => {
26142669 return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2670,7 +2725,7 @@ pub unsafe trait TryFromBytes {
26702725 where
26712726 Self : Sized ,
26722727 {
2673- let ( prefix, candidate) = match MaybeUninit :: < Self > :: read_from_suffix ( source) {
2728+ let ( prefix, candidate) = match CoreMaybeUninit :: < Self > :: read_from_suffix ( source) {
26742729 Ok ( candidate) => candidate,
26752730 Err ( e) => {
26762731 return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2743,7 +2798,7 @@ fn swap<T, U>((t, u): (T, U)) -> (U, T) {
27432798#[ inline( always) ]
27442799unsafe fn try_read_from < S , T : TryFromBytes > (
27452800 source : S ,
2746- mut candidate : MaybeUninit < T > ,
2801+ mut candidate : CoreMaybeUninit < T > ,
27472802) -> Result < T , TryReadError < S , T > > {
27482803 // We use `from_mut` despite not mutating via `c_ptr` so that we don't need
27492804 // to add a `T: Immutable` bound.
@@ -3032,60 +3087,11 @@ pub unsafe trait FromZeros: TryFromBytes {
30323087 where
30333088 Self : KnownLayout < PointerMetadata = usize > ,
30343089 {
3035- let size = match count. size_for_metadata ( Self :: LAYOUT ) {
3036- Some ( size) => size,
3037- None => return Err ( AllocError ) ,
3038- } ;
3039-
3040- let align = Self :: LAYOUT . align . get ( ) ;
3041-
3042- // TODO(https://github.com/rust-lang/rust/issues/55724): Use
3043- // `Layout::repeat` once it's stabilized.
3044- let layout = Layout :: from_size_align ( size, align) . or ( Err ( AllocError ) ) ?;
3045-
3046- let ptr = if layout. size ( ) != 0 {
3047- // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
3048- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3049- let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) } ;
3050- match NonNull :: new ( ptr) {
3051- Some ( ptr) => ptr,
3052- None => return Err ( AllocError ) ,
3053- }
3054- } else {
3055- // We use `transmute` instead of an `as` cast since Miri (with
3056- // strict provenance enabled) notices and complains that an `as`
3057- // cast creates a pointer with no provenance. Miri isn't smart
3058- // enough to realize that we're only executing this branch when
3059- // we're constructing a zero-sized `Box`, which doesn't require
3060- // provenance.
3061- //
3062- // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`.
3063- // All bits of a `usize` are initialized.
3064- #[ allow( clippy:: useless_transmute) ]
3065- let dangling = unsafe { mem:: transmute :: < usize , * mut u8 > ( align) } ;
3066- // SAFETY: `dangling` is constructed from `Self::LAYOUT.align`,
3067- // which is a `NonZeroUsize`, which is guaranteed to be non-zero.
3068- //
3069- // `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
3070- // is zero, but it does require a non-null dangling pointer for its
3071- // allocation.
3072- //
3073- // TODO(https://github.com/rust-lang/rust/issues/95228): Use
3074- // `std::ptr::without_provenance` once it's stable. That may
3075- // optimize better. As written, Rust may assume that this consumes
3076- // "exposed" provenance, and thus Rust may have to assume that this
3077- // may consume provenance from any pointer whose provenance has been
3078- // exposed.
3079- unsafe { NonNull :: new_unchecked ( dangling) }
3080- } ;
3081-
3082- let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
3083-
3084- // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure
3085- // to include a justification that `ptr.as_ptr()` is validly-aligned in
3086- // the ZST case (in which we manually construct a dangling pointer).
3087- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3088- Ok ( unsafe { Box :: from_raw ( ptr. as_ptr ( ) ) } )
3090+ // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of
3091+ // `new_box`. The referent of the pointer returned by `alloc_zeroed`
3092+ // (and, consequently, the `Box` derived from it) is a valid instance of
3093+ // `Self`, because `Self` is `FromZeros`.
3094+ unsafe { crate :: util:: new_box ( count, alloc:: alloc:: alloc_zeroed) }
30893095 }
30903096
30913097 /// Creates a `Vec<Self>` from zeroed bytes.
@@ -4532,7 +4538,7 @@ pub unsafe trait FromBytes: FromZeros {
45324538 Self : Sized ,
45334539 R : io:: Read ,
45344540 {
4535- let mut buf = MaybeUninit :: < Self > :: zeroed ( ) ;
4541+ let mut buf = CoreMaybeUninit :: < Self > :: zeroed ( ) ;
45364542 let ptr = Ptr :: from_mut ( & mut buf) ;
45374543 // SAFETY: `buf` consists entirely of initialized, zeroed bytes.
45384544 let ptr = unsafe { ptr. assume_validity :: < invariant:: Initialized > ( ) } ;
0 commit comments