-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Implement the special repr(C)-non-clike-enum layout #46123
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
r? @eddyb |
src/librustc/ty/layout.rs
Outdated
@@ -945,6 +945,10 @@ impl<'a, 'tcx> LayoutDetails { | |||
/// A univariant, but part of an enum. | |||
EnumVariant(Integer), | |||
} | |||
|
|||
// To be updated further down, if needed. | |||
let enum_union_align = ::std::cell::Cell::new(Align::from_bytes(1, 1).unwrap()); |
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.
You're not using this, are you?
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.
Nevermind.
Changed impl to reflect discussion in IRC. Also fixed a test that was asserting the old behaviour. |
src/librustc/ty/layout.rs
Outdated
@@ -943,8 +943,9 @@ impl<'a, 'tcx> LayoutDetails { | |||
/// A univariant, the last field of which may be coerced to unsized. | |||
MaybeUnsized, | |||
/// A univariant, but part of an enum. | |||
EnumVariant(Integer), | |||
EnumVariant(Size, Align), |
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.
Can you rename this to Prefixed
?
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.
oh right, forgot!
src/librustc/ty/layout.rs
Outdated
@@ -962,13 +963,11 @@ impl<'a, 'tcx> LayoutDetails { | |||
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect(); | |||
|
|||
// Anything with repr(C) or repr(packed) doesn't optimize. | |||
let can_optimize = (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty(); |
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.
I think I prefer naming this optimize
, making it mutable, and &=
-ing it below instead.
src/librustc/ty/layout.rs
Outdated
} | ||
// Round the offset up the union's aggregate alignment. | ||
offset = discr_size.abi_align(union_align); |
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.
What I meant was that you wouldn't need special discriminant vs union semantics, just applying a size&align prefix.
src/librustc/ty/layout.rs
Outdated
// repr(C) on an enum tells us to make a (tag, union) layout, | ||
// so we need to compute the alignment of the union here. | ||
// (enum_union_align is checked by univariant_uninterned) | ||
let mut union_align = min_ity.align(dl); |
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.
Rename this to prefix_align
, I guess.
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.
But it's not how aligned the prefix should be, it's how aligned the suffix should be.
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.
It's the alignment imposed by the prefix, the logic looking at it need not know why it's chosen the way it is.
src/librustc/ty/layout.rs
Outdated
// (enum_union_align is checked by univariant_uninterned) | ||
let mut union_align = min_ity.align(dl); | ||
if def.repr.c() { | ||
for fields in variants.iter() { |
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.
&variants
Comments addressed |
src/librustc/ty/layout.rs
Outdated
@@ -943,7 +943,7 @@ impl<'a, 'tcx> LayoutDetails { | |||
/// A univariant, the last field of which may be coerced to unsized. | |||
MaybeUnsized, | |||
/// A univariant, but part of an enum. |
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.
Can you change the comment to say "with a prefix of an arbitrary size & alignment (e.g. enum tag)" instead of "but part of an enum"?
src/librustc/ty/layout.rs
Outdated
@@ -1001,12 +998,11 @@ impl<'a, 'tcx> LayoutDetails { | |||
|
|||
let mut offset = Size::from_bytes(0); | |||
|
|||
if let StructKind::EnumVariant(discr) = kind { | |||
offset = discr.size(); | |||
if let StructKind::Prefixed(discr_size, prefix_align) = kind { |
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.
prefix_size
instead of discr_size
should do nicely.
src/librustc/ty/layout.rs
Outdated
@@ -1558,10 +1554,21 @@ impl<'a, 'tcx> LayoutDetails { | |||
let mut start_align = Align::from_bytes(256, 256).unwrap(); | |||
assert_eq!(Integer::for_abi_align(dl, start_align), None); | |||
|
|||
// repr(C) on an enum tells us to make a (tag, union) layout, | |||
// so we need to compute the alignment of the union here. |
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.
This comment could be expanded to describe how increasing the prefix alignment produces the same variant layouts as if they were separately computed as structs and then had some space inserted in the front.
cc @rust-lang/compiler @rust-lang/lang LGTM, should this wait on the RFC / have a FCP? |
Comments addressed. |
soooo do I hear an r+ @eddyb? or an fcp merge? :) |
@carols10cents But nobody answered... |
I do expect the RFC to be accepted, but I don't believe we have to block on it. I believe the current behavior is undefined, so we are within our rights to adjust it. FCP might be reasonable, though I think not really necessary, I don't feel like major controversy is expected here. |
@bors r+ |
📌 Commit 904ccbc has been approved by |
⌛ Testing commit 904ccbc9c2b1f8f24664a7ef89071738954f0028 with merge 2e0fd271c40ec90c0d6fa5b99929b81f12413d63... |
💔 Test failed - status-travis |
uhhh so apparently
is 16 bytes on i586-gnu-i686-musl, but u64 is only aligned to 4 bytes? wat
|
nevermind, I'm dumb. |
@bors r+ |
📌 Commit 0e63d27 has been approved by |
Implement the special repr(C)-non-clike-enum layout This is the second half of rust-lang/rfcs#2195 which specifies that ```rust #[repr(C, u8)] #[derive(Copy, Clone, Eq, PartialEq, Debug)] enum MyEnum { A(u32), // Single primitive value B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal C, // Empty D(Option<u32>), // Contains an enum E(Duration), // Contains a struct } ``` Has the same layout as ```rust #[repr(C)] struct MyEnumRepr { tag: MyEnumTag, payload: MyEnumPayload, } #[repr(C)] #[allow(non_snake_case)] union MyEnumPayload { A: MyEnumVariantA, B: MyEnumVariantB, D: MyEnumVariantD, E: MyEnumVariantE, } #[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E } #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32); #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16 } #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>); #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration); ```
☀️ Test successful - status-appveyor, status-travis |
This is the second half of rust-lang/rfcs#2195
which specifies that
Has the same layout as