@@ -11,8 +11,8 @@ use rustc_hir::intravisit::VisitorExt;
1111use  rustc_hir:: { self  as  hir,  AmbigArg } ; 
1212use  rustc_middle:: bug; 
1313use  rustc_middle:: ty:: { 
14-     self ,  Adt ,  AdtDef ,  AdtKind ,  GenericArgsRef ,  Ty ,  TyCtxt ,  TypeSuperVisitable ,   TypeVisitable , 
15-     TypeVisitableExt , 
14+     self ,  Adt ,  AdtDef ,  AdtKind ,  Binder ,   FnSig ,   GenericArgsRef ,  Ty ,  TyCtxt ,  TypeSuperVisitable , 
15+     TypeVisitable ,   TypeVisitableExt , 
1616} ; 
1717use  rustc_session:: { declare_lint,  declare_lint_pass} ; 
1818use  rustc_span:: def_id:: LocalDefId ; 
@@ -23,6 +23,8 @@ use super::repr_nullable_ptr;
2323use  crate :: lints:: { ImproperCTypes ,  ImproperCTypesLayer ,  UsesPowerAlignment } ; 
2424use  crate :: { LateContext ,  LateLintPass ,  LintContext ,  fluent_generated as  fluent} ; 
2525
26+ type  Sig < ' tcx >  = Binder < ' tcx ,  FnSig < ' tcx > > ; 
27+ 
2628/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple). 
2729#[ inline]  
2830fn  get_type_from_field < ' tcx > ( 
@@ -156,7 +158,6 @@ impl<'tcx> FfiResult<'tcx> {
156158    } 
157159    /// If the FfiPhantom variant, turns it into a FfiUnsafe version. 
158160/// Otherwise, keep unchanged. 
159- #[ expect( unused) ]  
160161fn  forbid_phantom ( self )  -> Self  { 
161162        match  self  { 
162163            Self :: FfiPhantom ( ty)  => { 
@@ -528,6 +529,41 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
528529        } 
529530    } 
530531
532+     /// Checks whether an `extern "ABI" fn` function pointer is indeed FFI-safe to call. 
533+ fn  visit_fnptr ( 
534+         & self , 
535+         _state :  VisitorState , 
536+         _outer_ty :  Option < Ty < ' tcx > > , 
537+         ty :  Ty < ' tcx > , 
538+         sig :  Sig < ' tcx > , 
539+     )  -> FfiResult < ' tcx >  { 
540+         use  FfiResult :: * ; 
541+         debug_assert ! ( !sig. abi( ) . is_rustic_abi( ) ) ; 
542+ 
543+         let  sig = self . cx . tcx . instantiate_bound_regions_with_erased ( sig) ; 
544+ 
545+         let  mut  all_ffires = FfiSafe ; 
546+ 
547+         for  arg in  sig. inputs ( )  { 
548+             let  ffi_res = self . visit_type ( VisitorState :: ArgumentTyInFnPtr ,  Some ( ty) ,  * arg) ; 
549+             all_ffires += ffi_res. forbid_phantom ( ) . wrap_all ( 
550+                 ty, 
551+                 fluent:: lint_improper_ctypes_fnptr_indirect_reason, 
552+                 None , 
553+             ) ; 
554+         } 
555+ 
556+         let  ret_ty = sig. output ( ) ; 
557+ 
558+         let  ffi_res = self . visit_type ( VisitorState :: ReturnTyInFnPtr ,  Some ( ty) ,  ret_ty) ; 
559+         all_ffires += ffi_res. forbid_phantom ( ) . wrap_all ( 
560+             ty, 
561+             fluent:: lint_improper_ctypes_fnptr_indirect_reason, 
562+             None , 
563+         ) ; 
564+         all_ffires
565+     } 
566+ 
531567    /// Checks if a simple numeric (int, float) type has an actual portable definition 
532568/// for the compile target. 
533569fn  visit_numeric ( & self ,  ty :  Ty < ' tcx > )  -> FfiResult < ' tcx >  { 
@@ -955,27 +991,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
955991                } 
956992            } 
957993
994+             // fnptrs are a special case, they always need to be treated as 
995+             // "the element rendered unsafe" because their unsafety doesn't affect 
996+             // their surroundings, and their type is often declared inline 
997+             // as a result, don't go into them when scanning for the safety of something else 
958998            ty:: FnPtr ( sig_tys,  hdr)  => { 
959999                let  sig = sig_tys. with ( hdr) ; 
9601000                if  sig. abi ( ) . is_rustic_abi ( )  { 
961-                     return   FfiResult :: new_with_reason ( 
1001+                     FfiResult :: new_with_reason ( 
9621002                        ty, 
9631003                        fluent:: lint_improper_ctypes_fnptr_reason, 
9641004                        Some ( fluent:: lint_improper_ctypes_fnptr_help) , 
965-                     ) ; 
966-                 } 
967- 
968-                 let  sig = tcx. instantiate_bound_regions_with_erased ( sig) ; 
969-                 for  arg in  sig. inputs ( )  { 
970-                     match  self . visit_type ( VisitorState :: ArgumentTyInFnPtr ,  Some ( ty) ,  * arg)  { 
971-                         FfiSafe  => { } 
972-                         r => return  r, 
973-                     } 
1005+                     ) 
1006+                 }  else  { 
1007+                     FfiSafe 
9741008                } 
975- 
976-                 let  ret_ty = sig. output ( ) ; 
977- 
978-                 self . visit_type ( VisitorState :: ReturnTyInFnPtr ,  Some ( ty) ,  ret_ty) 
9791009            } 
9801010
9811011            ty:: Foreign ( ..)  => FfiSafe , 
@@ -1046,10 +1076,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10461076                return  res; 
10471077            } 
10481078        } 
1049- 
10501079        self . visit_type ( state,  None ,  ty) 
10511080    } 
10521081
1082+     fn  check_for_fnptr ( & self ,  ty :  Ty < ' tcx > )  -> FfiResult < ' tcx >  { 
1083+         let  ty =  self . cx . tcx . try_normalize_erasing_regions ( self . cx . typing_env ( ) ,  ty) . unwrap_or ( ty) ; 
1084+ 
1085+         match  * ty. kind ( )  { 
1086+             ty:: FnPtr ( sig_tys,  hdr)  => { 
1087+                 let  sig = sig_tys. with ( hdr) ; 
1088+                 if  sig. abi ( ) . is_rustic_abi ( )  { 
1089+                     bug ! ( 
1090+                         "expected to inspect the type of an `extern \" ABI\" ` FnPtr, not an internal-ABI one" 
1091+                     ) 
1092+                 }  else  { 
1093+                     self . visit_fnptr ( VisitorState :: None ,  None ,  ty,  sig) 
1094+                 } 
1095+             } 
1096+             r @ _ => { 
1097+                 bug ! ( "expected to inspect the type of an `extern \" ABI\" ` FnPtr, not {:?}" ,  r, ) 
1098+             } 
1099+         } 
1100+     } 
1101+ 
10531102    fn  check_arg_for_power_alignment ( cx :  & LateContext < ' tcx > ,  ty :  Ty < ' tcx > )  -> bool  { 
10541103        let  tcx = cx. tcx ; 
10551104        assert ! ( tcx. sess. target. os == "aix" ) ; 
@@ -1117,7 +1166,6 @@ impl<'tcx> ImproperCTypesLint {
11171166fn  check_type_for_external_abi_fnptr ( 
11181167        & mut  self , 
11191168        cx :  & LateContext < ' tcx > , 
1120-         state :  VisitorState , 
11211169        hir_ty :  & hir:: Ty < ' tcx > , 
11221170        ty :  Ty < ' tcx > , 
11231171    )  { 
@@ -1160,8 +1208,7 @@ impl<'tcx> ImproperCTypesLint {
11601208        let  all_types = iter:: zip ( visitor. tys . drain ( ..) ,  visitor. spans . drain ( ..) ) ; 
11611209        all_types. for_each ( |( fn_ptr_ty,  span) | { 
11621210            let  visitor = ImproperCTypesVisitor :: new ( cx) ; 
1163-             // TODO: make a check_for_fnptr 
1164-             let  ffi_res = visitor. check_for_type ( state,  fn_ptr_ty) ; 
1211+             let  ffi_res = visitor. check_for_fnptr ( fn_ptr_ty) ; 
11651212
11661213            self . process_ffi_result ( cx,  span,  ffi_res,  CItemKind :: Callback ) 
11671214        } ) ; 
@@ -1172,21 +1219,18 @@ impl<'tcx> ImproperCTypesLint {
11721219fn  check_fn_for_external_abi_fnptr ( 
11731220        & mut  self , 
11741221        cx :  & LateContext < ' tcx > , 
1175-         fn_mode :  CItemKind , 
11761222        def_id :  LocalDefId , 
11771223        decl :  & ' tcx  hir:: FnDecl < ' _ > , 
11781224    )  { 
11791225        let  sig = cx. tcx . fn_sig ( def_id) . instantiate_identity ( ) ; 
11801226        let  sig = cx. tcx . instantiate_bound_regions_with_erased ( sig) ; 
11811227
11821228        for  ( input_ty,  input_hir)  in  iter:: zip ( sig. inputs ( ) ,  decl. inputs )  { 
1183-             let  state = VisitorState :: argument_from_fnmode ( fn_mode) ; 
1184-             self . check_type_for_external_abi_fnptr ( cx,  state,  input_hir,  * input_ty) ; 
1229+             self . check_type_for_external_abi_fnptr ( cx,  input_hir,  * input_ty) ; 
11851230        } 
11861231
11871232        if  let  hir:: FnRetTy :: Return ( ret_hir)  = decl. output  { 
1188-             let  state = VisitorState :: return_from_fnmode ( fn_mode) ; 
1189-             self . check_type_for_external_abi_fnptr ( cx,  state,  ret_hir,  sig. output ( ) ) ; 
1233+             self . check_type_for_external_abi_fnptr ( cx,  ret_hir,  sig. output ( ) ) ; 
11901234        } 
11911235    } 
11921236
@@ -1207,6 +1251,7 @@ impl<'tcx> ImproperCTypesLint {
12071251        ImproperCTypesVisitor :: check_struct_for_power_alignment ( cx,  item,  adt_def) ; 
12081252    } 
12091253
1254+     /// Check that an extern "ABI" static variable is of a ffi-safe type. 
12101255fn  check_foreign_static ( & self ,  cx :  & LateContext < ' tcx > ,  id :  hir:: OwnerId ,  span :  Span )  { 
12111256        let  ty = cx. tcx . type_of ( id) . instantiate_identity ( ) ; 
12121257        let  visitor = ImproperCTypesVisitor :: new ( cx) ; 
@@ -1359,20 +1404,14 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13591404                // fnptrs are a special case, they always need to be treated as 
13601405                // "the element rendered unsafe" because their unsafety doesn't affect 
13611406                // their surroundings, and their type is often declared inline 
1407+                 self . check_fn_for_external_abi_fnptr ( cx,  it. owner_id . def_id ,  sig. decl ) ; 
13621408                if  !abi. is_rustic_abi ( )  { 
13631409                    self . check_foreign_fn ( 
13641410                        cx, 
13651411                        CItemKind :: ImportedExtern , 
13661412                        it. owner_id . def_id , 
13671413                        sig. decl , 
13681414                    ) ; 
1369-                 }  else  { 
1370-                     self . check_fn_for_external_abi_fnptr ( 
1371-                         cx, 
1372-                         CItemKind :: ImportedExtern , 
1373-                         it. owner_id . def_id , 
1374-                         sig. decl , 
1375-                     ) ; 
13761415                } 
13771416            } 
13781417            hir:: ForeignItemKind :: Static ( ty,  _,  _)  if  !abi. is_rustic_abi ( )  => { 
@@ -1389,7 +1428,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
13891428            | hir:: ItemKind :: TyAlias ( _,  _,  ty)  => { 
13901429                self . check_type_for_external_abi_fnptr ( 
13911430                    cx, 
1392-                     VisitorState :: StaticTy , 
13931431                    ty, 
13941432                    cx. tcx . type_of ( item. owner_id ) . instantiate_identity ( ) , 
13951433                ) ; 
@@ -1422,7 +1460,6 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14221460    fn  check_field_def ( & mut  self ,  cx :  & LateContext < ' tcx > ,  field :  & ' tcx  hir:: FieldDef < ' tcx > )  { 
14231461        self . check_type_for_external_abi_fnptr ( 
14241462            cx, 
1425-             VisitorState :: StaticTy , 
14261463            field. ty , 
14271464            cx. tcx . type_of ( field. def_id ) . instantiate_identity ( ) , 
14281465        ) ; 
@@ -1448,10 +1485,9 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesLint {
14481485        // fnptrs are a special case, they always need to be treated as 
14491486        // "the element rendered unsafe" because their unsafety doesn't affect 
14501487        // their surroundings, and their type is often declared inline 
1488+         self . check_fn_for_external_abi_fnptr ( cx,  id,  decl) ; 
14511489        if  !abi. is_rustic_abi ( )  { 
14521490            self . check_foreign_fn ( cx,  CItemKind :: ExportedFunction ,  id,  decl) ; 
1453-         }  else  { 
1454-             self . check_fn_for_external_abi_fnptr ( cx,  CItemKind :: ExportedFunction ,  id,  decl) ; 
14551491        } 
14561492    } 
14571493} 
0 commit comments