This prints 1
in rustc 1.14.0-nightly (cae6ab1c4 2016-11-05):
pub enum Foo { SingleVariant }
fn main() {
println!("{}", ::std::mem::size_of::<Foo>());
}
I鈥檓 guessing this one byte is the enum鈥檚 discriminant. But since there鈥檚 a single variant, that discriminant is useless. Could such a type be zero-size? For what it鈥檚 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鈥檚 generated by a macro that can generate any number of variants depending on its arguments.
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
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.
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 transmute
d). Would a crater run be sufficient to evaluate the impact?
@ranma42
Sure. The layout of repr(Rust)
types is unspecified by design.
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.
@petrochenkov I think all of your example except the #[repr(C)]
should be zero-size. I don鈥檛 think it鈥檚 unexpected that a repr
attribute changes the memory representation.
I agree with @SimonSapin here. There's also #[repr(u8)]
and whatnot if you want to guarantee a specific size.
Duplicate of #15747.
Most helpful comment
@petrochenkov I think all of your example except the
#[repr(C)]
should be zero-size. I don鈥檛 think it鈥檚 unexpected that arepr
attribute changes the memory representation.