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

defining zero-sized structs #37

Open
nikomatsakis opened this issue Oct 11, 2018 · 11 comments
Open

defining zero-sized structs #37

nikomatsakis opened this issue Oct 11, 2018 · 11 comments
Labels
A-layout Topic: Related to data structure layout (`#[repr]`) S-not-opsem Despite being in this repo, this is not primarily a T-opsem question T-lang

Comments

@nikomatsakis
Copy link
Contributor

From #31:

"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."

Is that a sufficient definition for zero-sized structs? This seems like an important guarantee that we frequently rely upon for performance and other purposes, so it is worth specifying.

@nikomatsakis nikomatsakis added A-layout Topic: Related to data structure layout (`#[repr]`) active discussion topic labels Oct 11, 2018
@hanna-kruppe
Copy link

I'd rather spell out exactly the structural recursion that is going rather than hand wave it away with "transitively", but yes I think we should guarantee:

  • Arrays are ZSTs if the count is zero or the element type is ZST
  • A tuple is ZST if all elements are ZST
  • A struct is ZST if all fields are ZST
  • Empty enums are ZSTs

Enums are interesting because we could try to be smart around enums with a single variant but that will likely depend on the repr attribute which doesn't seem the case for structs (#[repr(C)] struct Foo {} is currently a ZST).

@asajeffrey
Copy link

What about a one-case enum whose body is zero-sized, e.g.:

enum Foo { OnlyCase(SomethingZeroSized) }

or a union all of whose cases are zero-sized?

@hanna-kruppe
Copy link

The only-variant-containing-ZST case could also be defined as ZST depending on repr attributes, but doesn't seem very useful.

Unions, good point, could probably be treated the same as structs, i.e., could be ZSTs even with repr(C).

@rodrimati1992
Copy link

Generic enums with 2 or more variants are zero-sized if every variant is Void except for a zero-sized variant.
https://play.rust-lang.org/?gist=0b3278bdd497b1bc3c9bccbb4ca828df&version=stable&mode=debug&edition=2015

@Mark-Simulacrum
Copy link
Member

Empty enums are ZSTs

Aren't empty enums considered uninhabited? I'm not sure if those types are technically ZSTs since there's no actual valid representation.

@hanna-kruppe
Copy link

hanna-kruppe commented Oct 11, 2018

@rodrimati1992 True, but I'd rather leave that sort of reasoning out of the picture for the initial step because:

@Mark-Simulacrum Empty enums are indeed uninhabited, but uninhabited types still have a size -- which is not necessarily zero, but definitely should be zero for empty enums.

@RalfJung
Copy link
Member

RalfJung commented Oct 11, 2018

Aren't empty enums considered uninhabited? I'm not sure if those types are technically ZSTs since there's no actual valid representation.

They are ZSTs in the sense that their size is 0 (layout.is_zst()). They are moreover uninhabited (layout.abi.is_uninhabited()). I think the latter currently implies the former, and that seems like a fairly reasonable axiom to me.

EDIT: Or maybe not, since we probably do consider (!, i32) to be uninhabited but cannot make it a ZST as @rkruppe reminded me.

@nikomatsakis
Copy link
Contributor Author

I'd rather spell out exactly the structural recursion that is going rather than hand wave it away with "transitively", but yes I think we should guarantee:

This seems reasonable, except that it seems .. fine to say something stronger about enums (e.g., that an enum is zero-sized if it has only one "inhabited" variant and that variant is zero-sized). However, you are correct that we can "start small" (no pun intended) and grow, so perhaps we should just leave a "footnote" of some sort about that (in particular since I don't care to define inhabited just now).

@nikomatsakis
Copy link
Contributor Author

It seems to me that the full text of this section ought to include notes about uninhabitedness and its connection to size as well.

@nikomatsakis
Copy link
Contributor Author

I am wondering if we ought to pull "zero-sized types" into a section all its own, since it seems a bit .. cross-cutting?

@RalfJung RalfJung added C-open-question Category: An open question that we should revisit S-writeup-needed Status: Ready for a writeup and no one is assigned and removed C-open-question Category: An open question that we should revisit labels Nov 29, 2018
@RalfJung RalfJung added the C-open-question Category: An open question that we should revisit label Aug 14, 2019
@RalfJung
Copy link
Member

I think the guarantee we really want (for it to be helpful with e.g. #164) is more like

"A struct consisting only of 1-ZST fields is itself a 1-ZST."

@JakobDegen JakobDegen added S-not-opsem Despite being in this repo, this is not primarily a T-opsem question T-lang and removed S-writeup-needed Status: Ready for a writeup and no one is assigned C-open-question Category: An open question that we should revisit labels Jun 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-layout Topic: Related to data structure layout (`#[repr]`) S-not-opsem Despite being in this repo, this is not primarily a T-opsem question T-lang
Projects
None yet
Development

No branches or pull requests

7 participants