@@ -498,10 +498,24 @@ declare_lint! {
498498 "proper use of libc types in foreign modules"
499499}
500500
501- declare_lint_pass ! ( ImproperCTypes => [ IMPROPER_CTYPES ] ) ;
501+ declare_lint_pass ! ( ImproperCTypesDeclarations => [ IMPROPER_CTYPES ] ) ;
502+
503+ declare_lint ! {
504+ IMPROPER_CTYPES_DEFINITIONS ,
505+ Warn ,
506+ "proper use of libc types in foreign item definitions"
507+ }
508+
509+ declare_lint_pass ! ( ImproperCTypesDefinitions => [ IMPROPER_CTYPES_DEFINITIONS ] ) ;
510+
511+ enum ImproperCTypesMode {
512+ Declarations ,
513+ Definitions ,
514+ }
502515
503516struct ImproperCTypesVisitor < ' a , ' tcx > {
504517 cx : & ' a LateContext < ' a , ' tcx > ,
518+ mode : ImproperCTypesMode ,
505519}
506520
507521enum FfiResult < ' tcx > {
@@ -811,20 +825,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
811825 ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache, inner_ty) ,
812826
813827 ty:: FnPtr ( sig) => {
814- match sig. abi ( ) {
815- Abi :: Rust | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic | Abi :: RustCall => {
816- return FfiUnsafe {
817- ty,
818- reason : "this function pointer has Rust-specific calling convention"
828+ if self . is_internal_abi ( sig. abi ( ) ) {
829+ return FfiUnsafe {
830+ ty,
831+ reason : "this function pointer has Rust-specific calling convention" . into ( ) ,
832+ help : Some (
833+ "consider using an `extern fn(...) -> ...` \
834+ function pointer instead"
819835 . into ( ) ,
820- help : Some (
821- "consider using an `extern fn(...) -> ...` \
822- function pointer instead"
823- . into ( ) ,
824- ) ,
825- } ;
826- }
827- _ => { }
836+ ) ,
837+ } ;
828838 }
829839
830840 let sig = cx. erase_late_bound_regions ( & sig) ;
@@ -857,15 +867,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
857867 FfiUnsafe { ty, reason : "opaque types have no C equivalent" . into ( ) , help : None }
858868 }
859869
860- ty:: Param ( ..)
861- | ty:: Infer ( ..)
870+ // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
871+ // so they are currently ignored for the purposes of this lint.
872+ ty:: Param ( ..) | ty:: Projection ( ..) => FfiSafe ,
873+
874+ ty:: Infer ( ..)
862875 | ty:: Bound ( ..)
863876 | ty:: Error ( _)
864877 | ty:: Closure ( ..)
865878 | ty:: Generator ( ..)
866879 | ty:: GeneratorWitness ( ..)
867880 | ty:: Placeholder ( ..)
868- | ty:: Projection ( ..)
869881 | ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
870882 }
871883 }
@@ -877,9 +889,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
877889 note : & str ,
878890 help : Option < & str > ,
879891 ) {
880- self . cx . struct_span_lint ( IMPROPER_CTYPES , sp, |lint| {
881- let mut diag =
882- lint. build ( & format ! ( "`extern` block uses type `{}`, which is not FFI-safe" , ty) ) ;
892+ let lint = match self . mode {
893+ ImproperCTypesMode :: Declarations => IMPROPER_CTYPES ,
894+ ImproperCTypesMode :: Definitions => IMPROPER_CTYPES_DEFINITIONS ,
895+ } ;
896+
897+ self . cx . struct_span_lint ( lint, sp, |lint| {
898+ let item_description = match self . mode {
899+ ImproperCTypesMode :: Declarations => "block" ,
900+ ImproperCTypesMode :: Definitions => "fn" ,
901+ } ;
902+ let mut diag = lint. build ( & format ! (
903+ "`extern` {} uses type `{}`, which is not FFI-safe" ,
904+ item_description, ty
905+ ) ) ;
883906 diag. span_label ( sp, "not FFI-safe" ) ;
884907 if let Some ( help) = help {
885908 diag. help ( help) ;
@@ -947,7 +970,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
947970
948971 // it is only OK to use this function because extern fns cannot have
949972 // any generic types right now:
950- let ty = self . cx . tcx . normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , ty) ;
973+ let ty = self . cx . tcx . normalize_erasing_regions ( self . cx . param_env , ty) ;
951974
952975 // C doesn't really support passing arrays by value - the only way to pass an array by value
953976 // is through a struct. So, first test that the top level isn't an array, and then
@@ -997,15 +1020,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
9971020 let ty = self . cx . tcx . type_of ( def_id) ;
9981021 self . check_type_for_ffi_and_report_errors ( span, ty, true , false ) ;
9991022 }
1023+
1024+ fn is_internal_abi ( & self , abi : Abi ) -> bool {
1025+ if let Abi :: Rust | Abi :: RustCall | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = abi {
1026+ true
1027+ } else {
1028+ false
1029+ }
1030+ }
10001031}
10011032
1002- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypes {
1033+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDeclarations {
10031034 fn check_foreign_item ( & mut self , cx : & LateContext < ' _ , ' _ > , it : & hir:: ForeignItem < ' _ > ) {
1004- let mut vis = ImproperCTypesVisitor { cx } ;
1035+ let mut vis = ImproperCTypesVisitor { cx, mode : ImproperCTypesMode :: Declarations } ;
10051036 let abi = cx. tcx . hir ( ) . get_foreign_abi ( it. hir_id ) ;
1006- if let Abi :: Rust | Abi :: RustCall | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = abi {
1007- // Don't worry about types in internal ABIs.
1008- } else {
1037+
1038+ if !vis. is_internal_abi ( abi) {
10091039 match it. kind {
10101040 hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
10111041 vis. check_foreign_fn ( it. hir_id , decl) ;
@@ -1019,6 +1049,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
10191049 }
10201050}
10211051
1052+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDefinitions {
1053+ fn check_fn (
1054+ & mut self ,
1055+ cx : & LateContext < ' a , ' tcx > ,
1056+ kind : hir:: intravisit:: FnKind < ' tcx > ,
1057+ decl : & ' tcx hir:: FnDecl < ' _ > ,
1058+ _: & ' tcx hir:: Body < ' _ > ,
1059+ _: Span ,
1060+ hir_id : hir:: HirId ,
1061+ ) {
1062+ use hir:: intravisit:: FnKind ;
1063+
1064+ let abi = match kind {
1065+ FnKind :: ItemFn ( _, _, header, ..) => header. abi ,
1066+ FnKind :: Method ( _, sig, ..) => sig. header . abi ,
1067+ _ => return ,
1068+ } ;
1069+
1070+ let mut vis = ImproperCTypesVisitor { cx, mode : ImproperCTypesMode :: Definitions } ;
1071+ if !vis. is_internal_abi ( abi) {
1072+ vis. check_foreign_fn ( hir_id, decl) ;
1073+ }
1074+ }
1075+ }
1076+
10221077declare_lint_pass ! ( VariantSizeDifferences => [ VARIANT_SIZE_DIFFERENCES ] ) ;
10231078
10241079impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for VariantSizeDifferences {
0 commit comments