Skip to content

Fields must fit in a struct, even for repr(Rust)#2166

Open
Darksonn wants to merge 1 commit intorust-lang:masterfrom
Darksonn:fields-struct-fit
Open

Fields must fit in a struct, even for repr(Rust)#2166
Darksonn wants to merge 1 commit intorust-lang:masterfrom
Darksonn:fields-struct-fit

Conversation

@Darksonn
Copy link
Member

This clarifies the repr(Rust) layout rules slightly by specifying that fields must fit in their struct. That is, the offset of a field plus its size must be less than the size of the struct.

Accidental stabilization. One question that needs to be addressed before we can merge this is the fact that we have guaranteed that fields of repr(Rust) do not overlap, even though one can imagine structs where this is not the case when the struct is uninhabited. For example:

// could this be size zero? it would violate sizeof<i32>() <= sizeof<Foo>()
struct Foo(i32, !);

// could the two integers both be at offset zero? it would violate the no-overlap guarantee
struct Foo(i32, i32, !);

So as part of this PR I am posing the following question to the lang team:

Should we undo the guarantee about fields not overlapping if the struct has uninhabited fields?

In any case, I think we should definitely guarantee that fields fit in the struct for inhabited repr(Rust) structs.

Context: #t-lang > ZST Uninhabited types with non-ZST fields @ 💬

@rustbot rustbot added the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Feb 11, 2026
@Darksonn
Copy link
Member Author

@rustbot label I-lang-nominated

@rustbot rustbot added the I-lang-nominated Nominated for discussion during a lang team meeting. label Feb 11, 2026

1. The fields are properly aligned.
2. The fields do not overlap.
2. The fields do not overlap and fit in the struct.
Copy link
Member

@RalfJung RalfJung Feb 11, 2026

Choose a reason for hiding this comment

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

The surrounding text is about " All user-defined composite types (structs, enums, and unions) " (layout.repr.intro). If some part of this text is meant to apply only to structs, that needs to be made clear upfront, not in the middle of a section.

Copy link
Member Author

Choose a reason for hiding this comment

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

Surely this section cannot apply to unions. It says the fields are not allowed to overlap.

Copy link
Member

Choose a reason for hiding this comment

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

It clearly shouldn't apply to unions, but I can't find anything in the wording that would prevent it from applying to unions.

Copy link
Member

Choose a reason for hiding this comment

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

Clearly if this was for structs only, the section identifier should make that explicit. But it is layout.repr.rust.layout, no "struct" anywhere.

Choose a reason for hiding this comment

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

How about something like:

Suggested change
2. The fields do not overlap and fit in the struct.
2. The fields fit in the type:
a. For structs, this means the fields do not overlap.
b. For enums and unions, this means that fields from the same variant do not overlap (but fields from different variants can overlap).

I'm not sure if it's worth splitting enum variants and union fields into separate sentences.

Copy link
Member

@RalfJung RalfJung Feb 12, 2026

Choose a reason for hiding this comment

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

For structs, the second guarantee means that

This is very strange -- re-interpreting what "fits in" means depending on the kind of type? I would rather have two separate guarantees:

  1. All fields fit in the type, i.e., the offset of each field plus its size does not exceed the size of the type.
  2. All fields in a struct, and all fields within a single enum variant, do not overlap. (For zero-sized fields, this implies that the field is not contained within the range of another field.)

Either way this would make a guarantee about enums that has been quite contentious during the offset_of_enum discussion (and ultimately prevented stabilizing that feature) so I am not sure we're willing to commit to this.

Copy link
Member Author

@Darksonn Darksonn Feb 12, 2026

Choose a reason for hiding this comment

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

Either way this would make a guarantee about enums that has been quite contentious during the offset_of_enum discussion (and ultimately prevented stabilizing that feature) so I am not sure we're willing to commit to this.

Yes, but please keep this orthogonal.

To clarify, this PR is currently worded without an exception for uninhabited types, but as I wrote in the original PR description, we need to figure out whether there needs to be an exception for uninhabited types before we can merge anything in this PR, and that's why I lang-nominated this.

Copy link
Member Author

@Darksonn Darksonn Feb 12, 2026

Choose a reason for hiding this comment

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

Alternate wording:

 The only data layout guarantees made by this representation are those required for soundness. They are:
 
  1. The fields are properly aligned.
- 2. The fields do not overlap and fit in the struct.
- 3. The alignment of the type is at least the maximum alignment of its fields.
+ 2. The alignment of the type is at least the maximum alignment of its fields.
+ 3. The fields fit in the type.
+ 4. Fields that can co-exist do not overlap.
 
 r[layout.repr.rust.alignment]
 Formally, the first guarantee means that the offset of any field is divisible by that field's alignment.
 
 r[layout.repr.rust.field-storage]
-The second guarantee means that the fields can be ordered such that the offset plus the size of each field is less than or equal to the offset of the next field in the ordering, or for the last field, the size of the struct. The ordering does not have to be the same as the order in which the fields are specified in the declaration of the type.
+The third guarantee means that for any field, the field's offset plus its size must be less than or equal to the size of the type.
+
+r[layout.repr.rust.field-overlap]
+Fields are said to overlap unless the size plus offset of one field is less than or equal to the offset of the other field. Fields are said to co-exist if the type can contain both fields at the same time, i.e. all fields of a struct co-exist, only fields of the same enum variant co-exist, and fields never co-exist in a union.
 
-Be aware that the second guarantee does not imply that the fields have distinct addresses: zero-sized types may have the same address as other fields in the same struct.
+Be aware that this does not imply that the fields have distinct addresses: zero-sized types may have the same address as other fields without overlapping with them.
 
 r[layout.repr.rust.unspecified]
 There are no other guarantees of data layout made by this representation.

Copy link
Member

Choose a reason for hiding this comment

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

Fields are said to overlap unless the size plus offset of one field is less than or equal to the offset of the other field.

I'd prefer a positive definition instead of a negative one:
Two fields are said to overlap if the size plus offset of one field is strictly within the range of the other field.

Or use the opposite term:
Two fields are non-overlapping if the size plus offset of one field is less than or equal to the offset of the other field (field1.offset + field1.size <= field2.offset || field2.offset + field2.size <= field1.offset).

(It took me reading this multiple times until I realized you hid a disjunction here so I think the condition is worth spelling out formally, not just in English.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe the best is to keep the "you can order fields such that" wording ...

Two fields are said to overlap if the size plus offset of one field is strictly within the range of the other field.

This definition does not work because it does not cover non-ZST fields of the same size and offset.

@RalfJung
Copy link
Member

RalfJung commented Feb 12, 2026

Should we undo the guarantee about fields not overlapping if the struct has uninhabited fields?

At least @scottmcm seems to agree that for structs we should guarantee that even uninhabited structs have space for all their fields (and presumably, the fields remain disjoint).

However, as currently worded the text is not just about structs but also about unions (where the no-overlap guarantee makes absolutely no sense) and enums. This is almost certainly also an accident. Not sure if it's best to discuss both of these at once -- I assume a PR that just rearranges the text to make it about structs only would not need much discussion.

@Darksonn
Copy link
Member Author

Darksonn commented Feb 12, 2026

True, but I think we do want the other existing guarantees for union and enums:

  1. The fields are properly aligned.
  2. The alignment of the type is at least the maximum alignment of its fields.

@Darksonn
Copy link
Member Author

I filed a PR to fix the struct/union/enum issue:

#2168

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

I-lang-nominated Nominated for discussion during a lang team meeting. S-waiting-on-review Status: The marked PR is awaiting review from a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants