@@ -600,6 +600,23 @@ fn is_repr_nullable_ptr<'tcx>(
600600}
601601
602602impl < ' 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+
603620 /// Checks if the given type is "ffi-safe" (has a stable, well-defined
604621 /// representation which can be exported to C code).
605622 fn check_type_for_ffi ( & self ,
@@ -834,7 +851,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
834851 ty:: RawPtr ( ty:: TypeAndMut { ty, .. } ) |
835852 ty:: Ref ( _, ty, _) => self . check_type_for_ffi ( cache, ty) ,
836853
837- ty:: Array ( ty , _) => self . check_type_for_ffi ( cache, ty ) ,
854+ ty:: Array ( inner_ty , _) => self . check_type_for_ffi ( cache, inner_ty ) ,
838855
839856 ty:: FnPtr ( sig) => {
840857 match sig. abi ( ) {
@@ -946,7 +963,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
946963 }
947964 }
948965
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 ) {
950967 // We have to check for opaque types before `normalize_erasing_regions`,
951968 // which will replace opaque types with their underlying concrete type.
952969 if self . check_for_opaque_ty ( sp, ty) {
@@ -957,6 +974,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
957974 // it is only OK to use this function because extern fns cannot have
958975 // any generic types right now:
959976 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+ }
960984
961985 match self . check_type_for_ffi ( & mut FxHashSet :: default ( ) , ty) {
962986 FfiResult :: FfiSafe => { }
@@ -975,21 +999,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
975999 let sig = self . cx . tcx . erase_late_bound_regions ( & sig) ;
9761000
9771001 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 ) ;
9791003 }
9801004
9811005 if let hir:: Return ( ref ret_hir) = decl. output {
9821006 let ret_ty = sig. output ( ) ;
9831007 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 ) ;
9851009 }
9861010 }
9871011 }
9881012
9891013 fn check_foreign_static ( & mut self , id : hir:: HirId , span : Span ) {
9901014 let def_id = self . cx . tcx . hir ( ) . local_def_id ( id) ;
9911015 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 ) ;
9931017 }
9941018}
9951019
0 commit comments