Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 14ea7a7

Browse files
committedJun 24, 2020
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 <[email protected]>
1 parent 3c90ae8 commit 14ea7a7

File tree

18 files changed

+533
-27
lines changed

18 files changed

+533
-27
lines changed
 

‎src/liballoc/boxed.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,13 @@
9292
//! pub struct Foo;
9393
//!
9494
//! #[no_mangle]
95+
//! #[allow(improper_ctypes_definitions)]
9596
//! pub extern "C" fn foo_new() -> Box<Foo> {
9697
//! Box::new(Foo)
9798
//! }
9899
//!
99100
//! #[no_mangle]
101+
//! #[allow(improper_ctypes_definitions)]
100102
//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
101103
//! ```
102104
//!

‎src/libpanic_abort/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use core::any::Any;
2222

2323
#[rustc_std_internal_symbol]
24+
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
2425
pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) {
2526
unreachable!()
2627
}

‎src/libpanic_unwind/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ extern "C" {
8181
mod dwarf;
8282

8383
#[rustc_std_internal_symbol]
84+
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
8485
pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) {
8586
Box::into_raw(imp::cleanup(payload))
8687
}

‎src/librustc_lint/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ macro_rules! late_lint_mod_passes {
167167
$args,
168168
[
169169
HardwiredLints: HardwiredLints,
170-
ImproperCTypes: ImproperCTypes,
170+
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
171+
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
171172
VariantSizeDifferences: VariantSizeDifferences,
172173
BoxPointers: BoxPointers,
173174
PathStatements: PathStatements,

‎src/librustc_lint/types.rs

Lines changed: 81 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -498,10 +498,24 @@ declare_lint! {
498498
"proper use of libc types in foreign modules"
499499
}
500500

501-
declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]);
501+
declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
502+
503+
declare_lint! {
504+
IMPROPER_CTYPES_DEFINITIONS,
505+
Warn,
506+
"proper use of libc types in foreign item definitions"
507+
}
508+
509+
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
510+
511+
enum ImproperCTypesMode {
512+
Declarations,
513+
Definitions,
514+
}
502515

503516
struct ImproperCTypesVisitor<'a, 'tcx> {
504517
cx: &'a LateContext<'a, 'tcx>,
518+
mode: ImproperCTypesMode,
505519
}
506520

507521
enum FfiResult<'tcx> {
@@ -811,20 +825,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
811825
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
812826

813827
ty::FnPtr(sig) => {
814-
match sig.abi() {
815-
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
816-
return FfiUnsafe {
817-
ty,
818-
reason: "this function pointer has Rust-specific calling convention"
828+
if self.is_internal_abi(sig.abi()) {
829+
return FfiUnsafe {
830+
ty,
831+
reason: "this function pointer has Rust-specific calling convention".into(),
832+
help: Some(
833+
"consider using an `extern fn(...) -> ...` \
834+
function pointer instead"
819835
.into(),
820-
help: Some(
821-
"consider using an `extern fn(...) -> ...` \
822-
function pointer instead"
823-
.into(),
824-
),
825-
};
826-
}
827-
_ => {}
836+
),
837+
};
828838
}
829839

830840
let sig = cx.erase_late_bound_regions(&sig);
@@ -857,15 +867,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
857867
FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
858868
}
859869

