@@ -349,7 +349,7 @@ use core::{
349
349
fmt:: { self , Debug , Display , Formatter } ,
350
350
hash:: Hasher ,
351
351
marker:: PhantomData ,
352
- mem:: { self , ManuallyDrop , MaybeUninit } ,
352
+ mem:: { self , ManuallyDrop , MaybeUninit as CoreMaybeUninit } ,
353
353
num:: {
354
354
NonZeroI128 , NonZeroI16 , NonZeroI32 , NonZeroI64 , NonZeroI8 , NonZeroIsize , NonZeroU128 ,
355
355
NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
@@ -727,6 +727,14 @@ pub unsafe trait KnownLayout {
727
727
/// This is `()` for sized types and `usize` for slice DSTs.
728
728
type PointerMetadata : PointerMetadata ;
729
729
730
+ /// A maybe-uninitialized analog of `Self`
731
+ ///
732
+ /// # Safety
733
+ ///
734
+ /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical.
735
+ #[ doc( hidden) ]
736
+ type MaybeUninit : ?Sized + KnownLayout < PointerMetadata = Self :: PointerMetadata > ;
737
+
730
738
/// The layout of `Self`.
731
739
///
732
740
/// # Safety
@@ -859,6 +867,35 @@ unsafe impl<T> KnownLayout for [T] {
859
867
860
868
type PointerMetadata = usize ;
861
869
870
+ // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are identical
871
+ // because `CoreMaybeUninit<T>` has the same size and alignment as `T` [1].
872
+ // Consequently, `[CoreMaybeUninit<T>]::LAYOUT` and `[T]::LAYOUT` are
873
+ // identical, because they both lack a fixed-sized prefix and because they
874
+ // inherit the alignments of their inner element type (which are identical)
875
+ // [2][3].
876
+ //
877
+ // `[CoreMaybeUninit<T>]` admits uninitialized bytes at all positions
878
+ // because `CoreMaybeUninit<T>` admits uninitialized bytes at all positions
879
+ // and because the inner elements of `[CoreMaybeUninit<T>]` are laid out
880
+ // back-to-back [2][3].
881
+ //
882
+ // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
883
+ //
884
+ // `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
885
+ // `T`
886
+ //
887
+ // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout:
888
+ //
889
+ // Slices have the same layout as the section of the array they slice.
890
+ //
891
+ // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout:
892
+ //
893
+ // An array of `[T; N]` has a size of `size_of::<T>() * N` and the same
894
+ // alignment of `T`. Arrays are laid out so that the zero-based `nth`
895
+ // element of the array is offset from the start of the array by `n *
896
+ // size_of::<T>()` bytes.
897
+ type MaybeUninit = [ CoreMaybeUninit < T > ] ;
898
+
862
899
const LAYOUT : DstLayout = DstLayout :: for_slice :: < T > ( ) ;
863
900
864
901
// SAFETY: `.cast` preserves address and provenance. The returned pointer
@@ -911,7 +948,7 @@ impl_known_layout!(
911
948
T => Option <T >,
912
949
T : ?Sized => PhantomData <T >,
913
950
T => Wrapping <T >,
914
- T => MaybeUninit <T >,
951
+ T => CoreMaybeUninit <T >,
915
952
T : ?Sized => * const T ,
916
953
T : ?Sized => * mut T
917
954
) ;
@@ -944,6 +981,21 @@ safety_comment! {
944
981
unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T ) ] UnsafeCell <T >) ;
945
982
}
946
983
984
+ safety_comment ! {
985
+ /// SAFETY:
986
+ /// - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT`
987
+ /// and `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit`
988
+ /// have the same:
989
+ /// - Fixed prefix size
990
+ /// - Alignment
991
+ /// - (For DSTs) trailing slice element size
992
+ /// - By consequence of the above, referents `T::MaybeUninit` and `T` have
993
+ /// the require the same kind of pointer metadata, and thus it is valid to
994
+ /// perform an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this
995
+ /// operation preserves referent size (ie, `size_of_val_raw`).
996
+ unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T :: MaybeUninit ) ] MaybeUninit <T >) ;
997
+ }
998
+
947
999
/// Analyzes whether a type is [`FromZeros`].
948
1000
///
949
1001
/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -2545,7 +2597,7 @@ pub unsafe trait TryFromBytes {
2545
2597
where
2546
2598
Self : Sized ,
2547
2599
{
2548
- let candidate = match MaybeUninit :: < Self > :: read_from_bytes ( source) {
2600
+ let candidate = match CoreMaybeUninit :: < Self > :: read_from_bytes ( source) {
2549
2601
Ok ( candidate) => candidate,
2550
2602
Err ( e) => {
2551
2603
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2606,7 +2658,7 @@ pub unsafe trait TryFromBytes {
2606
2658
where
2607
2659
Self : Sized ,
2608
2660
{
2609
- let ( candidate, suffix) = match MaybeUninit :: < Self > :: read_from_prefix ( source) {
2661
+ let ( candidate, suffix) = match CoreMaybeUninit :: < Self > :: read_from_prefix ( source) {
2610
2662
Ok ( candidate) => candidate,
2611
2663
Err ( e) => {
2612
2664
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2668,7 +2720,7 @@ pub unsafe trait TryFromBytes {
2668
2720
where
2669
2721
Self : Sized ,
2670
2722
{
2671
- let ( prefix, candidate) = match MaybeUninit :: < Self > :: read_from_suffix ( source) {
2723
+ let ( prefix, candidate) = match CoreMaybeUninit :: < Self > :: read_from_suffix ( source) {
2672
2724
Ok ( candidate) => candidate,
2673
2725
Err ( e) => {
2674
2726
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2741,7 +2793,7 @@ fn swap<T, U>((t, u): (T, U)) -> (U, T) {
2741
2793
#[ inline( always) ]
2742
2794
unsafe fn try_read_from < S , T : TryFromBytes > (
2743
2795
source : S ,
2744
- mut candidate : MaybeUninit < T > ,
2796
+ mut candidate : CoreMaybeUninit < T > ,
2745
2797
) -> Result < T , TryReadError < S , T > > {
2746
2798
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
2747
2799
// to add a `T: Immutable` bound.
@@ -3030,72 +3082,9 @@ pub unsafe trait FromZeros: TryFromBytes {
3030
3082
where
3031
3083
Self : KnownLayout < PointerMetadata = usize > ,
3032
3084
{
3033
- let size = match count. size_for_metadata ( Self :: LAYOUT ) {
3034
- Some ( size) => size,
3035
- None => return Err ( AllocError ) ,
3036
- } ;
3037
-
3038
- let align = Self :: LAYOUT . align . get ( ) ;
3039
- // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
3040
- // bug in which sufficiently-large allocations (those which, when
3041
- // rounded up to the alignment, overflow `isize`) are not rejected,
3042
- // which can cause undefined behavior. See #64 for details.
3043
- //
3044
- // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
3045
- #[ allow( clippy:: as_conversions) ]
3046
- let max_alloc = ( isize:: MAX as usize ) . saturating_sub ( align) ;
3047
- if size > max_alloc {
3048
- return Err ( AllocError ) ;
3049
- }
3050
-
3051
- // TODO(https://github.com/rust-lang/rust/issues/55724): Use
3052
- // `Layout::repeat` once it's stabilized.
3053
- let layout = Layout :: from_size_align ( size, align) . or ( Err ( AllocError ) ) ?;
3054
-
3055
- let ptr = if layout. size ( ) != 0 {
3056
- // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
3057
- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3058
- let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) } ;
3059
- match NonNull :: new ( ptr) {
3060
- Some ( ptr) => ptr,
3061
- None => return Err ( AllocError ) ,
3062
- }
3063
- } else {
3064
- let align = Self :: LAYOUT . align . get ( ) ;
3065
- // We use `transmute` instead of an `as` cast since Miri (with
3066
- // strict provenance enabled) notices and complains that an `as`
3067
- // cast creates a pointer with no provenance. Miri isn't smart
3068
- // enough to realize that we're only executing this branch when
3069
- // we're constructing a zero-sized `Box`, which doesn't require
3070
- // provenance.
3071
- //
3072
- // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`.
3073
- // All bits of a `usize` are initialized.
3074
- #[ allow( clippy:: useless_transmute) ]
3075
- let dangling = unsafe { mem:: transmute :: < usize , * mut u8 > ( align) } ;
3076
- // SAFETY: `dangling` is constructed from `Self::LAYOUT.align`,
3077
- // which is a `NonZeroUsize`, which is guaranteed to be non-zero.
3078
- //
3079
- // `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
3080
- // is zero, but it does require a non-null dangling pointer for its
3081
- // allocation.
3082
- //
3083
- // TODO(https://github.com/rust-lang/rust/issues/95228): Use
3084
- // `std::ptr::without_provenance` once it's stable. That may
3085
- // optimize better. As written, Rust may assume that this consumes
3086
- // "exposed" provenance, and thus Rust may have to assume that this
3087
- // may consume provenance from any pointer whose provenance has been
3088
- // exposed.
3089
- unsafe { NonNull :: new_unchecked ( dangling) }
3090
- } ;
3091
-
3092
- let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
3093
-
3094
- // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure
3095
- // to include a justification that `ptr.as_ptr()` is validly-aligned in
3096
- // the ZST case (in which we manually construct a dangling pointer).
3097
- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3098
- Ok ( unsafe { Box :: from_raw ( ptr. as_ptr ( ) ) } )
3085
+ // SAFETY: The referent of the pointer returned by `alloc_zeroed` is a
3086
+ // valid instance of `Self`, because `Self` is `FromZeros`.
3087
+ unsafe { crate :: util:: new_box ( count, alloc:: alloc:: alloc_zeroed) }
3099
3088
}
3100
3089
3101
3090
#[ deprecated( since = "0.8.0" , note = "renamed to `FromZeros::new_box_zeroed_with_elems`" ) ]
@@ -4557,7 +4546,7 @@ pub unsafe trait FromBytes: FromZeros {
4557
4546
Self : Sized ,
4558
4547
R : io:: Read ,
4559
4548
{
4560
- let mut buf = MaybeUninit :: < Self > :: zeroed ( ) ;
4549
+ let mut buf = CoreMaybeUninit :: < Self > :: zeroed ( ) ;
4561
4550
let ptr = Ptr :: from_mut ( & mut buf) ;
4562
4551
// SAFETY: `buf` consists entirely of initialized, zeroed bytes.
4563
4552
let ptr = unsafe { ptr. assume_validity :: < invariant:: Initialized > ( ) } ;
0 commit comments