@@ -984,6 +984,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
984984 mode : CItemKind ,
985985}
986986
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+
987995enum FfiResult < ' tcx > {
988996 FfiSafe ,
989997 FfiPhantom ( Ty < ' tcx > ) ,
@@ -1212,7 +1220,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12121220 /// Checks if the given field's type is "ffi-safe".
12131221 fn check_field_type_for_ffi (
12141222 & self ,
1215- cache : & mut FxHashSet < Ty < ' tcx > > ,
1223+ acc : & mut CTypesVisitorState < ' tcx > ,
12161224 field : & ty:: FieldDef ,
12171225 args : GenericArgsRef < ' tcx > ,
12181226 ) -> FfiResult < ' tcx > {
@@ -1222,13 +1230,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12221230 . tcx
12231231 . try_normalize_erasing_regions ( self . cx . param_env , field_ty)
12241232 . unwrap_or ( field_ty) ;
1225- self . check_type_for_ffi ( cache , field_ty)
1233+ self . check_type_for_ffi ( acc , field_ty)
12261234 }
12271235
12281236 /// Checks if the given `VariantDef`'s field types are "ffi-safe".
12291237 fn check_variant_for_ffi (
12301238 & self ,
1231- cache : & mut FxHashSet < Ty < ' tcx > > ,
1239+ acc : & mut CTypesVisitorState < ' tcx > ,
12321240 ty : Ty < ' tcx > ,
12331241 def : ty:: AdtDef < ' tcx > ,
12341242 variant : & ty:: VariantDef ,
@@ -1238,7 +1246,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12381246 let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
12391247 if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
12401248 // 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) {
12421250 FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
12431251 r => return r,
12441252 }
@@ -1256,7 +1264,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12561264 // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
12571265 let mut all_phantom = !variant. fields . is_empty ( ) ;
12581266 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) {
12601268 FfiSafe => false ,
12611269 // `()` fields are FFI-safe!
12621270 FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
@@ -1276,7 +1284,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12761284
12771285 /// Checks if the given type is "ffi-safe" (has a stable, well-defined
12781286 /// 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 > {
12801292 use FfiResult :: * ;
12811293
12821294 let tcx = self . cx . tcx ;
@@ -1285,7 +1297,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12851297 // `struct S(*mut S);`.
12861298 // FIXME: A recursion limit is necessary as well, for irregular
12871299 // recursive types.
1288- if !cache. insert ( ty) {
1300+ if !acc . cache . insert ( ty) {
12891301 return FfiSafe ;
12901302 }
12911303
@@ -1307,6 +1319,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13071319 }
13081320 match def. adt_kind ( ) {
13091321 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+
13101333 if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
13111334 return FfiUnsafe {
13121335 ty,
@@ -1353,7 +1376,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13531376 } ;
13541377 }
13551378
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)
13571380 }
13581381 AdtKind :: Enum => {
13591382 if def. variants ( ) . is_empty ( ) {
@@ -1377,7 +1400,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13771400 if let Some ( ty) =
13781401 repr_nullable_ptr ( self . cx . tcx , self . cx . param_env , ty, self . mode )
13791402 {
1380- return self . check_type_for_ffi ( cache , ty) ;
1403+ return self . check_type_for_ffi ( acc , ty) ;
13811404 }
13821405
13831406 return FfiUnsafe {
@@ -1398,7 +1421,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13981421 } ;
13991422 }
14001423
1401- match self . check_variant_for_ffi ( cache , ty, def, variant, args) {
1424+ match self . check_variant_for_ffi ( acc , ty, def, variant, args) {
14021425 FfiSafe => ( ) ,
14031426 r => return r,
14041427 }
@@ -1468,9 +1491,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14681491 FfiSafe
14691492 }
14701493
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) ,
14721495
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) ,
14741497
14751498 ty:: FnPtr ( sig) => {
14761499 if self . is_internal_abi ( sig. abi ( ) ) {
@@ -1483,7 +1506,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14831506
14841507 let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
14851508 for arg in sig. inputs ( ) {
1486- match self . check_type_for_ffi ( cache , * arg) {
1509+ match self . check_type_for_ffi ( acc , * arg) {
14871510 FfiSafe => { }
14881511 r => return r,
14891512 }
@@ -1494,7 +1517,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14941517 return FfiSafe ;
14951518 }
14961519
1497- self . check_type_for_ffi ( cache , ret_ty)
1520+ self . check_type_for_ffi ( acc , ret_ty)
14981521 }
14991522
15001523 ty:: Foreign ( ..) => FfiSafe ,
@@ -1617,7 +1640,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
16171640 return ;
16181641 }
16191642
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) {
16211645 FfiResult :: FfiSafe => { }
16221646 FfiResult :: FfiPhantom ( ty) => {
16231647 self . emit_ffi_unsafe_type_lint (
0 commit comments