@@ -1379,7 +1379,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1379
1379
}
1380
1380
}
1381
1381
1382
- fn check_foreign_fn ( & mut self , def_id : LocalDefId , decl : & hir:: FnDecl < ' _ > ) {
1382
+ /// Check if a function's argument types and result type are "ffi-safe".
1383
+ ///
1384
+ /// For a external ABI function, argument types and the result type are walked to find fn-ptr
1385
+ /// types that have external ABIs, as these still need checked.
1386
+ fn check_fn ( & mut self , def_id : LocalDefId , decl : & ' tcx hir:: FnDecl < ' _ > ) {
1387
+ let sig = self . cx . tcx . fn_sig ( def_id) . subst_identity ( ) ;
1388
+ let sig = self . cx . tcx . erase_late_bound_regions ( sig) ;
1389
+
1390
+ for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1391
+ for ( fn_ptr_ty, span) in self . find_fn_ptr_ty_with_external_abi ( input_hir, * input_ty) {
1392
+ self . check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, false , false ) ;
1393
+ }
1394
+ }
1395
+
1396
+ if let hir:: FnRetTy :: Return ( ref ret_hir) = decl. output {
1397
+ for ( fn_ptr_ty, span) in self . find_fn_ptr_ty_with_external_abi ( ret_hir, sig. output ( ) ) {
1398
+ self . check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, false , true ) ;
1399
+ }
1400
+ }
1401
+ }
1402
+
1403
+ /// Check if a function's argument types and result type are "ffi-safe".
1404
+ fn check_foreign_fn ( & mut self , def_id : LocalDefId , decl : & ' tcx hir:: FnDecl < ' _ > ) {
1383
1405
let sig = self . cx . tcx . fn_sig ( def_id) . subst_identity ( ) ;
1384
1406
let sig = self . cx . tcx . erase_late_bound_regions ( sig) ;
1385
1407
@@ -1388,8 +1410,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1388
1410
}
1389
1411
1390
1412
if let hir:: FnRetTy :: Return ( ref ret_hir) = decl. output {
1391
- let ret_ty = sig. output ( ) ;
1392
- self . check_type_for_ffi_and_report_errors ( ret_hir. span , ret_ty, false , true ) ;
1413
+ self . check_type_for_ffi_and_report_errors ( ret_hir. span , sig. output ( ) , false , true ) ;
1393
1414
}
1394
1415
}
1395
1416
@@ -1404,28 +1425,131 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1404
1425
SpecAbi :: Rust | SpecAbi :: RustCall | SpecAbi :: RustIntrinsic | SpecAbi :: PlatformIntrinsic
1405
1426
)
1406
1427
}
1428
+
1429
+ /// Find any fn-ptr types with external ABIs in `ty`.
1430
+ ///
1431
+ /// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
1432
+ fn find_fn_ptr_ty_with_external_abi (
1433
+ & self ,
1434
+ hir_ty : & hir:: Ty < ' tcx > ,
1435
+ ty : Ty < ' tcx > ,
1436
+ ) -> Vec < ( Ty < ' tcx > , Span ) > {
1437
+ struct FnPtrFinder < ' parent , ' a , ' tcx > {
1438
+ visitor : & ' parent ImproperCTypesVisitor < ' a , ' tcx > ,
1439
+ spans : Vec < Span > ,
1440
+ tys : Vec < Ty < ' tcx > > ,
1441
+ }
1442
+
1443
+ impl < ' parent , ' a , ' tcx > hir:: intravisit:: Visitor < ' _ > for FnPtrFinder < ' parent , ' a , ' tcx > {
1444
+ fn visit_ty ( & mut self , ty : & ' _ hir:: Ty < ' _ > ) {
1445
+ debug ! ( ?ty) ;
1446
+ if let hir:: TyKind :: BareFn ( hir:: BareFnTy { abi, .. } ) = ty. kind
1447
+ && !self . visitor . is_internal_abi ( * abi)
1448
+ {
1449
+ self . spans . push ( ty. span ) ;
1450
+ }
1451
+
1452
+ hir:: intravisit:: walk_ty ( self , ty)
1453
+ }
1454
+ }
1455
+
1456
+ impl < ' vis , ' a , ' tcx > ty:: visit:: TypeVisitor < TyCtxt < ' tcx > > for FnPtrFinder < ' vis , ' a , ' tcx > {
1457
+ type BreakTy = Ty < ' tcx > ;
1458
+
1459
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
1460
+ if let ty:: FnPtr ( sig) = ty. kind ( ) && !self . visitor . is_internal_abi ( sig. abi ( ) ) {
1461
+ self . tys . push ( ty) ;
1462
+ }
1463
+
1464
+ ty. super_visit_with ( self )
1465
+ }
1466
+ }
1467
+
1468
+ let mut visitor = FnPtrFinder { visitor : & * self , spans : Vec :: new ( ) , tys : Vec :: new ( ) } ;
1469
+ ty. visit_with ( & mut visitor) ;
1470
+ hir:: intravisit:: Visitor :: visit_ty ( & mut visitor, hir_ty) ;
1471
+
1472
+ iter:: zip ( visitor. tys . drain ( ..) , visitor. spans . drain ( ..) ) . collect ( )
1473
+ }
1407
1474
}
1408
1475
1409
1476
impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesDeclarations {
1410
- fn check_foreign_item ( & mut self , cx : & LateContext < ' _ > , it : & hir:: ForeignItem < ' _ > ) {
1477
+ fn check_foreign_item ( & mut self , cx : & LateContext < ' tcx > , it : & hir:: ForeignItem < ' tcx > ) {
1411
1478
let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Declaration } ;
1412
1479
let abi = cx. tcx . hir ( ) . get_foreign_abi ( it. hir_id ( ) ) ;
1413
1480
1414
- if !vis. is_internal_abi ( abi) {
1415
- match it. kind {
1416
- hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1417
- vis. check_foreign_fn ( it. owner_id . def_id , decl) ;
1418
- }
1419
- hir:: ForeignItemKind :: Static ( ref ty, _) => {
1420
- vis. check_foreign_static ( it. owner_id , ty. span ) ;
1421
- }
1422
- hir:: ForeignItemKind :: Type => ( ) ,
1481
+ match it. kind {
1482
+ hir:: ForeignItemKind :: Fn ( ref decl, _, _) if !vis. is_internal_abi ( abi) => {
1483
+ vis. check_foreign_fn ( it. owner_id . def_id , decl) ;
1484
+ }
1485
+ hir:: ForeignItemKind :: Static ( ref ty, _) if !vis. is_internal_abi ( abi) => {
1486
+ vis. check_foreign_static ( it. owner_id , ty. span ) ;
1423
1487
}
1488
+ hir:: ForeignItemKind :: Fn ( ref decl, _, _) => vis. check_fn ( it. owner_id . def_id , decl) ,
1489
+ hir:: ForeignItemKind :: Static ( ..) | hir:: ForeignItemKind :: Type => ( ) ,
1490
+ }
1491
+ }
1492
+ }
1493
+
1494
+ impl ImproperCTypesDefinitions {
1495
+ fn check_ty_maybe_containing_foreign_fnptr < ' tcx > (
1496
+ & mut self ,
1497
+ cx : & LateContext < ' tcx > ,
1498
+ hir_ty : & ' tcx hir:: Ty < ' _ > ,
1499
+ ty : Ty < ' tcx > ,
1500
+ ) {
1501
+ let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Definition } ;
1502
+ for ( fn_ptr_ty, span) in vis. find_fn_ptr_ty_with_external_abi ( hir_ty, ty) {
1503
+ vis. check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, true , false ) ;
1424
1504
}
1425
1505
}
1426
1506
}
1427
1507
1508
+ /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
1509
+ /// `extern "C" { }` blocks):
1510
+ ///
1511
+ /// - `extern "<abi>" fn` definitions are checked in the same way as the
1512
+ /// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
1513
+ /// - All other items which contain types (e.g. other functions, struct definitions, etc) are
1514
+ /// checked for extern fn-ptrs with external ABIs.
1428
1515
impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesDefinitions {
1516
+ fn check_item ( & mut self , cx : & LateContext < ' tcx > , item : & ' tcx hir:: Item < ' tcx > ) {
1517
+ match item. kind {
1518
+ hir:: ItemKind :: Static ( ty, ..)
1519
+ | hir:: ItemKind :: Const ( ty, ..)
1520
+ | hir:: ItemKind :: TyAlias ( ty, ..) => {
1521
+ self . check_ty_maybe_containing_foreign_fnptr (
1522
+ cx,
1523
+ ty,
1524
+ cx. tcx . type_of ( item. owner_id ) . subst_identity ( ) ,
1525
+ ) ;
1526
+ }
1527
+ // See `check_fn`..
1528
+ hir:: ItemKind :: Fn ( ..) => { }
1529
+ // See `check_field_def`..
1530
+ hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Struct ( ..) | hir:: ItemKind :: Enum ( ..) => { }
1531
+ // Doesn't define something that can contain a external type to be checked.
1532
+ hir:: ItemKind :: Impl ( ..)
1533
+ | hir:: ItemKind :: TraitAlias ( ..)
1534
+ | hir:: ItemKind :: Trait ( ..)
1535
+ | hir:: ItemKind :: OpaqueTy ( ..)
1536
+ | hir:: ItemKind :: GlobalAsm ( ..)
1537
+ | hir:: ItemKind :: ForeignMod { .. }
1538
+ | hir:: ItemKind :: Mod ( ..)
1539
+ | hir:: ItemKind :: Macro ( ..)
1540
+ | hir:: ItemKind :: Use ( ..)
1541
+ | hir:: ItemKind :: ExternCrate ( ..) => { }
1542
+ }
1543
+ }
1544
+
1545
+ fn check_field_def ( & mut self , cx : & LateContext < ' tcx > , field : & ' tcx hir:: FieldDef < ' tcx > ) {
1546
+ self . check_ty_maybe_containing_foreign_fnptr (
1547
+ cx,
1548
+ field. ty ,
1549
+ cx. tcx . type_of ( field. def_id ) . subst_identity ( ) ,
1550
+ ) ;
1551
+ }
1552
+
1429
1553
fn check_fn (
1430
1554
& mut self ,
1431
1555
cx : & LateContext < ' tcx > ,
@@ -1444,7 +1568,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
1444
1568
} ;
1445
1569
1446
1570
let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Definition } ;
1447
- if !vis. is_internal_abi ( abi) {
1571
+ if vis. is_internal_abi ( abi) {
1572
+ vis. check_fn ( id, decl) ;
1573
+ } else {
1448
1574
vis. check_foreign_fn ( id, decl) ;
1449
1575
}
1450
1576
}
0 commit comments