@@ -4,7 +4,7 @@ use rustc::hir::{ExprKind, Node};
44use crate :: hir:: def_id:: DefId ;
55use rustc:: hir:: lowering:: is_range_literal;
66use rustc:: ty:: subst:: SubstsRef ;
7- use rustc:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt } ;
7+ use rustc:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
88use rustc:: ty:: layout:: { self , IntegerExt , LayoutOf , VariantIdx , SizeSkeleton } ;
99use rustc:: { lint, util} ;
1010use rustc_index:: vec:: Idx ;
@@ -835,16 +835,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
835835 ty:: Array ( ty, _) => self . check_type_for_ffi ( cache, ty) ,
836836
837837 ty:: FnPtr ( sig) => {
838- match sig. abi ( ) {
839- Abi :: Rust | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic | Abi :: RustCall => {
840- return FfiUnsafe {
841- ty,
842- reason : "this function pointer has Rust-specific calling convention" ,
843- help : Some ( "consider using an `extern fn(...) -> ...` \
844- function pointer instead") ,
845- }
846- }
847- _ => { }
838+ if self . is_internal_abi ( sig. abi ( ) ) {
839+ return FfiUnsafe {
840+ ty,
841+ reason : "this function pointer has Rust-specific calling convention" ,
842+ help : Some ( "consider using an `extern fn(...) -> ...` \
843+ function pointer instead") ,
844+ } ;
848845 }
849846
850847 let sig = cx. erase_late_bound_regions ( & sig) ;
@@ -871,7 +868,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
871868
872869 ty:: Foreign ( ..) => FfiSafe ,
873870
874- ty:: Param ( ..) |
871+ // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
872+ // so they are currently ignored for the purposes of this lint, see #65134.
873+ ty:: Param ( ..) | ty:: Projection ( ..) => FfiSafe ,
874+
875875 ty:: Infer ( ..) |
876876 ty:: Bound ( ..) |
877877 ty:: Error |
@@ -880,7 +880,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
880880 ty:: GeneratorWitness ( ..) |
881881 ty:: Placeholder ( ..) |
882882 ty:: UnnormalizedProjection ( ..) |
883- ty:: Projection ( ..) |
884883 ty:: Opaque ( ..) |
885884 ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
886885 }
@@ -892,11 +891,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
892891 sp : Span ,
893892 note : & str ,
894893 help : Option < & str > ,
894+ is_foreign_item : bool ,
895895 ) {
896896 let mut diag = self . cx . struct_span_lint (
897897 IMPROPER_CTYPES ,
898898 sp,
899- & format ! ( "`extern` block uses type `{}`, which is not FFI-safe" , ty) ,
899+ & format ! (
900+ "`extern` {} uses type `{}`, which is not FFI-safe" ,
901+ if is_foreign_item { "block" } else { "fn" } ,
902+ ty,
903+ ) ,
900904 ) ;
901905 diag. span_label ( sp, "not FFI-safe" ) ;
902906 if let Some ( help) = help {
@@ -911,9 +915,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
911915 diag. emit ( ) ;
912916 }
913917
914- fn check_for_opaque_ty ( & mut self , sp : Span , ty : Ty < ' tcx > ) -> bool {
915- use crate :: rustc:: ty:: TypeFoldable ;
916-
918+ fn check_for_opaque_ty ( & mut self , sp : Span , ty : Ty < ' tcx > , is_foreign_item : bool ) -> bool {
917919 struct ProhibitOpaqueTypes < ' tcx > {
918920 ty : Option < Ty < ' tcx > > ,
919921 } ;
@@ -937,70 +939,81 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
937939 sp,
938940 "opaque types have no C equivalent" ,
939941 None ,
942+ is_foreign_item,
940943 ) ;
941944 true
942945 } else {
943946 false
944947 }
945948 }
946949
947- fn check_type_for_ffi_and_report_errors ( & mut self , sp : Span , ty : Ty < ' tcx > ) {
950+ fn check_type_for_ffi_and_report_errors (
951+ & mut self ,
952+ sp : Span ,
953+ ty : Ty < ' tcx > ,
954+ is_foreign_item : bool ,
955+ ) {
948956 // We have to check for opaque types before `normalize_erasing_regions`,
949957 // which will replace opaque types with their underlying concrete type.
950- if self . check_for_opaque_ty ( sp, ty) {
958+ if self . check_for_opaque_ty ( sp, ty, is_foreign_item ) {
951959 // We've already emitted an error due to an opaque type.
952960 return ;
953961 }
954962
955- // it is only OK to use this function because extern fns cannot have
956- // any generic types right now:
957- let ty = self . cx . tcx . normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , ty) ;
958-
963+ let ty = self . cx . tcx . normalize_erasing_regions ( self . cx . param_env , ty) ;
959964 match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
960965 FfiResult :: FfiSafe => { }
961966 FfiResult :: FfiPhantom ( ty) => {
962- self . emit_ffi_unsafe_type_lint ( ty, sp, "composed only of `PhantomData`" , None ) ;
967+ self . emit_ffi_unsafe_type_lint (
968+ ty, sp, "composed only of `PhantomData`" , None , is_foreign_item) ;
963969 }
964970 FfiResult :: FfiUnsafe { ty, reason, help } => {
965- self . emit_ffi_unsafe_type_lint ( ty, sp, reason, help) ;
971+ self . emit_ffi_unsafe_type_lint (
972+ ty, sp, reason, help, is_foreign_item) ;
966973 }
967974 }
968975 }
969976
970- fn check_foreign_fn ( & mut self , id : hir:: HirId , decl : & hir:: FnDecl ) {
977+ fn check_foreign_fn ( & mut self , id : hir:: HirId , decl : & hir:: FnDecl , is_foreign_item : bool ) {
971978 let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) ;
972979 let sig = self . cx . tcx . fn_sig ( def_id) ;
973980 let sig = self . cx . tcx . erase_late_bound_regions ( & sig) ;
974981
975982 for ( input_ty, input_hir) in sig. inputs ( ) . iter ( ) . zip ( & decl. inputs ) {
976- self . check_type_for_ffi_and_report_errors ( input_hir. span , input_ty) ;
983+ self . check_type_for_ffi_and_report_errors ( input_hir. span , input_ty, is_foreign_item ) ;
977984 }
978985
979986 if let hir:: Return ( ref ret_hir) = decl. output {
980987 let ret_ty = sig. output ( ) ;
981988 if !ret_ty. is_unit ( ) {
982- self . check_type_for_ffi_and_report_errors ( ret_hir. span , ret_ty) ;
989+ self . check_type_for_ffi_and_report_errors ( ret_hir. span , ret_ty, is_foreign_item ) ;
983990 }
984991 }
985992 }
986993
987994 fn check_foreign_static ( & mut self , id : hir:: HirId , span : Span ) {
988995 let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) ;
989996 let ty = self . cx . tcx . type_of ( def_id) ;
990- self . check_type_for_ffi_and_report_errors ( span, ty) ;
997+ self . check_type_for_ffi_and_report_errors ( span, ty, true ) ;
998+ }
999+
1000+ fn is_internal_abi ( & self , abi : Abi ) -> bool {
1001+ if let Abi :: Rust | Abi :: RustCall | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = abi {
1002+ true
1003+ } else {
1004+ false
1005+ }
9911006 }
9921007}
9931008
9941009impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypes {
9951010 fn check_foreign_item ( & mut self , cx : & LateContext < ' _ , ' _ > , it : & hir:: ForeignItem ) {
9961011 let mut vis = ImproperCTypesVisitor { cx } ;
9971012 let abi = cx. tcx . hir ( ) . get_foreign_abi ( it. hir_id ) ;
998- if let Abi :: Rust | Abi :: RustCall | Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = abi {
999- // Don't worry about types in internal ABIs.
1000- } else {
1013+ if !vis. is_internal_abi ( abi) {
10011014 match it. kind {
10021015 hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1003- vis. check_foreign_fn ( it. hir_id , decl) ;
1016+ vis. check_foreign_fn ( it. hir_id , decl, true ) ;
10041017 }
10051018 hir:: ForeignItemKind :: Static ( ref ty, _) => {
10061019 vis. check_foreign_static ( it. hir_id , ty. span ) ;
@@ -1009,6 +1022,29 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
10091022 }
10101023 }
10111024 }
1025+
1026+ fn check_fn (
1027+ & mut self ,
1028+ cx : & LateContext < ' a , ' tcx > ,
1029+ kind : hir:: intravisit:: FnKind < ' tcx > ,
1030+ decl : & ' tcx hir:: FnDecl ,
1031+ _: & ' tcx hir:: Body ,
1032+ _: Span ,
1033+ hir_id : hir:: HirId ,
1034+ ) {
1035+ use hir:: intravisit:: FnKind ;
1036+
1037+ let abi = match kind {
1038+ FnKind :: ItemFn ( _, _, header, ..) => ( header. abi ) ,
1039+ FnKind :: Method ( _, sig, ..) => ( sig. header . abi ) ,
1040+ _ => return ,
1041+ } ;
1042+
1043+ let mut vis = ImproperCTypesVisitor { cx } ;
1044+ if !vis. is_internal_abi ( abi) {
1045+ vis. check_foreign_fn ( hir_id, decl, false ) ;
1046+ }
1047+ }
10121048}
10131049
10141050declare_lint_pass ! ( VariantSizeDifferences => [ VARIANT_SIZE_DIFFERENCES ] ) ;
0 commit comments