@@ -1004,6 +1004,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> {
1004
1004
}
1005
1005
}
1006
1006
1007
+ /// Trait for context types that can compute layouts of things.
1007
1008
pub trait LayoutOf {
1008
1009
type Ty ;
1009
1010
type TyLayout ;
@@ -1014,6 +1015,39 @@ pub trait LayoutOf {
1014
1015
}
1015
1016
}
1016
1017
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
+
1017
1051
#[ derive( Copy , Clone , PartialEq , Eq ) ]
1018
1052
pub enum PointerKind {
1019
1053
/// Most general case, we know no restrictions to tell LLVM.
@@ -1055,10 +1089,14 @@ impl<'a, Ty> TyLayout<'a, Ty> {
1055
1089
where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
1056
1090
Ty :: for_variant ( self , cx, variant_index)
1057
1091
}
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).
1058
1095
pub fn field < C > ( self , cx : & C , i : usize ) -> C :: TyLayout
1059
1096
where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
1060
1097
Ty :: field ( self , cx, i)
1061
1098
}
1099
+
1062
1100
pub fn pointee_info_at < C > ( self , cx : & C , offset : Size ) -> Option < PointeeInfo >
1063
1101
where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
1064
1102
Ty :: pointee_info_at ( self , cx, offset)
@@ -1081,4 +1119,57 @@ impl<'a, Ty> TyLayout<'a, Ty> {
1081
1119
Abi :: Aggregate { sized } => sized && self . size . bytes ( ) == 0
1082
1120
}
1083
1121
}
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
+ }
1084
1175
}
0 commit comments