Skip to content

Commit da33935

Browse files
committed
rustc_target: treat enum variants like union members, in call ABIs.
1 parent 8f81593 commit da33935

File tree

2 files changed

+43
-9
lines changed

2 files changed

+43
-9
lines changed

src/librustc_target/abi/call/mod.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ impl<'a, Ty> TyLayout<'a, Ty> {
308308

309309
Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
310310
// Helper for computing `homogenous_aggregate`, allowing a custom
311-
// starting offset (TODO(eddyb): use this to handle variants).
311+
// starting offset (used below for handling variants).
312312
let from_fields_at =
313313
|layout: Self,
314314
start: Size|
@@ -354,6 +354,32 @@ impl<'a, Ty> TyLayout<'a, Ty> {
354354

355355
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
356356

357+
match &self.variants {
358+
abi::Variants::Single { .. } => {}
359+
abi::Variants::Multiple { variants, .. } => {
360+
// Treat enum variants like union members.
361+
// HACK(eddyb) pretend the `enum` field (discriminant)
362+
// is at the start of every variant (otherwise the gap
363+
// at the start of all variants would disqualify them).
364+
//
365+
// NB: for all tagged `enum`s (which include all non-C-like
366+
// `enum`s with defined FFI representation), this will
367+
// match the homogenous computation on the equivalent
368+
// `struct { tag; union { variant1; ... } }` and/or
369+
// `union { struct { tag; variant1; } ... }`
370+
// (the offsets of variant fields should be identical
371+
// between the two for either to be a homogenous aggregate).
372+
let variant_start = total;
373+
for variant_idx in variants.indices() {
374+
let (variant_result, variant_total) =
375+
from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
376+
377+
result = result.merge(variant_result)?;
378+
total = total.max(variant_total);
379+
}
380+
}
381+
}
382+
357383
// There needs to be no padding.
358384
if total != self.size {
359385
Err(Heterogeneous)

src/librustc_target/abi/call/x86_64.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,24 @@ where
5656

5757
Abi::Vector { .. } => Class::Sse,
5858

59-
Abi::ScalarPair(..) | Abi::Aggregate { .. } => match layout.variants {
60-
abi::Variants::Single { .. } => {
61-
for i in 0..layout.fields.count() {
62-
let field_off = off + layout.fields.offset(i);
63-
classify(cx, layout.field(cx, i), cls, field_off)?;
59+
Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
60+
for i in 0..layout.fields.count() {
61+
let field_off = off + layout.fields.offset(i);
62+
classify(cx, layout.field(cx, i), cls, field_off)?;
63+
}
64+
65+
match &layout.variants {
66+
abi::Variants::Single { .. } => {}
67+
abi::Variants::Multiple { variants, .. } => {
68+
// Treat enum variants like union members.
69+
for variant_idx in variants.indices() {
70+
classify(cx, layout.for_variant(cx, variant_idx), cls, off)?;
71+
}
6472
}
65-
return Ok(());
6673
}
67-
abi::Variants::Multiple { .. } => return Err(Memory),
68-
},
74+
75+
return Ok(());
76+
}
6977
};
7078

7179
// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).

0 commit comments

Comments
 (0)