@@ -354,7 +354,7 @@ use core::{
354
354
fmt:: { self , Debug , Display , Formatter } ,
355
355
hash:: Hasher ,
356
356
marker:: PhantomData ,
357
- mem:: { self , ManuallyDrop , MaybeUninit } ,
357
+ mem:: { self , ManuallyDrop , MaybeUninit as CoreMaybeUninit } ,
358
358
num:: {
359
359
NonZeroI128 , NonZeroI16 , NonZeroI32 , NonZeroI64 , NonZeroI8 , NonZeroIsize , NonZeroU128 ,
360
360
NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
@@ -711,6 +711,15 @@ pub unsafe trait KnownLayout {
711
711
/// This is `()` for sized types and `usize` for slice DSTs.
712
712
type PointerMetadata : PointerMetadata ;
713
713
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
+
714
723
/// The layout of `Self`.
715
724
///
716
725
/// # Safety
@@ -843,6 +852,35 @@ unsafe impl<T> KnownLayout for [T] {
843
852
844
853
type PointerMetadata = usize ;
845
854
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
+
846
884
const LAYOUT : DstLayout = DstLayout :: for_slice :: < T > ( ) ;
847
885
848
886
// SAFETY: `.cast` preserves address and provenance. The returned pointer
@@ -895,9 +933,11 @@ impl_known_layout!(
895
933
T => Option <T >,
896
934
T : ?Sized => PhantomData <T >,
897
935
T => Wrapping <T >,
898
- T => MaybeUninit <T >,
936
+ T => CoreMaybeUninit <T >,
899
937
T : ?Sized => * const T ,
900
- T : ?Sized => * mut T
938
+ T : ?Sized => * mut T ,
939
+ T : ?Sized => & ' _ T ,
940
+ T : ?Sized => & ' _ mut T ,
901
941
) ;
902
942
impl_known_layout ! ( const N : usize , T => [ T ; N ] ) ;
903
943
@@ -928,6 +968,21 @@ safety_comment! {
928
968
unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T ) ] UnsafeCell <T >) ;
929
969
}
930
970
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
+
931
986
/// Analyzes whether a type is [`FromZeros`].
932
987
///
933
988
/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -2547,7 +2602,7 @@ pub unsafe trait TryFromBytes {
2547
2602
where
2548
2603
Self : Sized ,
2549
2604
{
2550
- let candidate = match MaybeUninit :: < Self > :: read_from_bytes ( source) {
2605
+ let candidate = match CoreMaybeUninit :: < Self > :: read_from_bytes ( source) {
2551
2606
Ok ( candidate) => candidate,
2552
2607
Err ( e) => {
2553
2608
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2608,7 +2663,7 @@ pub unsafe trait TryFromBytes {
2608
2663
where
2609
2664
Self : Sized ,
2610
2665
{
2611
- let ( candidate, suffix) = match MaybeUninit :: < Self > :: read_from_prefix ( source) {
2666
+ let ( candidate, suffix) = match CoreMaybeUninit :: < Self > :: read_from_prefix ( source) {
2612
2667
Ok ( candidate) => candidate,
2613
2668
Err ( e) => {
2614
2669
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2670,7 +2725,7 @@ pub unsafe trait TryFromBytes {
2670
2725
where
2671
2726
Self : Sized ,
2672
2727
{
2673
- let ( prefix, candidate) = match MaybeUninit :: < Self > :: read_from_suffix ( source) {
2728
+ let ( prefix, candidate) = match CoreMaybeUninit :: < Self > :: read_from_suffix ( source) {
2674
2729
Ok ( candidate) => candidate,
2675
2730
Err ( e) => {
2676
2731
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2743,7 +2798,7 @@ fn swap<T, U>((t, u): (T, U)) -> (U, T) {
2743
2798
#[ inline( always) ]
2744
2799
unsafe fn try_read_from < S , T : TryFromBytes > (
2745
2800
source : S ,
2746
- mut candidate : MaybeUninit < T > ,
2801
+ mut candidate : CoreMaybeUninit < T > ,
2747
2802
) -> Result < T , TryReadError < S , T > > {
2748
2803
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
2749
2804
// to add a `T: Immutable` bound.
@@ -3032,60 +3087,11 @@ pub unsafe trait FromZeros: TryFromBytes {
3032
3087
where
3033
3088
Self : KnownLayout < PointerMetadata = usize > ,
3034
3089
{
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) }
3089
3095
}
3090
3096
3091
3097
/// Creates a `Vec<Self>` from zeroed bytes.
@@ -4532,7 +4538,7 @@ pub unsafe trait FromBytes: FromZeros {
4532
4538
Self : Sized ,
4533
4539
R : io:: Read ,
4534
4540
{
4535
- let mut buf = MaybeUninit :: < Self > :: zeroed ( ) ;
4541
+ let mut buf = CoreMaybeUninit :: < Self > :: zeroed ( ) ;
4536
4542
let ptr = Ptr :: from_mut ( & mut buf) ;
4537
4543
// SAFETY: `buf` consists entirely of initialized, zeroed bytes.
4538
4544
let ptr = unsafe { ptr. assume_validity :: < invariant:: Initialized > ( ) } ;
0 commit comments