@@ -600,6 +600,23 @@ fn is_repr_nullable_ptr<'tcx>(
600
600
}
601
601
602
602
impl < ' a , ' tcx > ImproperCTypesVisitor < ' a , ' tcx > {
603
+
604
+ /// Check if the type is array and emit an unsafe type lint.
605
+ fn check_for_array_ty ( & mut self , sp : Span , ty : Ty < ' tcx > ) -> bool {
606
+ if let ty:: Array ( ..) = ty. kind {
607
+ self . emit_ffi_unsafe_type_lint (
608
+ ty,
609
+ sp,
610
+ "passing raw arrays by value is not FFI-safe" ,
611
+ Some ( "consider passing a pointer to the array" ) ,
612
+ ) ;
613
+ true
614
+ } else {
615
+ false
616
+ }
617
+ }
618
+
619
+
603
620
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
604
621
/// representation which can be exported to C code).
605
622
fn check_type_for_ffi ( & self ,
@@ -834,7 +851,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
834
851
ty:: RawPtr ( ty:: TypeAndMut { ty, .. } ) |
835
852
ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( cache, ty) ,
836
853
837
- ty:: Array ( ty , _) => self . check_type_for_ffi ( cache, ty ) ,
854
+ ty:: Array ( inner_ty , _) => self . check_type_for_ffi ( cache, inner_ty ) ,
838
855
839
856
ty:: FnPtr ( sig) => {
840
857
match sig. abi ( ) {
@@ -946,7 +963,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
946
963
}
947
964
}
948
965
949
- fn check_type_for_ffi_and_report_errors ( & mut self , sp : Span , ty : Ty < ' tcx > ) {
966
+ fn check_type_for_ffi_and_report_errors ( & mut self , sp : Span , ty : Ty < ' tcx > , is_static : bool ) {
950
967
// We have to check for opaque types before `normalize_erasing_regions`,
951
968
// which will replace opaque types with their underlying concrete type.
952
969
if self . check_for_opaque_ty ( sp, ty) {
@@ -957,6 +974,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
957
974
// it is only OK to use this function because extern fns cannot have
958
975
// any generic types right now:
959
976
let ty = self . cx . tcx . normalize_erasing_regions ( ParamEnv :: reveal_all ( ) , ty) ;
977
+ // C doesn't really support passing arrays by value.
978
+ // The only way to pass an array by value is through a struct.
979
+ // So we first test that the top level isn't an array,
980
+ // and then recursively check the types inside.
981
+ if !is_static && self . check_for_array_ty ( sp, ty) {
982
+ return ;
983
+ }
960
984
961
985
match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
962
986
FfiResult :: FfiSafe => { }
@@ -975,21 +999,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
975
999
let sig = self . cx . tcx . erase_late_bound_regions ( & sig) ;
976
1000
977
1001
for ( input_ty, input_hir) in sig. inputs ( ) . iter ( ) . zip ( & decl. inputs ) {
978
- self . check_type_for_ffi_and_report_errors ( input_hir. span , input_ty) ;
1002
+ self . check_type_for_ffi_and_report_errors ( input_hir. span , input_ty, false ) ;
979
1003
}
980
1004
981
1005
if let hir:: Return ( ref ret_hir) = decl. output {
982
1006
let ret_ty = sig. output ( ) ;
983
1007
if !ret_ty. is_unit ( ) {
984
- self . check_type_for_ffi_and_report_errors ( ret_hir. span , ret_ty) ;
1008
+ self . check_type_for_ffi_and_report_errors ( ret_hir. span , ret_ty, false ) ;
985
1009
}
986
1010
}
987
1011
}
988
1012
989
1013
fn check_foreign_static ( & mut self , id : hir:: HirId , span : Span ) {
990
1014
let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) ;
991
1015
let ty = self . cx . tcx . type_of ( def_id) ;
992
- self . check_type_for_ffi_and_report_errors ( span, ty) ;
1016
+ self . check_type_for_ffi_and_report_errors ( span, ty, true ) ;
993
1017
}
994
1018
}
995
1019
0 commit comments