@@ -919,6 +919,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> {
919
919
}
920
920
}
921
921
922
+ /// Trait for context types that can compute layouts of things.
922
923
pub trait LayoutOf {
923
924
type Ty ;
924
925
type TyLayout ;
@@ -929,6 +930,39 @@ pub trait LayoutOf {
929
930
}
930
931
}
931
932
933
+ /// The `TyLayout` above will always be a `MaybeResult<TyLayout<'_, Self>>`.
934
+ /// We can't add the bound due to the lifetime, but this trait is still useful when
935
+ /// writing code that's generic over the `LayoutOf` impl.
936
+ pub trait MaybeResult < T > {
937
+ type Error ;
938
+
939
+ fn from ( x : Result < T , Self :: Error > ) -> Self ;
940
+ fn to_result ( self ) -> Result < T , Self :: Error > ;
941
+ }
942
+
943
+ impl < T > MaybeResult < T > for T {
944
+ type Error = !;
945
+
946
+ fn from ( x : Result < T , Self :: Error > ) -> Self {
947
+ let Ok ( x) = x;
948
+ x
949
+ }
950
+ fn to_result ( self ) -> Result < T , Self :: Error > {
951
+ Ok ( self )
952
+ }
953
+ }
954
+
955
+ impl < T , E > MaybeResult < T > for Result < T , E > {
956
+ type Error = E ;
957
+
958
+ fn from ( x : Result < T , Self :: Error > ) -> Self {
959
+ x
960
+ }
961
+ fn to_result ( self ) -> Result < T , Self :: Error > {
962
+ self
963
+ }
964
+ }
965
+
932
966
#[ derive( Copy , Clone , PartialEq , Eq ) ]
933
967
pub enum PointerKind {
934
968
/// Most general case, we know no restrictions to tell LLVM.
@@ -969,13 +1003,17 @@ impl<'a, Ty> TyLayout<'a, Ty> {
969
1003
{
970
1004
Ty :: for_variant ( self , cx, variant_index)
971
1005
}
1006
+
1007
+ /// Callers might want to use `C: LayoutOf<Ty=Ty, TyLayout: MaybeResult<Self>>`
1008
+ /// to allow recursion (see `might_permit_zero_init` below for an example).
972
1009
pub fn field < C > ( self , cx : & C , i : usize ) -> C :: TyLayout
973
1010
where
974
1011
Ty : TyLayoutMethods < ' a , C > ,
975
1012
C : LayoutOf < Ty = Ty > ,
976
1013
{
977
1014
Ty :: field ( self , cx, i)
978
1015
}
1016
+
979
1017
pub fn pointee_info_at < C > ( self , cx : & C , offset : Size ) -> Option < PointeeInfo >
980
1018
where
981
1019
Ty : TyLayoutMethods < ' a , C > ,
@@ -999,4 +1037,93 @@ impl<'a, Ty> TyLayout<'a, Ty> {
999
1037
Abi :: Aggregate { sized } => sized && self . size . bytes ( ) == 0 ,
1000
1038
}
1001
1039
}
1040
+
1041
+ /// Determines if this type permits "raw" initialization by just transmuting some
1042
+ /// memory into an instance of `T`.
1043
+ /// `zero` indicates if the memory is zero-initialized, or alternatively
1044
+ /// left entirely uninitialized.
1045
+ /// This is conservative: in doubt, it will answer `true`.
1046
+ ///
1047
+ /// FIXME: Once we removed all the conservatism, we could alternatively
1048
+ /// create an all-0/all-undef constant and run the vonst value validator to see if
1049
+ /// this is a valid value for the given type.
1050
+ pub fn might_permit_raw_init < C , E > (
1051
+ self ,
1052
+ cx : & C ,
1053
+ zero : bool ,
1054
+ ) -> Result < bool , E >
1055
+ where
1056
+ Self : Copy ,
1057
+ Ty : TyLayoutMethods < ' a , C > ,
1058
+ C : LayoutOf < Ty = Ty , TyLayout : MaybeResult < Self , Error = E > > + HasDataLayout
1059
+ {
1060
+ let scalar_allows_raw_init = move |s : & Scalar | -> bool {
1061
+ if zero {
1062
+ let range = & s. valid_range ;
1063
+ // The range must contain 0.
1064
+ range. contains ( & 0 ) ||
1065
+ ( * range. start ( ) > * range. end ( ) ) // wrap-around allows 0
1066
+ } else {
1067
+ // The range must include all values. `valid_range_exclusive` handles
1068
+ // the wrap-around using target arithmetic; with wrap-around then the full
1069
+ // range is one where `start == end`.
1070
+ let range = s. valid_range_exclusive ( cx) ;
1071
+ range. start == range. end
1072
+ }
1073
+ } ;
1074
+
1075
+ // Abi is the most informative here.
1076
+ let res = match & self . abi {
1077
+ Abi :: Uninhabited => false , // definitely UB
1078
+ Abi :: Scalar ( s) => scalar_allows_raw_init ( s) ,
1079
+ Abi :: ScalarPair ( s1, s2) =>
1080
+ scalar_allows_raw_init ( s1) && scalar_allows_raw_init ( s2) ,
1081
+ Abi :: Vector { element : s, count } =>
1082
+ * count == 0 || scalar_allows_raw_init ( s) ,
1083
+ Abi :: Aggregate { .. } => {
1084
+ match self . variants {
1085
+ Variants :: Multiple { .. } =>
1086
+ if zero {
1087
+ // FIXME(#66151):
1088
+ // could we identify the variant with discriminant 0, check that?
1089
+ true
1090
+ } else {
1091
+ // FIXME(#66151): This needs to have some sort of discriminant,
1092
+ // which cannot be undef. But for now we are conservative.
1093
+ true
1094
+ } ,
1095
+ Variants :: Single { .. } => {
1096
+ // For aggregates, recurse.
1097
+ match self . fields {
1098
+ FieldPlacement :: Union ( ..) => true , // An all-0 unit is fine.
1099
+ FieldPlacement :: Array { .. } =>
1100
+ // FIXME(#66151): The widely use smallvec 0.6 creates uninit arrays
1101
+ // with any element type, so let us not (yet) complain about that.
1102
+ /* count == 0 ||
1103
+ self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)? */
1104
+ true ,
1105
+ FieldPlacement :: Arbitrary { .. } => {
1106
+ // FIXME(#66151) cargo depends on sized-chunks 0.3.0 which
1107
+ // has some illegal zero-initialization, so let us not (yet)
1108
+ // complain about aggregates either.
1109
+ /* let mut res = true;
1110
+ // Check that all fields accept zero-init.
1111
+ for idx in 0..offsets.len() {
1112
+ let field = self.field(cx, idx).to_result()?;
1113
+ if !field.might_permit_raw_init(cx, zero)? {
1114
+ res = false;
1115
+ break;
1116
+ }
1117
+ }
1118
+ res */
1119
+ true
1120
+ }
1121
+ }
1122
+ }
1123
+ }
1124
+ }
1125
+ } ;
1126
+ trace ! ( "might_permit_raw_init({:?}, zero={}) = {}" , self . details, zero, res) ;
1127
+ Ok ( res)
1128
+ }
1002
1129
}
0 commit comments