@@ -963,12 +963,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
963
963
substs : SubstsRef < ' tcx > ,
964
964
) -> FfiResult < ' tcx > {
965
965
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 )
972
972
}
973
973
974
974
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
@@ -982,39 +982,43 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
982
982
) -> FfiResult < ' tcx > {
983
983
use FfiResult :: * ;
984
984
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 ( ) {
988
986
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
990
994
} 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
995
998
}
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.
999
1004
let mut all_phantom = !variant. fields . is_empty ( ) ;
1000
1005
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,
1014
1012
}
1015
1013
}
1016
1014
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
+ }
1018
1022
}
1019
1023
1020
1024
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
@@ -1217,25 +1221,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1217
1221
}
1218
1222
1219
1223
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
- }
1229
1224
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) {
1232
1226
FfiSafe => { }
1233
- _ => {
1234
- return r;
1235
- }
1227
+ r => return r,
1236
1228
}
1237
1229
}
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)
1239
1237
}
1240
1238
1241
1239
ty:: Foreign ( ..) => FfiSafe ,
@@ -1317,7 +1315,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1317
1315
if let Some ( ty) = self
1318
1316
. cx
1319
1317
. tcx
1320
- . normalize_erasing_regions ( self . cx . param_env , ty)
1318
+ . try_normalize_erasing_regions ( self . cx . param_env , ty)
1319
+ . unwrap_or ( ty)
1321
1320
. visit_with ( & mut ProhibitOpaqueTypes )
1322
1321
. break_value ( )
1323
1322
{
@@ -1335,16 +1334,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1335
1334
is_static : bool ,
1336
1335
is_return_type : bool ,
1337
1336
) {
1338
- // We have to check for opaque types before `normalize_erasing_regions`,
1339
- // which will replace opaque types with their underlying concrete type.
1340
1337
if self . check_for_opaque_ty ( sp, ty) {
1341
1338
// We've already emitted an error due to an opaque type.
1342
1339
return ;
1343
1340
}
1344
1341
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) ;
1348
1343
1349
1344
// C doesn't really support passing arrays by value - the only way to pass an array by value
1350
1345
// 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> {
1354
1349
}
1355
1350
1356
1351
// 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
1358
1353
// happened.
1359
1354
if is_return_type && ty. is_unit ( ) {
1360
1355
return ;
@@ -1370,9 +1365,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1370
1365
None ,
1371
1366
) ;
1372
1367
}
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 ( ) => { }
1376
1368
FfiResult :: FfiUnsafe { ty, reason, help } => {
1377
1369
self . emit_ffi_unsafe_type_lint ( ty, sp, reason, help) ;
1378
1370
}
0 commit comments