Currently, only enums where none of the variants have data (aka “C-like enums”) are FFI-safe, and only if they have #[repr(C)]
or #[repr(uN)]
for some integer size N. (Also, as a special case, Option<&T>
and equivalent types are FFI-safe.)
In the PR documenting this in the nomicon, I learned that enums with data (“non-C-like”) are not FFI-safe, even if they have #[repr(C)]
or #[repr(uN)]
and all of the data fields are FFI-safe. This surprises me: I would expect that, for instance,
#[repr(u8)]
enum TurtleAction {
Forward(distance: u16),
Rotate(angle: u16),
PenUp,
PenDown,
}
should be FFI-safe and have a totally stable representation. Specifically, that should have the same representation as #[repr(C)] struct TurtleActionFFI {action: u8; parameter: u16;}
.
I also learned, furthermore, that the improper_ctypes
lint (see source) already goes to the work of checking each enum variant, and only warns you if some field in the variant is itself non-FFI-safe. So, the lint would consider TurtleAction
to be FFI-safe.
The logic there is pretty similar to that for untagged unions, and my reading of the untagged union RFC is that those are probably intended to be FFI-safe if they contain FFI-safe data. And the only thing that tagged unions add is a tag at the beginning—that is, a C-like enum indicating which variant to look at, and C-like variants with #[repr]
are already FFI-safe. So there isn’t really much with an undefined representation here.
What needs to be done to stabilize the representation of (tagged) enums with #[repr(C)]
or #[repr(uN)]
? Would this be an RFC? I’m hoping this should be easy to stabilize, but I guess people just need to say “Yes, we won’t change the representation of these enums”?
If this is hard to stabilize quickly, I’d like to open a PR removing the above logic from the improper_ctypes
lint, and simply warning on all non-C-like enums regardless of contents (besides Option<&T>
, of course). It looks like the logic to check field members for FFI-safety was added when the current incarnation of the lint was written (PR #26583), and I see no discussion on the PR about enums either way, so I’d totally believe that it was written as a good-faith hint but not an ABI promise.
(Also, is there some documentation of what’s FFI-safe and what’s not? Even if the improper_ctypes
lint were able to be 100% accurate at all times, it’s not a good reference for humans. Is the Nomicon the right place for this?)
cc @ubsan, @Gankra, @steveklabnik (from the Nomicon PR), @eefriedman (author of the current improper_ctypes
lint)