@@ -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) ;
@@ -947,7 +970,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
947
970
948
971
// it is only OK to use this function because extern fns cannot have
949
972
// 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) ;
951
974
952
975
// C doesn't really support passing arrays by value - the only way to pass an array by value
953
976
// 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> {
997
1020
let ty = self . cx . tcx . type_of ( def_id) ;
998
1021
self . check_type_for_ffi_and_report_errors ( span, ty, true , false ) ;
999
1022
}
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
+ }
1000
1031
}
1001
1032
1002
- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypes {
1033
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDeclarations {
1003
1034
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 } ;
1005
1036
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) {
1009
1039
match it. kind {
1010
1040
hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1011
1041
vis. check_foreign_fn ( it. hir_id , decl) ;
@@ -1019,6 +1049,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
1019
1049
}
1020
1050
}
1021
1051
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
+
1022
1077
declare_lint_pass ! ( VariantSizeDifferences => [ VARIANT_SIZE_DIFFERENCES ] ) ;
1023
1078
1024
1079
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for VariantSizeDifferences {
0 commit comments