diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index c4d709aa1f985..34a59dbc262b0 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -360,7 +360,6 @@ lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stab lint_improper_ctypes_array_help = consider passing a pointer to the array lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe -lint_improper_ctypes_box = box cannot be represented as a single pointer lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead @@ -378,7 +377,9 @@ lint_improper_ctypes_enum_repr_help = lint_improper_ctypes_enum_repr_reason = enum has no representation hint lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead +lint_improper_ctypes_fnptr_indirect_reason = the function pointer to `{$ty}` is FFI-unsafe due to `{$inner_ty}` lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention + lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants @@ -389,7 +390,11 @@ lint_improper_ctypes_opaque = opaque types have no C equivalent lint_improper_ctypes_pat_help = consider using the base type instead lint_improper_ctypes_pat_reason = pattern types have no C equivalent -lint_improper_ctypes_slice_help = consider using a raw pointer instead + +lint_improper_ctypes_sized_ptr_to_unsafe_type = + this reference (`{$ty}`) is can safely be translated into a C pointer, but `{$inner_ty}` itself is not FFI-safe + +lint_improper_ctypes_slice_help = consider using a raw pointer to the slice's first element (and a length) instead lint_improper_ctypes_slice_reason = slices have no C equivalent lint_improper_ctypes_str_help = consider using `*const u8` and a length instead @@ -415,6 +420,10 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive +lint_improper_ctypes_unsized_box = this box for an unsized rust type contains metadata, which makes it incompatible with a C pointer +lint_improper_ctypes_unsized_ptr = this pointer to an unsized rust type contains metadata, which makes it incompatible with a C pointer +lint_improper_ctypes_unsized_ref = this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer + lint_incomplete_include = include macro expected single expression in source diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index cfa54fec839b3..f2382c04e9079 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -599,8 +599,6 @@ enum FfiResult<'tcx> { reason: DiagMessage, help: Option, }, - // NOTE: this `allow` is only here for one retroactively-added commit - #[allow(dead_code)] FfiUnsafeWrapper { ty: Ty<'tcx>, reason: DiagMessage, @@ -915,16 +913,47 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match *ty.kind() { ty::Adt(def, args) => { - if let Some(boxed) = ty.boxed_ty() - && matches!(self.mode, CItemKind::Definition) - { - if boxed.is_sized(tcx, self.cx.param_env) { - return FfiSafe; + if let Some(inner_ty) = ty.boxed_ty() { + if inner_ty.is_sized(tcx, self.cx.param_env) + || matches!(inner_ty.kind(), ty::Foreign(..)) + { + // discussion on declaration vs definition: + // see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm + // of this `match *ty.kind()` block + if matches!(self.mode, CItemKind::Definition) { + return FfiSafe; + } else { + let inner_res = self.check_type_for_ffi(acc, inner_ty); + return match inner_res { + FfiUnsafe { .. } | FfiUnsafeWrapper { .. } => FfiUnsafeWrapper { + ty, + reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type, + wrapped: Box::new(inner_res), + help: None, + }, + _ => inner_res, + }; + } } else { + let help = match inner_ty.kind() { + ty::Str => Some(fluent::lint_improper_ctypes_str_help), + ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help), + ty::Adt(def, _) + if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union) + && matches!( + tcx.get_diagnostic_name(def.did()), + Some(sym::cstring_type | sym::cstr_type) + ) + && !acc.base_ty.is_mutable_ptr() => + { + Some(fluent::lint_improper_ctypes_cstr_help) + } + _ => None, + }; return FfiUnsafe { ty, - reason: fluent::lint_improper_ctypes_box, - help: None, + reason: fluent::lint_improper_ctypes_unsized_box, + help, }; } } @@ -1087,15 +1116,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { help: Some(fluent::lint_improper_ctypes_tuple_help), }, - ty::RawPtr(ty, _) | ty::Ref(_, ty, _) - if { - matches!(self.mode, CItemKind::Definition) - && ty.is_sized(self.cx.tcx, self.cx.param_env) - } => - { - FfiSafe - } - ty::RawPtr(ty, _) if match ty.kind() { ty::Tuple(tuple) => tuple.is_empty(), @@ -1105,7 +1125,66 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } - ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty), + ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _) => { + if inner_ty.is_sized(tcx, self.cx.param_env) + || matches!(inner_ty.kind(), ty::Foreign(..)) + { + // there's a nuance on what this lint should do for function definitions + // (touched upon in https://github.com/rust-lang/rust/issues/66220 and https://github.com/rust-lang/rust/pull/72700) + // + // (`extern "C" fn fn_name(...) {...}`) versus declarations (`extern "C" {fn fn_name(...);}`). + // The big question is: what does "ABI safety" mean? if you have something translated to a C pointer + // (which has a stable layout) but points to FFI-unsafe type, is it safe? + // on one hand, the function's ABI will match that of a similar C-declared function API, + // on the other, dereferencing the pointer in not-rust will be painful. + // In this code, the opinion is split between function declarations and function definitions. + // For declarations, we see this as unsafe, but for definitions, we see this as safe. + // This is mostly because, for extern function declarations, the actual definition of the function is written somewhere else, + // so the fact that a pointer's pointee should be treated as opaque to one side or the other can be explicitely written out. + // For extern function definitions, however, both callee and some callers can be written in rust, + // so developers need to keep as much typing information as possible. + if matches!(self.mode, CItemKind::Definition) { + return FfiSafe; + } else if matches!(ty.kind(), ty::RawPtr(..)) + && matches!(inner_ty.kind(), ty::Tuple(tuple) if tuple.is_empty()) + { + FfiSafe + } else { + let inner_res = self.check_type_for_ffi(acc, inner_ty); + return match inner_res { + FfiSafe => inner_res, + _ => FfiUnsafeWrapper { + ty, + reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type, + wrapped: Box::new(inner_res), + help: None, + }, + }; + } + } else { + let help = match inner_ty.kind() { + ty::Str => Some(fluent::lint_improper_ctypes_str_help), + ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help), + ty::Adt(def, _) + if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union) + && matches!( + tcx.get_diagnostic_name(def.did()), + Some(sym::cstring_type | sym::cstr_type) + ) + && !acc.base_ty.is_mutable_ptr() => + { + Some(fluent::lint_improper_ctypes_cstr_help) + } + _ => None, + }; + let reason = match ty.kind() { + ty::RawPtr(..) => fluent::lint_improper_ctypes_unsized_ptr, + ty::Ref(..) => fluent::lint_improper_ctypes_unsized_ref, + _ => unreachable!(), + }; + FfiUnsafe { ty, reason, help } + } + } ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty), @@ -1123,7 +1202,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { for arg in sig.inputs() { match self.check_type_for_ffi(acc, *arg) { FfiSafe => {} - r => return r, + r => { + return FfiUnsafeWrapper { + ty, + reason: fluent::lint_improper_ctypes_fnptr_indirect_reason, + help: None, + wrapped: Box::new(r), + }; + } } } @@ -1132,7 +1218,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - self.check_type_for_ffi(acc, ret_ty) + match self.check_type_for_ffi(acc, ret_ty) { + r @ (FfiSafe | FfiPhantom(_)) => r, + r => FfiUnsafeWrapper { + ty: ty.clone(), + reason: fluent::lint_improper_ctypes_fnptr_indirect_reason, + help: None, + wrapped: Box::new(r), + }, + } } ty::Foreign(..) => FfiSafe, diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr index 044c1ae2dd42f..b5c718ec38147 100644 --- a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr +++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr @@ -4,6 +4,7 @@ warning: `extern` fn uses type `CStr`, which is not FFI-safe LL | type Foo = extern "C" fn(::std::ffi::CStr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr` = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` = note: `CStr`/`CString` do not have a guaranteed layout = note: `#[warn(improper_ctypes_definitions)]` on by default @@ -14,6 +15,7 @@ warning: `extern` block uses type `CStr`, which is not FFI-safe LL | fn meh(blah: Foo); | ^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr` = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` = note: `CStr`/`CString` do not have a guaranteed layout = note: `#[warn(improper_ctypes)]` on by default diff --git a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr index ebd6cec6ecd3f..f2ee21c316658 100644 --- a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr +++ b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr @@ -4,6 +4,7 @@ warning: `extern` fn uses type `str`, which is not FFI-safe LL | type ExternCallback = extern "C" fn(*const u8, u32, str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str` = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent = note: `#[warn(improper_ctypes_definitions)]` on by default @@ -14,6 +15,7 @@ warning: `extern` fn uses type `str`, which is not FFI-safe LL | pub extern "C" fn register_something(bind: ExternCallback) -> Struct { | ^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str` = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.rs b/tests/ui/lint/extern-C-fnptr-lints-slices.rs index 0c35eb37a4890..4e3832ab1b672 100644 --- a/tests/ui/lint/extern-C-fnptr-lints-slices.rs +++ b/tests/ui/lint/extern-C-fnptr-lints-slices.rs @@ -3,7 +3,7 @@ // It's an improper ctype (a slice) arg in an extern "C" fnptr. pub type F = extern "C" fn(&[u8]); -//~^ ERROR: `extern` fn uses type `[u8]`, which is not FFI-safe +//~^ ERROR: `extern` fn uses type `&[u8]`, which is not FFI-safe fn main() {} diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr index d13f93ca96f22..bbd16ce8ce16e 100644 --- a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr +++ b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr @@ -1,11 +1,12 @@ -error: `extern` fn uses type `[u8]`, which is not FFI-safe +error: `extern` fn uses type `&[u8]`, which is not FFI-safe --> $DIR/extern-C-fnptr-lints-slices.rs:5:14 | LL | pub type F = extern "C" fn(&[u8]); | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead - = note: slices have no C equivalent + = note: the function pointer to `for<'a> extern "C" fn(&'a [u8])` is FFI-unsafe due to `&[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer note: the lint level is defined here --> $DIR/extern-C-fnptr-lints-slices.rs:1:8 | diff --git a/tests/ui/lint/lint-ctypes-73249-2.stderr b/tests/ui/lint/lint-ctypes-73249-2.stderr index ef30a406969d3..9143e57174e40 100644 --- a/tests/ui/lint/lint-ctypes-73249-2.stderr +++ b/tests/ui/lint/lint-ctypes-73249-2.stderr @@ -4,6 +4,7 @@ error: `extern` block uses type `Qux`, which is not FFI-safe LL | fn lint_me() -> A<()>; | ^^^^^ not FFI-safe | + = note: this reference (`&Qux`) is can safely be translated into a C pointer, but `Qux` itself is not FFI-safe = note: opaque types have no C equivalent note: the lint level is defined here --> $DIR/lint-ctypes-73249-2.rs:2:9 diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr index bd127cf60044c..4bebca69b7f3b 100644 --- a/tests/ui/lint/lint-ctypes-94223.stderr +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -4,7 +4,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | pub fn bad(f: extern "C" fn([u8])) {} | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead + = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead = note: slices have no C equivalent note: the lint level is defined here --> $DIR/lint-ctypes-94223.rs:2:9 @@ -18,7 +19,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | pub fn bad_twice(f: Result) {} | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead + = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -27,7 +29,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | pub fn bad_twice(f: Result) {} | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead + = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -36,7 +39,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | struct BadStruct(extern "C" fn([u8])); | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead + = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -45,7 +49,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | A(extern "C" fn([u8])), | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead + = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -54,7 +59,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | A(extern "C" fn([u8])), | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead + = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -63,7 +69,8 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | type Foo = extern "C" fn([u8]); | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead + = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` + = help: consider using a raw pointer to the slice's first element (and a length) instead = note: slices have no C equivalent error: `extern` fn uses type `Option<&::FooType>`, which is not FFI-safe @@ -72,6 +79,7 @@ error: `extern` fn uses type `Option<&::FooType>`, which is not F LL | pub type Foo2 = extern "C" fn(Option<&::FooType>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `for<'a> extern "C" fn(Option<&'a ::FooType>)` is FFI-unsafe due to `Option<&::FooType>` = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint @@ -81,6 +89,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub static BAD: extern "C" fn(FfiUnsafe) = f; | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = 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 @@ -95,6 +104,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub static BAD_TWICE: Result = Ok(f); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = 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 @@ -109,6 +119,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub static BAD_TWICE: Result = Ok(f); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = 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 @@ -123,6 +134,7 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | + = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = 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 diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/lint-ctypes-cstr.rs index b04decd0bcacc..c4de5a44a9623 100644 --- a/tests/ui/lint/lint-ctypes-cstr.rs +++ b/tests/ui/lint/lint-ctypes-cstr.rs @@ -8,7 +8,7 @@ extern "C" { //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` fn take_cstr_ref(s: &CStr); - //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe + //~^ ERROR `extern` block uses type `&CStr`, which is not FFI-safe //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` fn take_cstring(s: CString); //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe @@ -27,7 +27,7 @@ extern "C" { } extern "C" fn rust_take_cstr_ref(s: &CStr) {} -//~^ ERROR `extern` fn uses type `CStr`, which is not FFI-safe +//~^ ERROR `extern` fn uses type `&CStr`, which is not FFI-safe //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` extern "C" fn rust_take_cstring(s: CString) {} //~^ ERROR `extern` fn uses type `CString`, which is not FFI-safe diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/lint-ctypes-cstr.stderr index 8957758d57732..7bf4d1068027f 100644 --- a/tests/ui/lint/lint-ctypes-cstr.stderr +++ b/tests/ui/lint/lint-ctypes-cstr.stderr @@ -12,14 +12,14 @@ note: the lint level is defined here LL | #![deny(improper_ctypes, improper_ctypes_definitions)] | ^^^^^^^^^^^^^^^ -error: `extern` block uses type `CStr`, which is not FFI-safe +error: `extern` block uses type `&CStr`, which is not FFI-safe --> $DIR/lint-ctypes-cstr.rs:10:25 | LL | fn take_cstr_ref(s: &CStr); | ^^^^^ not FFI-safe | = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` - = note: `CStr`/`CString` do not have a guaranteed layout + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` block uses type `CString`, which is not FFI-safe --> $DIR/lint-ctypes-cstr.rs:13:24 @@ -36,6 +36,7 @@ error: `extern` block uses type `CString`, which is not FFI-safe LL | fn take_cstring_ref(s: &CString); | ^^^^^^^^ not FFI-safe | + = note: this reference (`&CString`) is can safely be translated into a C pointer, but `CString` itself is not FFI-safe = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` = note: `CStr`/`CString` do not have a guaranteed layout @@ -45,6 +46,7 @@ error: `extern` block uses type `CString`, which is not FFI-safe LL | fn no_special_help_for_mut_cstring(s: *mut CString); | ^^^^^^^^^^^^ not FFI-safe | + = note: this reference (`*mut CString`) is can safely be translated into a C pointer, but `CString` itself is not FFI-safe = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout @@ -54,17 +56,18 @@ error: `extern` block uses type `CString`, which is not FFI-safe LL | fn no_special_help_for_mut_cstring_ref(s: &mut CString); | ^^^^^^^^^^^^ not FFI-safe | + = note: this reference (`&mut CString`) is can safely be translated into a C pointer, but `CString` itself is 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 `CStr`, which is not FFI-safe +error: `extern` fn uses type `&CStr`, which is not FFI-safe --> $DIR/lint-ctypes-cstr.rs:29:37 | LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {} | ^^^^^ not FFI-safe | = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` - = note: `CStr`/`CString` do not have a guaranteed layout + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer note: the lint level is defined here --> $DIR/lint-ctypes-cstr.rs:2:26 | diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/lint-ctypes-fn.rs index 73820c86d1a02..e16ff9573fd18 100644 --- a/tests/ui/lint/lint-ctypes-fn.rs +++ b/tests/ui/lint/lint-ctypes-fn.rs @@ -68,10 +68,10 @@ pub extern "C" fn ptr_unit(p: *const ()) { } pub extern "C" fn ptr_tuple(p: *const ((),)) { } pub extern "C" fn slice_type(p: &[u32]) { } -//~^ ERROR: uses type `[u32]` +//~^ ERROR: uses type `&[u32]` pub extern "C" fn str_type(p: &str) { } -//~^ ERROR: uses type `str` +//~^ ERROR: uses type `&str` pub extern "C" fn box_type(p: Box) { } @@ -124,7 +124,7 @@ pub extern "C" fn transparent_i128(p: TransparentI128) { } //~^ ERROR: uses type `i128` pub extern "C" fn transparent_str(p: TransparentStr) { } -//~^ ERROR: uses type `str` +//~^ ERROR: uses type `&str` pub extern "C" fn transparent_fn(p: TransparentBadFn) { } diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/lint-ctypes-fn.stderr index a62533a4be17b..0af4ded135da6 100644 --- a/tests/ui/lint/lint-ctypes-fn.stderr +++ b/tests/ui/lint/lint-ctypes-fn.stderr @@ -1,25 +1,25 @@ -error: `extern` fn uses type `[u32]`, which is not FFI-safe +error: `extern` fn uses type `&[u32]`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:70: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 + = help: consider using a raw pointer to the slice's first element (and a length) instead + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer note: the lint level is defined here --> $DIR/lint-ctypes-fn.rs:2:9 | LL | #![deny(improper_ctypes_definitions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `extern` fn uses type `str`, which is not FFI-safe +error: `extern` fn uses type `&str`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:73: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 + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:80:34 @@ -27,7 +27,8 @@ error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { } | ^^^^^^^^^ not FFI-safe | - = note: box cannot be represented as a single pointer + = help: consider using a raw pointer to the slice's first element (and a length) instead + = note: this box for an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` fn uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:83:35 @@ -35,7 +36,8 @@ error: `extern` fn uses type `Box`, which is not FFI-safe LL | pub extern "C" fn boxed_string(p: Box) { } | ^^^^^^^^ not FFI-safe | - = note: box cannot be represented as a single pointer + = help: consider using `*const u8` and a length instead + = note: this box for an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` fn uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:86:34 @@ -43,7 +45,7 @@ error: `extern` fn uses type `Box`, which is not FFI-safe LL | pub extern "C" fn boxed_trait(p: Box) { } | ^^^^^^^^^^^^^^ not FFI-safe | - = note: box cannot be represented as a single pointer + = note: this box for an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` fn uses type `char`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:89:32 @@ -149,14 +151,14 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` fn uses type `str`, which is not FFI-safe +error: `extern` fn uses type `&str`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:126: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 + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` fn uses type `PhantomData`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:172:43 diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/lint-ctypes.rs index dae07930aba60..615cdfd738ac3 100644 --- a/tests/ui/lint/lint-ctypes.rs +++ b/tests/ui/lint/lint-ctypes.rs @@ -48,15 +48,15 @@ extern "C" { pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` pub fn ptr_unit(p: *const ()); pub fn ptr_tuple(p: *const ((),)); //~ ERROR: uses type `((),)` - pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` - pub fn str_type(p: &str); //~ ERROR: uses type `str` + 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 `Box` pub fn opt_box_type(p: Option>); //~^ ERROR uses type `Option>` 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: &dyn Bar); //~ ERROR uses type `dyn Bar` + pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `&dyn Bar` 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 uses type `ZeroSize` @@ -68,7 +68,7 @@ extern "C" { pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()` pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box` pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` - pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` + pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `&str` pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box` pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]` diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/lint-ctypes.stderr index 2c81c7b8e4b67..fdb7ef1261085 100644 --- a/tests/ui/lint/lint-ctypes.stderr +++ b/tests/ui/lint/lint-ctypes.stderr @@ -4,6 +4,7 @@ error: `extern` block uses type `Foo`, which is not FFI-safe LL | pub fn ptr_type1(size: *const Foo); | ^^^^^^^^^^ not FFI-safe | + = note: this reference (`*const Foo`) is can safely be translated into a C pointer, but `Foo` itself is 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 @@ -23,6 +24,7 @@ error: `extern` block uses type `Foo`, which is not FFI-safe LL | pub fn ptr_type2(size: *const Foo); | ^^^^^^^^^^ not FFI-safe | + = note: this reference (`*const Foo`) is can safely be translated into a C pointer, but `Foo` itself is 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 @@ -37,26 +39,27 @@ error: `extern` block uses type `((),)`, which is not FFI-safe LL | pub fn ptr_tuple(p: *const ((),)); | ^^^^^^^^^^^^ not FFI-safe | + = note: this reference (`*const ((),)`) is can safely be translated into a C pointer, but `((),)` itself is not FFI-safe = help: consider using a struct instead = note: tuples have unspecified layout -error: `extern` block uses type `[u32]`, which is not FFI-safe +error: `extern` block uses type `&[u32]`, which is not FFI-safe --> $DIR/lint-ctypes.rs:51:26 | LL | pub fn slice_type(p: &[u32]); | ^^^^^^ not FFI-safe | - = help: consider using a raw pointer instead - = note: slices have no C equivalent + = help: consider using a raw pointer to the slice's first element (and a length) instead + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer -error: `extern` block uses type `str`, which is not FFI-safe +error: `extern` block uses type `&str`, which is not FFI-safe --> $DIR/lint-ctypes.rs:52: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 + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:53:24 @@ -101,13 +104,13 @@ LL | pub fn u128_type(p: u128); | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `dyn Bar`, which is not FFI-safe +error: `extern` block uses type `&dyn Bar`, which is not FFI-safe --> $DIR/lint-ctypes.rs:59:26 | LL | pub fn trait_type(p: &dyn Bar); | ^^^^^^^^ not FFI-safe | - = note: trait objects have no C equivalent + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` block uses type `(i32, i32)`, which is not FFI-safe --> $DIR/lint-ctypes.rs:60:26 @@ -197,14 +200,14 @@ LL | pub fn transparent_i128(p: TransparentI128); | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `str`, which is not FFI-safe +error: `extern` block uses type `&str`, which is not FFI-safe --> $DIR/lint-ctypes.rs:71: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 + = note: this reference to an unsized rust type contains metadata, which makes it incompatible with a C pointer error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:72:30 @@ -259,4 +262,3 @@ LL | pub static static_u128_array_type: [u128; 16]; = note: 128-bit integers don't currently have a known stable ABI error: aborting due to 27 previous errors -