@@ -960,6 +960,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> {
960
960
}
961
961
}
962
962
963
+ /// Trait for context types that can compute layouts of things.
963
964
pub trait LayoutOf {
964
965
type Ty ;
965
966
type TyLayout ;
@@ -970,6 +971,39 @@ pub trait LayoutOf {
970
971
}
971
972
}
972
973
974
+ /// The `TyLayout` above will always be a `MaybeResult<TyLayout<'_, Self>>`.
975
+ /// We can't add the bound due to the lifetime, but this trait is still useful when
976
+ /// writing code that's generic over the `LayoutOf` impl.
977
+ pub trait MaybeResult < T > {
978
+ type Error ;
979
+
980
+ fn from ( x : Result < T , Self :: Error > ) -> Self ;
981
+ fn to_result ( self ) -> Result < T , Self :: Error > ;
982
+ }
983
+
984
+ impl < T > MaybeResult < T > for T {
985
+ type Error = !;
986
+
987
+ fn from ( x : Result < T , Self :: Error > ) -> Self {
988
+ let Ok ( x) = x;
989
+ x
990
+ }
991
+ fn to_result ( self ) -> Result < T , Self :: Error > {
992
+ Ok ( self )
993
+ }
994
+ }
995
+
996
+ impl < T , E > MaybeResult < T > for Result < T , E > {
997
+ type Error = E ;
998
+
999
+ fn from ( x : Result < T , Self :: Error > ) -> Self {
1000
+ x
1001
+ }
1002
+ fn to_result ( self ) -> Result < T , Self :: Error > {
1003
+ self
1004
+ }
1005
+ }
1006
+
973
1007
#[ derive( Copy , Clone , PartialEq , Eq ) ]
974
1008
pub enum PointerKind {
975
1009
/// Most general case, we know no restrictions to tell LLVM.
@@ -1011,10 +1045,14 @@ impl<'a, Ty> TyLayout<'a, Ty> {
1011
1045
where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
1012
1046
Ty :: for_variant ( self , cx, variant_index)
1013
1047
}
1048
+
1049
+ /// Callers might want to use `C: LayoutOf<Ty=Ty, TyLayout: MaybeResult<Self>>`
1050
+ /// to allow recursion (see `might_permit_zero_init` below for an example).
1014
1051
pub fn field < C > ( self , cx : & C , i : usize ) -> C :: TyLayout
1015
1052
where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
1016
1053
Ty :: field ( self , cx, i)
1017
1054
}
1055
+
1018
1056
pub fn pointee_info_at < C > ( self , cx : & C , offset : Size ) -> Option < PointeeInfo >
1019
1057
where Ty : TyLayoutMethods < ' a , C > , C : LayoutOf < Ty = Ty > {
1020
1058
Ty :: pointee_info_at ( self , cx, offset)
@@ -1037,4 +1075,85 @@ impl<'a, Ty> TyLayout<'a, Ty> {
1037
1075
Abi :: Aggregate { sized } => sized && self . size . bytes ( ) == 0
1038
1076
}
1039
1077
}
1078
+
1079
+ /// Determines if this type permits "raw" initialization by just transmuting some
1080
+ /// memory into an instance of `T`.
1081
+ /// `zero` indicates if the memory is zero-initialized, or alternatively
1082
+ /// left entirely uninitialized.
1083
+ /// This is conservative: in doubt, it will answer `true`.
1084
+ pub fn might_permit_raw_init < C , E > (
1085
+ self ,
1086
+ cx : & C ,
1087
+ zero : bool ,
1088
+ ) -> Result < bool , E >
1089
+ where
1090
+ Self : Copy ,
1091
+ Ty : TyLayoutMethods < ' a , C > ,
1092
+ C : LayoutOf < Ty = Ty , TyLayout : MaybeResult < Self , Error = E > > + HasDataLayout
1093
+ {
1094
+ let scalar_allows_raw_init = move |s : & Scalar | -> bool {
1095
+ if zero {
1096
+ let range = & s. valid_range ;
1097
+ // The range must contain 0.
1098
+ range. contains ( & 0 ) ||
1099
+ ( * range. start ( ) > * range. end ( ) ) // wrap-around allows 0
1100
+ } else {
1101
+ // The range must include all values. `valid_range_exclusive` handles
1102
+ // the wrap-around using target arithmetic; with wrap-around then the full
1103
+ // range is one where `start == end`.
1104
+ let range = s. valid_range_exclusive ( cx) ;
1105
+ range. start == range. end
1106
+ }
1107
+ } ;
1108
+
1109
+ // Abi is the most informative here.
1110
+ let res = match & self . abi {
1111
+ Abi :: Uninhabited => false , // definitely UB
1112
+ Abi :: Scalar ( s) => scalar_allows_raw_init ( s) ,
1113
+ Abi :: ScalarPair ( s1, s2) =>
1114
+ scalar_allows_raw_init ( s1) && scalar_allows_raw_init ( s2) ,
1115
+ Abi :: Vector { element : s, count } =>
1116
+ * count == 0 || scalar_allows_raw_init ( s) ,
1117
+ Abi :: Aggregate { .. } => {
1118
+ match self . variants {
1119
+ Variants :: Multiple { .. } =>
1120
+ if zero {
1121
+ // FIXME(#66151):
1122
+ // could we identify the variant with discriminant 0, check that?
1123
+ true
1124
+ } else {
1125
+ // FIXME(#66151): This needs to have some sort of discriminant,
1126
+ // which cannot be undef. But for now we are conservative.
1127
+ true
1128
+ } ,
1129
+ Variants :: Single { .. } => {
1130
+ // For aggregates, recurse.
1131
+ match self . fields {
1132
+ FieldPlacement :: Union ( ..) => true , // An all-0 unit is fine.
1133
+ FieldPlacement :: Array { .. } =>
1134
+ // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
1135
+ // with any element type, so let us not (yet) complain about that.
1136
+ // count == 0 ||
1137
+ // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)?
1138
+ true ,
1139
+ FieldPlacement :: Arbitrary { ref offsets, .. } => {
1140
+ let mut res = true ;
1141
+ // Check that all fields accept zero-init.
1142
+ for idx in 0 ..offsets. len ( ) {
1143
+ let field = self . field ( cx, idx) . to_result ( ) ?;
1144
+ if !field. might_permit_raw_init ( cx, zero) ? {
1145
+ res = false ;
1146
+ break ;
1147
+ }
1148
+ }
1149
+ res
1150
+ }
1151
+ }
1152
+ }
1153
+ }
1154
+ }
1155
+ } ;
1156
+ trace ! ( "might_permit_raw_init({:?}, zero={}) = {}" , self . details, zero, res) ;
1157
+ Ok ( res)
1158
+ }
1040
1159
}
0 commit comments