diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f734f3182a931..ef9b3d38c637c 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -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: 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,25 +517,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if !def.repr.c() && def.repr.int.is_none() { // Special-case types like `Option`. 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"); - } - } - - 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"); + return FfiUnsafe { + ty: ty, + reason: "enum has no representation hint", + help: Some("consider adding a #[repr(...)] attribute \ + to this enum"), + }; } - - // 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. @@ -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::TyDynamic(..) => { - FfiUnsafe("found Rust trait type in foreign module, \ - consider using a raw pointer instead") - } - - ty::TyStr => { - FfiUnsafe("found Rust type `str` in foreign module; \ - consider using a `*const libc::c_char`") - } - - ty::TyTuple(..) => { - FfiUnsafe("found Rust tuple type in foreign module; \ - consider using a struct instead") - } + ty::TySlice(_) => FfiUnsafe { + ty: ty, + reason: "slices have no C equivalent", + help: Some("consider using a raw pointer instead"), + }, + + ty::TyDynamic(..) => FfiUnsafe { + ty: ty, + reason: "trait objects have no C equivalent", + help: None, + }, + + 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 { + 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 => { - self.cx.span_lint(IMPROPER_CTYPES, - sp, - &format!("found zero-sized type composed only \ - of phantom-data in a foreign-function.")); - } - 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. + FfiResult::FfiPhantom(ty) => { self.cx.span_lint(IMPROPER_CTYPES, sp, - &format!("found non-foreign-function-safe member in struct \ - marked #[repr(C)]: {}", - s)); + &format!("`extern` block uses type `{}` which is not FFI-safe: \ + composed only of PhantomData", ty)); } - 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(); } } } diff --git a/src/test/compile-fail/issue-14309.rs b/src/test/compile-fail/issue-14309.rs index 56261c34a0308..f76fa3e4a8ece 100644 --- a/src/test/compile-fail/issue-14309.rs +++ b/src/test/compile-fail/issue-14309.rs @@ -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() { } diff --git a/src/test/compile-fail/issue-16250.rs b/src/test/compile-fail/issue-16250.rs index 288fe4a9abb82..f9d01003005e4 100644 --- a/src/test/compile-fail/issue-16250.rs +++ b/src/test/compile-fail/issue-16250.rs @@ -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() { diff --git a/src/test/compile-fail/lint-ctypes-enum.rs b/src/test/compile-fail/lint-ctypes-enum.rs index e35dadbea9d4d..7b7ffd8fc107c 100644 --- a/src/test/compile-fail/lint-ctypes-enum.rs +++ b/src/test/compile-fail/lint-ctypes-enum.rs @@ -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() { } diff --git a/src/test/compile-fail/union/union-repr-c.rs b/src/test/compile-fail/union/union-repr-c.rs index 15a4197fe94c9..36c42ce1104e0 100644 --- a/src/test/compile-fail/union/union-repr-c.rs +++ b/src/test/compile-fail/union/union-repr-c.rs @@ -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() {} diff --git a/src/test/compile-fail/lint-ctypes.rs b/src/test/ui/lint-ctypes.rs similarity index 64% rename from src/test/compile-fail/lint-ctypes.rs rename to src/test/ui/lint-ctypes.rs index c22239dee0a80..77cb1ef0f5130 100644 --- a/src/test/compile-fail/lint-ctypes.rs +++ b/src/test/ui/lint-ctypes.rs @@ -51,27 +51,27 @@ pub struct TransparentCustomZst(i32, ZeroSize); pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); 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); //~ 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); //~ ERROR uses type `std::boxed::Box` + 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; //~ 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; //~ 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` + 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` pub fn good3(fptr: Option); pub fn good4(aptr: &[u8; 4 as usize]); diff --git a/src/test/ui/lint-ctypes.stderr b/src/test/ui/lint-ctypes.stderr new file mode 100644 index 0000000000000..748c311055fa9 --- /dev/null +++ b/src/test/ui/lint-ctypes.stderr @@ -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` which is not FFI-safe: this struct has unspecified layout + --> $DIR/lint-ctypes.rs:58:24 + | +58 | pub fn box_type(p: Box); //~ ERROR uses type `std::boxed::Box` + | ^^^^^^^^ + | + = 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` which is not FFI-safe: composed only of PhantomData + --> $DIR/lint-ctypes.rs:68:12 + | +68 | -> ::std::marker::PhantomData; //~ 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` 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` + | ^^^^^^^^^^ + | + = 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` 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` + | ^^^^^^^^^^^^^^^^ + | + = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct + +error: aborting due to 20 previous errors +