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

Should enum Foo { SingleVariant } be zero-size? #37649

Closed
SimonSapin opened this issue Nov 8, 2016 · 8 comments
Closed

Should enum Foo { SingleVariant } be zero-size? #37649

SimonSapin opened this issue Nov 8, 2016 · 8 comments

Comments

@SimonSapin
Copy link
Contributor

This prints 1 in rustc 1.14.0-nightly (cae6ab1 2016-11-05):

pub enum Foo { SingleVariant }
fn main() {
    println!("{}", ::std::mem::size_of::<Foo>());
}

I’m guessing this one byte is the enum’s discriminant. But since there’s a single variant, that discriminant is useless. Could such a type be zero-size? For what it’s worth, an empty enum Bar {} is already zero-size.

This type could be written struct Foo; which is zero-size, but a single-variant enum could come up if it’s generated by a macro that can generate any number of variants depending on its arguments.

@SimonSapin
Copy link
Contributor Author

frewsxcv and misdreavus on IRC point out that the discriminant is already eliminated in some cases:

playbot: enum Foo { SingleVariant(i32) } ::std::mem::size_of::<Foo>()
4
playbot: enum Foo { SingleVariant(()) } ::std::mem::size_of::<Foo>()
0
playbot: enum Foo { SingleVariant{} } ::std::mem::size_of::<Foo>()
1

@arielb1
Copy link
Contributor

arielb1 commented Nov 8, 2016

I'm quite sure it should be. This looks like a bug.

The thing is that an enum with 1 const-like variant counts as a "C-like" enum, and has a "semi-well-defined" representation. Not sure what to do about that.

@ranma42
Copy link
Contributor

ranma42 commented Nov 8, 2016

I agree that this inconsistency feels like a bug.

@arielb1 The section https://doc.rust-lang.org/reference.html#enumerations of the Rust reference seems to only state that it can be cast (using as) to get the discriminant. It would be possible to preserve this behaviour even with a 0-sized type.

The change would possibly break assumptions of existing crates on the size of such enumerations (for example when they are transmuted). Would a crater run be sufficient to evaluate the impact?

@arielb1
Copy link
Contributor

arielb1 commented Nov 8, 2016

@ranma42

Sure. The layout of repr(Rust) types is unspecified by design.

@petrochenkov
Copy link
Contributor

petrochenkov commented Nov 8, 2016

I agree that this inconsistency feels like a bug.

What about the size of

enum E {
    A = 10 // Enum behaves like an integer constant, it should probably be layed out as one
}

and then the size of

enum E {
    A = 0 // Should behave like previous one, it would be strange for layout to depend on concrete initialized value
}

and then

enum E {
    A // This is exact equivalent to the previous enum, why should it be layed out differently?
}

and what about this

#[repr(C)]
enum E {
    A // Hey, it looks so C-like I can probably transmute it to `c_int`!
}

I mean, whatever the behavior is, it would be inconsistent with something.
Now "C-like" takes priority over "univariant" and not otherwise. Seems okay, no strong reasons to change.

@SimonSapin
Copy link
Contributor Author

@petrochenkov I think all of your example except the #[repr(C)] should be zero-size. I don’t think it’s unexpected that a repr attribute changes the memory representation.

@eddyb
Copy link
Member

eddyb commented Nov 12, 2016

I agree with @SimonSapin here. There's also #[repr(u8)] and whatnot if you want to guarantee a specific size.

@mbrubeck
Copy link
Contributor

mbrubeck commented May 9, 2017

Duplicate of #15747.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants