diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-12-14 18:10:42 +0000 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-12-16 10:17:08 +0000 |
commit | e0588300adc00872b0e818477dba614348d2cb02 (patch) | |
tree | a696b3458140310c223e519b0b53d4481dc2c1de /gcc/rust/backend/rust-compile-expr.h | |
parent | 3629645386ad503606f29f95c2e16d0600df6e20 (diff) | |
download | gcc-e0588300adc00872b0e818477dba614348d2cb02.zip gcc-e0588300adc00872b0e818477dba614348d2cb02.tar.gz gcc-e0588300adc00872b0e818477dba614348d2cb02.tar.bz2 |
Add enum code generation
This adds a naieve first pass approach to enum type code generation. The
original idea was to use GCC's QUAL_UNION_TYPE but I have ran into issues
with the DECL_QUALIFIER as my understanding of how this works is incorrect.
This takes an enum such as:
```rust
enum AnEnum {
A,
B,
C (char),
D (x: i64, y: i64),
}
```
And turns this into one big union consisting of all fields as RECORD_TYPES.
```c
union AnEnum {
record A { RUST$ENUM$DISR };
record B { RUST$ENUM$DISR };
record C { RUST$ENUM$DISR, char };
record D { RUST$ENUM$DISR, i64, i64};
}
```
see: https://github.com/bminor/binutils-gdb/blob/527b8861cd472385fa9160a91dd6d65a25c41987/gdb/dwarf2/read.c#L9010-L9241
With the RUST$ENUM$DISR being the first field in all of the records this
means the alignment allows for indirect memory access of the struct to
use it as a qualifier field to figure out which variant is currently in
use. The data-less varients use their generated discriminat value during
type-checking the data variants use their HIR ID for their discriminant.
This will likely get redone to get improved GDB integration/updated to use
the QUAL_UNION_TYPE when we learn how to do this properly.
Fixes #79
Diffstat (limited to 'gcc/rust/backend/rust-compile-expr.h')
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 86 |
1 files changed, 74 insertions, 12 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h index 1e8e1f6..9895540 100644 --- a/gcc/rust/backend/rust-compile-expr.h +++ b/gcc/rust/backend/rust-compile-expr.h @@ -100,8 +100,8 @@ public: } translated - = ctx->get_backend ()->constructor_expression (tuple_type, vals, -1, - expr.get_locus ()); + = ctx->get_backend ()->constructor_expression (tuple_type, false, vals, + -1, expr.get_locus ()); } void visit (HIR::ReturnExpr &expr) override @@ -660,22 +660,84 @@ public: return; } - tree type = TyTyResolveCompile::compile (ctx, tyty); - rust_assert (type != nullptr); + // it must be an ADT + rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT); + TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty); + + // what variant is it? + int union_disriminator = struct_expr.union_index; + TyTy::VariantDef *variant = nullptr; + if (!adt->is_enum ()) + { + rust_assert (adt->number_of_variants () == 1); + variant = adt->get_variants ().at (0); + } + else + { + HirId variant_id; + bool ok = ctx->get_tyctx ()->lookup_variant_definition ( + struct_expr.get_struct_name ().get_mappings ().get_hirid (), + &variant_id); + rust_assert (ok); + + ok = adt->lookup_variant_by_id (variant_id, &variant, + &union_disriminator); + rust_assert (ok); + } + + // compile it + tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty); // this assumes all fields are in order from type resolution and if a base // struct was specified those fields are filed via accesors - std::vector<tree> vals; - for (auto &field : struct_expr.get_fields ()) + std::vector<tree> arguments; + for (size_t i = 0; i < struct_expr.get_fields ().size (); i++) { - tree expr = CompileStructExprField::Compile (field.get (), ctx); - vals.push_back (expr); + auto &argument = struct_expr.get_fields ().at (i); + auto rvalue = CompileStructExprField::Compile (argument.get (), ctx); + + // assignments are coercion sites so lets convert the rvalue if + // necessary + auto respective_field = variant->get_field_at_index (i); + auto expected = respective_field->get_field_type (); + + TyTy::BaseType *actual = nullptr; + bool ok = ctx->get_tyctx ()->lookup_type ( + argument->get_mappings ().get_hirid (), &actual); + + // coerce it if required/possible see + // compile/torture/struct_base_init_1.rs + if (ok) + { + rvalue = coercion_site (rvalue, actual, expected, + argument->get_locus ()); + } + + // add it to the list + arguments.push_back (rvalue); } - translated - = ctx->get_backend ()->constructor_expression (type, vals, - struct_expr.union_index, - struct_expr.get_locus ()); + // the constructor depends on whether this is actually an enum or not if + // its an enum we need to setup the discriminator + std::vector<tree> ctor_arguments; + if (adt->is_enum ()) + { + HirId variant_id = variant->get_id (); + mpz_t val; + mpz_init_set_ui (val, variant_id); + + tree t = TyTyResolveCompile::get_implicit_enumeral_node_type (ctx); + tree qualifier + = double_int_to_tree (t, mpz_get_double_int (t, val, true)); + + ctor_arguments.push_back (qualifier); + } + for (auto &arg : arguments) + ctor_arguments.push_back (arg); + + translated = ctx->get_backend ()->constructor_expression ( + compiled_adt_type, adt->is_enum (), ctor_arguments, union_disriminator, + struct_expr.get_locus ()); } void visit (HIR::GroupedExpr &expr) override |