@@ -993,6 +993,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
993993 mode : CItemKind ,
994994}
995995
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+
9961004enum FfiResult < ' tcx > {
9971005 FfiSafe ,
9981006 FfiPhantom ( Ty < ' tcx > ) ,
@@ -1179,7 +1187,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11791187 /// Checks if the given field's type is "ffi-safe".
11801188 fn check_field_type_for_ffi (
11811189 & self ,
1182- cache : & mut FxHashSet < Ty < ' tcx > > ,
1190+ acc : & mut CTypesVisitorState < ' tcx > ,
11831191 field : & ty:: FieldDef ,
11841192 args : GenericArgsRef < ' tcx > ,
11851193 ) -> FfiResult < ' tcx > {
@@ -1189,13 +1197,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11891197 . tcx
11901198 . try_normalize_erasing_regions ( self . cx . param_env , field_ty)
11911199 . unwrap_or ( field_ty) ;
1192- self . check_type_for_ffi ( cache , field_ty)
1200+ self . check_type_for_ffi ( acc , field_ty)
11931201 }
11941202
11951203 /// Checks if the given `VariantDef`'s field types are "ffi-safe".
11961204 fn check_variant_for_ffi (
11971205 & self ,
1198- cache : & mut FxHashSet < Ty < ' tcx > > ,
1206+ acc : & mut CTypesVisitorState < ' tcx > ,
11991207 ty : Ty < ' tcx > ,
12001208 def : ty:: AdtDef < ' tcx > ,
12011209 variant : & ty:: VariantDef ,
@@ -1206,7 +1214,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12061214 let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
12071215 if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
12081216 // 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) {
12101218 FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
12111219 r => return r,
12121220 }
@@ -1224,7 +1232,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12241232 // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
12251233 let mut all_phantom = !variant. fields . is_empty ( ) ;
12261234 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) {
12281236 FfiSafe => false ,
12291237 // `()` fields are FFI-safe!
12301238 FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
@@ -1244,7 +1252,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12441252
12451253 /// Checks if the given type is "ffi-safe" (has a stable, well-defined
12461254 /// 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 > {
12481260 use FfiResult :: * ;
12491261
12501262 let tcx = self . cx . tcx ;
@@ -1253,7 +1265,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12531265 // `struct S(*mut S);`.
12541266 // FIXME: A recursion limit is necessary as well, for irregular
12551267 // recursive types.
1256- if !cache. insert ( ty) {
1268+ if !acc . cache . insert ( ty) {
12571269 return FfiSafe ;
12581270 }
12591271
@@ -1275,6 +1287,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12751287 }
12761288 match def. adt_kind ( ) {
12771289 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+
12781301 if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
12791302 return FfiUnsafe {
12801303 ty,
@@ -1321,7 +1344,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13211344 } ;
13221345 }
13231346
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)
13251348 }
13261349 AdtKind :: Enum => {
13271350 if def. variants ( ) . is_empty ( ) {
@@ -1364,7 +1387,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13641387 } ;
13651388 }
13661389
1367- match self . check_variant_for_ffi ( cache , ty, def, variant, args) {
1390+ match self . check_variant_for_ffi ( acc , ty, def, variant, args) {
13681391 FfiSafe => ( ) ,
13691392 r => return r,
13701393 }
@@ -1434,9 +1457,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14341457 FfiSafe
14351458 }
14361459
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) ,
14381461
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) ,
14401463
14411464 ty:: FnPtr ( sig) => {
14421465 if self . is_internal_abi ( sig. abi ( ) ) {
@@ -1449,7 +1472,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14491472
14501473 let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
14511474 for arg in sig. inputs ( ) {
1452- match self . check_type_for_ffi ( cache , * arg) {
1475+ match self . check_type_for_ffi ( acc , * arg) {
14531476 FfiSafe => { }
14541477 r => return r,
14551478 }
@@ -1460,7 +1483,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14601483 return FfiSafe ;
14611484 }
14621485
1463- self . check_type_for_ffi ( cache , ret_ty)
1486+ self . check_type_for_ffi ( acc , ret_ty)
14641487 }
14651488
14661489 ty:: Foreign ( ..) => FfiSafe ,
@@ -1583,7 +1606,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
15831606 return ;
15841607 }
15851608
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) {
15871611 FfiResult :: FfiSafe => { }
15881612 FfiResult :: FfiPhantom ( ty) => {
15891613 self . emit_ffi_unsafe_type_lint (
0 commit comments