Skip to content

Commit e8aabe8

Browse files
committed
Organization of reprs
1 parent ad4342b commit e8aabe8

File tree

1 file changed

+56
-27
lines changed

1 file changed

+56
-27
lines changed

src/type-layout.md

+56-27
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ layout such as reinterpreting values as a different type.
149149
Because of this dual purpose, it is possible to create types that are not useful
150150
for interfacing with the C programming language.
151151

152-
This representation can be applied to structs, unions, and enums.
152+
This representation can be applied to structs, unions, and enums. The exception
153+
is [zero-variant enumerations] for which the `C` representation is an error.
153154

154155
#### \#[repr(C)] Structs
155156

@@ -222,7 +223,7 @@ assert_eq!(std::mem::size_of::<SizeRoundedUp>(), 8); // Size of 6 from b,
222223
assert_eq!(std::mem::align_of::<SizeRoundedUp>(), 4); // From a
223224
```
224225

225-
#### \#[repr(C)] Enums
226+
#### \#[repr(C)] Field-less Enums
226227

227228
For [field-less enums], the `C` representation has the size and alignment of
228229
the default `enum` size and alignment for the target platform's C ABI.
@@ -236,12 +237,21 @@ the default `enum` size and alignment for the target platform's C ABI.
236237
> mostly a `typedef` plus some named constants; in other words, an object of an
237238
> `enum` type can hold any integer value. For example, this is often used for
238239
> bitflags in `C`. In contrast, Rust’s field-less enums can only legally hold
239-
> the discrimnant values, everything else is undefined behaviour. Therefore,
240+
> the discrimnant values, everything else is [undefined behavior]. Therefore,
240241
> using a field-less enum in FFI to model a C `enum` is often wrong.
241242
242-
For enums with fields, the `C` representation has the same representation as
243-
it would with the [primitive representation] with the field-less enum in its
244-
description having the `C` representation.
243+
#### \#[repr(C)] Enums With Fields
244+
245+
For enums with fields, the `C` representation is a struct with representation
246+
`C` of two fields where the first field is a field-less enum with the `C`
247+
representation that has one variant for each variant in the enum with fields
248+
and the second field a union with the `C` representation that's fields consist
249+
of structs with the `C` representation corresponding to each variant in the
250+
enum. Each struct consists of the fields from the corresponding variant in the
251+
order defined in the enum with fields.
252+
253+
Because unions with non-copy fields aren't allowed, this representation can only
254+
be used if every field is also [`Copy`].
245255

246256
```rust
247257
// This Enum has the same layout as
@@ -272,33 +282,51 @@ union MyEnumPayload {
272282
}
273283

274284
#[repr(C)]
285+
#[derive(Clone, Copy)]
275286
struct MyEnumPayloadB(f32, u64);
276287

