@@ -1230,17 +1230,40 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1230
1230
}
1231
1231
}
1232
1232
1233
- fn check_foreign_fn ( & mut self , def_id : LocalDefId , decl : & hir:: FnDecl < ' _ > ) {
1233
+ /// Check if a function's argument types and result type are "ffi-safe".
1234
+ ///
1235
+ /// Argument types and the result type are checked for functions with external ABIs.
1236
+ /// For functions with internal ABIs, argument types and the result type are walked to find
1237
+ /// fn-ptr types that have external ABIs, as these still need checked.
1238
+ fn check_maybe_foreign_fn ( & mut self , abi : SpecAbi , def_id : LocalDefId , decl : & hir:: FnDecl < ' _ > ) {
1234
1239
let sig = self . cx . tcx . fn_sig ( def_id) . subst_identity ( ) ;
1235
1240
let sig = self . cx . tcx . erase_late_bound_regions ( sig) ;
1236
1241
1242
+ let is_internal_abi = self . is_internal_abi ( abi) ;
1243
+ let check_ty = |this : & mut ImproperCTypesVisitor < ' a , ' tcx > ,
1244
+ span : Span ,
1245
+ ty : Ty < ' tcx > ,
1246
+ is_return_type : bool | {
1247
+ // If this function has an external ABI, then its arguments and return type should be
1248
+ // checked..
1249
+ if !is_internal_abi {
1250
+ this. check_type_for_ffi_and_report_errors ( span, ty, false , is_return_type) ;
1251
+ return ;
1252
+ }
1253
+
1254
+ // ..but if this function has an internal ABI, then search the argument or return type
1255
+ // for any fn-ptr types with external ABI, which should be checked..
1256
+ if let Some ( fn_ptr_ty) = this. find_fn_ptr_ty_with_external_abi ( ty) {
1257
+ this. check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, false , is_return_type) ;
1258
+ }
1259
+ } ;
1260
+
1237
1261
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1238
- self . check_type_for_ffi_and_report_errors ( input_hir. span , * input_ty, false , false ) ;
1262
+ check_ty ( self , input_hir. span , * input_ty, false ) ;
1239
1263
}
1240
1264
1241
1265
if let hir:: FnRetTy :: Return ( ref ret_hir) = decl. output {
1242
- let ret_ty = sig. output ( ) ;
1243
- self . check_type_for_ffi_and_report_errors ( ret_hir. span , ret_ty, false , true ) ;
1266
+ check_ty ( self , ret_hir. span , sig. output ( ) , true ) ;
1244
1267
}
1245
1268
}
1246
1269
@@ -1255,23 +1278,45 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1255
1278
SpecAbi :: Rust | SpecAbi :: RustCall | SpecAbi :: RustIntrinsic | SpecAbi :: PlatformIntrinsic
1256
1279
)
1257
1280
}
1281
+
1282
+ /// Find any fn-ptr types with external ABIs in `ty`.
1283
+ ///
1284
+ /// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
1285
+ fn find_fn_ptr_ty_with_external_abi ( & self , ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
1286
+ struct FnPtrFinder < ' parent , ' a , ' tcx > ( & ' parent ImproperCTypesVisitor < ' a , ' tcx > ) ;
1287
+ impl < ' vis , ' a , ' tcx > ty:: visit:: TypeVisitor < TyCtxt < ' tcx > > for FnPtrFinder < ' vis , ' a , ' tcx > {
1288
+ type BreakTy = Ty < ' tcx > ;
1289
+
1290
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
1291
+ if let ty:: FnPtr ( sig) = ty. kind ( ) && !self . 0 . is_internal_abi ( sig. abi ( ) ) {
1292
+ ControlFlow :: Break ( ty)
1293
+ } else {
1294
+ ty. super_visit_with ( self )
1295
+ }
1296
+ }
1297
+ }
1298
+
1299
+ self . cx
1300
+ . tcx
1301
+ . normalize_erasing_regions ( self . cx . param_env , ty)
1302
+ . visit_with ( & mut FnPtrFinder ( & * self ) )
1303
+ . break_value ( )
1304
+ }
1258
1305
}
1259
1306
1260
1307
impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesDeclarations {
1261
1308
fn check_foreign_item ( & mut self , cx : & LateContext < ' _ > , it : & hir:: ForeignItem < ' _ > ) {
1262
1309
let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Declaration } ;
1263
1310
let abi = cx. tcx . hir ( ) . get_foreign_abi ( it. hir_id ( ) ) ;
1264
1311
1265
- if !vis. is_internal_abi ( abi) {
1266
- match it. kind {
1267
- hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1268
- vis. check_foreign_fn ( it. owner_id . def_id , decl) ;
1269
- }
1270
- hir:: ForeignItemKind :: Static ( ref ty, _) => {
1271
- vis. check_foreign_static ( it. owner_id , ty. span ) ;
1272
- }
1273
- hir:: ForeignItemKind :: Type => ( ) ,
1312
+ match it. kind {
1313
+ hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1314
+ vis. check_maybe_foreign_fn ( abi, it. owner_id . def_id , decl) ;
1315
+ }
1316
+ hir:: ForeignItemKind :: Static ( ref ty, _) if !vis. is_internal_abi ( abi) => {
1317
+ vis. check_foreign_static ( it. owner_id , ty. span ) ;
1274
1318
}
1319
+ hir:: ForeignItemKind :: Static ( ..) | hir:: ForeignItemKind :: Type => ( ) ,
1275
1320
}
1276
1321
}
1277
1322
}
@@ -1295,9 +1340,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
1295
1340
} ;
1296
1341
1297
1342
let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Definition } ;
1298
- if !vis. is_internal_abi ( abi) {
1299
- vis. check_foreign_fn ( id, decl) ;
1300
- }
1343
+ vis. check_maybe_foreign_fn ( abi, id, decl) ;
1301
1344
}
1302
1345
}
1303
1346
0 commit comments