Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guarantee that some structs are zero sized #163

Merged
merged 5 commits into from
Jul 26, 2019
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions reference/src/layout/structs-and-tuples.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,27 @@ compiler will not reorder it, to allow for the possibility of
unsizing. E.g., `struct Foo { x: u16, y: u32 }` and `struct Foo<T> {
x: u16, y: T }` where `T = u32` are not guaranteed to be identical.

#### Zero-sized structs

Structs with default layout (`repr(Rust)`), layout with increased alignment
(`repr(align(N))`), packed layout (`repr(packed(N))`), or C-compatible layout
(`repr(C)`) are zero-sized, if they contain no fields of non-zero size. That is,
Copy link
Member

Choose a reason for hiding this comment

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

Is this an "if and only if"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think so. If a struct contains a field of non-zero size, I don't see how it could end up being zero-sized.

Choose a reason for hiding this comment

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

I can't think of a counter-example, but it seems like only one direction is much commonly thought about and discussed, so I'd be a bit scared to commit to the other direction as well. Besides, it's usually more important to know when something definitely is a ZST (e.g., so you can ignore it for layout related questions), not when something definitely isn't a ZST.

Copy link
Member

Choose a reason for hiding this comment

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

Fair, but but then we should try to word this in a way that it is clear that only one direction is defined. In particular with the way that conditional and conclusion are reversed here, I think it is easy to interpret this as bidirectional.

English is such a bad language for precise specifications...

Copy link
Member

Choose a reason for hiding this comment

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

So, to make a concrete proposal (also removing a pointless double-negation):

If all fields of a struct have size 0, then the struct has size 0.

Your sentence lists a few representations explicitly, but is there any repr for which this does not make sense?

Copy link

@comex comex Jul 26, 2019

Choose a reason for hiding this comment

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

Well, that statement is trivially true if there struct has no fields. C++ allows structs with no fields but gives them a size of 1, and in theory there could be some kind of #[repr(C++)] that accounts for this.

I'm not sure how plausible #[repr(C++)] is, but another hypothetical use case could be to fix the ABI issue with passing small C++ classes by value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but is there any repr for which this does not make sense?

If we ever add a repr() for which this does not make sense, then this wouldn't hold for repr(transparent) either.

The current wording mentions all reprs that currently exist, except for repr(transparent) , for which this just follows from its rules.

Copy link
Member

Choose a reason for hiding this comment

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

If you really want to list the repr, I'd propose prepending something like:

For repr(Rust), repr(packed(N)), repr(align(N)) and repr(C):

(Btw, why is it packed but not aligned? Seems inconsistent...)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've reworded the guarantee with this feedback. Let me know if its ok now.

either the type has no fields, or all of its fields have zero size.

For example, all these types are zero-sized:

```rust
# use std::mem::size_of;
#[repr(align(32))] struct Zst0;
#[repr(C)] struct Zst1(Zst0);
struct Zst2(Zst1, Zst0);
# fn main() {
# assert_eq!(size_of::<Zst0>(), 0);
# assert_eq!(size_of::<Zst1>(), 0);
# assert_eq!(size_of::<Zst2>(), 0);
# }
```
gnzlbg marked this conversation as resolved.
Show resolved Hide resolved

#### Unresolved questions

During the course of the discussion in [#11] and [#12], various
Expand All @@ -131,15 +152,6 @@ issue has been opened for further discussion on the repository. This
section documents the questions and gives a few light details, but the
reader is referred to the issues for further discussion.

**Zero-sized structs ([#37]).** If you have a struct which --
transitively -- contains no data of non-zero size, then the size of
that struct will be zero as well. These zero-sized structs appear
frequently as exceptions in other layout considerations (e.g.,
single-field structs). An example of such a struct is
`std::marker::PhantomData`.

[#37]: https://github.com/rust-rfcs/unsafe-code-guidelines/issues/37

**Single-field structs ([#34]).** If you have a struct with single field
(`struct Foo { x: T }`), should we guarantee that the memory layout of
`Foo` is identical to the memory layout of `T` (note that ABI details
Expand Down