277288
#[repr(C)]
289+
#[derive(Clone, Copy)]
278290
struct MyEnumPayloadC { x: u32, y: u8 }
279291
```
280292

281-
It is an error for [zero-variant enumerations] to have the `C` representation.
282-
283293
<span id="c-primitive-representation">Combining the `C` representation and a
284-
primitive representation is only defined for enums with fields and it changes
285-
the representation of the tag, e.g. `MyEnumTag` in the previous example, to have
286-
the representation of the chosen primitive representation. So, if you chose the
287-
`u8` representation, then the tag would have a size and alignment of 1 byte.
288-
</span>
294+
primitive representation is only defined for enums with fields. The primitive
295+
representation modifies the `C` representation by changing the representation of
296+
the tag, e.g. `MyEnumTag` in the previous example, to have the representation of
297+
the chosen primitive representation. So, if you chose the `u8` representation,
298+
then the tag would have a size and alignment of 1 byte. </span>
289299

290-
### Primitive representations
300+
> Note: This representation was designed for primarily interfacing with C code
301+
> that already exists matching a common way Rust's enums are implemented in
302+
> C. If you have control over both the Rust and C code, such as using C as FFI
303+
> glue between Rust and some third language, then you should use a
304+
> [primitive representation](#primitive-representation-of-enums-with-fields)
305+
> instead.
306+
307+
### Primitive Representations
291308

292309
The *primitive representations* are the representations with the same names as
293310
the primitive integer types. That is: `u8`, `u16`, `u32`, `u64`, `usize`, `i8`,
294311
`i16`, `i32`, `i64`, and `isize`.
295312

296-
Primitive representations can only be applied to enumerations.
313+
Primitive representations can only be applied to enumerations, and have
314+
different behavior whether the enum has fields or no fields. It is an error
315+
for [zero-variant enumerations] to have a primitive representation.
316+
317+
Combining two primitive representations together is unspecified.
318+
319+
Combining the `C` representation and a primitive representation is described
320+
[above](#c-primitive-representation).
321+
322+
#### Primitive Fepresentation of Field-less Enums
297323

298324
For [field-less enums], they set the size and alignment to be the same as
299325
the primitive type of the same name. For example, a field-less enum with
300326
a `u8` representation can only have discriminants between 0 and 255 inclusive.
301327

328+
#### Primitive Representation of Enums With Fields
329+
302330
For enums with fields, the enum will have the same type layout a union with the
303331
`C` representation that's fields consist of structs with the `C` representation
304332
corresponding to each variant in the enum. The first field in each struct is
@@ -307,9 +335,12 @@ the enum with all fields in its variants removed and the rest of the fields
307335
consisting of the fields of the corresponding variant in the order defined in
308336
original enumeration.
309337

338+
Because unions with non-copy fields aren't allowed, this representation can only
339+
be used if every field is also [`Copy`].
340+
310341
> Note: This is commonly different than what is done in C and C++. Projects in
311342
> those languages often use a tuple of `(enum, payload)`. For making your enum
312-
> represented like that, see [the tagged union representation] below.
343+
> represented like that, use the `C` representation.
313344
314345
```rust
315346
// This custom enum
@@ -323,6 +354,7 @@ enum MyEnum {
323354

324355
// has the same type layout as this union
325356
#[repr(C)]
357+
#[derive(Clone, Copy)]
326358
union MyEnumRepr {
327359
A: MyEnumVariantA,
328360
B: MyEnumVariantB,
@@ -331,30 +363,26 @@ union MyEnumRepr {
331363
}
332364

333365
#[repr(u8)]
366+
#[derive(Clone, Copy)]
334367
enum MyEnumDiscriminant { A, B, C, D }
335368

336369
#[repr(C)]
370+
#[derive(Clone, Copy)]
337371
struct MyEnumVariantA(MyEnumDiscriminant, u32);
338372

339373
#[repr(C)]
374+
#[derive(Clone, Copy)]
340375
struct MyEnumVariantB(MyEnumDiscriminant, f32, u64);
341376

342377
#[repr(C)]
378+
#[derive(Clone, Copy)]
343379
struct MyEnumVariantC { tag: MyEnumDiscriminant, x: u32, y: u8 }
344380

345381
#[repr(C)]
382+
#[derive(Clone, Copy)]
346383
struct MyEnumVariantD(MyEnumDiscriminant);
347384
```
348385

349-
It is an error for [zero-variant enumerations] to have a primitive
350-
representation.
351-
352-
Combining two primitive representations together is unspecified.
353-
354-
Combining the `C` representation and a primitive representation is described
355-
[above][#c-primitive-representation].
356-
357-
358386
### The `align` Representation
359387

360388
The `align` representation can be used on `struct`s and `union`s to raise the
@@ -378,7 +406,7 @@ padding bytes and forcing the alignment of the type to `1`.
378406
The `align` and `packed` representations cannot be applied on the same type and
379407
a `packed` type cannot transitively contain another `align`ed type.
380408

381-
> Warning: Dereferencing an unaligned pointer is [undefined behaviour] and it is
409+
> Warning: Dereferencing an unaligned pointer is [undefined behavior] and it is
382410
> possible to [safely create unaligned pointers to `packed` fields][27060].
383411
> Like all ways to create undefined behavior in safe Rust, this is a bug.
384412
@@ -392,4 +420,5 @@ a `packed` type cannot transitively contain another `align`ed type.
392420
[zero-variant enumerations]: items/enumerations.html#zero-variant-enums
393421
[undefined behavior]: behavior-considered-undefined.html
394422
[27060]: https://github.com/rust-lang/rust/issues/27060
395-
[primitive representation]: #primitive-representations
423+
[primitive representation]: #primitive-representations
424+
[`Copy`]: special-types-and-traits.html#copy

0 commit comments

Comments
 (0)