@@ -985,6 +985,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
985985 mode : CItemKind ,
986986}
987987
988+ /// Accumulator for recursive ffi type checking
989+ struct CTypesVisitorState < ' tcx > {
990+ cache : FxHashSet < Ty < ' tcx > > ,
991+ /// The original type being checked, before we recursed
992+ /// to any other types it contains.
993+ base_ty : Ty < ' tcx > ,
994+ }
995+
988996enum FfiResult < ' tcx > {
989997 FfiSafe ,
990998 FfiPhantom ( Ty < ' tcx > ) ,
@@ -1213,7 +1221,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12131221 /// Checks if the given field's type is "ffi-safe".
12141222 fn check_field_type_for_ffi (
12151223 & self ,
1216- cache : & mut FxHashSet < Ty < ' tcx > > ,
1224+ acc : & mut CTypesVisitorState < ' tcx > ,
12171225 field : & ty:: FieldDef ,
12181226 args : GenericArgsRef < ' tcx > ,
12191227 ) -> FfiResult < ' tcx > {
@@ -1223,13 +1231,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12231231 . tcx
12241232 . try_normalize_erasing_regions ( self . cx . param_env , field_ty)
12251233 . unwrap_or ( field_ty) ;
1226- self . check_type_for_ffi ( cache , field_ty)
1234+ self . check_type_for_ffi ( acc , field_ty)
12271235 }
12281236
12291237 /// Checks if the given `VariantDef`'s field types are "ffi-safe".
12301238 fn check_variant_for_ffi (
12311239 & self ,
1232- cache : & mut FxHashSet < Ty < ' tcx > > ,
1240+ acc : & mut CTypesVisitorState < ' tcx > ,
12331241 ty : Ty < ' tcx > ,
12341242 def : ty:: AdtDef < ' tcx > ,
12351243 variant : & ty:: VariantDef ,
@@ -1239,7 +1247,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12391247 let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
12401248 if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
12411249 // Transparent newtypes have at most one non-ZST field which needs to be checked..
1242- match self . check_field_type_for_ffi ( cache , field, args) {
1250+ match self . check_field_type_for_ffi ( acc , field, args) {
12431251 FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
12441252 r => return r,
12451253 }
@@ -1257,7 +1265,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12571265 // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
12581266 let mut all_phantom = !variant. fields . is_empty ( ) ;
12591267 for field in & variant. fields {
1260- all_phantom &= match self . check_field_type_for_ffi ( cache , field, args) {
1268+ all_phantom &= match self . check_field_type_for_ffi ( acc , field, args) {
12611269 FfiSafe => false ,
12621270 // `()` fields are FFI-safe!
12631271 FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
@@ -1277,7 +1285,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12771285
12781286 /// Checks if the given type is "ffi-safe" (has a stable, well-defined
12791287 /// representation which can be exported to C code).
1280- fn check_type_for_ffi ( & self , cache : & mut FxHashSet < Ty < ' tcx > > , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1288+ fn check_type_for_ffi (
1289+ & self ,
1290+ acc : & mut CTypesVisitorState < ' tcx > ,
1291+ ty : Ty < ' tcx > ,
1292+ ) -> FfiResult < ' tcx > {
12811293 use FfiResult :: * ;
12821294
12831295 let tcx = self . cx . tcx ;
@@ -1286,7 +1298,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12861298 // `struct S(*mut S);`.
12871299 // FIXME: A recursion limit is necessary as well, for irregular
12881300 // recursive types.
1289- if !cache. insert ( ty) {
1301+ if !acc . cache . insert ( ty) {
12901302 return FfiSafe ;
12911303 }
12921304
@@ -1308,6 +1320,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13081320 }
13091321 match def. adt_kind ( ) {
13101322 AdtKind :: Struct | AdtKind :: Union => {
1323+ if let Some ( sym:: cstring_type | sym:: cstr_type) =
1324+ tcx. get_diagnostic_name ( def. did ( ) )
1325+ && !acc. base_ty . is_mutable_ptr ( )
1326+ {
1327+ return FfiUnsafe {
1328+ ty,
1329+ reason : fluent:: lint_improper_ctypes_cstr_reason,
1330+ help : Some ( fluent:: lint_improper_ctypes_cstr_help) ,
1331+ } ;
1332+ }
1333+
13111334 if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
13121335 return FfiUnsafe {
13131336 ty,
@@ -1354,7 +1377,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13541377 } ;
13551378 }
13561379
1357- self . check_variant_for_ffi ( cache , ty, def, def. non_enum_variant ( ) , args)
1380+ self . check_variant_for_ffi ( acc , ty, def, def. non_enum_variant ( ) , args)
13581381 }
13591382 AdtKind :: Enum => {
13601383 if def. variants ( ) . is_empty ( ) {
@@ -1378,7 +1401,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13781401 if let Some ( ty) =
13791402 repr_nullable_ptr ( self . cx . tcx , self . cx . param_env , ty, self . mode )
13801403 {
1381- return self . check_type_for_ffi ( cache , ty) ;
1404+ return self . check_type_for_ffi ( acc , ty) ;
13821405 }
13831406
13841407 return FfiUnsafe {
@@ -1399,7 +1422,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13991422 } ;
14001423 }
14011424
1402- match self . check_variant_for_ffi ( cache , ty, def, variant, args) {
1425+ match self . check_variant_for_ffi ( acc , ty, def, variant, args) {
14031426 FfiSafe => ( ) ,
14041427 r => return r,
14051428 }
@@ -1469,9 +1492,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14691492 FfiSafe
14701493 }
14711494
1472- ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( cache , ty) ,
1495+ ty:: RawPtr ( ty, _) | ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( acc , ty) ,
14731496
1474- ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache , inner_ty) ,
1497+ ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( acc , inner_ty) ,
14751498
14761499 ty:: FnPtr ( sig_tys, hdr) => {
14771500 let sig = sig_tys. with ( hdr) ;
@@ -1485,7 +1508,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14851508
14861509 let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
14871510 for arg in sig. inputs ( ) {
1488- match self . check_type_for_ffi ( cache , * arg) {
1511+ match self . check_type_for_ffi ( acc , * arg) {
14891512 FfiSafe => { }
14901513 r => return r,
14911514 }
@@ -1496,7 +1519,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14961519 return FfiSafe ;
14971520 }
14981521
1499- self . check_type_for_ffi ( cache , ret_ty)
1522+ self . check_type_for_ffi ( acc , ret_ty)
15001523 }
15011524
15021525 ty:: Foreign ( ..) => FfiSafe ,
@@ -1619,7 +1642,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
16191642 return ;
16201643 }
16211644
1622- match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
1645+ let mut acc = CTypesVisitorState { cache : FxHashSet :: default ( ) , base_ty : ty } ;
1646+ match self . check_type_for_ffi ( & mut acc, ty) {
16231647 FfiResult :: FfiSafe => { }
16241648 FfiResult :: FfiPhantom ( ty) => {
16251649 self . emit_ffi_unsafe_type_lint (
0 commit comments