Rollup merge of #48221 - rkruppe:improve-ctypes-lint, r=estebank

Overhaul improper_ctypes output

This snowballed into a rather big set of improvements to the diagnostics of the improper_ctypes lint. See commits for details, including effects of each change on the `compile-fail/improper-ctypes.rs` test (now a UI test), which is pretty gnarly and hopefully not representative of real code, but covers a lot of different error cases.

Fixes #42050
This commit is contained in:
Manish Goregaokar 2018-02-23 10:24:52 -08:00 committed by GitHub
commit 9f36a35e61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 313 additions and 163 deletions

View File

@ -10,7 +10,6 @@
#![allow(non_snake_case)]
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
@ -26,7 +25,6 @@ use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
use syntax::ast;
use syntax::abi::Abi;
use syntax::attr;
use syntax_pos::Span;
use syntax::codemap;
@ -353,13 +351,14 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
}
enum FfiResult {
enum FfiResult<'tcx> {
FfiSafe,
FfiPhantom,
FfiUnsafe(&'static str),
FfiBadStruct(DefId, &'static str),
FfiBadUnion(DefId, &'static str),
FfiBadEnum(DefId, &'static str),
FfiPhantom(Ty<'tcx>),
FfiUnsafe {
ty: Ty<'tcx>,
reason: &'static str,
help: Option<&'static str>,
},
}
/// Check if this enum can be safely exported based on the
@ -397,23 +396,12 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
false
}
fn is_ffi_safe(ty: attr::IntType) -> bool {
match ty {
attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) |
attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) |
attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) |
attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) |
attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true,
attr::SignedInt(ast::IntTy::Isize) | attr::UnsignedInt(ast::UintTy::Usize) => false
}
}
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check 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,
cache: &mut FxHashSet<Ty<'tcx>>,
ty: Ty<'tcx>) -> FfiResult {
ty: Ty<'tcx>) -> FfiResult<'tcx> {
use self::FfiResult::*;
let cx = self.cx.tcx;
@ -429,19 +417,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
match ty.sty {
ty::TyAdt(def, substs) => {
if def.is_phantom_data() {
return FfiPhantom;
return FfiPhantom(ty);
}
match def.adt_kind() {
AdtKind::Struct => {
if !def.repr.c() && !def.repr.transparent() {
return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
return FfiUnsafe {
ty: ty,
reason: "this struct has unspecified layout",
help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \
attribute to this struct"),
};
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe("found zero-size struct in foreign module, consider \
adding a member to this struct");
return FfiUnsafe {
ty: ty,
reason: "this struct has no fields",
help: Some("consider adding a member to this struct"),
};
}
// We can't completely trust repr(C) and repr(transparent) markings;
@ -467,28 +461,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiSafe => {
all_phantom = false;
}
FfiPhantom => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
FfiPhantom(..) => {}
FfiUnsafe { .. } => {
return r;
}
FfiUnsafe(s) => {
return FfiBadStruct(def.did, s);
}
}
}
if all_phantom { FfiPhantom } else { FfiSafe }
if all_phantom { FfiPhantom(ty) } else { FfiSafe }
}
AdtKind::Union => {
if !def.repr.c() {
return FfiUnsafe("found union without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
return FfiUnsafe {
ty: ty,
reason: "this union has unspecified layout",
help: Some("consider adding a #[repr(C)] attribute to this union"),
};
}
if def.non_enum_variant().fields.is_empty() {
return FfiUnsafe("found zero-size union in foreign module, consider \
adding a member to this union");
return FfiUnsafe {
ty: ty,
reason: "this union has no fields",
help: Some("consider adding a field to this union"),
};
}
let mut all_phantom = true;
@ -501,17 +497,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiSafe => {
all_phantom = false;
}
FfiPhantom => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
FfiPhantom(..) => {}
FfiUnsafe { .. } => {
return r;
}
FfiUnsafe(s) => {
return FfiBadUnion(def.did, s);
}
}
}
if all_phantom { FfiPhantom } else { FfiSafe }
if all_phantom { FfiPhantom(ty) } else { FfiSafe }
}
AdtKind::Enum => {
if def.variants.is_empty() {
@ -524,27 +517,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
if !def.repr.c() && def.repr.int.is_none() {
// Special-case types like `Option<extern fn()>`.
if !is_repr_nullable_ptr(cx, def, substs) {
return FfiUnsafe("found enum without foreign-function-safe \
representation annotation in foreign \
module, consider adding a #[repr(...)] \
attribute to the type");
return FfiUnsafe {
ty: ty,
reason: "enum has no representation hint",
help: Some("consider adding a #[repr(...)] attribute \
to this enum"),
};
}
}
if let Some(int_ty) = def.repr.int {
if !is_ffi_safe(int_ty) {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
}
// Enum with an explicitly sized discriminant; either
// a C-style enum or a discriminated union.
// The layout of enum variants is implicitly repr(C).
// FIXME: Is that correct?
}
// Check the contained variants.
for variant in &def.variants {
for field in &variant.fields {
@ -554,15 +535,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let r = self.check_type_for_ffi(cache, arg);
match r {
FfiSafe => {}
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
FfiUnsafe { .. } => {
return r;
}
FfiPhantom => {
return FfiBadEnum(def.did,
"Found phantom data in enum variant");
}
FfiUnsafe(s) => {
return FfiBadEnum(def.did, s);
FfiPhantom(..) => {
return FfiUnsafe {
ty: ty,
reason: "this enum contains a PhantomData field",
help: None,
};
}
}
}
@ -572,45 +553,44 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
}
ty::TyChar => {
FfiUnsafe("found Rust type `char` in foreign module, while \
`u32` or `libc::wchar_t` should be used")
}
ty::TyChar => FfiUnsafe {
ty: ty,
reason: "the `char` type has no C equivalent",
help: Some("consider using `u32` or `libc::wchar_t` instead"),
},
ty::TyInt(ast::IntTy::I128) => {
FfiUnsafe("found Rust type `i128` in foreign module, but \
128-bit integers don't currently have a known \
stable ABI")
}
ty::TyUint(ast::UintTy::U128) => {
FfiUnsafe("found Rust type `u128` in foreign module, but \
128-bit integers don't currently have a known \
stable ABI")
}
ty::TyInt(ast::IntTy::I128) | ty::TyUint(ast::UintTy::U128) => FfiUnsafe {
ty: ty,
reason: "128-bit integers don't currently have a known stable ABI",
help: None,
},
// Primitive types with a stable representation.
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
ty::TySlice(_) => {
FfiUnsafe("found Rust slice type in foreign module, \
consider using a raw pointer instead")
}
ty::TySlice(_) => FfiUnsafe {
ty: ty,
reason: "slices have no C equivalent",
help: Some("consider using a raw pointer instead"),
},
ty::TyDynamic(..) => {
FfiUnsafe("found Rust trait type in foreign module, \
consider using a raw pointer instead")
}
ty::TyDynamic(..) => FfiUnsafe {
ty: ty,
reason: "trait objects have no C equivalent",
help: None,
},
ty::TyStr => {
FfiUnsafe("found Rust type `str` in foreign module; \
consider using a `*const libc::c_char`")
}
ty::TyStr => FfiUnsafe {
ty: ty,
reason: "string slices have no C equivalent",
help: Some("consider using `*const u8` and a length instead"),
},
ty::TyTuple(..) => {
FfiUnsafe("found Rust tuple type in foreign module; \
consider using a struct instead")
}
ty::TyTuple(..) => FfiUnsafe {
ty: ty,
reason: "tuples have unspecified layout",
help: Some("consider using a struct instead"),
},
ty::TyRawPtr(ref m) |
ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
@ -620,9 +600,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
ty::TyFnPtr(sig) => {
match sig.abi() {
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
return FfiUnsafe("found function pointer with Rust calling convention in \
foreign module; consider using an `extern` function \
pointer")
return FfiUnsafe {
ty: ty,
reason: "this function pointer has Rust-specific calling convention",
help: Some("consider using an `fn \"extern\"(...) -> ...` \
function pointer instead"),
}
}
_ => {}
}
@ -670,40 +653,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
match self.check_type_for_ffi(&mut FxHashSet(), ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom => {
FfiResult::FfiPhantom(ty) => {
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found zero-sized type composed only \
of phantom-data in a foreign-function."));
&format!("`extern` block uses type `{}` which is not FFI-safe: \
composed only of PhantomData", ty));
}
FfiResult::FfiUnsafe(s) => {
self.cx.span_lint(IMPROPER_CTYPES, sp, s);
}
FfiResult::FfiBadStruct(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in struct \
marked #[repr(C)]: {}",
s));
}
FfiResult::FfiBadUnion(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant field.
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in union \
marked #[repr(C)]: {}",
s));
}
FfiResult::FfiBadEnum(_, s) => {
// FIXME: This diagnostic is difficult to read, and doesn't
// point at the relevant variant.
self.cx.span_lint(IMPROPER_CTYPES,
sp,
&format!("found non-foreign-function-safe member in enum: {}",
s));
FfiResult::FfiUnsafe { ty: unsafe_ty, reason, help } => {
let msg = format!("`extern` block uses type `{}` which is not FFI-safe: {}",
unsafe_ty, reason);
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
if let Some(s) = help {
diag.help(s);
}
if let ty::TyAdt(def, _) = unsafe_ty.sty {
if let Some(sp) = self.cx.tcx.hir.span_if_local(def.did) {
diag.span_note(sp, "type defined here");
}
}
diag.emit();
}
}
}

