Change:
(imported from improperly closed bug ) You cannot pass an array to or return an array from a C function. The signature is equivalent to for every in C. Therefore it is meaningless to write this in Rust, (or rather, it does not mean what a C programmer and/or FFI generation tool likely thinks it means): Option for dealing with this: We can extend our existing lint to detect cases like this and warn about them. We could make the form reject this signature, since the expected correspondence between Rust and C does not hold here. If the Rust FFI binding generation scripts/programs out there are generating this sort of code, they need to be fixed.
triage: P-low
Triage: array syntax has changed, here's the correct syntax: no warning or anything.
Triage: no change
This would have to be implemented as a lint now due to the potential of breaking existing builds. It should be easy enough to implement.

Discussion:
} impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { <ins> /// Check if the type is array and emit an unsafe type lint. fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { if let ty::Array(..) = ty.kind { self.emit_ffi_unsafe_type_lint( ty, sp, "passing raw arrays by value is not FFI-safe", Some("consider passing a pointer to the array"), ); true } else { false } } </ins> /// Checks if the given type is "ffi-safe" (has a stable, well-defined /// representation which can be exported to C code). fn check_type_for_ffi(&self,

ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => self.check_type_for_ffi(cache, ty), <del> ty::Array(ty, _) => self.check_type_for_ffi(cache, ty), </del> <ins> ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty), </ins> ty::FnPtr(sig) => { match sig.abi() {

} } <del> fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) { </del> <ins> fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>, is_static: bool) { </ins> // We have to check for opaque types before `normalize_erasing_regions`, // which will replace opaque types with their underlying concrete type. if self.check_for_opaque_ty(sp, ty) {

// it is only OK to use this function because extern fns cannot have // any generic types right now: let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); <ins> // C doesn't really support passing arrays by value. // The only way to pass an array by value is through a struct. // So we first test that the top level isn't an array, // and then recursively check the types inside. if !is_static && self.check_for_array_ty(sp, ty) { return; } </ins> match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { FfiResult::FfiSafe => {}

let sig = self.cx.tcx.erase_late_bound_regions(&sig); for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) { <del> self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty); </del> <ins> self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false); </ins> } if let hir::Return(ref ret_hir) = decl.output { let ret_ty = sig.output(); if !ret_ty.is_unit() { <del> self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty); </del> <ins> self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false); </ins> } } }

fn check_foreign_static(&mut self, id: hir::HirId, span: Span) { let def_id = self.cx.tcx.hir().local_def_id(id); let ty = self.cx.tcx.type_of(def_id); <del> self.check_type_for_ffi_and_report_errors(span, ty); </del> <ins> self.check_type_for_ffi_and_report_errors(span, ty, true); </ins> } }

pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box<u32>` <ins> pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]` pub static static_u128_type: u128; //~ ERROR: uses type `u128` pub static static_u128_array_type: [u128; 16]; //~ ERROR: uses type `u128` </ins> pub fn good3(fptr: Option<extern fn()>); pub fn good4(aptr: &[u8; 4 as usize]);

pub fn good17(p: TransparentCustomZst); #[allow(improper_ctypes)] pub fn good18(_: &String); <ins> pub fn good20(arr: *const [u8; 8]); pub static good21: [u8; 8]; </ins> } #[allow(improper_ctypes)]

= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout <del> error: aborting due to 20 previous errors </del> <ins> error: `extern` block uses type `[u8; 8]`, which is not FFI-safe --> $DIR/lint-ctypes.rs:68:27 | LL |     pub fn raw_array(arr: [u8; 8]); |                           ^^^^^^^ not FFI-safe | = help: consider passing a pointer to the array = note: passing raw arrays by value is not FFI-safe error: `extern` block uses type `u128`, which is not FFI-safe --> $DIR/lint-ctypes.rs:70:34 | LL |     pub static static_u128_type: u128; |                                  ^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe --> $DIR/lint-ctypes.rs:71:40 | LL |     pub static static_u128_array_type: [u128; 16]; |                                        ^^^^^^^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI error: aborting due to 23 previous errors </ins>