@@ -957,6 +957,14 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
957957 mode : CItemKind ,
958958}
959959
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+
960968enum FfiResult < ' tcx > {
961969 FfiSafe ,
962970 FfiPhantom ( Ty < ' tcx > ) ,
@@ -1143,7 +1151,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11431151 /// Checks if the given field's type is "ffi-safe".
11441152 fn check_field_type_for_ffi (
11451153 & self ,
1146- cache : & mut FxHashSet < Ty < ' tcx > > ,
1154+ acc : & mut CTypesVisitorState < ' tcx > ,
11471155 field : & ty:: FieldDef ,
11481156 args : GenericArgsRef < ' tcx > ,
11491157 ) -> FfiResult < ' tcx > {
@@ -1153,13 +1161,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11531161 . tcx
11541162 . try_normalize_erasing_regions ( self . cx . param_env , field_ty)
11551163 . unwrap_or ( field_ty) ;
1156- self . check_type_for_ffi ( cache , field_ty)
1164+ self . check_type_for_ffi ( acc , field_ty)
11571165 }
11581166
11591167 /// Checks if the given `VariantDef`'s field types are "ffi-safe".
11601168 fn check_variant_for_ffi (
11611169 & self ,
1162- cache : & mut FxHashSet < Ty < ' tcx > > ,
1170+ acc : & mut CTypesVisitorState < ' tcx > ,
11631171 ty : Ty < ' tcx > ,
11641172 def : ty:: AdtDef < ' tcx > ,
11651173 variant : & ty:: VariantDef ,
@@ -1170,7 +1178,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11701178 let transparent_with_all_zst_fields = if def. repr ( ) . transparent ( ) {
11711179 if let Some ( field) = transparent_newtype_field ( self . cx . tcx , variant) {
11721180 // 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) {
11741182 FfiUnsafe { ty, .. } if ty. is_unit ( ) => ( ) ,
11751183 r => return r,
11761184 }
@@ -1188,7 +1196,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11881196 // We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
11891197 let mut all_phantom = !variant. fields . is_empty ( ) ;
11901198 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) {
11921200 FfiSafe => false ,
11931201 // `()` fields are FFI-safe!
11941202 FfiUnsafe { ty, .. } if ty. is_unit ( ) => false ,
@@ -1208,7 +1216,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12081216
12091217 /// Checks if the given type is "ffi-safe" (has a stable, well-defined
12101218 /// 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 > {
12121224 use FfiResult :: * ;
12131225
12141226 let tcx = self . cx . tcx ;
@@ -1217,7 +1229,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12171229 // `struct S(*mut S);`.
12181230 // FIXME: A recursion limit is necessary as well, for irregular
12191231 // recursive types.
1220- if !cache. insert ( ty) {
1232+ if !acc . cache . insert ( ty) {
12211233 return FfiSafe ;
12221234 }
12231235
@@ -1239,6 +1251,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12391251 }
12401252 match def. adt_kind ( ) {
12411253 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+
12421265 if !def. repr ( ) . c ( ) && !def. repr ( ) . transparent ( ) {
12431266 return FfiUnsafe {
12441267 ty,
@@ -1285,7 +1308,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12851308 } ;
12861309 }
12871310
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)
12891312 }
12901313 AdtKind :: Enum => {
12911314 if def. variants ( ) . is_empty ( ) {
@@ -1328,7 +1351,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13281351 } ;
13291352 }
13301353
1331- match self . check_variant_for_ffi ( cache , ty, def, variant, args) {
1354+ match self . check_variant_for_ffi ( acc , ty, def, variant, args) {
13321355 FfiSafe => ( ) ,
13331356 r => return r,
13341357 }
@@ -1392,9 +1415,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13921415 FfiSafe
13931416 }
13941417
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) ,
13961419
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) ,
13981421
13991422 ty:: FnPtr ( sig) => {
14001423 if self . is_internal_abi ( sig. abi ( ) ) {
@@ -1407,7 +1430,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14071430
14081431 let sig = tcx. instantiate_bound_regions_with_erased ( sig) ;
14091432 for arg in sig. inputs ( ) {
1410- match self . check_type_for_ffi ( cache , * arg) {
1433+ match self . check_type_for_ffi ( acc , * arg) {
14111434 FfiSafe => { }
14121435 r => return r,
14131436 }
@@ -1418,7 +1441,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14181441 return FfiSafe ;
14191442 }
14201443
1421- self . check_type_for_ffi ( cache , ret_ty)
1444+ self . check_type_for_ffi ( acc , ret_ty)
14221445 }
14231446
14241447 ty:: Foreign ( ..) => FfiSafe ,
@@ -1541,7 +1564,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
15411564 return ;
15421565 }
15431566
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) {
15451569 FfiResult :: FfiSafe => { }
15461570 FfiResult :: FfiPhantom ( ty) => {
15471571 self . emit_ffi_unsafe_type_lint (
0 commit comments