@@ -4,7 +4,7 @@ use rustc::hir::{ExprKind, Node};
4
4
use crate :: hir:: def_id:: DefId ;
5
5
use rustc:: hir:: lowering:: is_range_literal;
6
6
use rustc:: ty:: subst:: SubstsRef ;
7
- use rustc:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt } ;
7
+ use rustc:: ty:: { self , AdtKind , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
8
8
use rustc:: ty:: layout:: { self , IntegerExt , LayoutOf , VariantIdx , SizeSkeleton } ;
9
9
use rustc:: { lint, util} ;
10
10
use rustc_index:: vec:: Idx ;
@@ -835,16 +835,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
835
835
ty:: Array ( ty, _) => self . check_type_for_ffi ( cache, ty) ,
836
836
837
837
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
+ } ;
848
845
}
849
846
850
847
let sig = cx. erase_late_bound_regions ( & sig) ;
@@ -871,7 +868,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
871
868
872
869
ty:: Foreign ( ..) => FfiSafe ,
873
870
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
+
875
875
ty:: Infer ( ..) |
876
876
ty:: Bound ( ..) |
877
877
ty:: Error |
@@ -880,7 +880,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
880
880
ty:: GeneratorWitness ( ..) |
881
881
ty:: Placeholder ( ..) |
882
882
ty:: UnnormalizedProjection ( ..) |
883
- ty:: Projection ( ..) |
884
883
ty:: Opaque ( ..) |
885
884
ty:: FnDef ( ..) => bug ! ( "unexpected type in foreign function: {:?}" , ty) ,
886
885
}
@@ -892,11 +891,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
892
891
sp : Span ,
893
892
note : & str ,
894
893
help : Option < & str > ,
894
+ is_foreign_item : bool ,
895
895
) {
896
896
let mut diag = self . cx . struct_span_lint (
897
897
IMPROPER_CTYPES ,
898
898
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
+ ) ,
900
904
) ;
901
905
diag. span_label ( sp, "not FFI-safe" ) ;
902
906
if let Some ( help) = help {
@@ -911,9 +915,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
911
915
diag. emit ( ) ;
912
916
}
913
917
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 {
917
919
struct ProhibitOpaqueTypes < ' tcx > {
918
920
ty : Option < Ty < ' tcx > > ,
919
921
} ;
@@ -937,70 +939,81 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
937
939
sp,
938
940
"opaque types have no C equivalent" ,
939
941
None ,
942
+ is_foreign_item,
940
943
) ;
941
944
true
942
945
} else {
943
946
false
944
947
}
945
948
}
946
949
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
+ ) {
948
956
// We have to check for opaque types before `normalize_erasing_regions`,
949
957
// 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 ) {
951
959
// We've already emitted an error due to an opaque type.
952
960
return ;
953
961
}
954
962
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) ;
959
964
match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
960
965
FfiResult :: FfiSafe => { }
961
966
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) ;
963
969
}
964
970
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) ;
966
973
}
967
974
}
968
975
}
969
976
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 ) {
971
978
let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) ;
972
979
let sig = self . cx . tcx . fn_sig ( def_id) ;
973
980
let sig = self . cx . tcx . erase_late_bound_regions ( & sig) ;
974
981
975
982
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 ) ;
977
984
}
978
985
979
986
if let hir:: Return ( ref ret_hir) = decl. output {
980
987
let ret_ty = sig. output ( ) ;
981
988
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 ) ;
983
990
}
984
991
}
985
992
}
986
993
987
994
fn check_foreign_static ( & mut self , id : hir:: HirId , span : Span ) {
988
995
let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) ;
989
996
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
+ }
991
1006
}
992
1007
}
993
1008
994
1009
impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for ImproperCTypes {
995
1010
fn check_foreign_item ( & mut self , cx : & LateContext < ' _ , ' _ > , it : & hir:: ForeignItem ) {
996
1011
let mut vis = ImproperCTypesVisitor { cx } ;
997
1012
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) {
1001
1014
match it. kind {
1002
1015
hir:: ForeignItemKind :: Fn ( ref decl, _, _) => {
1003
- vis. check_foreign_fn ( it. hir_id , decl) ;
1016
+ vis. check_foreign_fn ( it. hir_id , decl, true ) ;
1004
1017
}
1005
1018
hir:: ForeignItemKind :: Static ( ref ty, _) => {
1006
1019
vis. check_foreign_static ( it. hir_id , ty. span ) ;
@@ -1009,6 +1022,29 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
1009
1022
}
1010
1023
}
1011
1024
}
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
+ }
1012
1048
}
1013
1049
1014
1050
declare_lint_pass ! ( VariantSizeDifferences => [ VARIANT_SIZE_DIFFERENCES ] ) ;
0 commit comments