@@ -498,10 +498,24 @@ declare_lint! {
498
498
"proper use of libc types in foreign modules"
499
499
}
500
500
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
+ }
502
515
503
516
struct ImproperCTypesVisitor < ' a , ' tcx > {
504
517
cx : & ' a LateContext < ' a , ' tcx > ,
518
+ mode : ImproperCTypesMode ,
505
519
}
506
520
507
521
enum FfiResult < ' tcx > {
@@ -811,20 +825,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
811
825
ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache, inner_ty) ,
812
826
813
827
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"
819
835
. into ( ) ,
820
- help : Some (
821
- "consider using an `extern fn(...) -> ...` \
822
- function pointer instead"
823
- . into ( ) ,
824
- ) ,
825
- } ;
826
- }
827
- _ => { }
836
+ ) ,
837
+ } ;
828
838
}
829
839
830
840
let sig = cx. erase_late_bound_regions ( & sig) ;
@@ -857,15 +867,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
857
867
FfiUnsafe { ty, reason : "opaque types have no C equivalent" . into ( ) , help : None }
858
868
}
859
869
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 ( ..)
862
875
| ty:: Bound ( ..)
863
876
| ty:: Error ( _)
864
877
| ty:: Closure ( ..)
865
878
| ty:: Generator ( ..)
866
879
| ty:: GeneratorWitness ( ..)
867
880
| ty:: Placeholder ( ..)
868
- | ty:: Projection ( ..)
869
881
| ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
870
882
}
871
883
}
@@ -877,9 +889,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
877
889
note : & str ,
878
890
help : Option < & str > ,
879
891
) {
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
+ ) ) ;
883
906
diag. span_label ( sp, "not FFI-safe" ) ;
884
907
if let Some ( help) = help {
885
908
diag. help ( help) ;
@@ -936,7 +959,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
936
959
937
960
// it is only OK to use this function because extern fns cannot have
938
961
// any generic types right now:
939
- let ty = self . cx . tcx . normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , ty) ;
962
+ let ty = self . cx . tcx . normalize_erasing_regions ( self . cx . param_env , ty) ;
940
963
941
964
// C doesn't really support passing arrays by value - the only way to pass an array by value
942
965
// is through a struct. So, first test that the top level isn't an array, and then
@@ -986,15 +1009,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
986
1009
let ty = self . cx . tcx . type_of ( def_id) ;
987
1010
self . check_type_for_ffi_and_report_errors ( span, ty, true , false ) ;
988
1011
}
1012
+
1013
+ fn is_internal_abi ( & self , abi : Abi ) -> bool {
1014
+ if let Abi :: Rust | Abi :: RustCall | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = abi {
1015
+ true
1016
+ } else {
1017
+ false
1018
+ }
1019
+ }
989
1020
}
990
1021
991
- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypes {
1022
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDeclarations {
992
1023
fn check_foreign_item ( & mut self , cx : & LateContext < ' _ , ' _ > , it : & hir:: ForeignItem < ' _ > ) {
993
- let mut vis = ImproperCTypesVisitor { cx } ;
1024
+ let mut vis = ImproperCTypesVisitor { cx, mode : ImproperCTypesMode :: Declarations } ;
994
1025
let abi = cx. tcx . hir ( ) . get_foreign_abi ( it. hir_id ) ;
995
- if let Abi :: Rust | Abi :: RustCall | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = abi {
996
- // Don't worry about types in internal ABIs.
997
- } else {
1026
+
1027
+ if !vis. is_internal_abi ( abi) {
998
1028
match it. kind {
999
1029
hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1000
1030
vis. check_foreign_fn ( it. hir_id , decl) ;
@@ -1008,6 +1038,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
1008
1038
}
1009
1039
}
1010
1040
1041
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDefinitions {
1042
+ fn check_fn (
1043
+ & mut self ,
1044
+ cx : & LateContext < ' a , ' tcx > ,
1045
+ kind : hir:: intravisit:: FnKind < ' tcx > ,
1046
+ decl : & ' tcx hir:: FnDecl < ' _ > ,
1047
+ _: & ' tcx hir:: Body < ' _ > ,
1048
+ _: Span ,
1049
+ hir_id : hir:: HirId ,
1050
+ ) {
1051
+ use hir:: intravisit:: FnKind ;
1052
+
1053
+ let abi = match kind {
1054
+ FnKind :: ItemFn ( _, _, header, ..) => header. abi ,
1055
+ FnKind :: Method ( _, sig, ..) => sig. header . abi ,
1056
+ _ => return ,
1057
+ } ;
1058
+
1059
+ let mut vis = ImproperCTypesVisitor { cx, mode : ImproperCTypesMode :: Definitions } ;
1060
+ if !vis. is_internal_abi ( abi) {
1061
+ vis. check_foreign_fn ( hir_id, decl) ;
1062
+ }
1063
+ }
1064
+ }
1065
+
1011
1066
declare_lint_pass ! ( VariantSizeDifferences => [ VARIANT_SIZE_DIFFERENCES ] ) ;
1012
1067
1013
1068
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for VariantSizeDifferences {
0 commit comments