rustc_target: treat enum variants like union members, in call ABIs.
This commit is contained in:
parent
8f81593d6c
commit
da33935c26
@ -308,7 +308,7 @@ pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, H
|
||||
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
|
||||
// Helper for computing `homogenous_aggregate`, allowing a custom
|
||||
// starting offset (TODO(eddyb): use this to handle variants).
|
||||
// starting offset (used below for handling variants).
|
||||
let from_fields_at =
|
||||
|layout: Self,
|
||||
start: Size|
|
||||
@ -354,6 +354,32 @@ pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, H
|
||||
|
||||
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
|
||||
|
||||
match &self.variants {
|
||||
abi::Variants::Single { .. } => {}
|
||||
abi::Variants::Multiple { variants, .. } => {
|
||||
// Treat enum variants like union members.
|
||||
// HACK(eddyb) pretend the `enum` field (discriminant)
|
||||
// is at the start of every variant (otherwise the gap
|
||||
// at the start of all variants would disqualify them).
|
||||
//
|
||||
// NB: for all tagged `enum`s (which include all non-C-like
|
||||
// `enum`s with defined FFI representation), this will
|
||||
// match the homogenous computation on the equivalent
|
||||
// `struct { tag; union { variant1; ... } }` and/or
|
||||
// `union { struct { tag; variant1; } ... }`
|
||||
// (the offsets of variant fields should be identical
|
||||
// between the two for either to be a homogenous aggregate).
|
||||
let variant_start = total;
|
||||
for variant_idx in variants.indices() {
|
||||
let (variant_result, variant_total) =
|
||||
from_fields_at(self.for_variant(cx, variant_idx), variant_start)?;
|
||||
|
||||
result = result.merge(variant_result)?;
|
||||
total = total.max(variant_total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There needs to be no padding.
|
||||
if total != self.size {
|
||||
Err(Heterogeneous)
|
||||
|
@ -56,16 +56,24 @@ fn classify<'a, Ty, C>(
|
||||
|
||||
Abi::Vector { .. } => Class::Sse,
|
||||
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => match layout.variants {
|
||||
abi::Variants::Single { .. } => {
|
||||
Abi::ScalarPair(..) | Abi::Aggregate { .. } => {
|
||||
for i in 0..layout.fields.count() {
|
||||
let field_off = off + layout.fields.offset(i);
|
||||
classify(cx, layout.field(cx, i), cls, field_off)?;
|
||||
}
|
||||
|
||||
match &layout.variants {
|
||||
abi::Variants::Single { .. } => {}
|
||||
abi::Variants::Multiple { variants, .. } => {
|
||||
// Treat enum variants like union members.
|
||||
for variant_idx in variants.indices() {
|
||||
classify(cx, layout.for_variant(cx, variant_idx), cls, off)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
abi::Variants::Multiple { .. } => return Err(Memory),
|
||||
},
|
||||
};
|
||||
|
||||
// Fill in `cls` for scalars (Int/Sse) and vectors (Sse).
|
||||
|
Loading…
Reference in New Issue
Block a user