If I have a `#[repr(transparent)]` wrapper around a `PhantomData`, it's considered an improper C type when used in a struct field, even though the wrapped `PhantomData` would be allowed. Specifically ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c82e16eb77a88e4613e5812d1b1123e3)) ```rs #[repr(transparent)] #[derive(Copy, Clone)] struct MyPhantom(core::marker::PhantomData<u8>); #[repr(C)] #[derive(Copy, Clone)] pub struct Bar { pub x: i32, _marker: MyPhantom, } extern "C" { pub fn foo(bar: *mut Bar); } ``` produces the error ``` Compiling playground v0.0.1 (/playground) warning: `extern` block uses type `MyPhantom`, which is not FFI-safe --> src/lib.rs:13:21 | 13 | pub fn foo(bar: *mut Bar); | ^^^^^^^^ not FFI-safe | = note: this struct contains only zero-sized fields note: the type is defined here --> src/lib.rs:3:1 | 3 | struct MyPhantom(core::marker::PhantomData<u8>); | ^^^^^^^^^^^^^^^^ = note: `#[warn(improper_ctypes)]` on by default warning: `playground` (lib) generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.51s ``` This is over-zealous for a few reasons. 1. `PhantomData` on its own is allowed in C structs, so changing this to `_marker: PhantomData<u8>` would solve the warning (but defeats the point of my use case[^1]). 2. `#[repr(transparent)]` is supposed to be treated as the inner type for purposes of ABI, and the `improper_ctypes` lint is about ABI. 3. Using `#[repr(C)]` instead of `#[repr(transparent)]` solves this technically (it shuts the warning up), but seems pretty dodgy, since it's not actually laid out the way C would lay it out anymore (that is, we've guaranteed that `PhantomData` is never going to impact layout at all, and we *haven't* guaranteed this for zero-sized `#[repr(C)]` types which are notably not a real thing in C). TLDR: this lint fires on `#[repr(transparent)]` wrappers around `PhantomData` when they're used as struct fields. IMO these should be fine since `PhantomData` doesn't emit a warning in that case, and `#[repr(transparent)]` is supposed to defer to the inner type. [^1]: If you're curious about the real use case I have, a closer but still-basically-minimized version is [here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=614935f0bf5a85469cf646f1f89f4ebe). It's important that the type not be a direct `PhantomData` (basically `#[non_exhaustive]` is not really usable for FFI, but C has cases where considers appending new fields to the end of a type to be a non-breaking change). *(That said, firing this lint on a type passed by pointer is pretty weird anyway, since the indirection means doesn't actually have to be a valid C type (for the ABI), which is the basic complaint behind #66373, which is *not* what I'm complaining about. IMO this shouldn't fire even if `Bar` were being passed by value, as making the field `PhantomData` (instead of a wrapper around one) doesn't fire in that case)* <!-- TRIAGEBOT_START --> <!-- TRIAGEBOT_ASSIGN_START --> <!-- TRIAGEBOT_ASSIGN_DATA_START$${"user":"krtab"}$$TRIAGEBOT_ASSIGN_DATA_END --> <!-- TRIAGEBOT_ASSIGN_END --> <!-- TRIAGEBOT_END -->