Change:
<del> error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:11:1 | LL | struct NoFields; | ^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:14:1 | LL | struct ContainsOnlyZst(()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:17:1 | LL | struct ContainsOnlyZstArray([bool; 0]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0 --> $DIR/repr-transparent.rs:20:1 | LL | struct ContainsMultipleZst(PhantomData<*const i32>, NoFields); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2 --> $DIR/repr-transparent.rs:24:1 </del> <ins> error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2 --> $DIR/repr-transparent.rs:26:1 </ins> | LL | struct MultipleNonZst(u8, u8); | ^^^^^^^^^^^^^^^^^^^^^^--^^--^^ | |                     |   | | |                     |   this field is non-zero-sized | |                     this field is non-zero-sized <del> | needs exactly one non-zero-sized field, but has 2 </del> <ins> | needs at most one non-zero-sized field, but has 2 </ins> <del> error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2 --> $DIR/repr-transparent.rs:30:1 </del> <ins> error[E0690]: transparent struct needs at most one non-zero-sized field, but has 2 --> $DIR/repr-transparent.rs:32:1 </ins> | LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^-------------------^^ | |                               |    | | |                               |    this field is non-zero-sized | |                               this field is non-zero-sized <del> | needs exactly one non-zero-sized field, but has 2 </del> <ins> | needs at most one non-zero-sized field, but has 2 </ins> error[E0691]: zero-sized field in transparent struct has alignment larger than 1 <del> --> $DIR/repr-transparent.rs:34:32 </del> <ins> --> $DIR/repr-transparent.rs:36:32 </ins> | LL | struct NontrivialAlignZst(u32, [u16; 0]); |                                ^^^^^^^^ has alignment larger than 1 error[E0691]: zero-sized field in transparent struct has alignment larger than 1 <del> --> $DIR/repr-transparent.rs:40:24 </del> <ins> --> $DIR/repr-transparent.rs:42:24 </ins> | LL | struct GenericAlign<T>(ZstAlign32<T>, u32); |                        ^^^^^^^^^^^^^ has alignment larger than 1 error[E0084]: unsupported representation for zero-variant enum <del> --> $DIR/repr-transparent.rs:42:1 </del> <ins> --> $DIR/repr-transparent.rs:44:1 </ins> | LL | #[repr(transparent)] | ^^^^^^^^^^^^^^^^^^^^

Discussion:
But The reference says The transparent representation can only be used on a struct or an enum with a single variant that has: a single field with non-zero size, and any number of fields with size 0 and alignment 1 (e.g. PhantomData<T). I do not see a reason for this restriction. Maybe simply replace "a single" by "at most one" and remove the check.
Marked as bug because people might assume values have size 0 in unsafe code. Unlikely to be the case in real code.
Agreed. Cc
Discussed in the meeting. We agree with the sense of this but would like a specific semantics -- i.e., if all fields are ZSTs, then we need to define what the ABI behavior of the type is (if there is a single non-ZST field , then it behaves like , the "real value" -- but what does it act like if there are no real values?). Perhaps the answer is just "whatever happens if you try to pass ". If someone can supply a concrete rule that makes sense, we would like to approve it =)
To clarify: This removes a restriction, but it now allows a new possibility that didn't exist before, so what are the rules meant to be for that case? (Well, it did exist because of generics, but presumably the rules didn't expect it to exist.)
A possible rule is to use the ABI of the first 1-ZST Field if there are no non 1-ZST fields. One question I have, what about types with size 0 and alignment 1 (0 sized arrays like [u16;0] are examples). Under this rule, these types would still seem to be excluded. That could probably be to the first part at the same time as it's lifted to allow zero of such types. If a ZST that has an alignment 1 is in a repr(transparent) struct, the ABI follows that ZST specifically.
AFAIK "zero-sized-field" for means 1-ZST. Everything else would be buggy I think... So a ZST with alignment greater 1 behaves like a non-ZST. I don't think that should change.
If it's already permitted, that's brillaint.

