-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
Open
Labels
A-ABIArea: Concerning the application binary interface (ABI)Area: Concerning the application binary interface (ABI)A-FFIArea: Foreign function interface (FFI)Area: Foreign function interface (FFI)C-feature-requestCategory: A feature request, i.e: not implemented / a PR.Category: A feature request, i.e: not implemented / a PR.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-opsemRelevant to the opsem teamRelevant to the opsem team
Description
Code
#![allow(dead_code)]
use std::ptr::NonNull;
use std::marker::PhantomData;
#[repr(C)]
struct Pointer<'a, T: ?Sized> {
pointer: NonNull<T>,
_phantom: PhantomData<&'a T>,
}
#[repr(C)]
struct Slice<'a, T: ?Sized> {
pointer: NonNull<T>,
length: u64,
_phantom: PhantomData<&'a T>,
}
#[repr(C)]
struct Value<'vm, T: ?Sized> {
ty: &'vm (),
value: Option<&'vm T>,
}
unsafe extern "C" {
// Unambiguous: If `None`, the `Pointer.pointer` will be `null`.
fn pointer<'a>(_: Option<Pointer<'a, u8>>) -> Option<Pointer<'a, u8>>;
// Unambiguous: If `None`, the `Slice.pointer` will be `null`.
fn slice<'a>(_: Option<Slice<'a, u8>>) -> Option<Slice<'a, u8>>;
// Unambiguous: If `None`, the `Value.type` will be `null`.
fn value<'a>(_: Option<Value<'a, u8>>) -> Option<Value<'a, u8>>;
}Current output
warning: `extern` block uses type `Option<Pointer<'_, u8>>`, which is not FFI-safe
--> src/lib.rs:26:23
|
26 | fn pointer<'a>(_: Option<Pointer<'a, u8>>) -> Option<Pointer<'a, u8>>;
| ^^^^^^^^^^^^^^^^^^^^^^^ 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: `#[warn(improper_ctypes)]` on by default
warning: `extern` block uses type `Option<Pointer<'_, u8>>`, which is not FFI-safe
--> src/lib.rs:26:51
|
26 | fn pointer<'a>(_: Option<Pointer<'a, u8>>) -> Option<Pointer<'a, u8>>;
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
warning: `extern` block uses type `Option<Slice<'_, u8>>`, which is not FFI-safe
--> src/lib.rs:28:21
|
28 | fn slice<'a>(_: Option<Slice<'a, u8>>) -> Option<Slice<'a, u8>>;
| ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
warning: `extern` block uses type `Option<Slice<'_, u8>>`, which is not FFI-safe
--> src/lib.rs:28:47
|
28 | fn slice<'a>(_: Option<Slice<'a, u8>>) -> Option<Slice<'a, u8>>;
| ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
warning: `extern` block uses type `Option<Value<'_, u8>>`, which is not FFI-safe
--> src/lib.rs:30:21
|
30 | fn value<'a>(_: Option<Value<'a, u8>>) -> Option<Value<'a, u8>>;
| ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
warning: `extern` block uses type `Option<Value<'_, u8>>`, which is not FFI-safe
--> src/lib.rs:30:47
|
30 | fn value<'a>(_: Option<Value<'a, u8>>) -> Option<Value<'a, u8>>;
| ^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
= note: enum has no representation hint
warning: `playground` (lib) generated 6 warnings
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.54sDesired output
Compiling playground v0.0.1 (/playground)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.59sRationale and extra context
All enums with the following properties should be considered "FFI-safe":
- they have the "Null Pointer Optimization" (NPO) applied to them
- the value they contain is "FFI-safe"
- the value they contain has exactly one field that enables NPO, and this field has exactly one "invalid" value
In other words, an NPO-optimized enum is FFI-safe if the "null" value can be unambiguously determined.
arguably, NPO-optimized enums should also be considered FFI-safe when the "null" value can not be unambiguously determined, but that is a rabbit hole that I don't want to get into right now, and probably worthy of an RFC.
Other cases
Adding #[repr(transparent)] to struct Pointer can remove the first few warnings. However, #[repr(transparent)] also changes the calling convention, which may not be desired.
Rust Version
$ rustc --version --verbose
rustc 1.91.1 (ed61e7d7e 2025-11-07)
binary: rustc
commit-hash: ed61e7d7e242494fb7057f2657300d9e77bb4fcb
commit-date: 2025-11-07
host: x86_64-unknown-linux-gnu
release: 1.91.1
LLVM version: 21.1.2Anything else?
No response
Metadata
Metadata
Assignees
Labels
A-ABIArea: Concerning the application binary interface (ABI)Area: Concerning the application binary interface (ABI)A-FFIArea: Foreign function interface (FFI)Area: Foreign function interface (FFI)C-feature-requestCategory: A feature request, i.e: not implemented / a PR.Category: A feature request, i.e: not implemented / a PR.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-opsemRelevant to the opsem teamRelevant to the opsem team