-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Document #[repr] on non-C-like enums #25651
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @steveklabnik (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. The way Github handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see CONTRIBUTING.md for more information. |
This documents current behavior. Is repr(X) on non-C-like enums is a bug? In that case we need to fix that by rejecting code instead. |
I hope it's not a bug, it would be a breaking change if so. I am using the behaviour and I would assume others are to. The main reason was that the collections::enum_set::CLike is marked unstable and this seemed to do what I need anyways. |
Great to have that clear! @SimonSapin and I discovered that this is quite crucial for arrayvec and smallvec -- see issue servo/rust-smallvec#5 |
It seems very fragile to relay on on |
The idea of this PR was to make it non-fragile: The needed guarantee is written into the reference and a test to prove it added to the testsuite. |
I made a PR into your PR to add another test for the behavior that arrayvec relies on: bluss#1 |
I never knew you could submit PRs to PRs, that's neat. arrayvec uses |
I think it tests a slightly different case, but feel free to take it or not. |
Document #[repr] on non-C-like enums rustc accepts the following today: #[repr(u8)] enum Flag<T> { Dropped, Alive(T), } and it has a good use (it appears to me): this inhibits the non-nullable pointer optimization that the regular Option<T> and similar enums allow. Document this in the reference, and add tests to make sure it compiles. This means that we guarantee with `repr` that the discriminant will be present and with that size, but not sure if we want to guarantee anything more (no guarantee on placement in struct).
Oh, my tests are actually completely wrong |
Updated PR. Included @SimonSapin's testcase (thanks!), and fixed mine, which were embarrassingly completely incorrect the first time. |
assert!(size_of::<EC<&i32>>() > ptrsize); | ||
|
||
// test that a zero payload does not influence the discriminant | ||
let zero: &i32 = unsafe { zeroed() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is... this not undefined behavior? We explicitly tell LLVM that all &T
references are not null, and this is making a null one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. It should never load the value in the zero
variable or in its location inside the enum though, can it be safe that way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of inspecting the payload, could this just assert that the size of the enum is twice the size of a word?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well that's basically what the tests above already do. They are less specific maybe.
So we should remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think it's fine to remove.
rustc accepts the following today: #[repr(u8)] enum Flag<T> { Dropped, Alive(T), } and it has a good use (it appears to me): this inhibits the non-nullable pointer optimization that the regular Option<T> and similar enums allow. Document this in the reference, and add tests to make sure it compiles. This means that we guarantee with `repr` that the discriminant will be present and with that size, but not sure if we want to guarantee anything more (no guarantee on placement in struct).
Thanks, PR updated. Only tests sizes now. |
Thanks! |
Document #[repr] on non-C-like enums rustc accepts the following today: #[repr(u8)] enum Flag<T> { Dropped, Alive(T), } and it has a good use (it appears to me): this inhibits the non-nullable pointer optimization that the regular Option<T> and similar enums allow. Document this in the reference, and add tests to make sure it compiles. This means that we guarantee with `repr` that the discriminant will be present and with that size, but not sure if we want to guarantee anything more (no guarantee on placement in struct).
Document #[repr] on non-C-like enums rustc accepts the following today: #[repr(u8)] enum Flag<T> { Dropped, Alive(T), } and it has a good use (it appears to me): this inhibits the non-nullable pointer optimization that the regular Option<T> and similar enums allow. Document this in the reference, and add tests to make sure it compiles. This means that we guarantee with `repr` that the discriminant will be present and with that size, but not sure if we want to guarantee anything more (no guarantee on placement in struct).
⌛ Testing commit d0e6396 with merge c449a9f... |
💔 Test failed - auto-mac-32-opt |
assert_eq!(size_of::<Eu16<()>>(), 2); | ||
assert_eq!(size_of::<Ei32<()>>(), 4); | ||
assert_eq!(size_of::<Eu32<()>>(), 4); | ||
assert_eq!(size_of::<Ei64<()>>(), 8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thread '<main>' panicked at 'assertion failed:
(left == right)(left:
4, right:
8)', /Users/rustbuild/src/rust-buildbot/slave/auto-mac-32-opt/build/src/test/run-pass/enum-discrim-manual-sizing-2.rs:89
on 32-bit. Looks like there is a bug in #[repr]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm yes, that sounds like a bug in #[repr]
Document #[repr] on non-C-like enums rustc accepts the following today: #[repr(u8)] enum Flag<T> { Dropped, Alive(T), } and it has a good use (it appears to me): this inhibits the non-nullable pointer optimization that the regular Option<T> and similar enums allow. Document this in the reference, and add tests to make sure it compiles. This means that we guarantee with `repr` that the discriminant will be present and with that size, but not sure if we want to guarantee anything more (no guarantee on placement in struct).
We need to scrub this PR until the bug is fixed. I'll see what I can do though |
@bors: r- |
Closing for now, reported a bug. |
Document #[repr] on non-C-like enums
rustc accepts the following today:
and it has a good use (it appears to me): this inhibits the non-nullable
pointer optimization that the regular Option and similar enums allow.
Document this in the reference, and add tests to make sure it compiles.
This means that we guarantee with
repr
that the discriminant will bepresent and with that size, but not sure if we want to guarantee
anything more (no guarantee on placement in struct).