@@ -174,7 +174,8 @@ layout such as reinterpreting values as a different type.
174174Because of this dual purpose, it is possible to create types that are not useful
175175for interfacing with the C programming language.
176176
177- This representation can be applied to structs, unions, and enums.
177+ This representation can be applied to structs, unions, and enums. The exception
178+ is [ zero-variant enums] for which the ` C ` representation is an error.
178179
179180#### \# [ repr(C)] Structs
180181
@@ -273,9 +274,9 @@ assert_eq!(std::mem::size_of::<SizeRoundedUp>(), 8); // Size of 6 from b,
273274assert_eq! (std :: mem :: align_of :: <SizeRoundedUp >(), 4 ); // From a
274275```
275276
276- #### \# [ repr(C)] Enums
277+ #### \# [ repr(C)] Field-less Enums
277278
278- For [ C-like enumerations ] , the ` C ` representation has the size and alignment of
279+ For [ field-less enums ] , the ` C ` representation has the size and alignment of
279280the default ` enum ` size and alignment for the target platform's C ABI.
280281
281282> Note: The enum representation in C is implementation defined, so this is
@@ -285,40 +286,216 @@ the default `enum` size and alignment for the target platform's C ABI.
285286<div class =" warning " >
286287
287288Warning: There are crucial differences between an ` enum ` in the C language and
288- Rust's C-like enumerations with this representation. An ` enum ` in C is
289+ Rust's [ field-less enums ] with this representation. An ` enum ` in C is
289290mostly a ` typedef ` plus some named constants; in other words, an object of an
290291` enum ` type can hold any integer value. For example, this is often used for
291- bitflags in ` C ` . In contrast, Rust’s C-like enumerations can only legally hold
292- the discriminant values, everything else is undefined behaviour . Therefore,
293- using a C-like enumeration in FFI to model a C ` enum ` is often wrong.
292+ bitflags in ` C ` . In contrast, Rust’s [ field-less enums ] can only legally hold
293+ the discrimnant values, everything else is [ undefined behavior ] . Therefore,
294+ using a field-less enum in FFI to model a C ` enum ` is often wrong.
294295
295296</div >
296297
297- It is an error for [ zero-variant enumerations ] to have the ` C ` representation.
298+ #### \# [ repr(C) ] Enums With Fields
298299
299- For all other enumerations, the layout is unspecified.
300+ The representation of a ` repr(C) ` enum with fields is a ` repr(C) ` struct with
301+ two fields, also called a "tagged union" in C:
300302
301- Likewise, combining the ` C ` representation with a primitive representation, the
302- layout is unspecified.
303+ - a ` repr(C) ` version of the enum with all fields removed ("the tag")
304+ - a ` repr(C) ` union of ` repr(C) ` structs for the fields of each variant that had
305+ them ("the payload")
306+
307+ > Note: Due to the representation of ` repr(C) ` structs and unions, if a variant
308+ > has a single field there is no difference between putting that field directly
309+ > in the union or wrapping it in a struct; any system which wishes to manipulate
310+ > such an ` enum ` 's representation may therefore use whichever form is more
311+ > convenient or consistent for them.
312+
313+ ``` rust
314+ // This Enum has the same representation as ...
315+ #[repr(C )]
316+ enum MyEnum {
317+ A (u32 ),
318+ B (f32 , u64 ),
319+ C { x : u32 , y : u8 },
320+ D ,
321+ }
322+
323+ // ... this struct.
324+ #[repr(C )]
325+ struct MyEnumRepr {
326+ tag : MyEnumDiscriminant ,
327+ payload : MyEnumFields ,
328+ }
329+
330+ // This is the discriminant enum.
331+ #[repr(C )]
332+ enum MyEnumDiscriminant { A , B , C , D }
333+
334+ // This is the variant union.
335+ #[repr(C )]
336+ union MyEnumFields {
337+ A : MyAFields ,
338+ B : MyBFields ,
339+ C : MyCFields ,
340+ D : MyDFields ,
341+ }
342+
343+ #[repr(C )]
344+ #[derive(Copy , Clone )]
345+ struct MyAFields (u32 );
346+
347+ #[repr(C )]
348+ #[derive(Copy , Clone )]
349+ struct MyBFields (f32 , u64 );
350+
351+ #[repr(C )]
352+ #[derive(Copy , Clone )]
353+ struct MyCFields { x : u32 , y : u8 }
354+
355+ // This struct could be omitted (it is a zero-sized type), and it must be in
356+ // C/C++ headers.
357+ #[repr(C )]
358+ #[derive(Copy , Clone )]
359+ struct MyDFields ;
360+ ```
361+
362+ > Note: ` union ` s with non-` Copy ` fields are unstable, see [ 55149] .
303363
304364### Primitive representations
305365
306366The * primitive representations* are the representations with the same names as
307367the primitive integer types. That is: ` u8 ` , ` u16 ` , ` u32 ` , ` u64 ` , ` u128 ` ,
308368` usize ` , ` i8 ` , ` i16 ` , ` i32 ` , ` i64 ` , ` i128 ` , and ` isize ` .
309369
310- Primitive representations can only be applied to enumerations.
370+ Primitive representations can only be applied to enumerations and have
371+ different behavior whether the enum has fields or no fields. It is an error
372+ for [ zero-variant enumerations] to have a primitive representation. Combining
373+ two primitive representations together is an error.
374+
375+ #### Primitive Representation of Field-less Enums
376+
377+ For [ field-less enums] , primitive representations set the size and alignment to
378+ be the same as the primitive type of the same name. For example, a field-less
379+ enum with a ` u8 ` representation can only have discriminants between 0 and 255
380+ inclusive.
311381
312- For [ C-like enumerations] , they set the size and alignment to be the same as the
313- primitive type of the same name. For example, a C-like enumeration with a ` u8 `
314- representation can only have discriminants between 0 and 255 inclusive.
382+ #### Primitive Representation of Enums With Fields
315383
316- It is an error for [ zero-variant enumerations] to have a primitive
317- representation.
384+ The representation of a primitive representation enum is a ` repr(C) ` union of
385+ ` repr(C) ` structs for each variant with a field. The first field of each struct
386+ in the union is the primitive representation version of the enum with all fields
387+ removed ("the tag") and the remaining fields are the fields of that variant.
318388
319- For all other enumerations, the layout is unspecified.
389+ > Note: This representation is unchanged if the tag is given its own member in
390+ > the union, should that make manipulation more clear for you (although to
391+ > follow the C++ standard the tag member should be wrapped in a ` struct ` ).
392+
393+ ``` rust
394+ // This enum has the same representation as ...
395+ #[repr(u8 )]
396+ enum MyEnum {
397+ A (u32 ),
398+ B (f32 , u64 ),
399+ C { x : u32 , y : u8 },
400+ D ,
401+ }
402+
403+ // ... this union.
404+ #[repr(C )]
405+ union MyEnumRepr {
406+ A : MyVariantA ,
407+ B : MyVariantB ,
408+ C : MyVariantC ,
409+ D : MyVariantD ,
410+ }
411+
412+ // This is the discriminant enum.
413+ #[repr(u8 )]
414+ #[derive(Copy , Clone )]
415+ enum MyEnumDiscriminant { A , B , C , D }
416+
417+ #[repr(C )]
418+ #[derive(Clone , Copy )]
419+ struct MyVariantA (MyEnumDiscriminant , u32 );
420+
421+ #[repr(C )]
422+ #[derive(Clone , Copy )]
423+ struct MyVariantB (MyEnumDiscriminant , f32 , u64 );
424+
425+ #[repr(C )]
426+ #[derive(Clone , Copy )]
427+ struct MyVariantC { tag : MyEnumDiscriminant , x : u32 , y : u8 }
428+
429+ #[repr(C )]
430+ #[derive(Clone , Copy )]
431+ struct MyVariantD (MyEnumDiscriminant );
432+ ```
433+
434+ > Note: ` union ` s with non-` Copy ` fields are unstable, see [ 55149] .
435+
436+ #### Combining primitive representations of enums with fields and \# [ repr(C)]
437+
438+ For enums with fields, it is also possible to combine ` repr(C) ` and a
439+ primitive representation (e.g., ` repr(C, u8) ` ). This modifies the [ ` repr(C) ` ] by
440+ changing the representation of the discriminant enum to the chosen primitive
441+ instead. So, if you chose the ` u8 ` representation, then the discriminant enum
442+ would have a size and alignment of 1 byte.
443+
444+ The discriminant enum from the example [ earlier] [ `repr(C)` ] then becomes:
445+
446+ ``` rust
447+ #[repr(C , u8 )] // `u8` was added
448+ enum MyEnum {
449+ A (u32 ),
450+ B (f32 , u64 ),
451+ C { x : u32 , y : u8 },
452+ D ,
453+ }
454+
455+ // ...
456+
457+ #[repr(u8 )] // So `u8` is used here instead of `C`
458+ enum MyEnumDiscriminant { A , B , C , D }
459+
460+ // ...
461+ ```
462+
463+ For example, with a ` repr(C, u8) ` enum it is not possible to have 257 unique
464+ discriminants ("tags") whereas the same enum with only a ` repr(C) ` attribute
465+ will compile without any problems.
466+
467+ Using a primitive representation in addition to ` repr(C) ` can change the size of
468+ an enum from the ` repr(C) ` form:
469+
470+ ``` rust
471+ #[repr(C )]
472+ enum EnumC {
473+ Variant0 (u8 ),
474+ Variant1 ,
475+ }
476+
477+ #[repr(C , u8 )]
478+ enum Enum8 {
479+ Variant0 (u8 ),
480+ Variant1 ,
481+ }
482+
483+ #[repr(C , u16 )]
484+ enum Enum16 {
485+ Variant0 (u8 ),
486+ Variant1 ,
487+ }
488+
489+ // The size of the C representation is platform dependant
490+ assert_eq! (std :: mem :: size_of :: <EnumC >(), 8 );
491+ // One byte for the discriminant and one byte for the value in Enum8::Variant0
492+ assert_eq! (std :: mem :: size_of :: <Enum8 >(), 2 );
493+ // Two bytes for the discriminant and one byte for the value in Enum16::Variant0
494+ // plus one byte of padding.
495+ assert_eq! (std :: mem :: size_of :: <Enum16 >(), 4 );
496+ ```
320497
321- Likewise, combining two primitive representations together is unspecified.
498+ [ `repr(C)` ] : #reprc-enums-with-fields
322499
323500### The alignment modifiers
324501
@@ -379,12 +556,14 @@ used with any other representation.
379556[ `align_of` ] : ../std/mem/fn.align_of.html
380557[ `size_of` ] : ../std/mem/fn.size_of.html
381558[ `Sized` ] : ../std/marker/trait.Sized.html
559+ [ `Copy` ] : ../std/marker/trait.Copy.html
382560[ dynamically sized types ] : dynamically-sized-types.md
383- [ C-like enumerations ] : items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations
561+ [ field-less enums ] : items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations
384562[ enumerations ] : items/enumerations.md
385- [ zero-variant enumerations ] : items/enumerations.md#zero-variant-enums
563+ [ zero-variant enums ] : items/enumerations.md#zero-variant-enums
386564[ undefined behavior ] : behavior-considered-undefined.md
387565[ 27060 ] : https://github.com/rust-lang/rust/issues/27060
566+ [ 55149 ] : https://github.com/rust-lang/rust/issues/55149
388567[ `PhantomData<T>` ] : special-types-and-traits.md#phantomdatat
389568[ Default ] : #the-default-representation
390569[ `C` ] : #the-c-representation
0 commit comments