@@ -14,7 +14,7 @@ use rustc_middle::ty::subst::SubstsRef;
1414use rustc_middle:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
1515use rustc_span:: source_map;
1616use rustc_span:: symbol:: sym;
17- use rustc_span:: Span ;
17+ use rustc_span:: { Span , DUMMY_SP } ;
1818use rustc_target:: abi:: { Integer , LayoutOf , TagEncoding , VariantIdx , Variants } ;
1919use rustc_target:: spec:: abi:: Abi ;
2020
@@ -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 > {
@@ -804,27 +818,32 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
804818 help : Some ( "consider using a struct instead" . into ( ) ) ,
805819 } ,
806820
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+
807830 ty:: RawPtr ( ty:: TypeAndMut { ty, .. } ) | ty:: Ref ( _, ty, _) => {
808831 self . check_type_for_ffi ( cache, ty)
809832 }
810833
811834 ty:: Array ( inner_ty, _) => self . check_type_for_ffi ( cache, inner_ty) ,
812835
813836 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"
819844 . into ( ) ,
820- help : Some (
821- "consider using an `extern fn(...) -> ...` \
822- function pointer instead"
823- . into ( ) ,
824- ) ,
825- } ;
826- }
827- _ => { }
845+ ) ,
846+ } ;
828847 }
829848
830849 let sig = cx. erase_late_bound_regions ( & sig) ;
@@ -857,15 +876,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
857876 FfiUnsafe { ty, reason : "opaque types have no C equivalent" . into ( ) , help : None }
858877 }
859878
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+
860887 ty:: Param ( ..)
888+ | ty:: Projection ( ..)
861889 | ty:: Infer ( ..)
862890 | ty:: Bound ( ..)
863891 | ty:: Error ( _)
864892 | ty:: Closure ( ..)
865893 | ty:: Generator ( ..)
866894 | ty:: GeneratorWitness ( ..)
867895 | ty:: Placeholder ( ..)
868- | ty:: Projection ( ..)
869896 | ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
870897 }
871898 }
@@ -877,9 +904,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
877904 note : & str ,
878905 help : Option < & str > ,
879906 ) {
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+ ) ) ;
883921 diag. span_label ( sp, "not FFI-safe" ) ;
884922 if let Some ( help) = help {
885923 diag. help ( help) ;
@@ -947,7 +985,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
947985
948986 // it is only OK to use this function because extern fns cannot have
949987 // 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) ;
951989
952990 // C doesn't really support passing arrays by value - the only way to pass an array by value
953991 // 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> {
9971035 let ty = self . cx . tcx . type_of ( def_id) ;
9981036 self . check_type_for_ffi_and_report_errors ( span, ty, true , false ) ;
9991037 }
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+ }
10001046}
10011047
1002- impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypes {
1048+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypesDeclarations {
10031049 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 } ;
10051051 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) {
10091054 match it. kind {
10101055 hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
10111056 vis. check_foreign_fn ( it. hir_id , decl) ;
@@ -1019,6 +1064,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
10191064 }
10201065}
10211066
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+
10221092declare_lint_pass ! ( VariantSizeDifferences => [ VARIANT_SIZE_DIFFERENCES ] ) ;
10231093
10241094impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for VariantSizeDifferences {
0 commit comments