View File

@ -37,13 +37,13 @@ struct D {
}
extern "C" {
fn foo(x: A); //~ ERROR found struct without foreign-function-safe
fn bar(x: B); //~ ERROR foreign-function-safe
fn foo(x: A); //~ ERROR type `A` which is not FFI-safe
fn bar(x: B); //~ ERROR type `A`
fn baz(x: C);
fn qux(x: A2); //~ ERROR foreign-function-safe
fn quux(x: B2); //~ ERROR foreign-function-safe
fn qux(x: A2); //~ ERROR type `A`
fn quux(x: B2); //~ ERROR type `A`
fn corge(x: C2);
fn fred(x: D); //~ ERROR foreign-function-safe
fn fred(x: D); //~ ERROR type `A`
}
fn main() { }

View File

@ -13,7 +13,7 @@
pub struct Foo;
extern {
pub fn foo(x: (Foo)); //~ ERROR found struct without
pub fn foo(x: (Foo)); //~ ERROR unspecified layout
}
fn main() {

View File

@ -16,11 +16,23 @@ enum U { A }
enum B { C, D }
enum T { E, F, G }
#[repr(C)]
enum ReprC { A, B, C }
#[repr(u8)]
enum U8 { A, B, C }
#[repr(isize)]
enum Isize { A, B, C }
extern {
fn zf(x: Z);
fn uf(x: U); //~ ERROR found enum without foreign-function-safe
fn bf(x: B); //~ ERROR found enum without foreign-function-safe
fn tf(x: T); //~ ERROR found enum without foreign-function-safe
fn uf(x: U); //~ ERROR enum has no representation hint
fn bf(x: B); //~ ERROR enum has no representation hint
fn tf(x: T); //~ ERROR enum has no representation hint
fn reprc(x: ReprC);
fn u8(x: U8);
fn isize(x: Isize);
}
pub fn main() { }

View File

@ -22,7 +22,7 @@ union W {
extern "C" {
static FOREIGN1: U; // OK
static FOREIGN2: W; //~ ERROR found union without foreign-function-safe representation
static FOREIGN2: W; //~ ERROR union has unspecified layout
}
fn main() {}

View File

@ -51,27 +51,27 @@ pub struct TransparentCustomZst(i32, ZeroSize);
pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
extern {
pub fn ptr_type1(size: *const Foo); //~ ERROR: found struct without
pub fn ptr_type2(size: *const Foo); //~ ERROR: found struct without
pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type
pub fn str_type(p: &str); //~ ERROR: found Rust type
pub fn box_type(p: Box<u32>); //~ ERROR found struct without
pub fn char_type(p: char); //~ ERROR found Rust type
pub fn i128_type(p: i128); //~ ERROR found Rust type
pub fn u128_type(p: u128); //~ ERROR found Rust type
pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type
pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type
pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type
pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct
pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR found zero-sized type
pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo`
pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo`
pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
pub fn str_type(p: &str); //~ ERROR: uses type `str`
pub fn box_type(p: Box<u32>); //~ ERROR uses type `std::boxed::Box<u32>`
pub fn char_type(p: char); //~ ERROR uses type `char`
pub fn i128_type(p: i128); //~ ERROR uses type `i128`
pub fn u128_type(p: u128); //~ ERROR uses type `u128`
pub fn trait_type(p: &Clone); //~ ERROR uses type `std::clone::Clone`
pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields
pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData
pub fn zero_size_phantom_toplevel()
-> ::std::marker::PhantomData<bool>; //~ ERROR: found zero-sized type
pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
pub fn fn_contained(p: RustBadRet); //~ ERROR: found struct without
pub fn transparent_i128(p: TransparentI128); //~ ERROR: found Rust type `i128`
pub fn transparent_str(p: TransparentStr); //~ ERROR: found Rust type `str`
pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: found struct without
-> ::std::marker::PhantomData<bool>; //~ ERROR: composed only of PhantomData
pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific
pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific
pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box<u32>`
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>`
pub fn good3(fptr: Option<extern fn()>);
pub fn good4(aptr: &[u8; 4 as usize]);

View File

@ -0,0 +1,170 @@
error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
--> $DIR/lint-ctypes.rs:54:28
|
54 | pub fn ptr_type1(size: *const Foo); //~ ERROR: uses type `Foo`
| ^^^^^^^^^^
|
note: lint level defined here
--> $DIR/lint-ctypes.rs:11:9
|
11 | #![deny(improper_ctypes)]
| ^^^^^^^^^^^^^^^
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
note: type defined here
--> $DIR/lint-ctypes.rs:32:1
|
32 | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
--> $DIR/lint-ctypes.rs:55:28
|
55 | pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo`
| ^^^^^^^^^^
|
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
note: type defined here
--> $DIR/lint-ctypes.rs:32:1
|
32 | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent
--> $DIR/lint-ctypes.rs:56:26
|
56 | pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]`
| ^^^^^^
|
= help: consider using a raw pointer instead
error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent
--> $DIR/lint-ctypes.rs:57:24
|
57 | pub fn str_type(p: &str); //~ ERROR: uses type `str`
| ^^^^
|
= help: consider using `*const u8` and a length instead
error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
--> $DIR/lint-ctypes.rs:58:24
|
58 | pub fn box_type(p: Box<u32>); //~ ERROR uses type `std::boxed::Box<u32>`
| ^^^^^^^^
|
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent
--> $DIR/lint-ctypes.rs:59:25
|
59 | pub fn char_type(p: char); //~ ERROR uses type `char`
| ^^^^
|
= help: consider using `u32` or `libc::wchar_t` instead
error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
--> $DIR/lint-ctypes.rs:60:25
|
60 | pub fn i128_type(p: i128); //~ ERROR uses type `i128`
| ^^^^
error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
--> $DIR/lint-ctypes.rs:61:25
|
61 | pub fn u128_type(p: u128); //~ ERROR uses type `u128`
| ^^^^
error: `extern` block uses type `std::clone::Clone` which is not FFI-safe: trait objects have no C equivalent
--> $DIR/lint-ctypes.rs:62:26
|
62 | pub fn trait_type(p: &Clone); //~ ERROR uses type `std::clone::Clone`
| ^^^^^^
error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout
--> $DIR/lint-ctypes.rs:63:26
|
63 | pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
| ^^^^^^^^^^
|
= help: consider using a struct instead
error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout
--> $DIR/lint-ctypes.rs:64:27
|
64 | pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
| ^^^^^^^
|
= help: consider using a struct instead
error: `extern` block uses type `ZeroSize` which is not FFI-safe: this struct has no fields
--> $DIR/lint-ctypes.rs:65:25
|
65 | pub fn zero_size(p: ZeroSize); //~ ERROR struct has no fields
| ^^^^^^^^
|
= help: consider adding a member to this struct
note: type defined here
--> $DIR/lint-ctypes.rs:28:1
|
28 | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` block uses type `ZeroSizeWithPhantomData` which is not FFI-safe: composed only of PhantomData
--> $DIR/lint-ctypes.rs:66:33
|
66 | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~ ERROR composed only of PhantomData
| ^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` block uses type `std::marker::PhantomData<bool>` which is not FFI-safe: composed only of PhantomData
--> $DIR/lint-ctypes.rs:68:12
|
68 | -> ::std::marker::PhantomData<bool>; //~ ERROR: composed only of PhantomData
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention
--> $DIR/lint-ctypes.rs:69:23
|
69 | pub fn fn_type(p: RustFn); //~ ERROR function pointer has Rust-specific
| ^^^^^^
|
= help: consider using an `fn "extern"(...) -> ...` function pointer instead
error: `extern` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention
--> $DIR/lint-ctypes.rs:70:24
|
70 | pub fn fn_type2(p: fn()); //~ ERROR function pointer has Rust-specific
| ^^^^
|
= help: consider using an `fn "extern"(...) -> ...` function pointer instead
error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
--> $DIR/lint-ctypes.rs:71:28
|
71 | pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box<u32>`
| ^^^^^^^^^^
|
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
--> $DIR/lint-ctypes.rs:72:32
|
72 | pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128`
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent
--> $DIR/lint-ctypes.rs:73:31
|
73 | pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str`
| ^^^^^^^^^^^^^^
|
= help: consider using `*const u8` and a length instead
error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: this struct has unspecified layout
--> $DIR/lint-ctypes.rs:74:30
|
74 | pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box<u32>`
| ^^^^^^^^^^^^^^^^
|
= help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
error: aborting due to 20 previous errors