diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 217e10ab24f55..3b8c06ba154c6 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -624,7 +624,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { AdtKind::Struct => { if !def.repr.c() && !def.repr.transparent() { return FfiUnsafe { - ty: ty, + ty, reason: "this struct has unspecified layout", help: Some("consider adding a `#[repr(C)]` or \ `#[repr(transparent)]` attribute to this struct"), @@ -633,7 +633,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.non_enum_variant().fields.is_empty() { return FfiUnsafe { - ty: ty, + ty, reason: "this struct has no fields", help: Some("consider adding a member to this struct"), }; @@ -669,7 +669,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { AdtKind::Union => { if !def.repr.c() && !def.repr.transparent() { return FfiUnsafe { - ty: ty, + ty, reason: "this union has unspecified layout", help: Some("consider adding a `#[repr(C)]` or \ `#[repr(transparent)]` attribute to this union"), @@ -678,7 +678,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.non_enum_variant().fields.is_empty() { return FfiUnsafe { - ty: ty, + ty, reason: "this union has no fields", help: Some("consider adding a field to this union"), }; @@ -721,7 +721,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { // Special-case types like `Option`. if !is_repr_nullable_ptr(cx, ty, def, substs) { return FfiUnsafe { - ty: ty, + ty, reason: "enum has no representation hint", help: Some("consider adding a `#[repr(C)]`, \ `#[repr(transparent)]`, or integer `#[repr(...)]` \ @@ -750,7 +750,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } FfiPhantom(..) => { return FfiUnsafe { - ty: ty, + ty, reason: "this enum contains a PhantomData field", help: None, }; @@ -764,13 +764,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } ty::Char => FfiUnsafe { - ty: ty, + ty, reason: "the `char` type has no C equivalent", help: Some("consider using `u32` or `libc::wchar_t` instead"), }, ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe { - ty: ty, + ty, reason: "128-bit integers don't currently have a known stable ABI", help: None, }, @@ -779,25 +779,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe, ty::Slice(_) => FfiUnsafe { - ty: ty, + ty, reason: "slices have no C equivalent", help: Some("consider using a raw pointer instead"), }, ty::Dynamic(..) => FfiUnsafe { - ty: ty, + ty, reason: "trait objects have no C equivalent", help: None, }, ty::Str => FfiUnsafe { - ty: ty, + ty, reason: "string slices have no C equivalent", help: Some("consider using `*const u8` and a length instead"), }, ty::Tuple(..) => FfiUnsafe { - ty: ty, + ty, reason: "tuples have unspecified layout", help: Some("consider using a struct instead"), }, @@ -811,7 +811,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match sig.abi() { Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => { return FfiUnsafe { - ty: ty, + ty, reason: "this function pointer has Rust-specific calling convention", help: Some("consider using an `extern fn(...) -> ...` \ function pointer instead"), @@ -855,11 +855,76 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::UnnormalizedProjection(..) | ty::Projection(..) | ty::Opaque(..) | - ty::FnDef(..) => bug!("Unexpected type in foreign function"), + ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty), + } + } + + fn emit_ffi_unsafe_type_lint( + &mut self, + ty: Ty<'tcx>, + sp: Span, + note: &str, + help: Option<&str>, + ) { + let mut diag = self.cx.struct_span_lint( + IMPROPER_CTYPES, + sp, + &format!("`extern` block uses type `{}`, which is not FFI-safe", ty), + ); + diag.span_label(sp, "not FFI-safe"); + if let Some(help) = help { + diag.help(help); + } + diag.note(note); + if let ty::Adt(def, _) = ty.sty { + if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) { + diag.span_note(sp, "type defined here"); + } + } + diag.emit(); + } + + fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { + use crate::rustc::ty::TypeFoldable; + + struct ProhibitOpaqueTypes<'tcx> { + ty: Option>, + }; + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + if let ty::Opaque(..) = ty.sty { + self.ty = Some(ty); + true + } else { + ty.super_visit_with(self) + } + } + } + + let mut visitor = ProhibitOpaqueTypes { ty: None }; + ty.visit_with(&mut visitor); + if let Some(ty) = visitor.ty { + self.emit_ffi_unsafe_type_lint( + ty, + sp, + "opaque types have no C equivalent", + None, + ); + true + } else { + false } } fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) { + // We have to check for opaque types before `normalize_erasing_regions`, + // which will replace opaque types with their underlying concrete type. + if self.check_for_opaque_ty(sp, ty) { + // We've already emitted an error due to an opaque type. + return; + } + // 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); @@ -867,24 +932,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match self.check_type_for_ffi(&mut FxHashSet::default(), ty) { FfiResult::FfiSafe => {} FfiResult::FfiPhantom(ty) => { - self.cx.span_lint(IMPROPER_CTYPES, - sp, - &format!("`extern` block uses type `{}` which is not FFI-safe: \ - composed only of PhantomData", ty)); + self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None); } - 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::Adt(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(); + FfiResult::FfiUnsafe { ty, reason, help } => { + self.emit_ffi_unsafe_type_lint(ty, sp, reason, help); } } } diff --git a/src/test/ui/issues/issue-14309.rs b/src/test/ui/issues/issue-14309.rs index d0e532a264656..328a4c982b81e 100644 --- a/src/test/ui/issues/issue-14309.rs +++ b/src/test/ui/issues/issue-14309.rs @@ -27,7 +27,7 @@ struct D { } extern "C" { - fn foo(x: A); //~ ERROR type `A` which is not FFI-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 type `A` diff --git a/src/test/ui/issues/issue-14309.stderr b/src/test/ui/issues/issue-14309.stderr index e0491093a722a..f598e1f9e2f6d 100644 --- a/src/test/ui/issues/issue-14309.stderr +++ b/src/test/ui/issues/issue-14309.stderr @@ -1,8 +1,8 @@ -error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:30:15 | LL | fn foo(x: A); - | ^ + | ^ not FFI-safe | note: lint level defined here --> $DIR/issue-14309.rs:1:9 @@ -10,6 +10,7 @@ note: lint level defined here LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -18,13 +19,14 @@ LL | | x: i32 LL | | } | |_^ -error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:31:15 | LL | fn bar(x: B); - | ^ + | ^ not FFI-safe | = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -33,13 +35,14 @@ LL | | x: i32 LL | | } | |_^ -error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:33:15 | LL | fn qux(x: A2); - | ^^ + | ^^ not FFI-safe | = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -48,13 +51,14 @@ LL | | x: i32 LL | | } | |_^ -error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:34:16 | LL | fn quux(x: B2); - | ^^ + | ^^ not FFI-safe | = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout note: type defined here --> $DIR/issue-14309.rs:4:1 | @@ -63,13 +67,14 @@ LL | | x: i32 LL | | } | |_^ -error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `A`, which is not FFI-safe --> $DIR/issue-14309.rs:36:16 | LL | fn fred(x: D); - | ^ + | ^ not FFI-safe | = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout note: type defined here --> $DIR/issue-14309.rs:4:1 | diff --git a/src/test/ui/issues/issue-16250.rs b/src/test/ui/issues/issue-16250.rs index bf01627adfc1f..a3c6751ad897c 100644 --- a/src/test/ui/issues/issue-16250.rs +++ b/src/test/ui/issues/issue-16250.rs @@ -3,7 +3,7 @@ pub struct Foo; extern { - pub fn foo(x: (Foo)); //~ ERROR unspecified layout + pub fn foo(x: (Foo)); //~ ERROR `extern` block uses type `Foo` } fn main() { diff --git a/src/test/ui/issues/issue-16250.stderr b/src/test/ui/issues/issue-16250.stderr index f3686e82b05a4..5686ac3774215 100644 --- a/src/test/ui/issues/issue-16250.stderr +++ b/src/test/ui/issues/issue-16250.stderr @@ -1,8 +1,8 @@ -error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `Foo`, which is not FFI-safe --> $DIR/issue-16250.rs:6:20 | LL | pub fn foo(x: (Foo)); - | ^^^ + | ^^^ not FFI-safe | note: lint level defined here --> $DIR/issue-16250.rs:1:9 @@ -11,6 +11,7 @@ LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(improper_ctypes)]` implied by `#[deny(warnings)]` = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout note: type defined here --> $DIR/issue-16250.rs:3:1 | diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs index e1f4b0b34ebaa..3898e67a07f7e 100644 --- a/src/test/ui/lint/lint-ctypes-enum.rs +++ b/src/test/ui/lint/lint-ctypes-enum.rs @@ -36,36 +36,37 @@ struct Rust(T); extern { fn zf(x: Z); - 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 uf(x: U); //~ ERROR `extern` block uses type `U` + fn bf(x: B); //~ ERROR `extern` block uses type `B` + fn tf(x: T); //~ ERROR `extern` block uses type `T` fn repr_c(x: ReprC); fn repr_u8(x: U8); fn repr_isize(x: Isize); fn option_ref(x: Option<&'static u8>); fn option_fn(x: Option); fn nonnull(x: Option>); - fn unique(x: Option>); //~ ERROR enum has no representation hint + fn unique(x: Option>); + //~^ ERROR `extern` block uses type `std::option::Option>` fn nonzero_u8(x: Option); fn nonzero_u16(x: Option); fn nonzero_u32(x: Option); fn nonzero_u64(x: Option); fn nonzero_u128(x: Option); - //~^ ERROR 128-bit integers don't currently have a known stable ABI + //~^ ERROR `extern` block uses type `u128` fn nonzero_usize(x: Option); fn nonzero_i8(x: Option); fn nonzero_i16(x: Option); fn nonzero_i32(x: Option); fn nonzero_i64(x: Option); fn nonzero_i128(x: Option); - //~^ ERROR 128-bit integers don't currently have a known stable ABI + //~^ ERROR `extern` block uses type `i128` fn nonzero_isize(x: Option); fn transparent_struct(x: Option>); fn transparent_enum(x: Option>); fn transparent_union(x: Option>); - //~^ ERROR enum has no representation hint - fn repr_rust(x: Option>); //~ ERROR enum has no representation hint - fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR enum has no representation hint + //~^ ERROR `extern` block uses type + fn repr_rust(x: Option>); //~ ERROR `extern` block uses type + fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR `extern` block uses type } -pub fn main() { } +pub fn main() {} diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr index 20e438606642c..81939e6ee206c 100644 --- a/src/test/ui/lint/lint-ctypes-enum.stderr +++ b/src/test/ui/lint/lint-ctypes-enum.stderr @@ -1,8 +1,8 @@ -error: `extern` block uses type `U` which is not FFI-safe: enum has no representation hint +error: `extern` block uses type `U`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:39:13 | LL | fn uf(x: U); - | ^ + | ^ not FFI-safe | note: lint level defined here --> $DIR/lint-ctypes-enum.rs:3:9 @@ -10,81 +10,92 @@ note: lint level defined here LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint note: type defined here --> $DIR/lint-ctypes-enum.rs:9:1 | LL | enum U { A } | ^^^^^^^^^^^^ -error: `extern` block uses type `B` which is not FFI-safe: enum has no representation hint +error: `extern` block uses type `B`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:40:13 | LL | fn bf(x: B); - | ^ + | ^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint note: type defined here --> $DIR/lint-ctypes-enum.rs:10:1 | LL | enum B { C, D } | ^^^^^^^^^^^^^^^ -error: `extern` block uses type `T` which is not FFI-safe: enum has no representation hint +error: `extern` block uses type `T`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:41:13 | LL | fn tf(x: T); - | ^ + | ^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint note: type defined here --> $DIR/lint-ctypes-enum.rs:11:1 | LL | enum T { E, F, G } | ^^^^^^^^^^^^^^^^^^ -error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint +error: `extern` block uses type `std::option::Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:48:17 | LL | fn unique(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint -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-enum.rs:53:23 +error: `extern` block uses type `u128`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:54:23 | LL | fn nonzero_u128(x: Option); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI -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-enum.rs:60:23 +error: `extern` block uses type `i128`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:61:23 | LL | fn nonzero_i128(x: Option); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:65:28 +error: `extern` block uses type `std::option::Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:66:28 | LL | fn transparent_union(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint -error: `extern` block uses type `std::option::Option>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:67:20 +error: `extern` block uses type `std::option::Option>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:68:20 | LL | fn repr_rust(x: Option>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint -error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>` which is not FFI-safe: enum has no representation hint - --> $DIR/lint-ctypes-enum.rs:68:20 +error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:69:20 | LL | fn no_result(x: Result<(), num::NonZeroI32>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint error: aborting due to 9 previous errors diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs index a3d9b6febdbb7..e20503a395c89 100644 --- a/src/test/ui/lint/lint-ctypes.rs +++ b/src/test/ui/lint/lint-ctypes.rs @@ -1,7 +1,7 @@ -#![deny(improper_ctypes)] #![feature(rustc_private)] #![allow(private_in_public)] +#![deny(improper_ctypes)] extern crate libc; @@ -54,12 +54,13 @@ extern { pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn 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(p: ZeroSize); //~ ERROR uses type `ZeroSize` + pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); + //~^ ERROR uses type `ZeroSizeWithPhantomData` pub fn zero_size_phantom_toplevel() - -> ::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 + -> ::std::marker::PhantomData; //~ ERROR uses type `std::marker::PhantomData` + pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()` + pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()` 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` diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index c78463beb6559..e533a767b317f 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -1,170 +1,201 @@ -error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `Foo`, which is not FFI-safe --> $DIR/lint-ctypes.rs:46:28 | LL | pub fn ptr_type1(size: *const Foo); - | ^^^^^^^^^^ + | ^^^^^^^^^^ not FFI-safe | note: lint level defined here - --> $DIR/lint-ctypes.rs:1:9 + --> $DIR/lint-ctypes.rs:4:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout note: type defined here --> $DIR/lint-ctypes.rs:24:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^^ -error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `Foo`, which is not FFI-safe --> $DIR/lint-ctypes.rs:47:28 | LL | pub 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: type defined here --> $DIR/lint-ctypes.rs:24:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^^ -error: `extern` block uses type `[u32]` which is not FFI-safe: slices have no C equivalent +error: `extern` block uses type `[u32]`, which is not FFI-safe --> $DIR/lint-ctypes.rs:48:26 | LL | pub fn slice_type(p: &[u32]); - | ^^^^^^ + | ^^^^^^ not FFI-safe | = help: consider using a raw pointer instead + = note: slices have no C equivalent -error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent +error: `extern` block uses type `str`, which is not FFI-safe --> $DIR/lint-ctypes.rs:49:24 | LL | pub 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` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout +error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:50:24 | LL | pub fn box_type(p: Box); - | ^^^^^^^^ + | ^^^^^^^^ not FFI-safe | = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout -error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent +error: `extern` block uses type `char`, which is not FFI-safe --> $DIR/lint-ctypes.rs:51:25 | LL | pub 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` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI +error: `extern` block uses type `i128`, which is not FFI-safe --> $DIR/lint-ctypes.rs:52:25 | LL | pub fn i128_type(p: i128); - | ^^^^ + | ^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI +error: `extern` block uses type `u128`, which is not FFI-safe --> $DIR/lint-ctypes.rs:53:25 | LL | pub fn u128_type(p: u128); - | ^^^^ + | ^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `dyn std::clone::Clone` which is not FFI-safe: trait objects have no C equivalent +error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe --> $DIR/lint-ctypes.rs:54:26 | LL | pub fn trait_type(p: &dyn Clone); - | ^^^^^^^^^^ + | ^^^^^^^^^^ not FFI-safe + | + = note: trait objects have no C equivalent -error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout +error: `extern` block uses type `(i32, i32)`, which is not FFI-safe --> $DIR/lint-ctypes.rs:55:26 | LL | pub fn tuple_type(p: (i32, i32)); - | ^^^^^^^^^^ + | ^^^^^^^^^^ not FFI-safe | = help: consider using a struct instead + = note: tuples have unspecified layout -error: `extern` block uses type `(i32, i32)` which is not FFI-safe: tuples have unspecified layout +error: `extern` block uses type `(i32, i32)`, which is not FFI-safe --> $DIR/lint-ctypes.rs:56:27 | LL | pub fn tuple_type2(p: I32Pair); - | ^^^^^^^ + | ^^^^^^^ not FFI-safe | = help: consider using a struct instead + = note: tuples have unspecified layout -error: `extern` block uses type `ZeroSize` which is not FFI-safe: this struct has no fields +error: `extern` block uses type `ZeroSize`, which is not FFI-safe --> $DIR/lint-ctypes.rs:57:25 | LL | pub fn zero_size(p: ZeroSize); - | ^^^^^^^^ + | ^^^^^^^^ not FFI-safe | = help: consider adding a member to this struct + = note: this struct has no fields note: type defined here --> $DIR/lint-ctypes.rs:20:1 | LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^^ -error: `extern` block uses type `ZeroSizeWithPhantomData` which is not FFI-safe: composed only of PhantomData +error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe --> $DIR/lint-ctypes.rs:58:33 | LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: composed only of `PhantomData` +note: type defined here + --> $DIR/lint-ctypes.rs:43:1 + | +LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `extern` block uses type `std::marker::PhantomData` which is not FFI-safe: composed only of PhantomData - --> $DIR/lint-ctypes.rs:60:12 +error: `extern` block uses type `std::marker::PhantomData`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:61:12 | LL | -> ::std::marker::PhantomData; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: 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:61:23 +error: `extern` block uses type `fn()`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:62:23 | LL | pub 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` block uses type `fn()` which is not FFI-safe: this function pointer has Rust-specific calling convention - --> $DIR/lint-ctypes.rs:62:24 +error: `extern` block uses type `fn()`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:63:24 | LL | pub 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` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout - --> $DIR/lint-ctypes.rs:63:28 +error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:64:28 | LL | pub 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` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI - --> $DIR/lint-ctypes.rs:64:32 +error: `extern` block uses type `i128`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:65:32 | LL | pub fn transparent_i128(p: TransparentI128); - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ not FFI-safe + | + = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `str` which is not FFI-safe: string slices have no C equivalent - --> $DIR/lint-ctypes.rs:65:31 +error: `extern` block uses type `str`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:66:31 | LL | pub 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` block uses type `std::boxed::Box` which is not FFI-safe: this struct has unspecified layout - --> $DIR/lint-ctypes.rs:66:30 +error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:67:30 | LL | pub 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: aborting due to 20 previous errors diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs new file mode 100644 index 0000000000000..25d5f8ec68aa0 --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] + +#![deny(improper_ctypes)] + +type A = impl Fn(); + +pub fn ret_closure() -> A { + || {} +} + +extern "C" { + pub fn a(_: A); + //~^ ERROR `extern` block uses type `A`, which is not FFI-safe +} + +fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr new file mode 100644 index 0000000000000..136d564d1ab3d --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `A`, which is not FFI-safe + --> $DIR/opaque-ty-ffi-unsafe.rs:12:17 + | +LL | pub fn a(_: A); + | ^ not FFI-safe + | +note: lint level defined here + --> $DIR/opaque-ty-ffi-unsafe.rs:3:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + = note: opaque types have no C equivalent + +error: aborting due to previous error + diff --git a/src/test/ui/union/union-repr-c.rs b/src/test/ui/union/union-repr-c.rs index 658452d57f748..1367835e67781 100644 --- a/src/test/ui/union/union-repr-c.rs +++ b/src/test/ui/union/union-repr-c.rs @@ -12,7 +12,7 @@ union W { extern "C" { static FOREIGN1: U; // OK - static FOREIGN2: W; //~ ERROR union has unspecified layout + static FOREIGN2: W; //~ ERROR `extern` block uses type `W` } fn main() {} diff --git a/src/test/ui/union/union-repr-c.stderr b/src/test/ui/union/union-repr-c.stderr index c60817a849a3b..c8bc0380dee68 100644 --- a/src/test/ui/union/union-repr-c.stderr +++ b/src/test/ui/union/union-repr-c.stderr @@ -1,8 +1,8 @@ -error: `extern` block uses type `W` which is not FFI-safe: this union has unspecified layout +error: `extern` block uses type `W`, which is not FFI-safe --> $DIR/union-repr-c.rs:15:22 | LL | static FOREIGN2: W; - | ^ + | ^ not FFI-safe | note: lint level defined here --> $DIR/union-repr-c.rs:2:9 @@ -10,6 +10,7 @@ note: lint level defined here LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union + = note: this union has unspecified layout note: type defined here --> $DIR/union-repr-c.rs:9:1 |