aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile-expr.h
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-12-14 18:10:42 +0000
committerPhilip Herron <philip.herron@embecosm.com>2021-12-16 10:17:08 +0000
commite0588300adc00872b0e818477dba614348d2cb02 (patch)
treea696b3458140310c223e519b0b53d4481dc2c1de /gcc/rust/backend/rust-compile-expr.h
parent3629645386ad503606f29f95c2e16d0600df6e20 (diff)
downloadgcc-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.h86
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