@@ -1250,17 +1250,45 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1250
1250
}
1251
1251
}
1252
1252
1253
- fn check_foreign_fn ( & mut self , def_id : LocalDefId , decl : & hir:: FnDecl < ' _ > ) {
1253
+ /// Check if a function's argument types and result type are "ffi-safe".
1254
+ ///
1255
+ /// Argument types and the result type are checked for functions with external ABIs.
1256
+ /// For functions with internal ABIs, argument types and the result type are walked to find
1257
+ /// fn-ptr types that have external ABIs, as these still need checked.
1258
+ fn check_maybe_foreign_fn (
1259
+ & mut self ,
1260
+ abi : SpecAbi ,
1261
+ def_id : LocalDefId ,
1262
+ decl : & ' tcx hir:: FnDecl < ' _ > ,
1263
+ ) {
1254
1264
let sig = self . cx . tcx . fn_sig ( def_id) . subst_identity ( ) ;
1255
1265
let sig = self . cx . tcx . erase_late_bound_regions ( sig) ;
1256
1266
1267
+ let is_internal_abi = self . is_internal_abi ( abi) ;
1268
+ let check_ty = |this : & mut ImproperCTypesVisitor < ' a , ' tcx > ,
1269
+ hir_ty : & ' tcx hir:: Ty < ' _ > ,
1270
+ ty : Ty < ' tcx > ,
1271
+ is_return_type : bool | {
1272
+ // If this function has an external ABI, then its arguments and return type should be
1273
+ // checked..
1274
+ if !is_internal_abi {
1275
+ this. check_type_for_ffi_and_report_errors ( hir_ty. span , ty, false , is_return_type) ;
1276
+ return ;
1277
+ }
1278
+
1279
+ // ..but if this function has an internal ABI, then search the argument or return type
1280
+ // for any fn-ptr types with external ABI, which should be checked..
1281
+ for ( fn_ptr_ty, span) in this. find_fn_ptr_ty_with_external_abi ( hir_ty, ty) {
1282
+ this. check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, false , is_return_type) ;
1283
+ }
1284
+ } ;
1285
+
1257
1286
for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1258
- self . check_type_for_ffi_and_report_errors ( input_hir. span , * input_ty, false , false ) ;
1287
+ check_ty ( self , input_hir, * input_ty, false ) ;
1259
1288
}
1260
1289
1261
1290
if let hir:: FnRetTy :: Return ( ref ret_hir) = decl. output {
1262
- let ret_ty = sig. output ( ) ;
1263
- self . check_type_for_ffi_and_report_errors ( ret_hir. span , ret_ty, false , true ) ;
1291
+ check_ty ( self , ret_hir, sig. output ( ) , true ) ;
1264
1292
}
1265
1293
}
1266
1294
@@ -1275,28 +1303,134 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1275
1303
SpecAbi :: Rust | SpecAbi :: RustCall | SpecAbi :: RustIntrinsic | SpecAbi :: PlatformIntrinsic
1276
1304
)
1277
1305
}
1306
+
1307
+ /// Find any fn-ptr types with external ABIs in `ty`.
1308
+ ///
1309
+ /// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
1310
+ fn find_fn_ptr_ty_with_external_abi (
1311
+ & self ,
1312
+ hir_ty : & hir:: Ty < ' tcx > ,
1313
+ ty : Ty < ' tcx > ,
1314
+ ) -> Vec < ( Ty < ' tcx > , Span ) > {
1315
+ struct FnPtrFinder < ' parent , ' a , ' tcx > {
1316
+ visitor : & ' parent ImproperCTypesVisitor < ' a , ' tcx > ,
1317
+ spans : Vec < Span > ,
1318
+ tys : Vec < Ty < ' tcx > > ,
1319
+ }
1320
+
1321
+ impl < ' parent , ' a , ' tcx > hir:: intravisit:: Visitor < ' _ > for FnPtrFinder < ' parent , ' a , ' tcx > {
1322
+ fn visit_ty ( & mut self , ty : & ' _ hir:: Ty < ' _ > ) {
1323
+ debug ! ( ?ty) ;
1324
+ if let hir:: TyKind :: BareFn ( hir:: BareFnTy { abi, .. } ) = ty. kind
1325
+ && !self . visitor . is_internal_abi ( * abi)
1326
+ {
1327
+ self . spans . push ( ty. span ) ;
1328
+ }
1329
+
1330
+ hir:: intravisit:: walk_ty ( self , ty)
1331
+ }
1332
+ }
1333
+
1334
+ impl < ' vis , ' a , ' tcx > ty:: visit:: TypeVisitor < TyCtxt < ' tcx > > for FnPtrFinder < ' vis , ' a , ' tcx > {
1335
+ type BreakTy = Ty < ' tcx > ;
1336
+
1337
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
1338
+ if let ty:: FnPtr ( sig) = ty. kind ( ) && !self . visitor . is_internal_abi ( sig. abi ( ) ) {
1339
+ self . tys . push ( ty) ;
1340
+ }
1341
+
1342
+ ty. super_visit_with ( self )
1343
+ }
1344
+ }
1345
+
1346
+ let mut visitor = FnPtrFinder { visitor : & * self , spans : Vec :: new ( ) , tys : Vec :: new ( ) } ;
1347
+ self . cx
1348
+ . tcx
1349
+ . try_normalize_erasing_regions ( self . cx . param_env , ty)
1350
+ . unwrap_or ( ty)
1351
+ . visit_with ( & mut visitor) ;
1352
+ hir:: intravisit:: Visitor :: visit_ty ( & mut visitor, hir_ty) ;
1353
+
1354
+ iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) . collect ( )
1355
+ }
1278
1356
}
1279
1357
1280
1358
impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesDeclarations {
1281
- fn check_foreign_item ( & mut self , cx : & LateContext < ' _ > , it : & hir:: ForeignItem < ' _ > ) {
1359
+ fn check_foreign_item ( & mut self , cx : & LateContext < ' tcx > , it : & hir:: ForeignItem < ' tcx > ) {
1282
1360
let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Declaration } ;
1283
1361
let abi = cx. tcx . hir ( ) . get_foreign_abi ( it. hir_id ( ) ) ;
1284
1362
1285
- if !vis. is_internal_abi ( abi) {
1286
- match it. kind {
1287
- hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1288
- vis. check_foreign_fn ( it. owner_id . def_id , decl) ;
1289
- }
1290
- hir:: ForeignItemKind :: Static ( ref ty, _) => {
1291
- vis. check_foreign_static ( it. owner_id , ty. span ) ;
1292
- }
1293
- hir:: ForeignItemKind :: Type => ( ) ,
1363
+ match it. kind {
1364
+ hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1365
+ vis. check_maybe_foreign_fn ( abi, it. owner_id . def_id , decl) ;
1294
1366
}
1367
+ hir:: ForeignItemKind :: Static ( ref ty, _) if !vis. is_internal_abi ( abi) => {
1368
+ vis. check_foreign_static ( it. owner_id , ty. span ) ;
1369
+ }
1370
+ hir:: ForeignItemKind :: Static ( ..) | hir:: ForeignItemKind :: Type => ( ) ,
1295
1371
}
1296
1372
}
1297
1373
}
1298
1374
1375
+ impl ImproperCTypesDefinitions {
1376
+ fn check_ty_maybe_containing_foreign_fnptr < ' tcx > (
1377
+ & mut self ,
1378
+ cx : & LateContext < ' tcx > ,
1379
+ hir_ty : & ' tcx hir:: Ty < ' _ > ,
1380
+ ty : Ty < ' tcx > ,
1381
+ ) {
1382
+ let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Definition } ;
1383
+ for ( fn_ptr_ty, span) in vis. find_fn_ptr_ty_with_external_abi ( hir_ty, ty) {
1384
+ vis. check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, true , false ) ;
1385
+ }
1386
+ }
1387
+ }
1388
+
1389
+ /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1390
+ /// `extern "C" { }` blocks):
1391
+ ///
1392
+ /// - `extern "<abi>" fn` definitions are checked in the same way as the
1393
+ /// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1394
+ /// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1395
+ /// checked for extern fn-ptrs with external ABIs.
1299
1396
impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesDefinitions {
1397
+ fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: Item < ' tcx > ) {
1398
+ match item. kind {
1399
+ hir:: ItemKind :: Static ( ty, ..)
1400
+ | hir:: ItemKind :: Const ( ty, ..)
1401
+ | hir:: ItemKind :: TyAlias ( ty, ..) => {
1402
+ self . check_ty_maybe_containing_foreign_fnptr (
1403
+ cx,
1404
+ ty,
1405
+ cx. tcx . type_of ( item. owner_id ) . subst_identity ( ) ,
1406
+ ) ;
1407
+ }
1408
+ // See `check_fn`..
1409
+ hir:: ItemKind :: Fn ( ..) => { }
1410
+ // See `check_field_def`..
1411
+ hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Struct ( ..) | hir:: ItemKind :: Enum ( ..) => { }
1412
+ // Doesn't define something that can contain a external type to be checked.
1413
+ hir:: ItemKind :: Impl ( ..)
1414
+ | hir:: ItemKind :: TraitAlias ( ..)
1415
+ | hir:: ItemKind :: Trait ( ..)
1416
+ | hir:: ItemKind :: OpaqueTy ( ..)
1417
+ | hir:: ItemKind :: GlobalAsm ( ..)
1418
+ | hir:: ItemKind :: ForeignMod { .. }
1419
+ | hir:: ItemKind :: Mod ( ..)
1420
+ | hir:: ItemKind :: Macro ( ..)
1421
+ | hir:: ItemKind :: Use ( ..)
1422
+ | hir:: ItemKind :: ExternCrate ( ..) => { }
1423
+ }
1424
+ }
1425
+
1426
+ fn check_field_def ( & mut self , cx : & LateContext < ' tcx > , field : & ' tcx hir:: FieldDef < ' tcx > ) {
1427
+ self . check_ty_maybe_containing_foreign_fnptr (
1428
+ cx,
1429
+ field. ty ,
1430
+ cx. tcx . type_of ( field. def_id ) . subst_identity ( ) ,
1431
+ ) ;
1432
+ }
1433
+
1300
1434
fn check_fn (
1301
1435
& mut self ,
1302
1436
cx : & LateContext < ' tcx > ,
@@ -1315,9 +1449,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
1315
1449
} ;
1316
1450
1317
1451
let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Definition } ;
1318
- if !vis. is_internal_abi ( abi) {
1319
- vis. check_foreign_fn ( id, decl) ;
1320
- }
1452
+ vis. check_maybe_foreign_fn ( abi, id, decl) ;
1321
1453
}
1322
1454
}
1323
1455
0 commit comments