@@ -1004,6 +1004,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> {
10041004 }
10051005}
10061006
1007+ /// Trait for context types that can compute layouts of things.
10071008pub trait LayoutOf {
10081009 type Ty ;
10091010 type TyLayout ;
@@ -1014,6 +1015,39 @@ pub trait LayoutOf {
10141015 }
10151016}
10161017
1018+ /// The `TyLayout` above will always be a `MaybeResult<TyLayout<'_, Self>>`.
1019+ /// We can't add the bound due to the lifetime, but this trait is still useful when
1020+ /// writing code that's generic over the `LayoutOf` impl.
1021+ pub trait MaybeResult < T > {
1022+ type Error ;
1023+
1024+ fn from ( x : Result < T , Self :: Error > ) -> Self ;
1025+ fn to_result ( self ) -> Result < T , Self :: Error > ;
1026+ }
1027+
1028+ impl < T > MaybeResult < T > for T {
1029+ type Error = !;
1030+
1031+ fn from ( x : Result < T , Self :: Error > ) -> Self {
1032+ let Ok ( x) = x;
1033+ x
1034+ }
1035+ fn to_result ( self ) -> Result < T , Self :: Error > {
1036+ Ok ( self )
1037+ }
1038+ }
1039+
1040+ impl < T , E > MaybeResult < T > for Result < T , E > {
1041+ type Error = E ;
1042+
1043+ fn from ( x : Result < T , Self :: Error > ) -> Self {
1044+ x
1045+ }
1046+ fn to_result ( self ) -> Result < T , Self :: Error > {
1047+ self
1048+ }
1049+ }
1050+
10171051#[ derive( Copy , Clone , PartialEq , Eq ) ]
10181052pub enum PointerKind {
10191053 /// Most general case, we know no restrictions to tell LLVM.
@@ -1055,10 +1089,14 @@ impl<'a, Ty> TyLayout<'a, Ty> {
10551089 where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
10561090 Ty :: for_variant ( self , cx, variant_index)
10571091 }
1092+
1093+ /// Callers might want to use `C: LayoutOf<Ty=Ty, TyLayout: MaybeResult<Self>>`
1094+ /// to allow recursion (see `might_permit_zero_init` below for an example).
10581095 pub fn field < C > ( self , cx : & C , i : usize ) -> C :: TyLayout
10591096 where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
10601097 Ty :: field ( self , cx, i)
10611098 }
1099+
10621100 pub fn pointee_info_at < C > ( self , cx : & C , offset : Size ) -> Option < PointeeInfo >
10631101 where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
10641102 Ty :: pointee_info_at ( self , cx, offset)
@@ -1081,4 +1119,57 @@ impl<'a, Ty> TyLayout<'a, Ty> {
10811119 Abi :: Aggregate { sized } => sized && self . size . bytes ( ) == 0
10821120 }
10831121 }
1122+
1123+ /// Determines if zero-initializing this type might be okay.
1124+ /// This is conservative: in doubt, it will answer `true`.
1125+ pub fn might_permit_zero_init < C , E > (
1126+ & self ,
1127+ cx : & C ,
1128+ ) -> Result < bool , E >
1129+ where
1130+ Self : Copy ,
1131+ Ty : TyLayoutMethods < ' a , C > ,
1132+ C : LayoutOf < Ty = Ty , TyLayout : MaybeResult < Self , Error = E > >
1133+ {
1134+ fn scalar_allows_zero ( s : & Scalar ) -> bool {
1135+ ( * s. valid_range . start ( ) <= 0 ) || // `&& *s.valid_range.end() >= 0` would be redundant
1136+ ( * s. valid_range . start ( ) > * s. valid_range . end ( ) ) // wrap-around allows 0
1137+ }
1138+
1139+ // Abi is the most informative here.
1140+ let res = match & self . abi {
1141+ Abi :: Uninhabited => false , // definitely UB
1142+ Abi :: Scalar ( s) => scalar_allows_zero ( s) ,
1143+ Abi :: ScalarPair ( s1, s2) =>
1144+ scalar_allows_zero ( s1) && scalar_allows_zero ( s2) ,
1145+ Abi :: Vector { element : s, count } =>
1146+ * count == 0 || scalar_allows_zero ( s) ,
1147+ Abi :: Aggregate { .. } => {
1148+ // For aggregates, recurse.
1149+ let inner = match self . variants {
1150+ Variants :: Multiple { .. } => // FIXME: get variant with "0" discriminant.
1151+ return Ok ( true ) ,
1152+ Variants :: Single { index } => self . for_variant ( & cx, index) ,
1153+ } ;
1154+
1155+ match inner. fields {
1156+ FieldPlacement :: Union ( ..) => true , // An all-0 unit is fine.
1157+ FieldPlacement :: Array { .. } =>
1158+ // FIXME: The widely use smallvec 0.6 creates uninit arrays
1159+ // with any element type, so let us not (yet) complain about that.
1160+ // count == 0 || inner.field(cx, 0).to_result()?.might_permit_zero_init(cx)?
1161+ true ,
1162+ FieldPlacement :: Arbitrary { ref offsets, .. } =>
1163+ // Check that all fields accept zero-init.
1164+ ( 0 ..offsets. len ( ) ) . try_fold ( true , |accu, idx|
1165+ Ok ( accu &&
1166+ inner. field ( cx, idx) . to_result ( ) ?. might_permit_zero_init ( cx) ?
1167+ )
1168+ ) ?
1169+ }
1170+ }
1171+ } ;
1172+ trace ! ( "might_permit_zero_init({:?}) = {}" , self . details, res) ;
1173+ Ok ( res)
1174+ }
10841175}
0 commit comments