From 3946e44428726c00611cf8b7676f7e36c0ea3feb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 9 Aug 2017 10:04:55 -0700 Subject: [PATCH 01/22] Add unnamed fields RFC --- text/0000-unnamed-fields.md | 350 ++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 text/0000-unnamed-fields.md diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md new file mode 100644 index 00000000000..af998950b94 --- /dev/null +++ b/text/0000-unnamed-fields.md @@ -0,0 +1,350 @@ +- Feature Name: unnamed_fields +- Start Date: 2017-08-05 +- RFC PR: +- Rust Issue: + +# Summary +[summary]: #summary + +Allow unnamed fields of `union` and `struct` type, contained within structs and +unions, respectively; the fields they contain appear directly within the +containing structure, with the use of `union` and `struct` determining which +fields have non-overlapping storage (making them usable at the same time). +This allows grouping and laying out fields in arbitrary ways, to match C data +structures used in FFI. The C11 standard allows this, and C compilers have +allowed it for decades as an extension. This proposal allows Rust to represent +such types using the same names as the C structures, without interposing +artificial field names that will confuse users of well-established interfaces +from existing platforms. + +# Motivation +[motivation]: #motivation + +Numerous C interfaces follow a common pattern, consisting of a `struct` +containing discriminants and common fields, and an unnamed `union` of fields +specific to certain values of the discriminants. To group together fields used +together as part of the same variant, these interfaces also often use unnamed +`struct` types. + +Thus, `struct` defines a set of fields that can appear at the same time, and +`union` defines a set of mutually exclusive overlapping fields. + +This pattern appears throughout many C APIs. The Windows and POSIX APIs both +use this pattern extensively. However, Rust currently can't represent this +pattern in a straightforward way. While Rust supports structs and unions, every +such struct and union must have a field name. When creating a binding to such +an interface, whether manually or using a binding generator, the binding must +invent an artificial field name that does not appear in the original interface. + +This RFC proposes a minimal mechanism to support such interfaces in Rust. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +This explanation should appear after the definition of `union`, and after an +explanation of the rationale for `union` versus `enum` in Rust. + +Please note that most Rust code will want to use an `enum` to define types that +contain a discriminant and various disjoint fields. The unnamed field mechanism +here exist primarily for compatibility with interfaces defined by non-Rust +languages, such as C. Types declared with this mechanism require `unsafe` code +to access. + +A `struct` defines a set of fields all available at the same time, with storage +available for each. A `union` defines (in an unsafe, unchecked manner) a set of +mutually exclusive fields, with overlapping storage. Some types and interfaces +may require nesting such groupings. For instance, a `struct` may contain a set +of common fields and a `union` of fields needed for different variations of the +structure; conversely, a `union` contain a `struct` grouping together fields +needed simultaneously. + +Such groupings, however, do not always have associated types and names. A +structure may contain groupings of fields where the fields have meaningful +names, but the groupings of fields do not. In this case, the structure can +contain *unnamed fields* of `struct` or `union` type, to group the fields +together, and determine which fields overlap. + +As an example, when defining a `struct`, you may have a set of fields that will +never be used at the same time, so you could overlap the storage of those +fields. This pattern often occurs within C APIs, when defining an interface +similar to a Rust `enum`. You could do so by declaring a separate `union` type +and a field of that type. With the unnamed fields mechanism, you can also +define an unnamed grouping of overlapping fields inline within the `struct`, +using the `union` keyword: + +```rust +struct S { + a: u32, + union { + b: u32, + c: f32, + }, + d: u64, +} +``` + +Given a struct `s` of this type, code can access `s.a`, `s.d`, and either `s.b` +or `s.c`. Accesses to `a` and `d` can occur in safe code; accesses to `b` and +`c` require unsafe code, and `b` and `c` overlap, requiring care to access only +the field whose contents make sense at the time. As with any `union`, code +cannot borrow `s.b` and `s.c` simultaneously. + +Conversely, sometimes when defining a `union`, you may want to group multiple +fields together and make them available simultaneously, with non-overlapping +storage. You could do so by defining a separate `struct`, and placing an +instance of that `struct` within the `union`. With the unnamed fields +mechanism, you can also define an unnamed grouping of non-overlapping fields +inline within the `union`, using the `struct` keyword: + +```rust +union U { + a: u32, + struct { + b: u16, + c: f16, + }, + d: f32, +} +``` + +Given a union `u` of this type, code can access `u.a`, or `u.d`, or both `u.b` +and `u.c`. Since all of these fields can potentially overlap with others, +accesses to any of them require unsafe code; however, `b` and `c` do not +overlap with each other. Code can borrow `u.b` and `u.c` simultaneously, but +cannot borrow any other fields at the same time. + +Unnamed fields can contain other unnamed fields. For example: + +```rust +struct S { + a: u32, + union { + b: u32, + struct { + c: u16, + d: f16, + }, + e: f32, + }, + f: u64, +} +``` + +This structure contains six fields: `a`, `b`, `c`, `d`, `e`, and `f`. Safe code +can access fields `a` and `f`, at any time, since those fields do not lie +within a union and do not overlap with any other field. Unsafe code can access +the remaining fields. This definition effectively acts as the overlap of the +following three structures: + +```rust +// variant 1 +struct S { + a: u32, + b: u32, + f: u64, +} + +// variant 2 +struct S { + a: u32, + c: u16, + d: f16, + f: u64, +} + +// variant 3 +struct S { + a: u32, + e: f32, + f: u64, +} +``` + +## Instantiation + +Given the following declaration: + +```rust +struct S { + a: u32, + union { + b: u32, + struct { + c: u16, + d: f16, + }, + e: f32, + }, + f: u64, +} +``` + +All of the following will instantiate a value of type `S`: + +- `S { a: 1, b: 2, f: 3.0 }` +- `S { a: 1, c: 2, d: 3.0, f: 4.0 }` +- `S { a: 1, e: 2.0, f: 3.0 }` + +## Representation + +By default, Rust lays out structures using its native representation, +`repr(Rust)`; that representation permits any layout that can store all the +non-overlapping fields simultaneously, and makes no other guarantees about the +storage of unnamed fields. + +When using this mechanism to define a C interface, remember to use the +`repr(C)` attribute to match C's data structure layout. Any representation +attribute applied to the top-level structure also applies to every unnamed +field within that declaration. Such a structure defined with `repr(C)` will use +a representation identical to the same structure with all unnamed fields +transformed to equivalent named fields of a struct or union type with the same +fields. + +## Derive + +A `struct` or `union` containing unnamed fields may derive `Copy`, `Clone`, or +both, if all the fields it contains (including within unnamed fields) also +implement `Copy`. + +A `struct` containing unnamed fields may derive `Clone` if every field +contained directly in the `struct` implements `Clone`, and every field +contained within an unnamed `union` (directly or indirectly) implements `Copy`. + +## Ambiguous field names + +You cannot use this feature to define multiple fields with the same name. For +instance, the following definition will produce an error: + +```rust +struct S { + a: u32, + union { + a: u32, + b: f32, + }, +} +``` + +The error will identify the duplicate `a` fields as the sources of the error. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +## Parsing + +Within a struct's fields, in place of a field name and value, allow +`union { fields }`, where `fields` allows everything allowed within a `union` +declaration. Conversely, within a union's fields, in place of a field name +and value, allow `struct { fields }`, where `fields` allows everything allowed +within a `struct` declaration. + +Note that the keyword `struct` cannot appear as a field name, making it +entirely unambiguous. The contextual keyword `union` could theoretically appear +as a field name, but an open brace cannot appear immediately after a field +name, allowing disambiguation via a single token of context (`union {`). + +## Layout and Alignment + +The layout and alignment of a `struct` or `union` containing unnamed +fields should look the same as if each unnamed field has a separately declared +type and a named field of that type, rather than as if the fields appeared +directly within the containing `struct` or `union`. In some cases, this may +result in different alignment. + +## Simultaneous Borrows + +An unnamed `struct` within a `union` should behave the same with respect to +borrows as a named and typed `struct` within a `union`, allowing borrows of +multiple fields from within the `struct`, while not permitting borrows of other +fields in the `union`. + +## Visibility + +Each field within an unnamed `struct` or `union` may have an attached +visibility (`pub` or `pub(crate)`). An unnamed field itself does not have its +own visibility; all of its fields appear directly within the containing +structure, and their own visibilities apply. + +## Documentation + +Public fields within an unnamed `struct` or `union` should appear in the +rustdoc documentation of the outer structure, along with any doc comment or +attribute attached to those fields. The rendering should include all unnamed +fields that contain (at any level of nesting) a public field, and should +include the `// some fields omitted` note within any `struct` or `union` that +has non-public fields, including unnamed fields. + +Any unnamed field that contains only non-public fields should be omitted +entirely, rather than included with its fields omitted. Omitting an unnamed +field should trigger the `// some fields omitted` note. + +# Drawbacks +[drawbacks]: #drawbacks + +This introduces additional complexity in structure definitions. Strictly +speaking, C interfaces do not *require* this mechanism; any such interface +*could* define named struct or union types, and define named fields of that +type. This RFC provides a usability improvement for such interfaces. + +# Rationale and Alternatives +[alternatives]: #alternatives + +Choosing not to implement this feature would force binding generators (and the +authors of manual bindings) to invent new names for these groupings of fields. +Users would need to look up the names for those groupings, and would not be +able to rely on documentation for the underlying interface. Furthermore, +binding generators would not have any basis on which to generate a meaningful +name. + +Several alternative syntaxes could exist to designate the equivalent of +`struct` and `union`. Such syntaxes would declare the same underlying types. +However, inventing a novel syntax for this mechanism would make it less +familiar both to Rust users accustomed to structs and unions as well as to C +users accustomed to unnamed struct and union fields. + +We could introduce a mechanism to declare arbitrarily positioned fields, such +as attributes declaring the offset of each field. The same mechanism was also +proposed in response to the original union RFC. However, as in that case, using +struct and union syntax has the advantage of allowing the compiler to implement +the appropriate positioning and alignment of fields. + +In addition to introducing just this narrow mechanism for defining unnamed +fields, we could introduce a fully general mechanism for anonymous `struct` and +`union` types that can appear anywhere a type can appear, including in function +arguments and return values, named structure fields, or local variables. Such +an anonymous type mechanism would *not* replace the need for unnamed fields, +however, and vice versa. Furthermore, anonymous types would interact +extensively with far more aspects of Rust. Such a mechanism should appear in a +subsequent RFC. + +This mechanism intentionally does not provide any means to reference an unnamed +field as a whole, or its type. That intentional limitation avoids allowing such +unnamed types to propagate. + +# Unresolved questions +[unresolved]: #unresolved-questions + +This proposal does *not* support anonymous `struct` and `union` types that can +appear anywhere a type can appear, such as in the type of an arbitrary named +field or variable. Doing so would further simplify some C interfaces, as well +as native Rust constructs. + +However, such a change would also cascade into numerous other changes, such as +anonymous struct and union literals. Unlike this proposal, anonymous aggregate +types for named fields have a reasonable alternative, namely creating and using +separate types; binding generators could use that mechanism, and a macro could +allow declaring those types inline next to the fields that use them. + +Furthermore, during the pre-RFC process, that portion of the proposal proved +more controversial. And such a proposal would have a much more expansive impact +on the language as a whole, by introducing a new construct that works anywhere +a type can appear. Thus, this proposal provides the minimum change necessary to +enable bindings to these types of C interfaces. + +This proposal only permits an unnamed `struct` to appear within a `union` and +vice versa. An unnamed `union` within a `union` doesn't seem to have any useful +value. An unnamed `struct` within a `struct` works in C11, and does affect +alignment, but does not seem particularly useful without the ability to +reference the unnamed field. Nonetheless, extending this feature to allow +unnamed `struct` and `union` fields to appear within either a `struct` or +`union` would not introduce much additional complexity. From a29c4b78301895a56e5efcb05606b4d89d990619 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 9 Aug 2017 11:39:59 -0700 Subject: [PATCH 02/22] Explicitly note that we cannot implement this as a macro --- text/0000-unnamed-fields.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index af998950b94..dde33f9397d 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -296,6 +296,12 @@ able to rely on documentation for the underlying interface. Furthermore, binding generators would not have any basis on which to generate a meaningful name. +We cannot implement this feature as a macro, because it affects the names used +to reference the fields contained within an unnamed field. A macro could +extract and define types for the unnamed fields, but that macro would have to +give a name to those unnamed fields, and accesses would have to include the +intermediate name. + Several alternative syntaxes could exist to designate the equivalent of `struct` and `union`. Such syntaxes would declare the same underlying types. However, inventing a novel syntax for this mechanism would make it less From 49466b1425f30adce90ef9a6433805672d8f733c Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 9 Aug 2017 11:50:53 -0700 Subject: [PATCH 03/22] Mention alias mechanism as an alternative Also discuss the drawbacks of that alternative. --- text/0000-unnamed-fields.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index dde33f9397d..4ccda0dfaaf 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -302,6 +302,17 @@ extract and define types for the unnamed fields, but that macro would have to give a name to those unnamed fields, and accesses would have to include the intermediate name. +Rather than introducing unnamed fields, we could introduce a mechanism to +define field aliases for a type, such that for `struct S`, `s.b` desugars to +`s.b_or_c.b`. However, such a mechanism does not seem any simpler than unnamed +fields, and would not align as well with the potential future introduction of +full anonymous structure types. Furthermore, such a mechanism would need to +allow hiding the underlying paths for portability; for example, the `siginfo_t` +type on POSIX platforms allows portable access to certain named fields, but +different platforms overlap those fields differently. Finally, such a mechanism +would make it harder to create bindings for this common pattern in C +interfaces. + Several alternative syntaxes could exist to designate the equivalent of `struct` and `union`. Such syntaxes would declare the same underlying types. However, inventing a novel syntax for this mechanism would make it less From 55ae14f5b50271c817f5870193d02fe595fe7442 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 9 Aug 2017 11:52:09 -0700 Subject: [PATCH 04/22] Clarify the explanation of `siginfo_t` --- text/0000-unnamed-fields.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 4ccda0dfaaf..c499fa87c90 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -309,9 +309,9 @@ fields, and would not align as well with the potential future introduction of full anonymous structure types. Furthermore, such a mechanism would need to allow hiding the underlying paths for portability; for example, the `siginfo_t` type on POSIX platforms allows portable access to certain named fields, but -different platforms overlap those fields differently. Finally, such a mechanism -would make it harder to create bindings for this common pattern in C -interfaces. +different platforms overlap those fields differently using unnamed unions. +Finally, such a mechanism would make it harder to create bindings for this +common pattern in C interfaces. Several alternative syntaxes could exist to designate the equivalent of `struct` and `union`. Such syntaxes would declare the same underlying types. From ca3ca0c96515dbc5e9e54fd1944eebfc90643e35 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 17 Aug 2017 11:17:02 -0700 Subject: [PATCH 05/22] Mention other interface issues this does not attempt to address Deferred to future RFCs, in the interests of focusing on one problem at a time. --- text/0000-unnamed-fields.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index c499fa87c90..db5f3a0f3bd 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -365,3 +365,10 @@ alignment, but does not seem particularly useful without the ability to reference the unnamed field. Nonetheless, extending this feature to allow unnamed `struct` and `union` fields to appear within either a `struct` or `union` would not introduce much additional complexity. + +C structures can still include other constructs that Rust does not currently +represent, including bitfields, and variable-length arrays at the end of a +structure. Future RFCs may wish to introduce support for those constructs as +well. However, I do not believe it makes sense to require a solution for every +problem of interfacing with C simultaneously, nor to gate a solution for one +common issue on solutions for others. From 592b8b9d565752dcbe855868dd465147da362f22 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 17 Aug 2017 11:26:41 -0700 Subject: [PATCH 06/22] Add an explanation of the mental model, with a diagram --- text/0000-unnamed-fields.md | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index db5f3a0f3bd..68fc565d5ff 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -160,6 +160,48 @@ struct S { } ``` +## Mental model + +In the memory layout of a structure, the alternating uses of `struct { ... }` +and `union { ... }` change the "direction" that fields are being laid out: if +you think of memory addresses as going vertically, `struct` lays out fields +vertically, in sequence, and `union` lays out fields horizontally, overlapping +with each other. The following definition: + +```rust +struct S { + a: u32, + union { + b: u32, + struct { + c: u16, + d: f16, + }, + e: f32, + }, + f: u64, +} +``` + +corresponds to the following structure layout in memory: + +``` ++-----------+ 0 +| a | ++-----------+ 4 +| b | c | e | +| +---+ | 6 +| | d | | ++-----------+ 8 +| f | ++-----------+ 16 +``` + +The top-level `struct` lays out `a`, the unnamed `union`, and `f`, in +sequential order. The unnamed `union` lays out `b`, the unnamed `struct`, and +`e`, in parallel. The unnamed `struct` lays out `c` and `d` in sequential +order. + ## Instantiation Given the following declaration: From 275a2c2f29f5d525f69eb0eeceabf3b019d31602 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 17 Aug 2017 11:35:56 -0700 Subject: [PATCH 07/22] Per discussion, limit to repr(C) While this feature potentially has value as a layout mechanism for Rust data structures, it exists primarily to support native platform APIs. Accordingly, limit its applicability to only repr(C) data structures. Also document the use of `repr(packed)` with this mechanism. --- text/0000-unnamed-fields.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 68fc565d5ff..5c05cd63089 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -36,7 +36,11 @@ such struct and union must have a field name. When creating a binding to such an interface, whether manually or using a binding generator, the binding must invent an artificial field name that does not appear in the original interface. -This RFC proposes a minimal mechanism to support such interfaces in Rust. +This RFC proposes a minimal mechanism to support such interfaces in Rust. This +feature exists primarily to support ergonomic FFI interfaces that match the +layout of data structures for the native platform; this RFC intentionally +limits itself to the `repr(C)` structure representation, and does not provide +support for using this feature in Rust data structures using `repr(Rust)`. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -229,10 +233,9 @@ All of the following will instantiate a value of type `S`: ## Representation -By default, Rust lays out structures using its native representation, -`repr(Rust)`; that representation permits any layout that can store all the -non-overlapping fields simultaneously, and makes no other guarantees about the -storage of unnamed fields. +This feature exists to support the layout of native platform data structures. +Structures using the default `repr(Rust)` layout cannot use this feature, and +the compiler should produce an error when attempting to do so. When using this mechanism to define a C interface, remember to use the `repr(C)` attribute to match C's data structure layout. Any representation @@ -242,6 +245,9 @@ a representation identical to the same structure with all unnamed fields transformed to equivalent named fields of a struct or union type with the same fields. +Similarly, applying `repr(packed)` to the top-level data structure will also +apply it to all the contained structures. + ## Derive A `struct` or `union` containing unnamed fields may derive `Copy`, `Clone`, or From 49db3d4d366662b2bdee517ab6cbf5302c08a310 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 17 Aug 2017 11:51:04 -0700 Subject: [PATCH 08/22] Document precedent for limiting to repr(C) Variadic functions require extern "C". --- text/0000-unnamed-fields.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 5c05cd63089..6908e728d28 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -40,7 +40,9 @@ This RFC proposes a minimal mechanism to support such interfaces in Rust. This feature exists primarily to support ergonomic FFI interfaces that match the layout of data structures for the native platform; this RFC intentionally limits itself to the `repr(C)` structure representation, and does not provide -support for using this feature in Rust data structures using `repr(Rust)`. +support for using this feature in Rust data structures using `repr(Rust)`. As +precedent, Rust's support for variadic argument lists only permits its use on +`extern "C"` functions. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation From bd37bd28feff9c92cfb1c66b7730513d46611471 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 17 Aug 2017 12:10:23 -0700 Subject: [PATCH 09/22] Add alternative syntax for declaring unnamed fields with named types Suggested by Peter Atashian. --- text/0000-unnamed-fields.md | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 6908e728d28..9712a3f6ea7 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -339,6 +339,8 @@ type. This RFC provides a usability improvement for such interfaces. # Rationale and Alternatives [alternatives]: #alternatives +## Not implementing this feature at all + Choosing not to implement this feature would force binding generators (and the authors of manual bindings) to invent new names for these groupings of fields. Users would need to look up the names for those groupings, and would not be @@ -346,12 +348,43 @@ able to rely on documentation for the underlying interface. Furthermore, binding generators would not have any basis on which to generate a meaningful name. +## Not implementable as a macro + We cannot implement this feature as a macro, because it affects the names used to reference the fields contained within an unnamed field. A macro could extract and define types for the unnamed fields, but that macro would have to give a name to those unnamed fields, and accesses would have to include the intermediate name. +## Unnamed fields using `_` with named types + +Rather than allowing the inline definition of the contents of unnamed `struct` +or `union` fields, we could allow declaring an unnamed field with a named type. +For instance: + +```rust +union U { x: i64, y: f64 } +struct S { _: U, z: usize } +``` + +Given these declarations, `S` would contain fields `x`, `y`, and `z`, with `x` +and `y` overlapping. Rust currently does not allow `_` as a field name, so +introducing this alternative syntax would not create any compatibility issue. +This alternative syntax has the advantage of declaring the type layouts +explicitly, simplifying the language definition. It also allows reusing the +type definitions for fields within multiple structures, such as a common +header. While C11 does not directly support inlining of separately defined +structures, compilers do support it as an extension. + +This syntax would have the disadvantage of allowing the structure and union +declarations to appear arbitrarily far apart from each other, potentially even +in separate modules. It would also require careful implementation of rustdoc +support, to show the resulting structure layout. Finally, it would require the +introduction of names for the intermediate structures, such as in binding +generators. + +## Field aliases + Rather than introducing unnamed fields, we could introduce a mechanism to define field aliases for a type, such that for `struct S`, `s.b` desugars to `s.b_or_c.b`. However, such a mechanism does not seem any simpler than unnamed @@ -363,18 +396,24 @@ different platforms overlap those fields differently using unnamed unions. Finally, such a mechanism would make it harder to create bindings for this common pattern in C interfaces. +## Alternate syntax + Several alternative syntaxes could exist to designate the equivalent of `struct` and `union`. Such syntaxes would declare the same underlying types. However, inventing a novel syntax for this mechanism would make it less familiar both to Rust users accustomed to structs and unions as well as to C users accustomed to unnamed struct and union fields. +## Arbitrary field positioning + We could introduce a mechanism to declare arbitrarily positioned fields, such as attributes declaring the offset of each field. The same mechanism was also proposed in response to the original union RFC. However, as in that case, using struct and union syntax has the advantage of allowing the compiler to implement the appropriate positioning and alignment of fields. +## General anonymous types + In addition to introducing just this narrow mechanism for defining unnamed fields, we could introduce a fully general mechanism for anonymous `struct` and `union` types that can appear anywhere a type can appear, including in function From bb350be4d7548065788703e49a9f29190e06b10d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 12:54:56 -0700 Subject: [PATCH 10/22] Allow struct-in-struct and union-in-union --- text/0000-unnamed-fields.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 9712a3f6ea7..d72c6d1083f 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -119,6 +119,9 @@ accesses to any of them require unsafe code; however, `b` and `c` do not overlap with each other. Code can borrow `u.b` and `u.c` simultaneously, but cannot borrow any other fields at the same time. +Structs can also contain unnamed structs, and unions can contain unnamed +unions. + Unnamed fields can contain other unnamed fields. For example: ```rust @@ -447,14 +450,6 @@ on the language as a whole, by introducing a new construct that works anywhere a type can appear. Thus, this proposal provides the minimum change necessary to enable bindings to these types of C interfaces. -This proposal only permits an unnamed `struct` to appear within a `union` and -vice versa. An unnamed `union` within a `union` doesn't seem to have any useful -value. An unnamed `struct` within a `struct` works in C11, and does affect -alignment, but does not seem particularly useful without the ability to -reference the unnamed field. Nonetheless, extending this feature to allow -unnamed `struct` and `union` fields to appear within either a `struct` or -`union` would not introduce much additional complexity. - C structures can still include other constructs that Rust does not currently represent, including bitfields, and variable-length arrays at the end of a structure. Future RFCs may wish to introduce support for those constructs as From bd98f9f20f18e0fc608733de1474a1848c383fb7 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 20:11:36 -0700 Subject: [PATCH 11/22] Don't enumerate (a subset of) possible visibilities for fields --- text/0000-unnamed-fields.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index d72c6d1083f..6c5cf1eaf88 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -314,9 +314,9 @@ fields in the `union`. ## Visibility Each field within an unnamed `struct` or `union` may have an attached -visibility (`pub` or `pub(crate)`). An unnamed field itself does not have its -own visibility; all of its fields appear directly within the containing -structure, and their own visibilities apply. +visibility. An unnamed field itself does not have its own visibility; all of +its fields appear directly within the containing structure, and their own +visibilities apply. ## Documentation From 3ce66a119b6a616b9d46f2b498eb876cd37998e5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 20:20:21 -0700 Subject: [PATCH 12/22] Update summary and parsing section for struct-in-struct and union-in-union --- text/0000-unnamed-fields.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 6c5cf1eaf88..83766715922 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -6,16 +6,16 @@ # Summary [summary]: #summary -Allow unnamed fields of `union` and `struct` type, contained within structs and -unions, respectively; the fields they contain appear directly within the -containing structure, with the use of `union` and `struct` determining which -fields have non-overlapping storage (making them usable at the same time). -This allows grouping and laying out fields in arbitrary ways, to match C data -structures used in FFI. The C11 standard allows this, and C compilers have -allowed it for decades as an extension. This proposal allows Rust to represent -such types using the same names as the C structures, without interposing -artificial field names that will confuse users of well-established interfaces -from existing platforms. +Allow unnamed fields of `struct` and `union` type, contained within an outer +struct or union; the fields they contain appear directly within the containing +structure, with the use of `union` and `struct` determining which fields have +non-overlapping storage (making them usable at the same time). This allows +grouping and laying out fields in arbitrary ways, to match C data structures +used in FFI. The C11 standard allows this, and C compilers have allowed it for +decades as an extension. This proposal allows Rust to represent such types +using the same names as the C structures, without interposing artificial field +names that will confuse users of well-established interfaces from existing +platforms. # Motivation [motivation]: #motivation @@ -286,10 +286,8 @@ The error will identify the duplicate `a` fields as the sources of the error. ## Parsing Within a struct's fields, in place of a field name and value, allow -`union { fields }`, where `fields` allows everything allowed within a `union` -declaration. Conversely, within a union's fields, in place of a field name -and value, allow `struct { fields }`, where `fields` allows everything allowed -within a `struct` declaration. +`struct { fields }` or `union { fields }`, where `fields` allows +everything allowed within a `struct` or `union` declaration, respectively. Note that the keyword `struct` cannot appear as a field name, making it entirely unambiguous. The contextual keyword `union` could theoretically appear From e1641666604341d4c5fe5ddf4dbe8de242ed8e89 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 21:02:08 -0700 Subject: [PATCH 13/22] Change the syntax to use a field name of `_` --- text/0000-unnamed-fields.md | 85 ++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 83766715922..35709cf895b 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -81,7 +81,7 @@ using the `union` keyword: ```rust struct S { a: u32, - union { + _: union { b: u32, c: f32, }, @@ -89,11 +89,13 @@ struct S { } ``` -Given a struct `s` of this type, code can access `s.a`, `s.d`, and either `s.b` -or `s.c`. Accesses to `a` and `d` can occur in safe code; accesses to `b` and -`c` require unsafe code, and `b` and `c` overlap, requiring care to access only -the field whose contents make sense at the time. As with any `union`, code -cannot borrow `s.b` and `s.c` simultaneously. +The underscore `_` indicates the absence of a field name; the fields within the +unnamed union will appear directly with the containing structure. Given a +struct `s` of this type, code can access `s.a`, `s.d`, and either `s.b` or +`s.c`. Accesses to `a` and `d` can occur in safe code; accesses to `b` and `c` +require unsafe code, and `b` and `c` overlap, requiring care to access only the +field whose contents make sense at the time. As with any `union`, code cannot +borrow `s.b` and `s.c` simultaneously. Conversely, sometimes when defining a `union`, you may want to group multiple fields together and make them available simultaneously, with non-overlapping @@ -105,7 +107,7 @@ inline within the `union`, using the `struct` keyword: ```rust union U { a: u32, - struct { + _: struct { b: u16, c: f16, }, @@ -127,9 +129,9 @@ Unnamed fields can contain other unnamed fields. For example: ```rust struct S { a: u32, - union { + _: union { b: u32, - struct { + _: struct { c: u16, d: f16, }, @@ -180,9 +182,9 @@ with each other. The following definition: ```rust struct S { a: u32, - union { + _: union { b: u32, - struct { + _: struct { c: u16, d: f16, }, @@ -218,9 +220,9 @@ Given the following declaration: ```rust struct S { a: u32, - union { + _: union { b: u32, - struct { + _: struct { c: u16, d: f16, }, @@ -271,7 +273,7 @@ instance, the following definition will produce an error: ```rust struct S { a: u32, - union { + _: union { a: u32, b: f32, }, @@ -285,14 +287,16 @@ The error will identify the duplicate `a` fields as the sources of the error. ## Parsing -Within a struct's fields, in place of a field name and value, allow -`struct { fields }` or `union { fields }`, where `fields` allows +Within a struct or union's fields, in place of a field name and value, allow +`_: struct { fields }` or `_: union { fields }`, where `fields` allows everything allowed within a `struct` or `union` declaration, respectively. -Note that the keyword `struct` cannot appear as a field name, making it -entirely unambiguous. The contextual keyword `union` could theoretically appear -as a field name, but an open brace cannot appear immediately after a field -name, allowing disambiguation via a single token of context (`union {`). +The name `_` cannot currently appear as a field name, so this will not +introduce any compatibility issues with existing code. The keyword `struct` +cannot appear as a field type, making it entirely unambiguous. The contextual +keyword `union` could theoretically appear as a type name, but an open brace +cannot appear immediately after a field type, allowing disambiguation via a +single token of context (`union {`). ## Layout and Alignment @@ -357,11 +361,19 @@ extract and define types for the unnamed fields, but that macro would have to give a name to those unnamed fields, and accesses would have to include the intermediate name. -## Unnamed fields using `_` with named types +## Leaving out the `_: ` in unnamed fields -Rather than allowing the inline definition of the contents of unnamed `struct` -or `union` fields, we could allow declaring an unnamed field with a named type. -For instance: +Rather than declaring unnamed fields with an `_`, as in `_: union { fields }` +and `_: struct { fields }`, we could omit the field name entirely, and write +`union { fields }` and `struct { fields }` directly. This would more closely +match the C syntax. However, this does not provide as natural an extension to +support references to named structures. + +## Unnamed fields with named types + +In addition to allowing the inline definition of the contents of unnamed +`struct` or `union` fields, we could also allow declaring an unnamed field with +a named type. For instance: ```rust union U { x: i64, y: f64 } @@ -369,20 +381,17 @@ struct S { _: U, z: usize } ``` Given these declarations, `S` would contain fields `x`, `y`, and `z`, with `x` -and `y` overlapping. Rust currently does not allow `_` as a field name, so -introducing this alternative syntax would not create any compatibility issue. -This alternative syntax has the advantage of declaring the type layouts -explicitly, simplifying the language definition. It also allows reusing the -type definitions for fields within multiple structures, such as a common -header. While C11 does not directly support inlining of separately defined -structures, compilers do support it as an extension. - -This syntax would have the disadvantage of allowing the structure and union -declarations to appear arbitrarily far apart from each other, potentially even -in separate modules. It would also require careful implementation of rustdoc -support, to show the resulting structure layout. Finally, it would require the -introduction of names for the intermediate structures, such as in binding -generators. +and `y` overlapping. + +This syntax makes it possible to give a name to the intermediate type, while +still leaving the field unnamed. While C11 does not directly support inlining +of separately defined structures, compilers do support it as an extension. This +syntax would allow for the common definition of sets of fields inlined into +several structures, such as a common header. + +This syntax would also support an obvious translation of inline-declared +structures with names, by moving the declaration out-of-line; a macro could +perform such a translation. ## Field aliases From 45350b4d5f8fa2c91ff1dd75a6f2e646ab3893c7 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 21:02:41 -0700 Subject: [PATCH 14/22] Add a section on pattern matching --- text/0000-unnamed-fields.md | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 35709cf895b..4bd3aa85125 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -238,6 +238,59 @@ All of the following will instantiate a value of type `S`: - `S { a: 1, c: 2, d: 3.0, f: 4.0 }` - `S { a: 1, e: 2.0, f: 3.0 }` +## Pattern matching + +Code can pattern match on a structure containing unnamed fields as though all +the fields appeared at the top level. For instance, the following code matches +a discriminant and extracts the corresponding field. + +```rust +struct S { + a: u32, + _: union { + b: u32, + _: struct { + c: u16, + d: f16, + }, + e: f32, + }, + f: u64, +} + +unsafe fn func(s: S) { + match s { + S { a: 0, b, f } => println!("b: {}, f: {}", b, f), + S { a: 1, c, d, f } => println!("c: {}, d: {}, f: {}", c, d, f), + S { a: 2, e, f } => println!("e: {}, f: {}", e, f), + S { a, f, .. } => println!("a: {} (unknown), f: {}", a, f), + } +} +``` + +If a match goes through one or more `union` fields (named or unnamed), it +requires unsafe code; a match that goes through only `struct` fields can occur +in safe code. + +Checks for exhaustiveness work identically to matches on structures with named +fields. For instance, if the above match omitted the last case, it would +receive a warning for a non-exhaustive match. + +A pattern must include a `..` if it does not match all fields, other than union +fields for which it matches another branch of the union. Failing to do so will +produce error E0027 (pattern does not mention field). For example: + +- Omitting the `f` from any of the first three cases would require adding `..` +- Omitting `b` from the first case, or `e` from the third case, would require + adding `..` +- Omitting *either* `c` or `d` from the second case would require adding `..` + +Effectively, the pattern acts as if it groups all matches of the fields within +an unnamed struct or union into a sub-pattern that matches those fields out of +the unnamed struct or union, and then produces errors accordingly if a +sub-pattern matching an unnamed struct doesn't mention all fields of that struct, +or if a pattern doesn't mention *any* fields in an unnamed union. + ## Representation This feature exists to support the layout of native platform data structures. From c7961d8e371186a2b6b616da7a658c4a2a6c9723 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 21:28:15 -0700 Subject: [PATCH 15/22] Explicitly state that the layout and alignment must match the C ABI Keep the explanation for what that means in practice, but state the more critical constraint up front. --- text/0000-unnamed-fields.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 4bd3aa85125..872b43b34be 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -353,11 +353,12 @@ single token of context (`union {`). ## Layout and Alignment -The layout and alignment of a `struct` or `union` containing unnamed -fields should look the same as if each unnamed field has a separately declared -type and a named field of that type, rather than as if the fields appeared -directly within the containing `struct` or `union`. In some cases, this may -result in different alignment. +The layout and alignment of a `struct` or `union` containing unnamed fields +must match the C ABI for the equivalent structure. In particular, it should +have the same layout that it would if each unnamed field had a separately +declared type and a named field of that type, rather than as if the fields +appeared directly within the containing `struct` or `union`. This may, in +particular, affect alignment. ## Simultaneous Borrows From e504dd771cb77a3407829b0d45ab41bad57d1ff5 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 21:40:29 -0700 Subject: [PATCH 16/22] Allow unnamed fields with named types --- text/0000-unnamed-fields.md | 61 ++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 872b43b34be..d95d1ed213b 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -171,6 +171,39 @@ struct S { } ``` +## Unnamed fields with named types + +An unnamed field may also use a named `struct` or `union` type. For instance: + +```rust +union U { + x: i64, + y: f64, +} + +struct S { + _: U, + z: usize, +} +``` + +Given these declarations, `S` would contain fields `x`, `y`, and `z`, with `x` +and `y` overlapping. Such a declaration behaves in every way like the +equivalent declaration with an unnamed type declared within `S`, except that +this version of the declaration also defines a named union type `U`. + +This syntax makes it possible to give a name to the intermediate type, while +still leaving the field unnamed. While C11 does not directly support inlining +of separately defined structures, compilers do support it as an extension, and +this addition allows the translation of such code. + +This syntax allows for the common definition of sets of fields inlined into +several structures, such as a common header. + +This syntax would also support an obvious translation of inline-declared +structures with names, by moving the declaration out-of-line; a macro could +easily perform such a translation. + ## Mental model In the memory layout of a structure, the alternating uses of `struct { ... }` @@ -344,6 +377,10 @@ Within a struct or union's fields, in place of a field name and value, allow `_: struct { fields }` or `_: union { fields }`, where `fields` allows everything allowed within a `struct` or `union` declaration, respectively. +Additionally, allow `_` as the name of a field whose type refers to a `struct` +or `union`. All of the fields of that `struct` or `union` must be visible to +the current module. + The name `_` cannot currently appear as a field name, so this will not introduce any compatibility issues with existing code. The keyword `struct` cannot appear as a field type, making it entirely unambiguous. The contextual @@ -423,30 +460,6 @@ and `_: struct { fields }`, we could omit the field name entirely, and write match the C syntax. However, this does not provide as natural an extension to support references to named structures. -## Unnamed fields with named types - -In addition to allowing the inline definition of the contents of unnamed -`struct` or `union` fields, we could also allow declaring an unnamed field with -a named type. For instance: - -```rust -union U { x: i64, y: f64 } -struct S { _: U, z: usize } -``` - -Given these declarations, `S` would contain fields `x`, `y`, and `z`, with `x` -and `y` overlapping. - -This syntax makes it possible to give a name to the intermediate type, while -still leaving the field unnamed. While C11 does not directly support inlining -of separately defined structures, compilers do support it as an extension. This -syntax would allow for the common definition of sets of fields inlined into -several structures, such as a common header. - -This syntax would also support an obvious translation of inline-declared -structures with names, by moving the declaration out-of-line; a macro could -perform such a translation. - ## Field aliases Rather than introducing unnamed fields, we could introduce a mechanism to From 917e07364495d53397ddef2927d5d8992e303c9f Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 7 Sep 2017 21:51:53 -0700 Subject: [PATCH 17/22] Clarify union field borrowing --- text/0000-unnamed-fields.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index d95d1ed213b..ad2be6903cc 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -94,8 +94,9 @@ unnamed union will appear directly with the containing structure. Given a struct `s` of this type, code can access `s.a`, `s.d`, and either `s.b` or `s.c`. Accesses to `a` and `d` can occur in safe code; accesses to `b` and `c` require unsafe code, and `b` and `c` overlap, requiring care to access only the -field whose contents make sense at the time. As with any `union`, code cannot -borrow `s.b` and `s.c` simultaneously. +field whose contents make sense at the time. As with any `union`, borrows of +any `union` field borrow the entire union, so code cannot borrow `s.b` and +`s.c` simultaneously if any of the borrows uses `&mut`. Conversely, sometimes when defining a `union`, you may want to group multiple fields together and make them available simultaneously, with non-overlapping From 9e2f5f07abd9e0ff522d83afcfcdb3da3b7d1a21 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Sep 2017 09:34:26 -0700 Subject: [PATCH 18/22] Explicitly add `repr(C)` in all examples Since the feature requires `repr(C)`, the examples should reflect that. --- text/0000-unnamed-fields.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index ad2be6903cc..cca308fd45c 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -79,6 +79,7 @@ define an unnamed grouping of overlapping fields inline within the `struct`, using the `union` keyword: ```rust +#[repr(C)] struct S { a: u32, _: union { @@ -106,6 +107,7 @@ mechanism, you can also define an unnamed grouping of non-overlapping fields inline within the `union`, using the `struct` keyword: ```rust +#[repr(C)] union U { a: u32, _: struct { @@ -128,6 +130,7 @@ unions. Unnamed fields can contain other unnamed fields. For example: ```rust +#[repr(C)] struct S { a: u32, _: union { @@ -150,6 +153,7 @@ following three structures: ```rust // variant 1 +#[repr(C)] struct S { a: u32, b: u32, @@ -157,6 +161,7 @@ struct S { } // variant 2 +#[repr(C)] struct S { a: u32, c: u16, @@ -165,6 +170,7 @@ struct S { } // variant 3 +#[repr(C)] struct S { a: u32, e: f32, @@ -177,11 +183,13 @@ struct S { An unnamed field may also use a named `struct` or `union` type. For instance: ```rust +#[repr(C)] union U { x: i64, y: f64, } +#[repr(C)] struct S { _: U, z: usize, @@ -214,6 +222,7 @@ vertically, in sequence, and `union` lays out fields horizontally, overlapping with each other. The following definition: ```rust +#[repr(C)] struct S { a: u32, _: union { @@ -252,6 +261,7 @@ order. Given the following declaration: ```rust +#[repr(C)] struct S { a: u32, _: union { @@ -279,6 +289,7 @@ the fields appeared at the top level. For instance, the following code matches a discriminant and extracts the corresponding field. ```rust +#[repr(C)] struct S { a: u32, _: union { @@ -358,6 +369,7 @@ You cannot use this feature to define multiple fields with the same name. For instance, the following definition will produce an error: ```rust +#[repr(C)] struct S { a: u32, _: union { From a8263572e249fb116ff5d9b3795010efb8aa6984 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 8 Sep 2017 09:34:51 -0700 Subject: [PATCH 19/22] Only propagate repr(C); show how to write repr(packed) explicitly --- text/0000-unnamed-fields.md | 46 +++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index cca308fd45c..ef5b79e0476 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -342,16 +342,42 @@ This feature exists to support the layout of native platform data structures. Structures using the default `repr(Rust)` layout cannot use this feature, and the compiler should produce an error when attempting to do so. -When using this mechanism to define a C interface, remember to use the -`repr(C)` attribute to match C's data structure layout. Any representation -attribute applied to the top-level structure also applies to every unnamed -field within that declaration. Such a structure defined with `repr(C)` will use -a representation identical to the same structure with all unnamed fields -transformed to equivalent named fields of a struct or union type with the same -fields. - -Similarly, applying `repr(packed)` to the top-level data structure will also -apply it to all the contained structures. +When using this mechanism to define a C interface, always use the `repr(C)` +attribute to match C's data structure layout. For convenience, `repr(C)` +applied to the top-level structure will automatically apply to every unnamed +struct within that declaration, since unnamed fields only permit `repr(C)`. +This only applies to `repr(C)`, not to any other attribute. + +Such a structure defined with `repr(C)` will use a representation identical to +the same structure with all unnamed fields transformed to equivalent named +fields of a struct or union type with the same fields. + +However, applying `repr(packed)` (or any other attribute) to the top-level data +structure does not automatically apply it to all the contained structures. To +apply `repr(packed)` to an unnamed field, place the attribute before the field +declaration: + +```rust +#[repr(C)] +union S { + a: u32, + #[repr(packed)] + _: struct { + b: u8, + c: u16, + }, + _: struct { + d: u8, + e: f16, + }, +} +``` + +In this declaration, the first unnamed struct uses `repr(packed)`, while the +second does not. + +Unnamed fields with named types use the representation attributes attached to +the named type. The named type must use `repr(C)`. ## Derive From 2ceb8e7669a090b12fcceba53a5ce2d5249158a0 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 18 Sep 2017 13:18:09 -0700 Subject: [PATCH 20/22] Add a clarification for a corner case involving generics --- text/0000-unnamed-fields.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index ef5b79e0476..0ef875d6fc8 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -213,6 +213,10 @@ This syntax would also support an obvious translation of inline-declared structures with names, by moving the declaration out-of-line; a macro could easily perform such a translation. +Note that the intermediate type name in the declaration must resolve to a +concrete type, and cannot involve a generic type parameter of the containing +structure. + ## Mental model In the memory layout of a structure, the alternating uses of `struct { ... }` From adcdbf0217406e7adeffe864bfbda5fcdf0031fe Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 29 Jan 2018 12:12:16 -0800 Subject: [PATCH 21/22] Explicitly prohibit type parameters as named types of unnamed fields --- text/0000-unnamed-fields.md | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/text/0000-unnamed-fields.md b/text/0000-unnamed-fields.md index 0ef875d6fc8..05838b295d2 100644 --- a/text/0000-unnamed-fields.md +++ b/text/0000-unnamed-fields.md @@ -411,6 +411,49 @@ struct S { The error will identify the duplicate `a` fields as the sources of the error. +## Generics and type parameters + +You can use this feature with a struct or union that has a generic type: + +```rust +#[repr(C)] +struct S { + a: u32, + _: union { + b: T, + c: u64, + } +} +``` + +You may also use a generic struct or union parameterized by a type as the named +type of an unnamed field, since the compiler can know all the resulting field +names at declaration time without knowing the generic type: + +```rust +#[repr(C)] +struct S { + a: u32, + _: U, + _: U2, +} +``` + +However, you cannot use a type parameter itself as the named type of an unnamed +field: + +```rust +#[repr(C)] +struct S { + a: u32, + _: T, // error +} +``` + +This avoids situations in which the compiler must delay producing an error on a +field name conflict between `T` and `S` (or on the use of a non-struct, +non-union type for `T`) until it knows a specific type for `T`. + # Reference-level explanation [reference-level-explanation]: #reference-level-explanation @@ -503,6 +546,15 @@ and `_: struct { fields }`, we could omit the field name entirely, and write match the C syntax. However, this does not provide as natural an extension to support references to named structures. +## Allowing type parameters + +We could allow the type parameters of generic types as the named type of an +unamed field. This could allow creative flexibility in API design, such as +having a generic type that adds a field alongside the fields of the type it +contains. However, this could also lead to much more complex errors that do not +arise until the point that code references the generic type. Prohibiting the +use of type parameters in this way will not impact common uses of this feature. + ## Field aliases Rather than introducing unnamed fields, we could introduce a mechanism to From 1242d1a322a52cd7402f1f15e25b574562edd692 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 9 Apr 2018 11:16:27 +0200 Subject: [PATCH 22/22] RFC 2102 --- text/{0000-unnamed-fields.md => 2102-unnamed-fields.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename text/{0000-unnamed-fields.md => 2102-unnamed-fields.md} (99%) diff --git a/text/0000-unnamed-fields.md b/text/2102-unnamed-fields.md similarity index 99% rename from text/0000-unnamed-fields.md rename to text/2102-unnamed-fields.md index 05838b295d2..bdcbc3b4538 100644 --- a/text/0000-unnamed-fields.md +++ b/text/2102-unnamed-fields.md @@ -1,7 +1,7 @@ -- Feature Name: unnamed_fields +- Feature Name: `unnamed_fields` - Start Date: 2017-08-05 -- RFC PR: -- Rust Issue: +- RFC PR: [rust-lang/rfcs#2102](https://github.com/rust-lang/rfcs/pull/2102) +- Rust Issue: [rust-lang/rust#49804](https://github.com/rust-lang/rust/issues/49804) # Summary [summary]: #summary