860-
ty::Param(..)
861-
| ty::Infer(..)
870+
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
871+
// so they are currently ignored for the purposes of this lint.
872+
ty::Param(..) | ty::Projection(..) => FfiSafe,
873+
874+
ty::Infer(..)
862875
| ty::Bound(..)
863876
| ty::Error(_)
864877
| ty::Closure(..)
865878
| ty::Generator(..)
866879
| ty::GeneratorWitness(..)
867880
| ty::Placeholder(..)
868-
| ty::Projection(..)
869881
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
870882
}
871883
}
@@ -877,9 +889,20 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
877889
note: &str,
878890
help: Option<&str>,
879891
) {
880-
self.cx.struct_span_lint(IMPROPER_CTYPES, sp, |lint| {
881-
let mut diag =
882-
lint.build(&format!("`extern` block uses type `{}`, which is not FFI-safe", ty));
892+
let lint = match self.mode {
893+
ImproperCTypesMode::Declarations => IMPROPER_CTYPES,
894+
ImproperCTypesMode::Definitions => IMPROPER_CTYPES_DEFINITIONS,
895+
};
896+
897+
self.cx.struct_span_lint(lint, sp, |lint| {
898+
let item_description = match self.mode {
899+
ImproperCTypesMode::Declarations => "block",
900+
ImproperCTypesMode::Definitions => "fn",
901+
};
902+
let mut diag = lint.build(&format!(
903+
"`extern` {} uses type `{}`, which is not FFI-safe",
904+
item_description, ty
905+
));
883906
diag.span_label(sp, "not FFI-safe");
884907
if let Some(help) = help {
885908
diag.help(help);
@@ -947,7 +970,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
947970

948971
// it is only OK to use this function because extern fns cannot have
949972
// any generic types right now:
950-
let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
973+
let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
951974

952975
// C doesn't really support passing arrays by value - the only way to pass an array by value
953976
// 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> {
9971020
let ty = self.cx.tcx.type_of(def_id);
9981021
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
9991022
}
1023+
1024+
fn is_internal_abi(&self, abi: Abi) -> bool {
1025+
if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
1026+
true
1027+
} else {
1028+
false
1029+
}
1030+
}
10001031
}
10011032

1002-
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
1033+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDeclarations {
10031034
fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem<'_>) {
1004-
let mut vis = ImproperCTypesVisitor { cx };
1035+
let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Declarations };
10051036
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
1006-
if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
1007-
// Don't worry about types in internal ABIs.
1008-
} else {
1037+
1038+
if !vis.is_internal_abi(abi) {
10091039
match it.kind {
10101040
hir::ForeignItemKind::Fn(ref decl, _, _) => {
10111041
vis.check_foreign_fn(it.hir_id, decl);
@@ -1019,6 +1049,31 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes {
10191049
}
10201050
}
10211051

1052+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypesDefinitions {
1053+
fn check_fn(
1054+
&mut self,
1055+
cx: &LateContext<'a, 'tcx>,
1056+
kind: hir::intravisit::FnKind<'tcx>,
1057+
decl: &'tcx hir::FnDecl<'_>,
1058+
_: &'tcx hir::Body<'_>,
1059+
_: Span,
1060+
hir_id: hir::HirId,
1061+
) {
1062+
use hir::intravisit::FnKind;
1063+
1064+
let abi = match kind {
1065+
FnKind::ItemFn(_, _, header, ..) => header.abi,
1066+
FnKind::Method(_, sig, ..) => sig.header.abi,
1067+
_ => return,
1068+
};
1069+
1070+
let mut vis = ImproperCTypesVisitor { cx, mode: ImproperCTypesMode::Definitions };
1071+
if !vis.is_internal_abi(abi) {
1072+
vis.check_foreign_fn(hir_id, decl);
1073+
}
1074+
}
1075+
}
1076+
10221077
declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
10231078

10241079
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {

‎src/librustc_llvm/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub struct RustString {
1515

1616
/// Appending to a Rust string -- used by RawRustStringOstream.
1717
#[no_mangle]
18+
#[cfg_attr(not(bootstrap), allow(improper_ctypes_definitions))]
1819
pub unsafe extern "C" fn LLVMRustStringWriteImpl(
1920
sr: &RustString,
2021
ptr: *const c_char,

‎src/libstd/sys/sgx/abi/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
5656
// able to specify this
5757
#[cfg(not(test))]
5858
#[no_mangle]
59+
#[allow(improper_ctypes_definitions)]
5960
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
6061
// FIXME: how to support TLS in library mode?
6162
let tls = Box::new(tls::Tls::new());

‎src/test/ui/abi/abi-sysv64-register-usage.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64);
3838

3939
#[cfg(target_arch = "x86_64")]
4040
#[inline(never)]
41+
#[allow(improper_ctypes_definitions)]
4142
pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct {
4243
foo.0 *= 1;
4344
foo.1 *= 2;

‎src/test/ui/align-with-extern-c-fn.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#[repr(align(16))]
1111
pub struct A(i64);
1212

13+
#[allow(improper_ctypes_definitions)]
1314
pub extern "C" fn foo(x: A) {}
1415

1516
fn main() {

‎src/test/ui/issues/issue-16441.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
struct Empty;
66

77
// This used to cause an ICE
8+
#[allow(improper_ctypes_definitions)]
89
extern "C" fn ice(_a: Empty) {}
910

1011
fn main() {

‎src/test/ui/issues/issue-26997.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub struct Foo {
66
}
77

88
impl Foo {
9+
#[allow(improper_ctypes_definitions)]
910
pub extern fn foo_new() -> Foo {
1011
Foo { x: 21, y: 33 }
1112
}

‎src/test/ui/issues/issue-28600.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct Test;
66
impl Test {
77
#[allow(dead_code)]
88
#[allow(unused_variables)]
9+
#[allow(improper_ctypes_definitions)]
910
pub extern fn test(val: &str) {
1011

1112
}

‎src/test/ui/issues/issue-38763.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
pub struct Foo(i128);
66

77
#[no_mangle]
8+
#[allow(improper_ctypes_definitions)]
89
pub extern "C" fn foo(x: Foo) -> Foo { x }
910

1011
fn main() {

‎src/test/ui/issues/issue-51907.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ trait Foo {
66

77
struct Bar;
88
impl Foo for Bar {
9+
#[allow(improper_ctypes_definitions)]
910
extern fn borrow(&self) {}
11+
#[allow(improper_ctypes_definitions)]
1012
extern fn take(self: Box<Self>) {}
1113
}
1214

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

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#![feature(rustc_private)]
2+
3+
#![allow(private_in_public)]
4+
#![deny(improper_ctypes_definitions)]
5+
6+
extern crate libc;
7+
8+
use std::default::Default;
9+
use std::marker::PhantomData;
10+
11+
trait Mirror { type It: ?Sized; }
12+
13+
impl<T: ?Sized> Mirror for T { type It = Self; }
14+
15+
#[repr(C)]
16+
pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
17+
18+
#[repr(C)]
19+
pub struct StructWithProjectionAndLifetime<'a>(
20+
&'a mut <StructWithProjectionAndLifetime<'a> as Mirror>::It
21+
);
22+
23+
pub type I32Pair = (i32, i32);
24+
25+
#[repr(C)]
26+
pub struct ZeroSize;
27+
28+
pub type RustFn = fn();
29+
30+
pub type RustBadRet = extern fn() -> Box<u32>;
31+
32+
pub type CVoidRet = ();
33+
34+
pub struct Foo;
35+
36+
#[repr(transparent)]
37+
pub struct TransparentI128(i128);
38+
39+
#[repr(transparent)]
40+
pub struct TransparentStr(&'static str);
41+
42+
#[repr(transparent)]
43+
pub struct TransparentBadFn(RustBadRet);
44+
45+
#[repr(transparent)]
46+
pub struct TransparentInt(u32);
47+
48+
#[repr(transparent)]
49+
pub struct TransparentRef<'a>(&'a TransparentInt);
50+
51+
#[repr(transparent)]
52+
pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>);
53+
54+
#[repr(transparent)]
55+
pub struct TransparentUnit<U>(f32, PhantomData<U>);
56+
57+
#[repr(transparent)]
58+
pub struct TransparentCustomZst(i32, ZeroSize);
59+
60+
#[repr(C)]
61+
pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
62+
63+
pub extern "C" fn ptr_type1(size: *const Foo) { }
64+
//~^ ERROR: uses type `Foo`
65+
66+
pub extern "C" fn ptr_type2(size: *const Foo) { }
67+
//~^ ERROR: uses type `Foo`
68+
69+
pub extern "C" fn slice_type(p: &[u32]) { }
70+
//~^ ERROR: uses type `[u32]`
71+
72+
pub extern "C" fn str_type(p: &str) { }
73+
//~^ ERROR: uses type `str`
74+
75+
pub extern "C" fn box_type(p: Box<u32>) { }
76+
//~^ ERROR uses type `std::boxed::Box<u32>`
77+
78+
pub extern "C" fn char_type(p: char) { }
79+
//~^ ERROR uses type `char`
80+
81+
pub extern "C" fn i128_type(p: i128) { }
82+
//~^ ERROR uses type `i128`
83+
84+
pub extern "C" fn u128_type(p: u128) { }
85+
//~^ ERROR uses type `u128`
86+
87+
pub extern "C" fn tuple_type(p: (i32, i32)) { }
88+
//~^ ERROR uses type `(i32, i32)`
89+
90+
pub extern "C" fn tuple_type2(p: I32Pair) { }
91+
//~^ ERROR uses type `(i32, i32)`
92+
93+
pub extern "C" fn zero_size(p: ZeroSize) { }
94+
//~^ ERROR uses type `ZeroSize`
95+
96+
pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
97+
//~^ ERROR uses type `ZeroSizeWithPhantomData`
98+
99+
pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
100+
//~^ ERROR uses type `std::marker::PhantomData<bool>`
101+
Default::default()
102+
}
103+
104+
pub extern "C" fn fn_type(p: RustFn) { }
105+
//~^ ERROR uses type `fn()`
106+
107+
pub extern "C" fn fn_type2(p: fn()) { }
108+
//~^ ERROR uses type `fn()`
109+
110+
pub extern "C" fn fn_contained(p: RustBadRet) { }
111+
//~^ ERROR: uses type `std::boxed::Box<u32>`
112+
113+
pub extern "C" fn transparent_i128(p: TransparentI128) { }
114+
//~^ ERROR: uses type `i128`
115+
116+
pub extern "C" fn transparent_str(p: TransparentStr) { }
117+
//~^ ERROR: uses type `str`
118+
119+
pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
120+
//~^ ERROR: uses type `std::boxed::Box<u32>`
121+
122+
pub extern "C" fn good3(fptr: Option<extern fn()>) { }
123+
124+
pub extern "C" fn good4(aptr: &[u8; 4 as usize]) { }
125+
126+
pub extern "C" fn good5(s: StructWithProjection) { }
127+
128+
pub extern "C" fn good6(s: StructWithProjectionAndLifetime) { }
129+
130+
pub extern "C" fn good7(fptr: extern fn() -> ()) { }
131+
132+
pub extern "C" fn good8(fptr: extern fn() -> !) { }
133+
134+
pub extern "C" fn good9() -> () { }
135+
136+
pub extern "C" fn good10() -> CVoidRet { }
137+
138+
pub extern "C" fn good11(size: isize) { }
139+
140+
pub extern "C" fn good12(size: usize) { }
141+
142+
pub extern "C" fn good13(n: TransparentInt) { }
143+
144+
pub extern "C" fn good14(p: TransparentRef) { }
145+
146+
pub extern "C" fn good15(p: TransparentLifetime) { }
147+
148+
pub extern "C" fn good16(p: TransparentUnit<ZeroSize>) { }
149+
150+
pub extern "C" fn good17(p: TransparentCustomZst) { }
151+
152+
#[allow(improper_ctypes_definitions)]
153+
pub extern "C" fn good18(_: &String) { }
154+
155+
#[cfg(not(target_arch = "wasm32"))]
156+
pub extern "C" fn good1(size: *const libc::c_int) { }
157+
158+
#[cfg(not(target_arch = "wasm32"))]
159+
pub extern "C" fn good2(size: *const libc::c_uint) { }
160+
161+
pub extern "C" fn unused_generic1<T>(size: *const Foo) { }
162+
//~^ ERROR: uses type `Foo`
163+
164+
pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
165+
//~^ ERROR uses type `std::marker::PhantomData<bool>`
166+
Default::default()
167+
}
168+
169+
pub extern "C" fn used_generic1<T>(x: T) { }
170+
171+
pub extern "C" fn used_generic2<T>(x: T, size: *const Foo) { }
172+
//~^ ERROR: uses type `Foo`
173+
174+
pub extern "C" fn used_generic3<T: Default>() -> T {
175+
Default::default()
176+
}
177+
178+
pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
179+
//~^ ERROR: uses type `std::vec::Vec<T>`
180+
181+
pub extern "C" fn used_generic5<T>() -> Vec<T> {
182+
//~^ ERROR: uses type `std::vec::Vec<T>`
183+
Default::default()
184+
}
185+
186+
fn main() {}
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
error: `extern` fn uses type `Foo`, which is not FFI-safe
2+
--> $DIR/lint-ctypes-fn.rs:63:35
3+
|
4+
LL | pub extern "C" fn ptr_type1(size: *const Foo) { }
5+
| ^^^^^^^^^^ not FFI-safe
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/lint-ctypes-fn.rs:4:9
9+
|
10+
LL | #![deny(improper_ctypes_definitions)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
13+
= note: this struct has unspecified layout
14+
note: the type is defined here
15+
--> $DIR/lint-ctypes-fn.rs:34:1
16+
|
17+
LL | pub struct Foo;
18+
| ^^^^^^^^^^^^^^^
19+
20+
error: `extern` fn uses type `Foo`, which is not FFI-safe
21+
--> $DIR/lint-ctypes-fn.rs:66:35
22+
|
23+
LL | pub extern "C" fn ptr_type2(size: *const Foo) { }
24+
| ^^^^^^^^^^ not FFI-safe
25+
|
26+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
27+
= note: this struct has unspecified layout
28+
note: the type is defined here
29+
--> $DIR/lint-ctypes-fn.rs:34:1
30+
|
31+
LL | pub struct Foo;
32+
| ^^^^^^^^^^^^^^^
33+
34+
error: `extern` fn uses type `[u32]`, which is not FFI-safe
35+
--> $DIR/lint-ctypes-fn.rs:69:33
36+
|
37+
LL | pub extern "C" fn slice_type(p: &[u32]) { }
38+
| ^^^^^^ not FFI-safe
39+
|
40+
= help: consider using a raw pointer instead
41+
= note: slices have no C equivalent
42+
43+
error: `extern` fn uses type `str`, which is not FFI-safe
44+
--> $DIR/lint-ctypes-fn.rs:72:31
45+
|
46+
LL | pub extern "C" fn str_type(p: &str) { }
47+
| ^^^^ not FFI-safe
48+
|
49+
= help: consider using `*const u8` and a length instead
50+
= note: string slices have no C equivalent
51+
52+
error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
53+
--> $DIR/lint-ctypes-fn.rs:75:31
54+
|
55+
LL | pub extern "C" fn box_type(p: Box<u32>) { }
56+
| ^^^^^^^^ not FFI-safe
57+
|
58+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
59+
= note: this struct has unspecified layout
60+
61+
error: `extern` fn uses type `char`, which is not FFI-safe
62+
--> $DIR/lint-ctypes-fn.rs:78:32
63+
|
64+
LL | pub extern "C" fn char_type(p: char) { }
65+
| ^^^^ not FFI-safe
66+
|
67+
= help: consider using `u32` or `libc::wchar_t` instead
68+
= note: the `char` type has no C equivalent
69+
70+
error: `extern` fn uses type `i128`, which is not FFI-safe
71+
--> $DIR/lint-ctypes-fn.rs:81:32
72+
|
73+
LL | pub extern "C" fn i128_type(p: i128) { }
74+
| ^^^^ not FFI-safe
75+
|
76+
= note: 128-bit integers don't currently have a known stable ABI
77+
78+
error: `extern` fn uses type `u128`, which is not FFI-safe
79+
--> $DIR/lint-ctypes-fn.rs:84:32
80+
|
81+
LL | pub extern "C" fn u128_type(p: u128) { }
82+
| ^^^^ not FFI-safe
83+
|
84+
= note: 128-bit integers don't currently have a known stable ABI
85+
86+
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
87+
--> $DIR/lint-ctypes-fn.rs:87:33
88+
|
89+
LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
90+
| ^^^^^^^^^^ not FFI-safe
91+
|
92+
= help: consider using a struct instead
93+
= note: tuples have unspecified layout
94+
95+
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
96+
--> $DIR/lint-ctypes-fn.rs:90:34
97+
|
98+
LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
99+
| ^^^^^^^ not FFI-safe
100+
|
101+
= help: consider using a struct instead
102+
= note: tuples have unspecified layout
103+
104+
error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
105+
--> $DIR/lint-ctypes-fn.rs:93:32
106+
|
107+
LL | pub extern "C" fn zero_size(p: ZeroSize) { }
108+
| ^^^^^^^^ not FFI-safe
109+
|
110+
= help: consider adding a member to this struct
111+
= note: this struct has no fields
112+
note: the type is defined here
113+
--> $DIR/lint-ctypes-fn.rs:26:1
114+
|
115+
LL | pub struct ZeroSize;
116+
| ^^^^^^^^^^^^^^^^^^^^
117+
118+
error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
119+
--> $DIR/lint-ctypes-fn.rs:96:40
120+
|
121+
LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
122+
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
123+
|
124+
= note: composed only of `PhantomData`
125+
note: the type is defined here
126+
--> $DIR/lint-ctypes-fn.rs:61:1
127+
|
128+
LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
129+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
130+
131+
error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
132+
--> $DIR/lint-ctypes-fn.rs:99:51
133+
|
134+
LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
135+
| ^^^^^^^^^^^^^^^^^ not FFI-safe
136+
|
137+
= note: composed only of `PhantomData`
138+
139+
error: `extern` fn uses type `fn()`, which is not FFI-safe
140+
--> $DIR/lint-ctypes-fn.rs:104:30
141+
|
142+
LL | pub extern "C" fn fn_type(p: RustFn) { }
143+
| ^^^^^^ not FFI-safe
144+
|
145+
= help: consider using an `extern fn(...) -> ...` function pointer instead
146+
= note: this function pointer has Rust-specific calling convention
147+
148+
error: `extern` fn uses type `fn()`, which is not FFI-safe
149+
--> $DIR/lint-ctypes-fn.rs:107:31
150+
|
151+
LL | pub extern "C" fn fn_type2(p: fn()) { }
152+
| ^^^^ not FFI-safe
153+
|
154+
= help: consider using an `extern fn(...) -> ...` function pointer instead
155+
= note: this function pointer has Rust-specific calling convention
156+
157+
error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
158+
--> $DIR/lint-ctypes-fn.rs:110:35
159+
|
160+
LL | pub extern "C" fn fn_contained(p: RustBadRet) { }
161+
| ^^^^^^^^^^ not FFI-safe
162+
|
163+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
164+
= note: this struct has unspecified layout
165+
166+
error: `extern` fn uses type `i128`, which is not FFI-safe
167+
--> $DIR/lint-ctypes-fn.rs:113:39
168+
|
169+
LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
170+
| ^^^^^^^^^^^^^^^ not FFI-safe
171+
|
172+
= note: 128-bit integers don't currently have a known stable ABI
173+
174+
error: `extern` fn uses type `str`, which is not FFI-safe
175+
--> $DIR/lint-ctypes-fn.rs:116:38
176+
|
177+
LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
178+
| ^^^^^^^^^^^^^^ not FFI-safe
179+
|
180+
= help: consider using `*const u8` and a length instead
181+
= note: string slices have no C equivalent
182+
183+
error: `extern` fn uses type `std::boxed::Box<u32>`, which is not FFI-safe
184+
--> $DIR/lint-ctypes-fn.rs:119:37
185+
|
186+
LL | pub extern "C" fn transparent_fn(p: TransparentBadFn) { }
187+
| ^^^^^^^^^^^^^^^^ not FFI-safe
188+
|
189+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
190+
= note: this struct has unspecified layout
191+
192+
error: `extern` fn uses type `Foo`, which is not FFI-safe
193+
--> $DIR/lint-ctypes-fn.rs:161:44
194+
|
195+
LL | pub extern "C" fn unused_generic1<T>(size: *const Foo) { }
196+
| ^^^^^^^^^^ not FFI-safe
197+
|
198+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
199+
= note: this struct has unspecified layout
200+
note: the type is defined here
201+
--> $DIR/lint-ctypes-fn.rs:34:1
202+
|
203+
LL | pub struct Foo;
204+
| ^^^^^^^^^^^^^^^
205+
206+
error: `extern` fn uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
207+
--> $DIR/lint-ctypes-fn.rs:164:43
208+
|
209+
LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
210+
| ^^^^^^^^^^^^^^^^^ not FFI-safe
211+
|
212+
= note: composed only of `PhantomData`
213+
214+
error: `extern` fn uses type `Foo`, which is not FFI-safe
215+
--> $DIR/lint-ctypes-fn.rs:171:48
216+
|
217+
LL | pub extern "C" fn used_generic2<T>(x: T, size: *const Foo) { }
218+
| ^^^^^^^^^^ not FFI-safe
219+
|
220+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
221+
= note: this struct has unspecified layout
222+
note: the type is defined here
223+
--> $DIR/lint-ctypes-fn.rs:34:1
224+
|
225+
LL | pub struct Foo;
226+
| ^^^^^^^^^^^^^^^
227+
228+
error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
229+
--> $DIR/lint-ctypes-fn.rs:178:39
230+
|
231+
LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
232+
| ^^^^^^ not FFI-safe
233+
|
234+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
235+
= note: this struct has unspecified layout
236+
237+
error: `extern` fn uses type `std::vec::Vec<T>`, which is not FFI-safe
238+
--> $DIR/lint-ctypes-fn.rs:181:41
239+
|
240+
LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
241+
| ^^^^^^ not FFI-safe
242+
|
243+
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
244+
= note: this struct has unspecified layout
245+
246+
error: aborting due to 24 previous errors
247+

‎src/test/ui/mir/mir_cast_fn_ret.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// run-pass
2+
#[allow(improper_ctypes_definitions)]
23
pub extern "C" fn tuple2() -> (u16, u8) {
34
(1, 2)
45
}
56

7+
#[allow(improper_ctypes_definitions)]
68
pub extern "C" fn tuple3() -> (u8, u8, u8) {
79
(1, 2, 3)
810
}

‎src/test/ui/mir/mir_codegen_calls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ fn test8() -> isize {
7474
Two::two()
7575
}
7676

77+
#[allow(improper_ctypes_definitions)]
7778
extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
7879
x + y.0 * y.1
7980
}

0 commit comments

Comments
 (0)
Please sign in to comment.