Skip to content

Commit 2f1a4b3

Browse files
authored
Rollup merge of #66305 - elichai:2019-11-array_ffi, r=eddyb
Add by-value arrays to `improper_ctypes` lint Hi, C doesn't have a notion of passing arrays by value, only by reference/pointer. Rust currently will pass it correctly by reference by it looks very misleading, and can confuse the borrow checker to think a move had occurred. Fixes #58905 and fixes #24578. We could also improve the borrow checker here but I think it's kinda a waste of work if we instead just tell the user it's an invalid FFI call. (My first PR to `rustc` so if I missed some test or formatting guideline please tell me :) )
2 parents b92b705 + b3666b6 commit 2f1a4b3

File tree

3 files changed

+62
-6
lines changed

3 files changed

+62
-6
lines changed

src/librustc_lint/types.rs

+29-5
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,23 @@ fn is_repr_nullable_ptr<'tcx>(
591591
}
592592

593593
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
594+
595+
/// Check if the type is array and emit an unsafe type lint.
596+
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
597+
if let ty::Array(..) = ty.kind {
598+
self.emit_ffi_unsafe_type_lint(
599+
ty,
600+
sp,
601+
"passing raw arrays by value is not FFI-safe",
602+
Some("consider passing a pointer to the array"),
603+
);
604+
true
605+
} else {
606+
false
607+
}
608+
}
609+
610+
594611
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
595612
/// representation which can be exported to C code).
596613
fn check_type_for_ffi(&self,
@@ -825,7 +842,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
825842
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
826843
ty::Ref(_, ty, _) => self.check_type_for_ffi(cache, ty),
827844

828-
ty::Array(ty, _) => self.check_type_for_ffi(cache, ty),
845+
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
829846

830847
ty::FnPtr(sig) => {
831848
match sig.abi() {
@@ -937,7 +954,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
937954
}
938955
}
939956

940-
fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
957+
fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>, is_static: bool) {
941958
// We have to check for opaque types before `normalize_erasing_regions`,
942959
// which will replace opaque types with their underlying concrete type.
943960
if self.check_for_opaque_ty(sp, ty) {
@@ -948,6 +965,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
948965
// it is only OK to use this function because extern fns cannot have
949966
// any generic types right now:
950967
let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
968+
// C doesn't really support passing arrays by value.
969+
// The only way to pass an array by value is through a struct.
970+
// So we first test that the top level isn't an array,
971+
// and then recursively check the types inside.
972+
if !is_static && self.check_for_array_ty(sp, ty) {
973+
return;
974+
}
951975

952976
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
953977
FfiResult::FfiSafe => {}
@@ -966,21 +990,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
966990
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
967991

968992
for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
969-
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
993+
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false);
970994
}
971995

972996
if let hir::Return(ref ret_hir) = decl.output {
973997
let ret_ty = sig.output();
974998
if !ret_ty.is_unit() {
975-
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
999+
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false);
9761000
}
9771001
}
9781002
}
9791003

9801004
fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
9811005
let def_id = self.cx.tcx.hir().local_def_id(id);
9821006
let ty = self.cx.tcx.type_of(def_id);
983-
self.check_type_for_ffi_and_report_errors(span, ty);
1007+
self.check_type_for_ffi_and_report_errors(span, ty, true);
9841008
}
9851009
}
9861010

src/test/ui/lint/lint-ctypes.rs

+7
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ extern {
6565
pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128`
6666
pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
6767
pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box<u32>`
68+
pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]`
69+
70+
pub static static_u128_type: u128; //~ ERROR: uses type `u128`
71+
pub static static_u128_array_type: [u128; 16]; //~ ERROR: uses type `u128`
6872

6973
pub fn good3(fptr: Option<extern fn()>);
7074
pub fn good4(aptr: &[u8; 4 as usize]);
@@ -83,6 +87,9 @@ extern {
8387
pub fn good17(p: TransparentCustomZst);
8488
#[allow(improper_ctypes)]
8589
pub fn good18(_: &String);
90+
pub fn good20(arr: *const [u8; 8]);
91+
pub static good21: [u8; 8];
92+
8693
}
8794

8895
#[allow(improper_ctypes)]

src/test/ui/lint/lint-ctypes.stderr

+26-1
Original file line numberDiff line numberDiff line change
@@ -197,5 +197,30 @@ LL | pub fn transparent_fn(p: TransparentBadFn);
197197
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
198198
= note: this struct has unspecified layout
199199

200-
error: aborting due to 20 previous errors
200+
error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
201+
--> $DIR/lint-ctypes.rs:68:27
202+
|
203+
LL | pub fn raw_array(arr: [u8; 8]);
204+
| ^^^^^^^ not FFI-safe
205+
|
206+
= help: consider passing a pointer to the array
207+
= note: passing raw arrays by value is not FFI-safe
208+
209+
error: `extern` block uses type `u128`, which is not FFI-safe
210+
--> $DIR/lint-ctypes.rs:70:34
211+
|
212+
LL | pub static static_u128_type: u128;
213+
| ^^^^ not FFI-safe
214+
|
215+
= note: 128-bit integers don't currently have a known stable ABI
216+
217+
error: `extern` block uses type `u128`, which is not FFI-safe
218+
--> $DIR/lint-ctypes.rs:71:40
219+
|
220+
LL | pub static static_u128_array_type: [u128; 16];
221+
| ^^^^^^^^^^ not FFI-safe
222+
|
223+
= note: 128-bit integers don't currently have a known stable ABI
224+
225+
error: aborting due to 23 previous errors
201226

0 commit comments

Comments
 (0)