Skip to content

Commit c813590

Browse files
committed
Organization of reprs
1 parent ad4342b commit c813590

File tree

1 file changed

+52
-22
lines changed

1 file changed

+52
-22
lines changed

src/type-layout.md

+52-22
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,46 @@ 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>
299+
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.
289306
290-
### Primitive representations
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+
#### Primitive Fepresentation of Field-less Enums
297318

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

323+
#### Primitive Representation of Enums With Fields
324+
302325
For enums with fields, the enum will have the same type layout a union with the
303326
`C` representation that's fields consist of structs with the `C` representation
304327
corresponding to each variant in the enum. The first field in each struct is
@@ -307,9 +330,12 @@ the enum with all fields in its variants removed and the rest of the fields
307330
consisting of the fields of the corresponding variant in the order defined in
308331
original enumeration.
309332

333+
Because unions with non-copy fields aren't allowed, this representation can only
334+
be used if every field is also [`Copy`].
335+
310336
> Note: This is commonly different than what is done in C and C++. Projects in
311337
> those languages often use a tuple of `(enum, payload)`. For making your enum
312-
> represented like that, see [the tagged union representation] below.
338+
> represented like that, use the `C` representation.
313339
314340
```rust
315341
// This custom enum
@@ -323,6 +349,7 @@ enum MyEnum {
323349

324350
// has the same type layout as this union
325351
#[repr(C)]
352+
#[derive(Clone, Copy)]
326353
union MyEnumRepr {
327354
A: MyEnumVariantA,
328355
B: MyEnumVariantB,
@@ -331,28 +358,30 @@ union MyEnumRepr {
331358
}
332359

333360
#[repr(u8)]
361+
#[derive(Clone, Copy)]
334362
enum MyEnumDiscriminant { A, B, C, D }
335363

336364
#[repr(C)]
365+
#[derive(Clone, Copy)]
337366
struct MyEnumVariantA(MyEnumDiscriminant, u32);
338367

339368
#[repr(C)]
369+
#[derive(Clone, Copy)]
340370
struct MyEnumVariantB(MyEnumDiscriminant, f32, u64);
341371

342372
#[repr(C)]
373+
#[derive(Clone, Copy)]
343374
struct MyEnumVariantC { tag: MyEnumDiscriminant, x: u32, y: u8 }
344375

345376
#[repr(C)]
377+
#[derive(Clone, Copy)]
346378
struct MyEnumVariantD(MyEnumDiscriminant);
347379
```
348380

349-
It is an error for [zero-variant enumerations] to have a primitive
350-
representation.
351-
352381
Combining two primitive representations together is unspecified.
353382

354383
Combining the `C` representation and a primitive representation is described
355-
[above][#c-primitive-representation].
384+
[above](#c-primitive-representation).
356385

357386

358387
### The `align` Representation
@@ -378,7 +407,7 @@ padding bytes and forcing the alignment of the type to `1`.
378407
The `align` and `packed` representations cannot be applied on the same type and
379408
a `packed` type cannot transitively contain another `align`ed type.
380409

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

0 commit comments

Comments
 (0)