@@ -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 ,
@@ -732,6 +732,15 @@ pub unsafe trait KnownLayout {
732732 /// This is `()` for sized types and `usize` for slice DSTs.
733733 type PointerMetadata : PointerMetadata ;
734734
735+ /// A maybe-uninitialized analog of `Self`
736+ ///
737+ /// # Safety
738+ ///
739+ /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical.
740+ /// `Self::MaybeUninit` admits uninitialized bytes in all positions.
741+ #[ doc( hidden) ]
742+ type MaybeUninit : ?Sized + KnownLayout < PointerMetadata = Self :: PointerMetadata > ;
743+
735744 /// The layout of `Self`.
736745 ///
737746 /// # Safety
@@ -864,6 +873,35 @@ unsafe impl<T> KnownLayout for [T] {
864873
865874 type PointerMetadata = usize ;
866875
876+ // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are identical
877+ // because `CoreMaybeUninit<T>` has the same size and alignment as `T` [1].
878+ // Consequently, `[CoreMaybeUninit<T>]::LAYOUT` and `[T]::LAYOUT` are
879+ // identical, because they both lack a fixed-sized prefix and because they
880+ // inherit the alignments of their inner element type (which are identical)
881+ // [2][3].
882+ //
883+ // `[CoreMaybeUninit<T>]` admits uninitialized bytes at all positions
884+ // because `CoreMaybeUninit<T>` admits uninitialized bytes at all positions
885+ // and because the inner elements of `[CoreMaybeUninit<T>]` are laid out
886+ // back-to-back [2][3].
887+ //
888+ // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
889+ //
890+ // `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
891+ // `T`
892+ //
893+ // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout:
894+ //
895+ // Slices have the same layout as the section of the array they slice.
896+ //
897+ // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout:
898+ //
899+ // An array of `[T; N]` has a size of `size_of::<T>() * N` and the same
900+ // alignment of `T`. Arrays are laid out so that the zero-based `nth`
901+ // element of the array is offset from the start of the array by `n *
902+ // size_of::<T>()` bytes.
903+ type MaybeUninit = [ CoreMaybeUninit < T > ] ;
904+
867905 const LAYOUT : DstLayout = DstLayout :: for_slice :: < T > ( ) ;
868906
869907 // SAFETY: `.cast` preserves address and provenance. The returned pointer
@@ -916,9 +954,11 @@ impl_known_layout!(
916954 T => Option <T >,
917955 T : ?Sized => PhantomData <T >,
918956 T => Wrapping <T >,
919- T => MaybeUninit <T >,
957+ T => CoreMaybeUninit <T >,
920958 T : ?Sized => * const T ,
921- T : ?Sized => * mut T
959+ T : ?Sized => * mut T ,
960+ T : ?Sized => & ' _ T ,
961+ T : ?Sized => & ' _ mut T ,
922962) ;
923963impl_known_layout ! ( const N : usize , T => [ T ; N ] ) ;
924964
@@ -949,6 +989,21 @@ safety_comment! {
949989 unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T ) ] UnsafeCell <T >) ;
950990}
951991
992+ safety_comment ! {
993+ /// SAFETY:
994+ /// - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT`
995+ /// and `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit`
996+ /// have the same:
997+ /// - Fixed prefix size
998+ /// - Alignment
999+ /// - (For DSTs) trailing slice element size
1000+ /// - By consequence of the above, referents `T::MaybeUninit` and `T` have
1001+ /// the require the same kind of pointer metadata, and thus it is valid to
1002+ /// perform an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this
1003+ /// operation preserves referent size (ie, `size_of_val_raw`).
1004+ unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T :: MaybeUninit ) ] MaybeUninit <T >) ;
1005+ }
1006+
9521007/// Analyzes whether a type is [`FromZeros`].
9531008///
9541009/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -2550,7 +2605,7 @@ pub unsafe trait TryFromBytes {
25502605 where
25512606 Self : Sized ,
25522607 {
2553- let candidate = match MaybeUninit :: < Self > :: read_from_bytes ( source) {
2608+ let candidate = match CoreMaybeUninit :: < Self > :: read_from_bytes ( source) {
25542609 Ok ( candidate) => candidate,
25552610 Err ( e) => {
25562611 return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2611,7 +2666,7 @@ pub unsafe trait TryFromBytes {
26112666 where
26122667 Self : Sized ,
26132668 {
2614- let ( candidate, suffix) = match MaybeUninit :: < Self > :: read_from_prefix ( source) {
2669+ let ( candidate, suffix) = match CoreMaybeUninit :: < Self > :: read_from_prefix ( source) {
26152670 Ok ( candidate) => candidate,
26162671 Err ( e) => {
26172672 return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2673,7 +2728,7 @@ pub unsafe trait TryFromBytes {
26732728 where
26742729 Self : Sized ,
26752730 {
2676- let ( prefix, candidate) = match MaybeUninit :: < Self > :: read_from_suffix ( source) {
2731+ let ( prefix, candidate) = match CoreMaybeUninit :: < Self > :: read_from_suffix ( source) {
26772732 Ok ( candidate) => candidate,
26782733 Err ( e) => {
26792734 return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2746,7 +2801,7 @@ fn swap<T, U>((t, u): (T, U)) -> (U, T) {
27462801#[ inline( always) ]
27472802unsafe fn try_read_from < S , T : TryFromBytes > (
27482803 source : S ,
2749- mut candidate : MaybeUninit < T > ,
2804+ mut candidate : CoreMaybeUninit < T > ,
27502805) -> Result < T , TryReadError < S , T > > {
27512806 // We use `from_mut` despite not mutating via `c_ptr` so that we don't need
27522807 // to add a `T: Immutable` bound.
@@ -3035,72 +3090,11 @@ pub unsafe trait FromZeros: TryFromBytes {
30353090 where
30363091 Self : KnownLayout < PointerMetadata = usize > ,
30373092 {
3038- let size = match count. size_for_metadata ( Self :: LAYOUT ) {
3039- Some ( size) => size,
3040- None => return Err ( AllocError ) ,
3041- } ;
3042-
3043- let align = Self :: LAYOUT . align . get ( ) ;
3044- // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
3045- // bug in which sufficiently-large allocations (those which, when
3046- // rounded up to the alignment, overflow `isize`) are not rejected,
3047- // which can cause undefined behavior. See #64 for details.
3048- //
3049- // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
3050- #[ allow( clippy:: as_conversions) ]
3051- let max_alloc = ( isize:: MAX as usize ) . saturating_sub ( align) ;
3052- if size > max_alloc {
3053- return Err ( AllocError ) ;
3054- }
3055-
3056- // TODO(https://github.com/rust-lang/rust/issues/55724): Use
3057- // `Layout::repeat` once it's stabilized.
3058- let layout = Layout :: from_size_align ( size, align) . or ( Err ( AllocError ) ) ?;
3059-
3060- let ptr = if layout. size ( ) != 0 {
3061- // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
3062- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3063- let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) } ;
3064- match NonNull :: new ( ptr) {
3065- Some ( ptr) => ptr,
3066- None => return Err ( AllocError ) ,
3067- }
3068- } else {
3069- let align = Self :: LAYOUT . align . get ( ) ;
3070- // We use `transmute` instead of an `as` cast since Miri (with
3071- // strict provenance enabled) notices and complains that an `as`
3072- // cast creates a pointer with no provenance. Miri isn't smart
3073- // enough to realize that we're only executing this branch when
3074- // we're constructing a zero-sized `Box`, which doesn't require
3075- // provenance.
3076- //
3077- // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`.
3078- // All bits of a `usize` are initialized.
3079- #[ allow( clippy:: useless_transmute) ]
3080- let dangling = unsafe { mem:: transmute :: < usize , * mut u8 > ( align) } ;
3081- // SAFETY: `dangling` is constructed from `Self::LAYOUT.align`,
3082- // which is a `NonZeroUsize`, which is guaranteed to be non-zero.
3083- //
3084- // `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
3085- // is zero, but it does require a non-null dangling pointer for its
3086- // allocation.
3087- //
3088- // TODO(https://github.com/rust-lang/rust/issues/95228): Use
3089- // `std::ptr::without_provenance` once it's stable. That may
3090- // optimize better. As written, Rust may assume that this consumes
3091- // "exposed" provenance, and thus Rust may have to assume that this
3092- // may consume provenance from any pointer whose provenance has been
3093- // exposed.
3094- unsafe { NonNull :: new_unchecked ( dangling) }
3095- } ;
3096-
3097- let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
3098-
3099- // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure
3100- // to include a justification that `ptr.as_ptr()` is validly-aligned in
3101- // the ZST case (in which we manually construct a dangling pointer).
3102- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3103- Ok ( unsafe { Box :: from_raw ( ptr. as_ptr ( ) ) } )
3093+ // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of
3094+ // `new_box`. The referent of the pointer returned by `alloc_zeroed`
3095+ // (and, consequently, the `Box` derived from it) is a valid instance of
3096+ // `Self`, because `Self` is `FromZeros`.
3097+ unsafe { crate :: util:: new_box ( count, alloc:: alloc:: alloc_zeroed) }
31043098 }
31053099
31063100 #[ deprecated( since = "0.8.0" , note = "renamed to `FromZeros::new_box_zeroed_with_elems`" ) ]
@@ -4562,7 +4556,7 @@ pub unsafe trait FromBytes: FromZeros {
45624556 Self : Sized ,
45634557 R : io:: Read ,
45644558 {
4565- let mut buf = MaybeUninit :: < Self > :: zeroed ( ) ;
4559+ let mut buf = CoreMaybeUninit :: < Self > :: zeroed ( ) ;
45664560 let ptr = Ptr :: from_mut ( & mut buf) ;
45674561 // SAFETY: `buf` consists entirely of initialized, zeroed bytes.
45684562 let ptr = unsafe { ptr. assume_validity :: < invariant:: Initialized > ( ) } ;
0 commit comments