@@ -14,7 +14,7 @@ use rustc_middle::ty::subst::SubstsRef;
14
14
use rustc_middle:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
15
15
use rustc_span:: source_map;
16
16
use rustc_span:: symbol:: sym;
17
- use rustc_span:: Span ;
17
+ use rustc_span:: { Span , DUMMY_SP } ;
18
18
use rustc_target:: abi:: { Integer , LayoutOf , TagEncoding , VariantIdx , Variants } ;
19
19
use rustc_target:: spec:: abi:: Abi ;
20
20
@@ -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 > {
@@ -804,27 +818,32 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
804
818
help : Some ( "consider using a struct instead" . into ( ) ) ,
805
819
} ,
806
820
821
+ ty:: RawPtr ( ty:: TypeAndMut { ty, .. } ) | ty:: Ref ( _, ty, _)
822
+ if {
823
+ matches ! ( self . mode, ImproperCTypesMode :: Definitions )
824
+ && ty. is_sized ( self . cx . tcx . at ( DUMMY_SP ) , self . cx . param_env )
825
+ } =>
826
+ {
827
+ FfiSafe
828
+ }
829
+
807
830
ty:: RawPtr ( ty:: TypeAndMut { ty, .. } ) | ty:: Ref ( _, ty, _) => {
808
831
self . check_type_for_ffi ( cache, ty)
809
832
}
810
833
811
834
ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache, inner_ty) ,
812
835
813
836
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"
837
+ if self . is_internal_abi ( sig. abi ( ) ) {
838
+ return FfiUnsafe {
839
+ ty,
840
+ reason : "this function pointer has Rust-specific calling convention" . into ( ) ,
841
+ help : Some (
842
+ "consider using an `extern fn(...) -> ...` \
843
+ function pointer instead"
819
844
. into ( ) ,
820
- help : Some (
821
- "consider using an `extern fn(...) -> ...` \
822
- function pointer instead"
823
- . into ( ) ,
824
- ) ,
825
- } ;
826
- }
827
- _ => { }
845
+ ) ,
846
+ } ;
828
847
}
829
848
830
849
let sig = cx. erase_late_bound_regions ( & sig) ;
@@ -857,15 +876,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
857
876
FfiUnsafe { ty, reason : "opaque types have no C equivalent" . into ( ) , help : None }
858
877
}
859
878
879
+ // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
880
+ // so they are currently ignored for the purposes of this lint.
881
+ ty:: Param ( ..) | ty:: Projection ( ..)
882
+ if matches ! ( self . mode, ImproperCTypesMode :: Definitions ) =>
883
+ {
884
+ FfiSafe
885
+ }
886
+
860
887
ty:: Param ( ..)
888
+ | ty:: Projection ( ..)
861
889
| ty:: Infer ( ..)
862
890
| ty:: Bound ( ..)
863
891
| ty:: Error ( _)
864
892
| ty:: Closure ( ..)
865
893
| ty:: Generator ( ..)
866
894
| ty:: GeneratorWitness ( ..)
867
895
| ty:: Placeholder ( ..)
868
- | ty:: Projection ( ..)
869
896
| ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
870
897
}
871
898
}
@@ -877,9 +904,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
877
904
note : & str ,
878
905
help : Option < & str > ,
879
906
) {
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) ) ;
907
+ let lint = match self . mode {
908
+ ImproperCTypesMode :: Declarations => IMPROPER_CTYPES ,
909
+ ImproperCTypesMode :: Definitions => IMPROPER_CTYPES_DEFINITIONS ,
910
+ } ;
911
+
912
+ self . cx . struct_span_lint ( lint, sp, |lint| {
913
+ let item_description = match self . mode {
914
+ ImproperCTypesMode :: Declarations => "block" ,
915
+ ImproperCTypesMode :: Definitions => "fn" ,
916
+ } ;
917
+ let mut diag = lint. build ( & format ! (
918
+ "`extern` {} uses type `{}`, which is not FFI-safe" ,
919
+ item_description, ty
920
+ ) ) ;
883
921
diag. span_label ( sp, "not FFI-safe" ) ;
884
922
if let Some ( help) = help {
885
923
diag. help ( help) ;
@@ -947,7 +985,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
947
985
948
986
// it is only OK to use this function because extern fns cannot have
949
987
// any generic types right now:
950
- let ty = self . cx . tcx . normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , ty) ;
988
+ let ty = self . cx . tcx . normalize_erasing_regions ( self . cx . param_env , ty) ;
951
989
952
990
// C doesn't really support passing arrays by value - the only way to pass an array by value
953
991
// is through a struct. So, first test that the top level isn't an array, and then
@@ -997,15 +1035,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
997
1035
let ty = self . cx . tcx . type_of ( def_id) ;
998
1036
self . check_type_for_ffi_and_report_errors ( span, ty, true , false ) ;
999
1037
}
1038
+
1039
+ fn is_internal_abi ( & self , abi : Abi ) -> bool {
1040
+ if let Abi :: Rust | Abi :: RustCall | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = abi {
1041
+ true
1042
+ } else {
1043
+ false
1044
+ }
1045
+ }
1000
1046
}
1001
1047
1002
- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypes {
1048
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDeclarations {
1003
1049
fn check_foreign_item ( & mut self , cx : & LateContext < ' _ , ' _ > , it : & hir:: ForeignItem < ' _ > ) {
1004
- let mut vis = ImproperCTypesVisitor { cx } ;
1050
+ let mut vis = ImproperCTypesVisitor { cx, mode : ImproperCTypesMode :: Declarations } ;
1005
1051
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 {
1052
+
1053
+ if !vis. is_internal_abi ( abi) {
1009
1054
match it. kind {
1010
1055
hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1011
1056
vis. check_foreign_fn ( it. hir_id , decl) ;
@@ -1019,6 +1064,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
1019
1064
}
1020
1065
}
1021
1066
1067
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDefinitions {
1068
+ fn check_fn (
1069
+ & mut self ,
1070
+ cx : & LateContext < ' a , ' tcx > ,
1071
+ kind : hir:: intravisit:: FnKind < ' tcx > ,
1072
+ decl : & ' tcx hir:: FnDecl < ' _ > ,
1073
+ _: & ' tcx hir:: Body < ' _ > ,
1074
+ _: Span ,
1075
+ hir_id : hir:: HirId ,
1076
+ ) {
1077
+ use hir:: intravisit:: FnKind ;
1078
+
1079
+ let abi = match kind {
1080
+ FnKind :: ItemFn ( _, _, header, ..) => header. abi ,
1081
+ FnKind :: Method ( _, sig, ..) => sig. header . abi ,
1082
+ _ => return ,
1083
+ } ;
1084
+
1085
+ let mut vis = ImproperCTypesVisitor { cx, mode : ImproperCTypesMode :: Definitions } ;
1086
+ if !vis. is_internal_abi ( abi) {
1087
+ vis. check_foreign_fn ( hir_id, decl) ;
1088
+ }
1089
+ }
1090
+ }
1091
+
1022
1092
declare_lint_pass ! ( VariantSizeDifferences => [ VARIANT_SIZE_DIFFERENCES ] ) ;
1023
1093
1024
1094
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for VariantSizeDifferences {
0 commit comments