@@ -919,6 +919,7 @@ impl<'a, Ty> Deref for TyLayout<'a, Ty> {
919919 }
920920}
921921
922+ /// Trait for context types that can compute layouts of things.
922923pub trait LayoutOf {
923924 type Ty ;
924925 type TyLayout ;
@@ -929,6 +930,39 @@ pub trait LayoutOf {
929930 }
930931}
931932
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+
932966#[ derive( Copy , Clone , PartialEq , Eq ) ]
933967pub enum PointerKind {
934968 /// Most general case, we know no restrictions to tell LLVM.
@@ -969,13 +1003,17 @@ impl<'a, Ty> TyLayout<'a, Ty> {
9691003 {
9701004 Ty :: for_variant ( self , cx, variant_index)
9711005 }
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).
9721009 pub fn field < C > ( self , cx : & C , i : usize ) -> C :: TyLayout
9731010 where
9741011 Ty : TyLayoutMethods < ' a , C > ,
9751012 C : LayoutOf < Ty = Ty > ,
9761013 {
9771014 Ty :: field ( self , cx, i)
9781015 }
1016+
9791017 pub fn pointee_info_at < C > ( self , cx : & C , offset : Size ) -> Option < PointeeInfo >
9801018 where
9811019 Ty : TyLayoutMethods < ' a , C > ,
@@ -999,4 +1037,81 @@ impl<'a, Ty> TyLayout<'a, Ty> {
9991037 Abi :: Aggregate { sized } => sized && self . size . bytes ( ) == 0 ,
10001038 }
10011039 }
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+ pub fn might_permit_raw_init < C , E > (
1047+ self ,
1048+ cx : & C ,
1049+ zero : bool ,
1050+ ) -> Result < bool , E >
1051+ where
1052+ Self : Copy ,
1053+ Ty : TyLayoutMethods < ' a , C > ,
1054+ C : LayoutOf < Ty = Ty , TyLayout : MaybeResult < Self , Error = E > >
1055+ {
1056+ let scalar_allows_raw_init = move |s : & Scalar | -> bool {
1057+ let range = & s. valid_range ;
1058+ if zero {
1059+ // The range must contain 0.
1060+ range. contains ( & 0 ) ||
1061+ ( * range. start ( ) > * range. end ( ) ) // wrap-around allows 0
1062+ } else {
1063+ // The range must include all values.
1064+ * range. start ( ) == range. end ( ) . wrapping_add ( 1 )
1065+ }
1066+ } ;
1067+
1068+ // Abi is the most informative here.
1069+ let res = match & self . abi {
1070+ Abi :: Uninhabited => false , // definitely UB
1071+ Abi :: Scalar ( s) => scalar_allows_raw_init ( s) ,
1072+ Abi :: ScalarPair ( s1, s2) =>
1073+ scalar_allows_raw_init ( s1) && scalar_allows_raw_init ( s2) ,
1074+ Abi :: Vector { element : s, count } =>
1075+ * count == 0 || scalar_allows_raw_init ( s) ,
1076+ Abi :: Aggregate { .. } => {
1077+ match self . variants {
1078+ Variants :: Multiple { .. } =>
1079+ if zero {
1080+ // FIXME: could we identify the variant with discriminant 0, check that?
1081+ true
1082+ } else {
1083+ // FIXME: This needs to have some sort of discriminant,
1084+ // which cannot be undef. But for now we are conservative.
1085+ true
1086+ } ,
1087+ Variants :: Single { .. } => {
1088+ // For aggregates, recurse.
1089+ match self . fields {
1090+ FieldPlacement :: Union ( ..) => true , // An all-0 unit is fine.
1091+ FieldPlacement :: Array { .. } =>
1092+ // FIXME: The widely use smallvec 0.6 creates uninit arrays
1093+ // with any element type, so let us not (yet) complain about that.
1094+ // count == 0 ||
1095+ // self.field(cx, 0).to_result()?.might_permit_raw_init(cx, zero)?
1096+ true ,
1097+ FieldPlacement :: Arbitrary { ref offsets, .. } => {
1098+ let mut res = true ;
1099+ // Check that all fields accept zero-init.
1100+ for idx in 0 ..offsets. len ( ) {
1101+ let field = self . field ( cx, idx) . to_result ( ) ?;
1102+ if !field. might_permit_raw_init ( cx, zero) ? {
1103+ res = false ;
1104+ break ;
1105+ }
1106+ }
1107+ res
1108+ }
1109+ }
1110+ }
1111+ }
1112+ }
1113+ } ;
1114+ trace ! ( "might_permit_raw_init({:?}, zero={}) = {}" , self . details, zero, res) ;
1115+ Ok ( res)
1116+ }
10021117}
0 commit comments