@@ -963,12 +963,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
963963 substs : SubstsRef < ' tcx > ,
964964 ) -> FfiResult < ' tcx > {
965965 let field_ty = field. ty ( self . cx . tcx , substs) ;
966- if field_ty. has_opaque_types ( ) {
967- self . check_type_for_ffi ( cache , field_ty )
968- } else {
969- let field_ty = self . cx . tcx . normalize_erasing_regions ( self . cx . param_env , field_ty) ;
970- self . check_type_for_ffi ( cache , field_ty)
971- }
966+ let field_ty = self
967+ . cx
968+ . tcx
969+ . try_normalize_erasing_regions ( self . cx . param_env , field_ty)
970+ . unwrap_or ( field_ty) ;
971+ self . check_type_for_ffi ( cache , field_ty )
972972 }
973973
974974 /// Checks if the given `VariantDef`'s field types are "ffi-safe".
@@ -982,39 +982,43 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
982982 ) -> FfiResult < ' tcx > {
983983 use FfiResult :: * ;
984984
985- let transparent_safety = def. repr ( ) . transparent ( ) . then ( || {
986- // Can assume that at most one field is not a ZST, so only check
987- // that field's type for FFI-safety.
985+ let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
988986 if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
989- return self . check_field_type_for_ffi ( cache, field, substs) ;
987+ // Transparent newtypes have at most one non-ZST field which needs to be checked..
988+ match self . check_field_type_for_ffi ( cache, field, substs) {
989+ FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
990+ r => return r,
991+ }
992+
993+ false
990994 } else {
991- // All fields are ZSTs; this means that the type should behave
992- // like (), which is FFI-unsafe... except if all fields are PhantomData,
993- // which is tested for below
994- FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_struct_zst, help : None }
995+ // ..or have only ZST fields, which is FFI-unsafe (unless those fields are all
996+ // `PhantomData`).
997+ true
995998 }
996- } ) ;
997- // We can't completely trust repr(C) markings; make sure the fields are
998- // actually safe.
999+ } else {
1000+ false
1001+ } ;
1002+
1003+ // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
9991004 let mut all_phantom = !variant. fields . is_empty ( ) ;
10001005 for field in & variant. fields {
1001- match self . check_field_type_for_ffi ( cache, & field, substs) {
1002- FfiSafe => {
1003- all_phantom = false ;
1004- }
1005- FfiPhantom ( ..) if !def. repr ( ) . transparent ( ) && def. is_enum ( ) => {
1006- return FfiUnsafe {
1007- ty,
1008- reason : fluent:: lint_improper_ctypes_enum_phantomdata,
1009- help : None ,
1010- } ;
1011- }
1012- FfiPhantom ( ..) => { }
1013- r => return transparent_safety. unwrap_or ( r) ,
1006+ all_phantom &= match self . check_field_type_for_ffi ( cache, & field, substs) {
1007+ FfiSafe => false ,
1008+ // `()` fields are FFI-safe!
1009+ FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
1010+ FfiPhantom ( ..) => true ,
1011+ r @ FfiUnsafe { .. } => return r,
10141012 }
10151013 }
10161014
1017- if all_phantom { FfiPhantom ( ty) } else { transparent_safety. unwrap_or ( FfiSafe ) }
1015+ if all_phantom {
1016+ FfiPhantom ( ty)
1017+ } else if transparent_with_all_zst_fields {
1018+ FfiUnsafe { ty, reason : fluent:: lint_improper_ctypes_struct_zst, help : None }
1019+ } else {
1020+ FfiSafe
1021+ }
10181022 }
10191023
10201024 /// Checks if the given type is "ffi-safe" (has a stable, well-defined
@@ -1217,25 +1221,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12171221 }
12181222
12191223 let sig = tcx. erase_late_bound_regions ( sig) ;
1220- if !sig. output ( ) . is_unit ( ) {
1221- let r = self . check_type_for_ffi ( cache, sig. output ( ) ) ;
1222- match r {
1223- FfiSafe => { }
1224- _ => {
1225- return r;
1226- }
1227- }
1228- }
12291224 for arg in sig. inputs ( ) {
1230- let r = self . check_type_for_ffi ( cache, * arg) ;
1231- match r {
1225+ match self . check_type_for_ffi ( cache, * arg) {
12321226 FfiSafe => { }
1233- _ => {
1234- return r;
1235- }
1227+ r => return r,
12361228 }
12371229 }
1238- FfiSafe
1230+
1231+ let ret_ty = sig. output ( ) ;
1232+ if ret_ty. is_unit ( ) {
1233+ return FfiSafe ;
1234+ }
1235+
1236+ self . check_type_for_ffi ( cache, ret_ty)
12391237 }
12401238
12411239 ty:: Foreign ( ..) => FfiSafe ,
@@ -1317,7 +1315,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13171315 if let Some ( ty) = self
13181316 . cx
13191317 . tcx
1320- . normalize_erasing_regions ( self . cx . param_env , ty)
1318+ . try_normalize_erasing_regions ( self . cx . param_env , ty)
1319+ . unwrap_or ( ty)
13211320 . visit_with ( & mut ProhibitOpaqueTypes )
13221321 . break_value ( )
13231322 {
@@ -1335,16 +1334,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13351334 is_static : bool ,
13361335 is_return_type : bool ,
13371336 ) {
1338- // We have to check for opaque types before `normalize_erasing_regions`,
1339- // which will replace opaque types with their underlying concrete type.
13401337 if self . check_for_opaque_ty ( sp, ty) {
13411338 // We've already emitted an error due to an opaque type.
13421339 return ;
13431340 }
13441341
1345- // it is only OK to use this function because extern fns cannot have
1346- // any generic types right now:
1347- let ty = self . cx . tcx . normalize_erasing_regions ( self . cx . param_env , ty) ;
1342+ let ty = self . cx . tcx . try_normalize_erasing_regions ( self . cx . param_env , ty) . unwrap_or ( ty) ;
13481343
13491344 // C doesn't really support passing arrays by value - the only way to pass an array by value
13501345 // is through a struct. So, first test that the top level isn't an array, and then
@@ -1354,7 +1349,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13541349 }
13551350
13561351 // Don't report FFI errors for unit return types. This check exists here, and not in
1357- // `check_foreign_fn` (where it would make more sense) so that normalization has definitely
1352+ // the caller (where it would make more sense) so that normalization has definitely
13581353 // happened.
13591354 if is_return_type && ty. is_unit ( ) {
13601355 return ;
@@ -1370,9 +1365,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13701365 None ,
13711366 ) ;
13721367 }
1373- // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
1374- // argument, which after substitution, is `()`, then this branch can be hit.
1375- FfiResult :: FfiUnsafe { ty, .. } if is_return_type && ty. is_unit ( ) => { }
13761368 FfiResult :: FfiUnsafe { ty, reason, help } => {
13771369 self . emit_ffi_unsafe_type_lint ( ty, sp, reason, help) ;
13781370 }
0 commit comments