@@ -1379,17 +1379,40 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13791379 }
13801380 }
13811381
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+ /// Argument types and the result type are checked for functions with external ABIs.
1385+ /// For functions with internal ABIs, argument types and the result type are walked to find
1386+ /// fn-ptr types that have external ABIs, as these still need checked.
1387+ fn check_maybe_foreign_fn ( & mut self , abi : SpecAbi , def_id : LocalDefId , decl : & hir:: FnDecl < ' _ > ) {
13831388 let sig = self . cx . tcx . fn_sig ( def_id) . subst_identity ( ) ;
13841389 let sig = self . cx . tcx . erase_late_bound_regions ( sig) ;
13851390
1391+ let is_internal_abi = self . is_internal_abi ( abi) ;
1392+ let check_ty = |this : & mut ImproperCTypesVisitor < ' a , ' tcx > ,
1393+ span : Span ,
1394+ ty : Ty < ' tcx > ,
1395+ is_return_type : bool | {
1396+ // If this function has an external ABI, then its arguments and return type should be
1397+ // checked..
1398+ if !is_internal_abi {
1399+ this. check_type_for_ffi_and_report_errors ( span, ty, false , is_return_type) ;
1400+ return ;
1401+ }
1402+
1403+ // ..but if this function has an internal ABI, then search the argument or return type
1404+ // for any fn-ptr types with external ABI, which should be checked..
1405+ if let Some ( fn_ptr_ty) = this. find_fn_ptr_ty_with_external_abi ( ty) {
1406+ this. check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, false , is_return_type) ;
1407+ }
1408+ } ;
1409+
13861410 for ( input_ty, input_hir) in iter:: zip ( sig. inputs ( ) , decl. inputs ) {
1387- self . check_type_for_ffi_and_report_errors ( input_hir. span , * input_ty, false , false ) ;
1411+ check_ty ( self , input_hir. span , * input_ty, false ) ;
13881412 }
13891413
13901414 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 ) ;
1415+ check_ty ( self , ret_hir. span , sig. output ( ) , true ) ;
13931416 }
13941417 }
13951418
@@ -1404,23 +1427,45 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14041427 SpecAbi :: Rust | SpecAbi :: RustCall | SpecAbi :: RustIntrinsic | SpecAbi :: PlatformIntrinsic
14051428 )
14061429 }
1430+
1431+ /// Find any fn-ptr types with external ABIs in `ty`.
1432+ ///
1433+ /// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
1434+ fn find_fn_ptr_ty_with_external_abi ( & self , ty : Ty < ' tcx > ) -> Option < Ty < ' tcx > > {
1435+ struct FnPtrFinder < ' parent , ' a , ' tcx > ( & ' parent ImproperCTypesVisitor < ' a , ' tcx > ) ;
1436+ impl < ' vis , ' a , ' tcx > ty:: visit:: TypeVisitor < TyCtxt < ' tcx > > for FnPtrFinder < ' vis , ' a , ' tcx > {
1437+ type BreakTy = Ty < ' tcx > ;
1438+
1439+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> ControlFlow < Self :: BreakTy > {
1440+ if let ty:: FnPtr ( sig) = ty. kind ( ) && !self . 0 . is_internal_abi ( sig. abi ( ) ) {
1441+ ControlFlow :: Break ( ty)
1442+ } else {
1443+ ty. super_visit_with ( self )
1444+ }
1445+ }
1446+ }
1447+
1448+ self . cx
1449+ . tcx
1450+ . normalize_erasing_regions ( self . cx . param_env , ty)
1451+ . visit_with ( & mut FnPtrFinder ( & * self ) )
1452+ . break_value ( )
1453+ }
14071454}
14081455
14091456impl < ' tcx > LateLintPass < ' tcx > for ImproperCTypesDeclarations {
14101457 fn check_foreign_item ( & mut self , cx : & LateContext < ' _ > , it : & hir:: ForeignItem < ' _ > ) {
14111458 let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Declaration } ;
14121459 let abi = cx. tcx . hir ( ) . get_foreign_abi ( it. hir_id ( ) ) ;
14131460
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 => ( ) ,
1461+ match it. kind {
1462+ hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1463+ vis. check_maybe_foreign_fn ( abi, it. owner_id . def_id , decl) ;
1464+ }
1465+ hir:: ForeignItemKind :: Static ( ref ty, _) if !vis. is_internal_abi ( abi) => {
1466+ vis. check_foreign_static ( it. owner_id , ty. span ) ;
14231467 }
1468+ hir:: ForeignItemKind :: Static ( ..) | hir:: ForeignItemKind :: Type => ( ) ,
14241469 }
14251470 }
14261471}
@@ -1444,9 +1489,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
14441489 } ;
14451490
14461491 let mut vis = ImproperCTypesVisitor { cx, mode : CItemKind :: Definition } ;
1447- if !vis. is_internal_abi ( abi) {
1448- vis. check_foreign_fn ( id, decl) ;
1449- }
1492+ vis. check_maybe_foreign_fn ( abi, id, decl) ;
14501493 }
14511494}
14521495
0 commit comments