From 44c79c86e4694d88e612acd6acfb8948aada93aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Sep 2025 12:25:04 +0200 Subject: [PATCH 1/3] fix field-less repr(C) enum docs --- src/type-layout.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/type-layout.md b/src/type-layout.md index 425f82d5c9..976c462461 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -344,11 +344,15 @@ assert_eq!(std::mem::align_of::(), 4); // From a r[layout.repr.c.enum] #### `#[repr(C)]` Field-less Enums -For [field-less enums], the `C` representation has the size and alignment of -the default `enum` size and alignment for the target platform's C ABI. +For [field-less enums], the `C` representation requires the discriminant values to +be representable by the `int` type in the target platform's C ABI. +Nevertheless, the type of the discriminant is `isize`. +The size and alignment of the enum then match that of a C enum with the same +discriminant values (and without a fixed underlying type). > [!NOTE] > The enum representation in C is implementation defined, so this is really a "best guess". In particular, this may be incorrect when the C code of interest is compiled with certain flags. +> For maximum portability, it is always preferred to set the size and alignment explicitly using a [primitive representation](#r-layout.repr.primitive.enum) on the Rust side, and a fixed underlying type on the C side. > [!WARNING] > There are crucial differences between an `enum` in the C language and Rust's [field-less enums] with this representation. An `enum` in C is mostly a `typedef` plus some named constants; in other words, an object of an `enum` type can hold any integer value. For example, this is often used for bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold the discriminant values, everything else is [undefined behavior]. Therefore, using a field-less enum in FFI to model a C `enum` is often wrong. @@ -436,10 +440,11 @@ two primitive representations together is an error. r[layout.repr.primitive.enum] #### Primitive Representation of Field-less Enums -For [field-less enums], primitive representations set the size and alignment to -be the same as the primitive type of the same name. For example, a field-less -enum with a `u8` representation can only have discriminants between 0 and 255 -inclusive. +For [field-less enums], primitive representations set the type of the discriminants +to the primitive type of the same name. Furthermore, the enum's size and alignment are +guaranteed to match that type. For example, a field-less +enum with a `u8` representation has discriminants of type `u8` and hence +can only have discriminants between 0 and 255 inclusive. r[layout.repr.primitive.adt] #### Primitive Representation of Enums With Fields From 5bc25154a3f90c8cad742f9f3ddac1acdecaf7b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Oct 2025 13:43:56 +0200 Subject: [PATCH 2/3] also allow enums where all discriminant values fit an unsigned int --- src/type-layout.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/type-layout.md b/src/type-layout.md index 976c462461..bc25f59d85 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -345,7 +345,8 @@ r[layout.repr.c.enum] #### `#[repr(C)]` Field-less Enums For [field-less enums], the `C` representation requires the discriminant values to -be representable by the `int` type in the target platform's C ABI. +either all be representable by the `int` type in the target platform's C ABI, +or to all be representable by the `unsigned int` type. Nevertheless, the type of the discriminant is `isize`. The size and alignment of the enum then match that of a C enum with the same discriminant values (and without a fixed underlying type). From 3582e38e64adda8ee0995d860d7f3b4f9225d9e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Oct 2025 14:01:47 +0200 Subject: [PATCH 3/3] emphasize that the isize values matter --- src/type-layout.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/type-layout.md b/src/type-layout.md index bc25f59d85..f5906864aa 100644 --- a/src/type-layout.md +++ b/src/type-layout.md @@ -350,6 +350,7 @@ or to all be representable by the `unsigned int` type. Nevertheless, the type of the discriminant is `isize`. The size and alignment of the enum then match that of a C enum with the same discriminant values (and without a fixed underlying type). +Crucially, the equivalent C type is determined based on the discriminant values *after* they have been cast to `isize`. > [!NOTE] > The enum representation in C is implementation defined, so this is really a "best guess". In particular, this may be incorrect when the C code of interest is compiled with certain flags.