diff options
| author | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2020-01-22 02:52:54 +0200 |
|---|---|---|
| committer | Eduard-Mihai Burtescu <edy.burt@gmail.com> | 2020-02-08 06:50:59 +0200 |
| commit | da33935c260bf8859d20b83dec40be7fc3d82310 (patch) | |
| tree | 6dd92c533f447c308f481cdd50c7074e94a1f3c5 | |
| parent | 8f81593d6c9b731973c0f8e57548948101dda928 (diff) | |
| download | rust-da33935c260bf8859d20b83dec40be7fc3d82310.tar.gz rust-da33935c260bf8859d20b83dec40be7fc3d82310.zip | |
rustc_target: treat enum variants like union members, in call ABIs.
| -rw-r--r-- | src/librustc_target/abi/call/mod.rs | 28 | ||||
| -rw-r--r-- | src/librustc_target/abi/call/x86_64.rs | 24 |
2 files changed, 43 insertions, 9 deletions
diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 748fd2b6579..e3cbf176c35 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -308,7 +308,7 @@ impl<'a, Ty> TyLayout<'a, Ty> { 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 @@ impl<'a, Ty> TyLayout<'a, Ty> { 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) diff --git a/src/librustc_target/abi/call/x86_64.rs b/src/librustc_target/abi/call/x86_64.rs index a547d7262e2..4c192c46786 100644 --- a/src/librustc_target/abi/call/x86_64.rs +++ b/src/librustc_target/abi/call/x86_64.rs @@ -56,16 +56,24 @@ where Abi::Vector { .. } => Class::Sse, - Abi::ScalarPair(..) | Abi::Aggregate { .. } => match layout.variants { - abi::Variants::Single { .. } => { - for i in 0..layout.fields.count() { - let field_off = off + layout.fields.offset(i); - classify(cx, layout.field(cx, i), cls, field_off)?; + 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), - }, + + return Ok(()); + } }; // Fill in `cls` for scalars (Int/Sse) and vectors (Sse). |
