@@ -957,6 +957,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
957
957
mode : CItemKind ,
958
958
}
959
959
960
+ /// Accumulator for recursive ffi type checking
961
+ struct CTypesVisitorState < ' tcx > {
962
+ cache : FxHashSet < Ty < ' tcx > > ,
963
+ /// The original type being checked, before we recursed
964
+ /// to any other types it contains.
965
+ base_ty : Ty < ' tcx > ,
966
+ }
967
+
960
968
enum FfiResult < ' tcx > {
961
969
FfiSafe ,
962
970
FfiPhantom ( Ty < ' tcx > ) ,
@@ -1143,7 +1151,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1143
1151
/// Checks if the given field's type is "ffi-safe".
1144
1152
fn check_field_type_for_ffi (
1145
1153
& self ,
1146
- cache : & mut FxHashSet < Ty < ' tcx > > ,
1154
+ acc : & mut CTypesVisitorState < ' tcx > ,
1147
1155
field : & ty:: FieldDef ,
1148
1156
args : GenericArgsRef < ' tcx > ,
1149
1157
) -> FfiResult < ' tcx > {
@@ -1153,13 +1161,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1153
1161
. tcx
1154
1162
. try_normalize_erasing_regions ( self . cx . param_env , field_ty)
1155
1163
. unwrap_or ( field_ty) ;
1156
- self . check_type_for_ffi ( cache , field_ty)
1164
+ self . check_type_for_ffi ( acc , field_ty)
1157
1165
}
1158
1166
1159
1167
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
1160
1168
fn check_variant_for_ffi (
1161
1169
& self ,
1162
- cache : & mut FxHashSet < Ty < ' tcx > > ,
1170
+ acc : & mut CTypesVisitorState < ' tcx > ,
1163
1171
ty : Ty < ' tcx > ,
1164
1172
def : ty:: AdtDef < ' tcx > ,
1165
1173
variant : & ty:: VariantDef ,
@@ -1170,7 +1178,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1170
1178
let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
1171
1179
if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
1172
1180
// Transparent newtypes have at most one non-ZST field which needs to be checked..
1173
- match self . check_field_type_for_ffi ( cache , field, args) {
1181
+ match self . check_field_type_for_ffi ( acc , field, args) {
1174
1182
FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
1175
1183
r => return r,
1176
1184
}
@@ -1188,7 +1196,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1188
1196
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
1189
1197
let mut all_phantom = !variant. fields . is_empty ( ) ;
1190
1198
for field in & variant. fields {
1191
- all_phantom &= match self . check_field_type_for_ffi ( cache , field, args) {
1199
+ all_phantom &= match self . check_field_type_for_ffi ( acc , field, args) {
1192
1200
FfiSafe => false ,
1193
1201
// `()` fields are FFI-safe!
1194
1202
FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
@@ -1208,7 +1216,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1208
1216
1209
1217
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
1210
1218
/// representation which can be exported to C code).
1211
- fn check_type_for_ffi ( & self , cache : & mut FxHashSet < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1219
+ fn check_type_for_ffi (
1220
+ & self ,
1221
+ acc : & mut CTypesVisitorState < ' tcx > ,
1222
+ ty : Ty < ' tcx > ,
1223
+ ) -> FfiResult < ' tcx > {
1212
1224
use FfiResult :: * ;
1213
1225
1214
1226
let tcx = self . cx . tcx ;
@@ -1217,7 +1229,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1217
1229
// `struct S(*mut S);`.
1218
1230
// FIXME: A recursion limit is necessary as well, for irregular
1219
1231
// recursive types.
1220
- if !cache. insert ( ty) {
1232
+ if !acc . cache . insert ( ty) {
1221
1233
return FfiSafe ;
1222
1234
}
1223
1235
@@ -1239,6 +1251,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1239
1251
}
1240
1252
match def. adt_kind ( ) {
1241
1253
AdtKind :: Struct | AdtKind :: Union => {
1254
+ if let Some ( sym:: cstring_type | sym:: cstr_type) =
1255
+ tcx. get_diagnostic_name ( def. did ( ) )
1256
+ && !acc. base_ty . is_mutable_ptr ( )
1257
+ {
1258
+ return FfiUnsafe {
1259
+ ty,
1260
+ reason : fluent:: lint_improper_ctypes_cstr_reason,
1261
+ help : Some ( fluent:: lint_improper_ctypes_cstr_help) ,
1262
+ } ;
1263
+ }
1264
+
1242
1265
if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
1243
1266
return FfiUnsafe {
1244
1267
ty,
@@ -1285,7 +1308,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1285
1308
} ;
1286
1309
}
1287
1310
1288
- self . check_variant_for_ffi ( cache , ty, def, def. non_enum_variant ( ) , args)
1311
+ self . check_variant_for_ffi ( acc , ty, def, def. non_enum_variant ( ) , args)
1289
1312
}
1290
1313
AdtKind :: Enum => {
1291
1314
if def. variants ( ) . is_empty ( ) {
@@ -1328,7 +1351,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1328
1351
} ;
1329
1352
}
1330
1353
1331
- match self . check_variant_for_ffi ( cache , ty, def, variant, args) {
1354
+ match self . check_variant_for_ffi ( acc , ty, def, variant, args) {
1332
1355
FfiSafe => ( ) ,
1333
1356
r => return r,
1334
1357
}
@@ -1392,9 +1415,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1392
1415
FfiSafe
1393
1416
}
1394
1417
1395
- ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( cache , ty) ,
1418
+ ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( acc , ty) ,
1396
1419
1397
- ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache , inner_ty) ,
1420
+ ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc , inner_ty) ,
1398
1421
1399
1422
ty:: FnPtr ( sig) => {
1400
1423
if self . is_internal_abi ( sig. abi ( ) ) {
@@ -1407,7 +1430,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1407
1430
1408
1431
let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
1409
1432
for arg in sig. inputs ( ) {
1410
- match self . check_type_for_ffi ( cache , * arg) {
1433
+ match self . check_type_for_ffi ( acc , * arg) {
1411
1434
FfiSafe => { }
1412
1435
r => return r,
1413
1436
}
@@ -1418,7 +1441,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1418
1441
return FfiSafe ;
1419
1442
}
1420
1443
1421
- self . check_type_for_ffi ( cache , ret_ty)
1444
+ self . check_type_for_ffi ( acc , ret_ty)
1422
1445
}
1423
1446
1424
1447
ty:: Foreign ( ..) => FfiSafe ,
@@ -1541,7 +1564,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1541
1564
return ;
1542
1565
}
1543
1566
1544
- match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
1567
+ let mut acc = CTypesVisitorState { cache : FxHashSet :: default ( ) , base_ty : ty } ;
1568
+ match self . check_type_for_ffi ( & mut acc, ty) {
1545
1569
FfiResult :: FfiSafe => { }
1546
1570
FfiResult :: FfiPhantom ( ty) => {
1547
1571
self . emit_ffi_unsafe_type_lint (
0 commit comments