@mark(c) enum (ADR-0086)

The @mark(c) marker, originally restricted to functions and structs by ADR-0085, additionally applies to enum declarations. @mark(c) enum types are gated behind the c_ffi_extras preview feature.

A @mark(c) enum uses c_int as its discriminant type, regardless of variant count. This matches C's default enum discriminant convention.

A field-less @mark(c) enum (every variant is a unit variant) lowers to a bare c_int value: size = sizeof(c_int), alignment = alignof(c_int). Niche optimisation is disabled.

A field-less @mark(c) enum is permitted at the FFI boundary as a parameter or return type of any @mark(c) fn or link_extern item declaration.

A data-carrying @mark(c) enum (at least one variant carries fields) uses the C tagged-union layout: the discriminant of type c_int sits at offset 0, followed by a payload region. The payload region starts at offset max(alignof(c_int), max(alignof(variant_i))) and is sized to max(size(variant_i)). Total enum size is payload_offset + payload_size, rounded up to enum alignment = max(alignof(c_int), max(alignof(variant_i))). Niche optimisation is disabled. Each variant payload field must itself satisfy the C-FFI-type rules from §10.1 — non-FFI fields are rejected with a diagnostic that names the offending variant and field.

A non-@mark(c) enum cannot cross the FFI boundary by value. The diagnostic surfaces the type name and the FFI position.
@mark(c) enum Event {
    Quit,
    KeyPress(c_int),
    MouseMove { x: c_int, y: c_int },
}

link_extern("foo") {
    fn poll_event() -> Event;
}

fn main() -> i32 {
    let red: Event = Event::Quit;
    0
}