lints: add improper_ctypes_definitions

This commit adds a new lint - `improper_ctypes_definitions` - which
functions identically to `improper_ctypes`, but on `extern "C" fn`
definitions (as opposed to `improper_ctypes`'s `extern "C" {}`
declarations).

Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
David Wood 2020-05-28 15:57:09 +01:00
parent 3c90ae8404
commit 14ea7a777f
No known key found for this signature in database
GPG key ID: 2592E76C87381FD9
18 changed files with 533 additions and 27 deletions

View file

@ -92,11 +92,13 @@
//! pub struct Foo;
//!
//! #[no_mangle]
//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_new() -> Box<Foo> {
//! Box::new(Foo)
//! }
//!
//! #[no_mangle]
//! #[allow(improper_ctypes_definitions)]
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
//! ```
//!

View file

@ -21,6 +21,7 @@
use core::any::Any;
#[rustc_std_internal_symbol]
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
unreachable!()
}

View file

@ -81,6 +81,7 @@ extern "C" {
mod dwarf;
#[rustc_std_internal_symbol]
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
Box::into_raw(imp::cleanup(payload))
}

View file

@ -167,7 +167,8 @@ macro_rules! late_lint_mod_passes {
$args,
[
HardwiredLints: HardwiredLints,
ImproperCTypes: ImproperCTypes,
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
VariantSizeDifferences: VariantSizeDifferences,
BoxPointers: BoxPointers,
PathStatements: PathStatements,

View file

@ -498,10 +498,24 @@ declare_lint! {
"proper use of libc types in foreign modules"
}
declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]);
declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
declare_lint! {
IMPROPER_CTYPES_DEFINITIONS,
Warn,
"proper use of libc types in foreign item definitions"
}
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
enum ImproperCTypesMode {
Declarations,
Definitions,
}
struct ImproperCTypesVisitor<'a, 'tcx> {
cx: &'a LateContext<'a, 'tcx>,
mode: ImproperCTypesMode,
}
enum FfiResult<'tcx> {
@ -811,20 +825,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
ty::FnPtr(sig) => {
match sig.abi() {
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
return FfiUnsafe {
ty,
reason: "this function pointer has Rust-specific calling convention"
if self.is_internal_abi(sig.abi()) {
return FfiUnsafe {
ty,
reason: "this function pointer has Rust-specific calling convention".into(),
help: Some(
"consider using an `extern fn(...) -> ...` \
function pointer instead"
.into(),
help: Some(
"consider using an `extern fn(...) -> ...` \
function pointer instead"
.into(),
),
};
}
_ => {}
),
};
}
let sig = cx.erase_late_bound_regions(&sig);
@ -857,15 +867,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
}
ty::Param(..)
| ty::Infer(..)
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
// so they are currently ignored for the purposes of this lint.
ty::Param(..) | ty::Projection(..) => FfiSafe,
ty::Infer(..)
| ty::Bound(..)
| ty::Error(_)
| ty::Closure(..)
| ty::Generator(..)
| ty::GeneratorWitness(..)
| ty::Placeholder(..)
| ty::Projection(..)
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
}
}
@ -877,9 +889,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
note: &str,
help: Option<&str>,
) {
self.cx.struct_span_lint(IMPROPER_CTYPES, sp, |lint| {
let mut diag =
lint.build(&format!("`extern` block uses type `{}`, which is not FFI-safe", ty));
let lint = match self.mode {
ImproperCTypesMode::Declarations => IMPROPER_CTYPES,
ImproperCTypesMode::Definitions => IMPROPER_CTYPES_DEFINITIONS,
};
self.cx.struct_span_lint(lint, sp, |lint| {
let item_description = match self.mode {
ImproperCTypesMode::Declarations => "block",
ImproperCTypesMode::Definitions => "fn",
};
let mut diag = lint.build(&format!(
"`extern` {} uses type `{}`, which is not FFI-safe",
item_description, ty
));
diag.span_label(sp, "not FFI-safe");
if let Some(help) = help {
diag.help(help);
@ -947,7 +970,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// 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);
let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
// C doesn't really support passing arrays by value - the only way to pass an array by value
// is through a struct. So, first test that the top level isn't an array, and then
@ -997,15 +1020,22 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
let ty = self.cx.tcx.type_of(def_id);
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
}
fn is_internal_abi(&self, abi: Abi) -> bool {
if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
true
} else {
false
}
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDeclarations {
fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem<'_>) {
let mut vis = ImproperCTypesVisitor { cx };
let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Declarations };
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
// Don't worry about types in internal ABIs.
} else {
if !vis.is_internal_abi(abi) {
match it.kind {
hir::ForeignItemKind::Fn(ref decl, _, _) => {
vis.check_foreign_fn(it.hir_id, decl);
@ -1019,6 +1049,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDefinitions {
fn check_fn(
&mut self,
cx: &LateContext<'a, 'tcx>,
kind: hir::intravisit::FnKind<'tcx>,
decl: &'tcx hir::FnDecl<'_>,
_: &'tcx hir::Body<'_>,
_: Span,
hir_id: hir::HirId,
) {
use hir::intravisit::FnKind;
let abi = match kind {
FnKind::ItemFn(_, _, header, ..) => header.abi,
FnKind::Method(_, sig, ..) => sig.header.abi,
_ => return,
};
let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Definitions };
if !vis.is_internal_abi(abi) {
vis.check_foreign_fn(hir_id, decl);
}
}
}
declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {

View file

@ -15,6 +15,7 @@ pub struct RustString {
/// Appending to a Rust string -- used by RawRustStringOstream.
#[no_mangle]
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
pub unsafe extern "C" fn LLVMRustStringWriteImpl(
sr: &RustString,
ptr: *const c_char,

View file

@ -56,6 +56,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
// able to specify this
#[cfg(not(test))]
#[no_mangle]
#[allow(improper_ctypes_definitions)]
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
// FIXME: how to support TLS in library mode?
let tls = Box::new(tls::Tls::new());

View file

@ -38,6 +38,7 @@ pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64);
#[cfg(target_arch = "x86_64")]
#[inline(never)]
#[allow(improper_ctypes_definitions)]
pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct {
foo.0 *= 1;
foo.1 *= 2;

View file

@ -10,6 +10,7 @@
#[repr(align(16))]
pub struct A(i64);
#[allow(improper_ctypes_definitions)]
pub extern "C" fn foo(x: A) {}
fn main() {

View file

@ -5,6 +5,7 @@
struct Empty;
// This used to cause an ICE
#[allow(improper_ctypes_definitions)]
extern "C" fn ice(_a: Empty) {}
fn main() {

View file

@ -6,6 +6,7 @@ pub struct Foo {
}
impl Foo {
#[allow(improper_ctypes_definitions)]
pub extern fn foo_new() -> Foo {
Foo { x: 21, y: 33 }
}

View file

@ -6,6 +6,7 @@ struct Test;
impl Test {
#[allow(dead_code)]
#[allow(unused_variables)]
#[allow(improper_ctypes_definitions)]
pub extern fn test(val: &str) {
}

View file

@ -5,6 +5,7 @@
pub struct Foo(i128);
#[no_mangle]
#[allow(improper_ctypes_definitions)]
pub extern "C" fn foo(x: Foo) -> Foo { x }
fn main() {

View file

@ -6,7 +6,9 @@ trait Foo {
struct Bar;
impl Foo for Bar {
#[allow(improper_ctypes_definitions)]
extern fn borrow(&self) {}
#[allow(improper_ctypes_definitions)]
extern fn take(self: Box<Self>) {}
}

View file

@ -0,0 +1,186 @@
#![feature(rustc_private)]
#![allow(private_in_public)]
#![deny(improper_ctypes_definitions)]
extern crate libc;
use std::default::Default;
use std::marker::PhantomData;
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
#[repr(C)]
pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
#[repr(C)]
pub struct StructWithProjectionAndLifetime<'a>(
&'a mut <StructWithProjectionAndLifetime<'a> as Mirror>::It
);
pub type I32Pair = (i32, i32);
#[repr(C)]
pub struct ZeroSize;
pub type RustFn = fn();
pub type RustBadRet = extern fn() -> Box<u32>;
pub type CVoidRet = ();
pub struct Foo;
#[repr(transparent)]
pub struct TransparentI128(i128);
#[repr(transparent)]
pub struct TransparentStr(&'static str);
#[repr(transparent)]
pub struct TransparentBadFn(RustBadRet);
#[repr(transparent)]
pub struct TransparentInt(u32);
#[repr(transparent)]
pub struct TransparentRef<'a>(&'a TransparentInt);
#[repr(transparent)]
pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
#[repr(transparent)]
pub struct TransparentUnit<U>(f32, PhantomData<U>);
#[repr(transparent)]
pub struct TransparentCustomZst(i32, ZeroSize);
#[repr(C)]
pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
pub extern "C" fn ptr_type1(size: *const Foo) { }
//~^ ERROR: uses type `Foo`
pub extern "C" fn ptr_type2(size: *const Foo) { }
//~^ ERROR: uses type `Foo`
pub extern "C" fn slice_type(p: &[u32]) { }
//~^ ERROR: uses type `[u32]`
pub extern "C" fn str_type(p: &str) { }
//~^ ERROR: uses type `str`
pub extern "C" fn box_type(p: Box<u32>) { }
//~^ ERROR uses type `std::boxed::Box<u32>`
pub extern "C" fn char_type(p: char) { }
//~^ ERROR uses type `char`
pub extern "C" fn i128_type(p: i128) { }
//~^ ERROR uses type `i128`
pub extern "C" fn u128_type(p: u128) { }
//~^ ERROR uses type `u128`
pub extern "C" fn tuple_type(p: (i32, i32)) { }
//~^ ERROR uses type `(i32, i32)`
pub extern "C" fn tuple_type2(p: I32Pair) { }
//~^ ERROR uses type `(i32, i32)`
pub extern "C" fn zero_size(p: ZeroSize) { }
//~^ ERROR uses type `ZeroSize`
pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
//~^ ERROR uses type `ZeroSizeWithPhantomData`
pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
//~^ ERROR uses type `std::marker::PhantomData<bool>`
Default::default()
}
pub extern "C" fn fn_type(p: RustFn) { }
//~^ ERROR uses type `fn()`
pub extern "C" fn fn_type2(p: fn()) { }
//~^ ERROR uses type `fn()`
pub extern "C" fn fn_contained(p: RustBadRet) { }
//~^ ERROR: uses type `std::boxed::Box<u32>`
pub extern "C" fn transparent_i128(p: TransparentI128) { }
//~^ ERROR: uses type `i128`
pub extern "C" fn transparent_str(p: TransparentStr) { }
//~^ ERROR: uses type `str`
pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
//~^ ERROR: uses type `std::boxed::Box<u32>`
pub extern "C" fn good3(fptr: Option<extern fn()>) { }
pub extern "C" fn good4(aptr: &[u8; 4 as usize]) { }
pub extern "C" fn good5(s: StructWithProjection) { }
pub extern "C" fn good6(s: StructWithProjectionAndLifetime) { }
pub extern "C" fn good7(fptr: extern fn() -> ()) { }
pub extern "C" fn good8(fptr: extern fn() -> !) { }
pub extern "C" fn good9() -> () { }
pub extern "C" fn good10() -> CVoidRet { }
pub extern "C" fn good11(size: isize) { }
pub extern "C" fn good12(size: usize) { }
pub extern "C" fn good13(n: TransparentInt) { }
pub extern "C" fn good14(p: TransparentRef) { }
pub extern "C" fn good15(p: TransparentLifetime) { }
pub extern "C" fn good16(p: TransparentUnit<ZeroSize>) { }
pub extern "C" fn good17(p: TransparentCustomZst) { }
#[allow(improper_ctypes_definitions)]
pub extern "C" fn good18(_: &String) { }
#[cfg(not(target_arch = "wasm32"))]
pub extern "C" fn good1(size: *const libc::c_int) { }
#[cfg(not(target_arch = "wasm32"))]
pub extern "C" fn good2(size: *const libc::c_uint) { }
pub extern "C" fn unused_generic1<T>(size: *const Foo) { }
//~^ ERROR: uses type `Foo`
pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
//~^ ERROR uses type `std::marker::PhantomData<bool>`
Default::default()
}
pub extern "C" fn used_generic1<T>(x: T) { }
pub extern "C" fn used_generic2<T>(x: T, size: *const Foo) { }
//~^ ERROR: uses type `Foo`
pub extern "C" fn used_generic3<T: Default>() -> T {
Default::default()
}
pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
//~^ ERROR: uses type `std::vec::Vec<T>`
pub extern "C" fn used_generic5<T>() -> Vec<T> {
//~^ ERROR: uses type `std::vec::Vec<T>`
Default::default()
}
fn main() {}

View file

@ -0,0 +1,247 @@
error: `extern` fn uses type `Foo`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:63:35
|
LL | pub extern "C" fn ptr_type1(size: *const Foo) { }
| ^^^^^^^^^^ not FFI-safe
|
note: the lint level is defined here
--> $DIR/lint-ctypes-fn.rs:4:9
|
LL | #![deny(improper_ctypes_definitions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:34:1
|
LL | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` fn uses type `Foo`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:66:35
|
LL | pub extern "C" fn ptr_type2(size: *const Foo) { }
| ^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:34:1
|
LL | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` fn uses type `[u32]`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:69:33
|
LL | pub extern "C" fn slice_type(p: &[u32]) { }
| ^^^^^^ not FFI-safe
|
= help: consider using a raw pointer instead
= note: slices have no C equivalent
error: `extern` fn uses type `str`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:72:31
|
LL | pub extern "C" fn str_type(p: &str) { }
| ^^^^ not FFI-safe
|
= help: consider using `*const u8` and a length instead
= note: string slices have no C equivalent
error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:75:31
|
LL | pub extern "C" fn box_type(p: Box<u32>) { }
| ^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
error: `extern` fn uses type `char`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:78:32
|
LL | pub extern "C" fn char_type(p: char) { }
| ^^^^ not FFI-safe
|
= help: consider using `u32` or `libc::wchar_t` instead
= note: the `char` type has no C equivalent
error: `extern` fn uses type `i128`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:81:32
|
LL | pub extern "C" fn i128_type(p: i128) { }
| ^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `u128`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:84:32
|
LL | pub extern "C" fn u128_type(p: u128) { }
| ^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:87:33
|
LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
| ^^^^^^^^^^ not FFI-safe
|
= help: consider using a struct instead
= note: tuples have unspecified layout
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:90:34
|
LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
| ^^^^^^^ not FFI-safe
|
= help: consider using a struct instead
= note: tuples have unspecified layout
error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:93:32
|
LL | pub extern "C" fn zero_size(p: ZeroSize) { }
| ^^^^^^^^ not FFI-safe
|
= help: consider adding a member to this struct
= note: this struct has no fields
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:26:1
|
LL | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:96:40
|
LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:61:1
|
LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:99:51
|
LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
error: `extern` fn uses type `fn()`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:104:30
|
LL | pub extern "C" fn fn_type(p: RustFn) { }
| ^^^^^^ not FFI-safe
|
= help: consider using an `extern fn(...) -> ...` function pointer instead
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `fn()`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:107:31
|
LL | pub extern "C" fn fn_type2(p: fn()) { }
| ^^^^ not FFI-safe
|
= help: consider using an `extern fn(...) -> ...` function pointer instead
= note: this function pointer has Rust-specific calling convention
error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:110:35
|
LL | pub extern "C" fn fn_contained(p: RustBadRet) { }
| ^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
error: `extern` fn uses type `i128`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:113:39
|
LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
| ^^^^^^^^^^^^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` fn uses type `str`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:116:38
|
LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
| ^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider using `*const u8` and a length instead
= note: string slices have no C equivalent
error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:119:37
|
LL | pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
| ^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
error: `extern` fn uses type `Foo`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:161:44
|
LL | pub extern "C" fn unused_generic1<T>(size: *const Foo) { }
| ^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:34:1
|
LL | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:164:43
|
LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
| ^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
error: `extern` fn uses type `Foo`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:171:48
|
LL | pub extern "C" fn used_generic2<T>(x: T, size: *const Foo) { }
| ^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
--> $DIR/lint-ctypes-fn.rs:34:1
|
LL | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:178:39
|
LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
| ^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
--> $DIR/lint-ctypes-fn.rs:181:41
|
LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
| ^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
error: aborting due to 24 previous errors

View file

@ -1,8 +1,10 @@
// run-pass
#[allow(improper_ctypes_definitions)]
pub extern "C" fn tuple2() -> (u16, u8) {
(1, 2)
}
#[allow(improper_ctypes_definitions)]
pub extern "C" fn tuple3() -> (u8, u8, u8) {
(1, 2, 3)
}

View file

@ -74,6 +74,7 @@ fn test8() -> isize {
Two::two()
}
#[allow(improper_ctypes_definitions)]
extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
x + y.0 * y.1
}