In which case my point can be reduced to a point of clarification, it would be good if the documentation noted that ("At most one non-zero-sized field or zero-sized field with an alignment greater than 1", wording could probably be changed, I'm much better writing normative text than text for users). If its not already permitted, adding it seems to be an extension of what is being discussed here.
It's not a permission though, it's a restriction? For example, the following type is rejected, as it should:
On the other hand, this is also rejected: Even though it has exactly one non-1-ZST field. So looks like the actual check is more something like All fields except for 1 must be zero-sized And additionally all zero-sized fields must have alignment 1
This is what my point is. If we permit transparent types with only ZST's, it seems like it would be equally inconsistent if we don't allow a transparent type with exactly one ZST that isn't a 1-ZST (and any number of 1-ZSTs). The consistency issue raised above would apply here, if it's possible to have a generic transparent type which is monomorphized with , but its not permitted to include directly, even if all other fields are 1-ZSTs.
Fully agreed.
Point of clarification: What is a 1-ZST? A ZST with alignment 1?
Yes. (This is terminology the as it was very helpful for layout discussions.)
OK, so, to restate the above point: We should check whether you can use generics to "sneak" in a ZST with alignment other than 1 (e.g., ). However, I don't think that you can. Based on some quick play experiments I believe we treat generic types "as if" they were a non-zero-sized field. Ah, ok, I think I understand now. The point is that we enforce (currently) a rule that says "any ZST must have alignment 1 in a repr(transparent) type" but that rule can be circumvented via generics. So, the proposed rule is something like.

A type T must meet the following rules: It may have any number of 1-ZST fields In addition, it may have at most one other field of type U If that other field is present, then T behaves like type U for the purposes of ABIs. Otherwise it behaves like...? Is there a reason we can't just say ?
As I mentioned, it may be reasonable to say the first member if all members are 1-ZSTs. I can't see a reason that it wouldn't work just saying , though.
Ah, sorry, I missed that comment. I agree that "first member" is an option, though I have a mild preference for avoiding a reliance on the ordering that things were written. That said, I also have a mild preference for avoiding introducing an arbitrary type like . I doubt it matters much in practice since I imagine that all 1-ZSTs basically behave the same with respect to the ABI, though.
I wouldn't call "arbitrary". It is basically the canonical "informationless type" in Rust, or "final element" in category theory speak -- similar to how is the canonical "uninhabited type" or "initial element". So, specifying as a canonical representative of 1-ZST makes a lot of sense IMO.
That's a good point. So here is a proposed set of rules: A type must meet the following rules: It may have any number of 1-ZST fields In addition, it may have at most one other field of type U If that other field is present, then T behaves like type U for ABI purposes. Otherwise, T consists only of 1-ZST types, and it behaves like , which is the "canonical" 1-ZST. I'm going to go ahead and kick off an FCP request... fcp merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [ ] [x] [x] [x] [x] [x] No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.

+1 to not having anything order-dependent in a braced-struct. Hmm, the lint considers an . But then an empty struct is UB(!?) in C, so I guess there isn't a canonical ABI for this. reviewed
:bell: This is now entering its final comment period, as per the . :bell:
GCC-compatible compilers do , treating as zero-sized types. As a result, ABIs often do document the behavior when C empty structs are passed or returned by value. Unfortunately, C++ has an entirely different interpretation of empty structs, where they get a padding byte to make them not zero-sized. This definitely changes their representation in memory, and sometimes also changes their representation when passing or returning them by value… depending on the ABI. As such, empty structs are best avoided entirely.
Indeed, ZSTs exist though only in "non-standardized" extensions. The real question here is whether there exists some "special" 1-ZST that would be treated differently by the ABI than any other 1-ZST. I do not believe that is the case, which is why is kind of "as good as any other". (There are some C structs, as I understand it, that are treated somewhat specially by ABIs, but very few -- I think maybe having to do with complex types? Can't remember.)
The final comment period, with a disposition to merge, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon.
are you interested in preparing a fix for this?
Removing nomination as we have resolved this fr the lang-team's perspective, though we still need to do implementation work here.