@@ -993,6 +993,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
993
993
mode : CItemKind ,
994
994
}
995
995
996
+ /// Accumulator for recursive ffi type checking
997
+ struct CTypesVisitorState < ' tcx > {
998
+ cache : FxHashSet < Ty < ' tcx > > ,
999
+ /// The original type being checked, before we recursed
1000
+ /// to any other types it contains.
1001
+ base_ty : Ty < ' tcx > ,
1002
+ }
1003
+
996
1004
enum FfiResult < ' tcx > {
997
1005
FfiSafe ,
998
1006
FfiPhantom ( Ty < ' tcx > ) ,
@@ -1179,7 +1187,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1179
1187
/// Checks if the given field's type is "ffi-safe".
1180
1188
fn check_field_type_for_ffi (
1181
1189
& self ,
1182
- cache : & mut FxHashSet < Ty < ' tcx > > ,
1190
+ acc : & mut CTypesVisitorState < ' tcx > ,
1183
1191
field : & ty:: FieldDef ,
1184
1192
args : GenericArgsRef < ' tcx > ,
1185
1193
) -> FfiResult < ' tcx > {
@@ -1189,13 +1197,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1189
1197
. tcx
1190
1198
. try_normalize_erasing_regions ( self . cx . param_env , field_ty)
1191
1199
. unwrap_or ( field_ty) ;
1192
- self . check_type_for_ffi ( cache , field_ty)
1200
+ self . check_type_for_ffi ( acc , field_ty)
1193
1201
}
1194
1202
1195
1203
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
1196
1204
fn check_variant_for_ffi (
1197
1205
& self ,
1198
- cache : & mut FxHashSet < Ty < ' tcx > > ,
1206
+ acc : & mut CTypesVisitorState < ' tcx > ,
1199
1207
ty : Ty < ' tcx > ,
1200
1208
def : ty:: AdtDef < ' tcx > ,
1201
1209
variant : & ty:: VariantDef ,
@@ -1206,7 +1214,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1206
1214
let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
1207
1215
if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
1208
1216
// Transparent newtypes have at most one non-ZST field which needs to be checked..
1209
- match self . check_field_type_for_ffi ( cache , field, args) {
1217
+ match self . check_field_type_for_ffi ( acc , field, args) {
1210
1218
FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
1211
1219
r => return r,
1212
1220
}
@@ -1224,7 +1232,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1224
1232
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
1225
1233
let mut all_phantom = !variant. fields . is_empty ( ) ;
1226
1234
for field in & variant. fields {
1227
- all_phantom &= match self . check_field_type_for_ffi ( cache , field, args) {
1235
+ all_phantom &= match self . check_field_type_for_ffi ( acc , field, args) {
1228
1236
FfiSafe => false ,
1229
1237
// `()` fields are FFI-safe!
1230
1238
FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
@@ -1244,7 +1252,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1244
1252
1245
1253
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
1246
1254
/// representation which can be exported to C code).
1247
- fn check_type_for_ffi ( & self , cache : & mut FxHashSet < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1255
+ fn check_type_for_ffi (
1256
+ & self ,
1257
+ acc : & mut CTypesVisitorState < ' tcx > ,
1258
+ ty : Ty < ' tcx > ,
1259
+ ) -> FfiResult < ' tcx > {
1248
1260
use FfiResult :: * ;
1249
1261
1250
1262
let tcx = self . cx . tcx ;
@@ -1253,7 +1265,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1253
1265
// `struct S(*mut S);`.
1254
1266
// FIXME: A recursion limit is necessary as well, for irregular
1255
1267
// recursive types.
1256
- if !cache. insert ( ty) {
1268
+ if !acc . cache . insert ( ty) {
1257
1269
return FfiSafe ;
1258
1270
}
1259
1271
@@ -1275,6 +1287,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1275
1287
}
1276
1288
match def. adt_kind ( ) {
1277
1289
AdtKind :: Struct | AdtKind :: Union => {
1290
+ if let Some ( sym:: cstring_type | sym:: cstr_type) =
1291
+ tcx. get_diagnostic_name ( def. did ( ) )
1292
+ && !acc. base_ty . is_mutable_ptr ( )
1293
+ {
1294
+ return FfiUnsafe {
1295
+ ty,
1296
+ reason : fluent:: lint_improper_ctypes_cstr_reason,
1297
+ help : Some ( fluent:: lint_improper_ctypes_cstr_help) ,
1298
+ } ;
1299
+ }
1300
+
1278
1301
if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
1279
1302
return FfiUnsafe {
1280
1303
ty,
@@ -1321,7 +1344,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1321
1344
} ;
1322
1345
}
1323
1346
1324
- self . check_variant_for_ffi ( cache , ty, def, def. non_enum_variant ( ) , args)
1347
+ self . check_variant_for_ffi ( acc , ty, def, def. non_enum_variant ( ) , args)
1325
1348
}
1326
1349
AdtKind :: Enum => {
1327
1350
if def. variants ( ) . is_empty ( ) {
@@ -1364,7 +1387,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1364
1387
} ;
1365
1388
}
1366
1389
1367
- match self . check_variant_for_ffi ( cache , ty, def, variant, args) {
1390
+ match self . check_variant_for_ffi ( acc , ty, def, variant, args) {
1368
1391
FfiSafe => ( ) ,
1369
1392
r => return r,
1370
1393
}
@@ -1434,9 +1457,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1434
1457
FfiSafe
1435
1458
}
1436
1459
1437
- ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( cache , ty) ,
1460
+ ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( acc , ty) ,
1438
1461
1439
- ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache , inner_ty) ,
1462
+ ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc , inner_ty) ,
1440
1463
1441
1464
ty:: FnPtr ( sig) => {
1442
1465
if self . is_internal_abi ( sig. abi ( ) ) {
@@ -1449,7 +1472,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1449
1472
1450
1473
let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
1451
1474
for arg in sig. inputs ( ) {
1452
- match self . check_type_for_ffi ( cache , * arg) {
1475
+ match self . check_type_for_ffi ( acc , * arg) {
1453
1476
FfiSafe => { }
1454
1477
r => return r,
1455
1478
}
@@ -1460,7 +1483,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1460
1483
return FfiSafe ;
1461
1484
}
1462
1485
1463
- self . check_type_for_ffi ( cache , ret_ty)
1486
+ self . check_type_for_ffi ( acc , ret_ty)
1464
1487
}
1465
1488
1466
1489
ty:: Foreign ( ..) => FfiSafe ,
@@ -1583,7 +1606,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1583
1606
return ;
1584
1607
}
1585
1608
1586
- match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
1609
+ let mut acc = CTypesVisitorState { cache : FxHashSet :: default ( ) , base_ty : ty } ;
1610
+ match self . check_type_for_ffi ( & mut acc, ty) {
1587
1611
FfiResult :: FfiSafe => { }
1588
1612
FfiResult :: FfiPhantom ( ty) => {
1589
1613
self . emit_ffi_unsafe_type_lint (
0 commit comments