Skip to content

Structs with no fields or all-ZST fields are ZSTs#2262

Merged
traviscross merged 1 commit into
rust-lang:masterfrom
DanielEScherzer:zst-structs
Jul 7, 2026
Merged

Structs with no fields or all-ZST fields are ZSTs#2262
traviscross merged 1 commit into
rust-lang:masterfrom
DanielEScherzer:zst-structs

Conversation

@DanielEScherzer

@DanielEScherzer DanielEScherzer commented May 5, 2026

Copy link
Copy Markdown
Contributor

Guarantee that structs with Rust representation and with no fields, or where all fields are ZSTs, are themselves ZSTs.

Guarantee that enums with Rust representation with a single struct-like variant with no fields, or where all fields are ZSTs, are themselves ZSTs.

@rustbot rustbot added the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label May 5, 2026
@DanielEScherzer DanielEScherzer changed the title New rule: items.struct.zst New rules for ZSTs May 5, 2026
@traviscross traviscross changed the title New rules for ZSTs New rules for structs with no fields May 5, 2026
@traviscross traviscross changed the title New rules for structs with no fields Structs with no fields are ZSTs May 5, 2026
@traviscross traviscross changed the title Structs with no fields are ZSTs Structs with no fields or all-ZST fields are ZSTs May 5, 2026
@DanielEScherzer DanielEScherzer force-pushed the zst-structs branch 2 times, most recently from 6a2c83a to 5011dcd Compare May 5, 2026 20:26
@traviscross traviscross added I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-1 Lang team prioritization drag level 1. T-lang Relevant to the language team. labels May 5, 2026
@traviscross

Copy link
Copy Markdown
Contributor

cc @RalfJung @rust-lang/opsem

Comment thread src/type-layout.md Outdated
For [structs] with no fields, or where all fields are [zero-sized], it is further guaranteed that the structs are themselves [zero-sized].

r[layout.repr.rust.enum-struct-like-zst]
For [enums] (without a primitive representation specified) with a single struct-like variant with no fields or where all fields are [zero-sized], the enum itself is [zero-sized].

@theemathas theemathas May 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems bizarre to guarantee this for struct-like variants but not unit-like variants or tuple-like variants.

View changes since the review

@RalfJung

RalfJung commented May 6, 2026

Copy link
Copy Markdown
Member

That seems reasonable to me (specifically for repr(Rust); not necessarily for other reprs). Someone should check whether it is honored by -Zrandomize-layout.

@traviscross

traviscross commented May 6, 2026

Copy link
Copy Markdown
Contributor

We talked about this in the lang call today. Let's propose to do this with the correction that, for enums, we mean those repr(Rust) enums without a primitive representation specified and that have a single field-struct-like variant, a single unit-struct-like variant, or a single tuple-struct-like variant where the struct-like thing has no fields or where all of the fields are zero-sized.

@rfcbot fcp merge lang

@rust-rfcbot

rust-rfcbot commented May 6, 2026

Copy link
Copy Markdown
Collaborator

@traviscross has proposed to merge this. The next step is review by the rest of the tagged team members:

Concerns:

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!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@traviscross

Copy link
Copy Markdown
Contributor

@rfcbot concern check-randomize-layout

@tmandry

tmandry commented May 6, 2026

Copy link
Copy Markdown
Member

This seems stronger than what we guarantee for non-ZST structs, which require #[repr(transparent)] to have the same representation as the inner type. In the lang meeting, @steffahn pointed out that the non-ZST case is harder because certain types get passed in registers, etc.

I don't see a reason not to make this guarantee, and it seems like a useful one, so let's do it.

@rfcbot reviewed

@traviscross traviscross added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-1 Lang team prioritization drag level 1. labels May 13, 2026
@zachs18

zachs18 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Should we also guarantee that zero-variant repr(Rust) enums are ZSTs? They currently are in practice.


Someone should check whether it is honored by -Zrandomize-layout.

Yes, I believe it is. IIUC the current implementation of -Zrandomize-layout only reorderes fields, never introduces any "extra" padding1. Shuffling the field order cannot make a ZST into a non-ZST (or vice versa), so the current implementation upholds the proposed guarantees.

reasoning

When the -Zrandomize-layout flag is enabled, the compiler enables ReprFlags::RANDOMIZE_LAYOUT for types defined in that crate (src) (unstable_opts.randomize_layout is not mentioned anywhere else in the compiler).

ReprFlags::RANDOMIZE_LAYOUT is mentioned in four places in the compiler:

  1. When it is declared (src)
  2. When it is enabled (see previous section)
  3. In SizeSkeleton, which IIUC ignores it when computing the size of generic NPO-optimized enums and newtype structs/enums (src)
    1. NPO is irrelevant here (there are no ZSTs eligible for NPO optimization)
    2. For newtypes over ZSTs, this should correctly give a ZST size regardless of RANDOMIZE_LAYOUT
  4. When it is used in ReprOptions::can_randomize_type_layout which returns !self.inhibit_struct_field_reordering() && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT) (src)

ReprOptions::can_randomize_type_layout is used in one place in the compiler: in layout computation (fn univariant_biased) where the field list (excluding the unsized tail) is shuffled if it returns true (instead of being optimized by sorting by alignment) (src). Shuffling (or sorting) the field order cannot make a ZST into a non-ZST (or vice versa), so the current implementation upholds the proposed guarantees.

