@@ -11,7 +11,7 @@ use rustc_index::vec::Idx;
1111use rustc_middle:: mir:: interpret:: { sign_extend, truncate} ;
1212use rustc_middle:: ty:: layout:: { IntegerExt , SizeSkeleton } ;
1313use rustc_middle:: ty:: subst:: SubstsRef ;
14- use rustc_middle:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt } ;
14+ use rustc_middle:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
1515use rustc_span:: source_map;
1616use rustc_span:: symbol:: sym;
1717use rustc_span:: Span ;
@@ -597,6 +597,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
597597 }
598598 }
599599
600+ /// Checks if the given field's type is "ffi-safe".
601+ fn check_field_type_for_ffi (
602+ & self ,
603+ cache : & mut FxHashSet < Ty < ' tcx > > ,
604+ field : & ty:: FieldDef ,
605+ substs : SubstsRef < ' tcx > ,
606+ ) -> FfiResult < ' tcx > {
607+ let field_ty = field. ty ( self . cx . tcx , substs) ;
608+ if field_ty. has_opaque_types ( ) {
609+ self . check_type_for_ffi ( cache, field_ty)
610+ } else {
611+ let field_ty = self . cx . tcx . normalize_erasing_regions ( self . cx . param_env , field_ty) ;
612+ self . check_type_for_ffi ( cache, field_ty)
613+ }
614+ }
615+
600616 /// Checks if the given type is "ffi-safe" (has a stable, well-defined
601617 /// representation which can be exported to C code).
602618 fn check_type_for_ffi ( & self , cache : & mut FxHashSet < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
@@ -654,11 +670,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
654670 if let Some ( field) =
655671 def. transparent_newtype_field ( cx, self . cx . param_env )
656672 {
657- let field_ty = cx. normalize_erasing_regions (
658- self . cx . param_env ,
659- field. ty ( cx, substs) ,
660- ) ;
661- self . check_type_for_ffi ( cache, field_ty)
673+ self . check_field_type_for_ffi ( cache, field, substs)
662674 } else {
663675 FfiSafe
664676 }
@@ -667,11 +679,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
667679 // actually safe.
668680 let mut all_phantom = true ;
669681 for field in & def. non_enum_variant ( ) . fields {
670- let field_ty = cx. normalize_erasing_regions (
671- self . cx . param_env ,
672- field. ty ( cx, substs) ,
673- ) ;
674- let r = self . check_type_for_ffi ( cache, field_ty) ;
682+ let r = self . check_field_type_for_ffi ( cache, field, substs) ;
675683 match r {
676684 FfiSafe => {
677685 all_phantom = false ;
@@ -886,6 +894,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
886894
887895 ty:: Foreign ( ..) => FfiSafe ,
888896
897+ // While opaque types are checked for earlier, if a projection in a struct field
898+ // normalizes to an opaque type, then it will reach this branch.
899+ ty:: Opaque ( ..) => {
900+ FfiUnsafe { ty, reason : "opaque types have no C equivalent" , help : None }
901+ }
902+
889903 ty:: Param ( ..)
890904 | ty:: Infer ( ..)
891905 | ty:: Bound ( ..)
@@ -895,7 +909,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
895909 | ty:: GeneratorWitness ( ..)
896910 | ty:: Placeholder ( ..)
897911 | ty:: Projection ( ..)
898- | ty:: Opaque ( ..)
899912 | ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
900913 }
901914 }
@@ -925,8 +938,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
925938 }
926939
927940 fn check_for_opaque_ty ( & mut self , sp : Span , ty : Ty < ' tcx > ) -> bool {
928- use rustc_middle:: ty:: TypeFoldable ;
929-
930941 struct ProhibitOpaqueTypes < ' tcx > {
931942 ty : Option < Ty < ' tcx > > ,
932943 } ;
0 commit comments