@@ -984,6 +984,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
984
984
mode : CItemKind ,
985
985
}
986
986
987
+ /// Accumulator for recursive ffi type checking
988
+ struct CTypesVisitorState < ' tcx > {
989
+ cache : FxHashSet < Ty < ' tcx > > ,
990
+ /// The original type being checked, before we recursed
991
+ /// to any other types it contains.
992
+ base_ty : Ty < ' tcx > ,
993
+ }
994
+
987
995
enum FfiResult < ' tcx > {
988
996
FfiSafe ,
989
997
FfiPhantom ( Ty < ' tcx > ) ,
@@ -1212,7 +1220,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1212
1220
/// Checks if the given field's type is "ffi-safe".
1213
1221
fn check_field_type_for_ffi (
1214
1222
& self ,
1215
- cache : & mut FxHashSet < Ty < ' tcx > > ,
1223
+ acc : & mut CTypesVisitorState < ' tcx > ,
1216
1224
field : & ty:: FieldDef ,
1217
1225
args : GenericArgsRef < ' tcx > ,
1218
1226
) -> FfiResult < ' tcx > {
@@ -1222,13 +1230,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1222
1230
. tcx
1223
1231
. try_normalize_erasing_regions ( self . cx . param_env , field_ty)
1224
1232
. unwrap_or ( field_ty) ;
1225
- self . check_type_for_ffi ( cache , field_ty)
1233
+ self . check_type_for_ffi ( acc , field_ty)
1226
1234
}
1227
1235
1228
1236
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
1229
1237
fn check_variant_for_ffi (
1230
1238
& self ,
1231
- cache : & mut FxHashSet < Ty < ' tcx > > ,
1239
+ acc : & mut CTypesVisitorState < ' tcx > ,
1232
1240
ty : Ty < ' tcx > ,
1233
1241
def : ty:: AdtDef < ' tcx > ,
1234
1242
variant : & ty:: VariantDef ,
@@ -1238,7 +1246,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1238
1246
let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
1239
1247
if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
1240
1248
// Transparent newtypes have at most one non-ZST field which needs to be checked..
1241
- match self . check_field_type_for_ffi ( cache , field, args) {
1249
+ match self . check_field_type_for_ffi ( acc , field, args) {
1242
1250
FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
1243
1251
r => return r,
1244
1252
}
@@ -1256,7 +1264,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1256
1264
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
1257
1265
let mut all_phantom = !variant. fields . is_empty ( ) ;
1258
1266
for field in & variant. fields {
1259
- all_phantom &= match self . check_field_type_for_ffi ( cache , field, args) {
1267
+ all_phantom &= match self . check_field_type_for_ffi ( acc , field, args) {
1260
1268
FfiSafe => false ,
1261
1269
// `()` fields are FFI-safe!
1262
1270
FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
@@ -1276,7 +1284,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1276
1284
1277
1285
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
1278
1286
/// representation which can be exported to C code).
1279
- fn check_type_for_ffi ( & self , cache : & mut FxHashSet < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1287
+ fn check_type_for_ffi (
1288
+ & self ,
1289
+ acc : & mut CTypesVisitorState < ' tcx > ,
1290
+ ty : Ty < ' tcx > ,
1291
+ ) -> FfiResult < ' tcx > {
1280
1292
use FfiResult :: * ;
1281
1293
1282
1294
let tcx = self . cx . tcx ;
@@ -1285,7 +1297,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1285
1297
// `struct S(*mut S);`.
1286
1298
// FIXME: A recursion limit is necessary as well, for irregular
1287
1299
// recursive types.
1288
- if !cache. insert ( ty) {
1300
+ if !acc . cache . insert ( ty) {
1289
1301
return FfiSafe ;
1290
1302
}
1291
1303
@@ -1307,6 +1319,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1307
1319
}
1308
1320
match def. adt_kind ( ) {
1309
1321
AdtKind :: Struct | AdtKind :: Union => {
1322
+ if let Some ( sym:: cstring_type | sym:: cstr_type) =
1323
+ tcx. get_diagnostic_name ( def. did ( ) )
1324
+ && !acc. base_ty . is_mutable_ptr ( )
1325
+ {
1326
+ return FfiUnsafe {
1327
+ ty,
1328
+ reason : fluent:: lint_improper_ctypes_cstr_reason,
1329
+ help : Some ( fluent:: lint_improper_ctypes_cstr_help) ,
1330
+ } ;
1331
+ }
1332
+
1310
1333
if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
1311
1334
return FfiUnsafe {
1312
1335
ty,
@@ -1353,7 +1376,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1353
1376
} ;
1354
1377
}
1355
1378
1356
- self . check_variant_for_ffi ( cache , ty, def, def. non_enum_variant ( ) , args)
1379
+ self . check_variant_for_ffi ( acc , ty, def, def. non_enum_variant ( ) , args)
1357
1380
}
1358
1381
AdtKind :: Enum => {
1359
1382
if def. variants ( ) . is_empty ( ) {
@@ -1377,7 +1400,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1377
1400
if let Some ( ty) =
1378
1401
repr_nullable_ptr ( self . cx . tcx , self . cx . param_env , ty, self . mode )
1379
1402
{
1380
- return self . check_type_for_ffi ( cache , ty) ;
1403
+ return self . check_type_for_ffi ( acc , ty) ;
1381
1404
}
1382
1405
1383
1406
return FfiUnsafe {
@@ -1398,7 +1421,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1398
1421
} ;
1399
1422
}
1400
1423
1401
- match self . check_variant_for_ffi ( cache , ty, def, variant, args) {
1424
+ match self . check_variant_for_ffi ( acc , ty, def, variant, args) {
1402
1425
FfiSafe => ( ) ,
1403
1426
r => return r,
1404
1427
}
@@ -1468,9 +1491,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1468
1491
FfiSafe
1469
1492
}
1470
1493
1471
- ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( cache , ty) ,
1494
+ ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( acc , ty) ,
1472
1495
1473
- ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache , inner_ty) ,
1496
+ ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc , inner_ty) ,
1474
1497
1475
1498
ty:: FnPtr ( sig) => {
1476
1499
if self . is_internal_abi ( sig. abi ( ) ) {
@@ -1483,7 +1506,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1483
1506
1484
1507
let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
1485
1508
for arg in sig. inputs ( ) {
1486
- match self . check_type_for_ffi ( cache , * arg) {
1509
+ match self . check_type_for_ffi ( acc , * arg) {
1487
1510
FfiSafe => { }
1488
1511
r => return r,
1489
1512
}
@@ -1494,7 +1517,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1494
1517
return FfiSafe ;
1495
1518
}
1496
1519
1497
- self . check_type_for_ffi ( cache , ret_ty)
1520
+ self . check_type_for_ffi ( acc , ret_ty)
1498
1521
}
1499
1522
1500
1523
ty:: Foreign ( ..) => FfiSafe ,
@@ -1617,7 +1640,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1617
1640
return ;
1618
1641
}
1619
1642
1620
- match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
1643
+ let mut acc = CTypesVisitorState { cache : FxHashSet :: default ( ) , base_ty : ty } ;
1644
+ match self . check_type_for_ffi ( & mut acc, ty) {
1621
1645
FfiResult :: FfiSafe => { }
1622
1646
FfiResult :: FfiPhantom ( ty) => {
1623
1647
self . emit_ffi_unsafe_type_lint (
0 commit comments