I opened a PR rust-lang/rust#157905 to update the comments in some of the places where -Zrandomize-layout is implemented referring back to this FCP to ensure that future changes to -Zrandomize-layout do not break these guarantees.

@/rustbot label I-lang-nominated

~~Nominating for possibly resolving the -Zrandomize-layout concern (and maybe considering zero-variant repr(Rust) enums) ~~

Footnotes

  1. other than the padding necessary to make fields aligned, and since 0 is a multiple of any alignment, this padding is never added for struct-like layouts if all fields are zero-sized

@rustbot

rustbot commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Error: Label I-lang-nominated can only be set by Rust team members

Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #triagebot on Zulip.

@traviscross

Copy link
Copy Markdown
Contributor

@rfcbot resolve check-randomize-layout

Thanks @zachs18. I looked into this and concur.

Should we also guarantee that zero-variant repr(Rust) enums are ZSTs? They currently are in practice.

Probably. Let's do that in a separate Reference PR.

@rust-rfcbot

Copy link
Copy Markdown
Collaborator

🔔 This is now entering its final comment period, as per the review above. 🔔

@rust-rfcbot

Copy link
Copy Markdown
Collaborator

The final comment period, with a disposition to merge, as per the review above, 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.

@chorman0773

Copy link
Copy Markdown
Contributor

without a primitive representation specified

This wording doesn't seem super clear on whether or not repr(C) enums are excluded (which they should be, because they are implicitly repr(C, Int), where Int is a target-specific integer type, but that isn't "specified" in the repr attribute).

@DanielEScherzer

Copy link
Copy Markdown
Contributor Author

We talked about this in the lang call today. Let's propose to do this with the correction that, for enums, we mean those repr(Rust) enums without a primitive representation specified and that have a single field-struct-like variant, a single unit-struct-like variant, or a single tuple-struct-like variant where the struct-like thing has no fields or where all of the fields are zero-sized.

If/when FCP passes I'll apply this correction

Done, fa61cbd

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: The marked PR is awaiting review from a maintainer and removed S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. labels Jun 30, 2026
Comment thread src/glossary.md Outdated
Comment thread src/type-layout.md Outdated
Comment thread src/type-layout.md Outdated
@DanielEScherzer

DanielEScherzer commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

without a primitive representation specified

This wording doesn't seem super clear on whether or not repr(C) enums are excluded (which they should be, because they are implicitly repr(C, Int), where Int is a target-specific integer type, but that isn't "specified" in the repr attribute).

In the glossary, the new entries start with - `repr(Rust)` [structs] and - `repr(Rust)` [enums] s so I think it is clear there

On the type layout page, the entries are under the ### The `Rust` representation section heading; the other layout rules there don't explicitly note that they are for the rust representation because that is clear from the location and context

Comment thread src/type-layout.md Outdated
Comment thread src/type-layout.md Outdated
@DanielEScherzer DanielEScherzer force-pushed the zst-structs branch 3 times, most recently from edec521 to 034e3cf Compare July 7, 2026 19:02
Comment thread src/type-layout.md Outdated
For [structs] with no fields or where all fields are [zero sized], it is further guaranteed that the structs are themselves [zero sized].

r[layout.repr.rust.enum-struct-like-zst]
For [enums] (without a primitive representation specified) with a single field-struct-like variant, a single unit-struct-like variant, or a single tuple-struct-like variant and where the struct-like thing has no fields or where all of the fields are [zero sized], the enums themselves are [zero sized].

@traviscross traviscross Jul 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add links to cross-reference each of these, here and in the glossary.

View changes since the review

Comment thread src/type-layout.md Outdated
For [structs] with no fields or where all fields are [zero sized], it is further guaranteed that the structs are themselves [zero sized].

r[layout.repr.rust.enum-struct-like-zst]
For [enums] (without a primitive representation specified) with a single field-struct-like variant, a single unit-struct-like variant, or a single tuple-struct-like variant and where the struct-like thing has no fields or where all of the fields are [zero sized], the enums themselves are [zero sized].

@traviscross traviscross Jul 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add links to cross-reference each of these, here and in the glossary.

View changes since the review

New rule `layout.repr.rust.struct-zst` adds the guarantee that
`repr(Rust)` structs with no fields or all ZST fields are ZSTs.

New rule `layout.repr.rust.enum-struct-like-zst` adds the guarantee
that `repr(Rust)` enums with a single struct-like variant with no
fields or all ZST fields are ZSTs.

The glossary entry for ZSTs is expanded with references to these
guarantees and examples.
@traviscross

Copy link
Copy Markdown
Contributor

Thanks @DanielEScherzer.

@traviscross traviscross added this pull request to the merge queue Jul 7, 2026
Merged via the queue into rust-lang:master with commit 1358a77 Jul 7, 2026
6 checks passed
@rustbot rustbot removed the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Jul 7, 2026
@DanielEScherzer DanielEScherzer deleted the zst-structs branch July 7, 2026 19:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

disposition-merge finished-final-comment-period I-lang-radar Items that are on lang's radar and will need eventual work or consideration. T-lang Relevant to the language team. to-announce

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants