aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc187
-rw-r--r--gcc/rust/backend/rust-compile-expr.h86
-rw-r--r--gcc/rust/backend/rust-compile-resolve-path.cc49
-rw-r--r--gcc/rust/backend/rust-compile-type.cc166
-rw-r--r--gcc/rust/backend/rust-compile-type.h2
-rw-r--r--gcc/rust/backend/rust-compile.cc4
-rw-r--r--gcc/rust/rust-backend.h4
-rw-r--r--gcc/rust/rust-gcc.cc111
-rw-r--r--gcc/rust/typecheck/rust-tyty.h8
-rw-r--r--gcc/testsuite/rust/compile/torture/enum1.rs13
10 files changed, 475 insertions, 155 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 7c8aa29..fa88e48 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -168,19 +168,36 @@ CompileExpr::visit (HIR::CallExpr &expr)
// must be a tuple constructor
bool is_fn = tyty->get_kind () == TyTy::TypeKind::FNDEF
|| tyty->get_kind () == TyTy::TypeKind::FNPTR;
- if (!is_fn)
+ bool is_adt_ctor = !is_fn;
+ if (is_adt_ctor)
{
rust_assert (tyty->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (tyty);
tree compiled_adt_type = TyTyResolveCompile::compile (ctx, tyty);
- rust_assert (!adt->is_enum ());
- rust_assert (adt->number_of_variants () == 1);
- auto variant = adt->get_variants ().at (0);
+ // what variant is it?
+ int union_disriminator = -1;
+ 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 (
+ expr.get_fnexpr ()->get_mappings ().get_hirid (), &variant_id);
+ rust_assert (ok);
+
+ ok = adt->lookup_variant_by_id (variant_id, &variant,
+ &union_disriminator);
+ rust_assert (ok);
+ }
// 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;
+ std::vector<tree> arguments;
for (size_t i = 0; i < expr.get_arguments ().size (); i++)
{
auto &argument = expr.get_arguments ().at (i);
@@ -200,95 +217,111 @@ CompileExpr::visit (HIR::CallExpr &expr)
rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
// add it to the list
- vals.push_back (rvalue);
+ arguments.push_back (rvalue);
}
- translated
- = ctx->get_backend ()->constructor_expression (compiled_adt_type, vals,
- -1, expr.get_locus ());
- }
- else
- {
- auto get_parameter_tyty_at_index
- = [] (const TyTy::BaseType *base, size_t index,
- TyTy::BaseType **result) -> bool {
- bool is_fn = base->get_kind () == TyTy::TypeKind::FNDEF
- || base->get_kind () == TyTy::TypeKind::FNPTR;
- rust_assert (is_fn);
-
- if (base->get_kind () == TyTy::TypeKind::FNPTR)
- {
- const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (base);
- *result = fn->param_at (index);
+ // 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);
- return true;
- }
+ translated = ctx->get_backend ()->constructor_expression (
+ compiled_adt_type, adt->is_enum (), ctor_arguments, union_disriminator,
+ expr.get_locus ());
- const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base);
- auto param = fn->param_at (index);
- *result = param.second;
+ return;
+ }
- return true;
- };
+ auto get_parameter_tyty_at_index
+ = [] (const TyTy::BaseType *base, size_t index,
+ TyTy::BaseType **result) -> bool {
+ bool is_fn = base->get_kind () == TyTy::TypeKind::FNDEF
+ || base->get_kind () == TyTy::TypeKind::FNPTR;
+ rust_assert (is_fn);
- bool is_varadic = false;
- if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
- {
- const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
- is_varadic = fn->is_varadic ();
- }
+ if (base->get_kind () == TyTy::TypeKind::FNPTR)
+ {
+ const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (base);
+ *result = fn->param_at (index);
- size_t required_num_args;
- if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
- {
- const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
- required_num_args = fn->num_params ();
- }
- else
- {
- const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (tyty);
- required_num_args = fn->num_params ();
- }
+ return true;
+ }
- std::vector<tree> args;
- for (size_t i = 0; i < expr.get_arguments ().size (); i++)
- {
- auto &argument = expr.get_arguments ().at (i);
- auto rvalue = CompileExpr::Compile (argument.get (), ctx);
+ const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (base);
+ auto param = fn->param_at (index);
+ *result = param.second;
- if (is_varadic && i >= required_num_args)
- {
- args.push_back (rvalue);
- continue;
- }
+ return true;
+ };
- // assignments are coercion sites so lets convert the rvalue if
- // necessary
- bool ok;
- TyTy::BaseType *expected = nullptr;
- ok = get_parameter_tyty_at_index (tyty, i, &expected);
- rust_assert (ok);
+ bool is_varadic = false;
+ if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
+ is_varadic = fn->is_varadic ();
+ }
- TyTy::BaseType *actual = nullptr;
- ok = ctx->get_tyctx ()->lookup_type (
- argument->get_mappings ().get_hirid (), &actual);
- rust_assert (ok);
+ size_t required_num_args;
+ if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ const TyTy::FnType *fn = static_cast<const TyTy::FnType *> (tyty);
+ required_num_args = fn->num_params ();
+ }
+ else
+ {
+ const TyTy::FnPtr *fn = static_cast<const TyTy::FnPtr *> (tyty);
+ required_num_args = fn->num_params ();
+ }
- // coerce it if required
- rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
+ std::vector<tree> args;
+ for (size_t i = 0; i < expr.get_arguments ().size (); i++)
+ {
+ auto &argument = expr.get_arguments ().at (i);
+ auto rvalue = CompileExpr::Compile (argument.get (), ctx);
- // add it to the list
+ if (is_varadic && i >= required_num_args)
+ {
args.push_back (rvalue);
+ continue;
}
- // must be a call to a function
- auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
- auto fncontext = ctx->peek_fn ();
- translated
- = ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address,
- args, nullptr,
- expr.get_locus ());
+ // assignments are coercion sites so lets convert the rvalue if
+ // necessary
+ bool ok;
+ TyTy::BaseType *expected = nullptr;
+ ok = get_parameter_tyty_at_index (tyty, i, &expected);
+ rust_assert (ok);
+
+ TyTy::BaseType *actual = nullptr;
+ ok = ctx->get_tyctx ()->lookup_type (
+ argument->get_mappings ().get_hirid (), &actual);
+ rust_assert (ok);
+
+ // coerce it if required
+ rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
+
+ // add it to the list
+ args.push_back (rvalue);
}
+
+ // must be a call to a function
+ auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
+ auto fncontext = ctx->peek_fn ();
+ translated
+ = ctx->get_backend ()->call_expression (fncontext.fndecl, fn_address, args,
+ nullptr, expr.get_locus ());
}
void
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
diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc
index cb3f0df..07133b9 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.cc
+++ b/gcc/rust/backend/rust-compile-resolve-path.cc
@@ -45,6 +45,10 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
const Analysis::NodeMapping &mappings,
Location expr_locus, bool is_qualified_path)
{
+ TyTy::BaseType *lookup = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
+ rust_assert (ok);
+
// need to look up the reference for this identifier
NodeId ref_node_id = UNKNOWN_NODEID;
if (ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (),
@@ -63,8 +67,44 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
// in that case the caller should attempt ResolvePathType::Compile
if (ref_node_id == UNKNOWN_NODEID)
{
- rust_error_at (expr_locus, "unknown nodeid for path expr");
- return ctx->get_backend ()->error_expression ();
+ // it might be an enum data-less enum variant
+ if (lookup->get_kind () != TyTy::TypeKind::ADT)
+ return ctx->get_backend ()->error_expression ();
+
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
+ if (!adt->is_enum ())
+ return ctx->get_backend ()->error_expression ();
+
+ HirId variant_id;
+ if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
+ &variant_id))
+ return ctx->get_backend ()->error_expression ();
+
+ int union_disriminator = -1;
+ TyTy::VariantDef *variant = nullptr;
+ if (!adt->lookup_variant_by_id (variant_id, &variant,
+ &union_disriminator))
+ return ctx->get_backend ()->error_expression ();
+
+ // FIXME should really return error_mark_node and or rust_internal_error
+ // error_mark_node
+ rust_assert (variant->get_variant_type ()
+ == TyTy::VariantDef::VariantType::NUM);
+
+ // we need the actual gcc type
+ tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
+
+ // make the ctor for the union
+ mpz_t val;
+ mpz_init_set_ui (val, variant->get_discriminant ());
+ tree t = TyTyResolveCompile::get_implicit_enumeral_node_type (ctx);
+ tree qualifier
+ = double_int_to_tree (t, mpz_get_double_int (t, val, true));
+
+ return ctx->get_backend ()->constructor_expression (compiled_adt_type,
+ true, {qualifier},
+ union_disriminator,
+ expr_locus);
}
HirId ref;
@@ -86,9 +126,6 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
return ctx->get_backend ()->var_expression (var, expr_locus);
// it might be a function call
- TyTy::BaseType *lookup = nullptr;
- bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
- rust_assert (ok);
if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
{
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
@@ -102,7 +139,7 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
// let the query system figure it out
return query_compile (ref, lookup, final_segment, mappings, expr_locus,
is_qualified_path);
-}
+} // namespace Compile
tree
ResolvePathRef::query_compile (HirId ref, TyTy::BaseType *lookup,
diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc
index 76ab4db..c147a51 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -18,9 +18,48 @@
#include "rust-compile-type.h"
+#include "tree.h"
+
namespace Rust {
namespace Compile {
+static const std::string RUST_ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR";
+
+// see: gcc/c/c-decl.c:8230-8241
+// https://github.com/Rust-GCC/gccrs/blob/0024bc2f028369b871a65ceb11b2fddfb0f9c3aa/gcc/c/c-decl.c#L8229-L8241
+tree
+TyTyResolveCompile::get_implicit_enumeral_node_type (Context *ctx)
+{
+ // static tree enum_node = NULL_TREE;
+ // if (enum_node == NULL_TREE)
+ // {
+ // enum_node = make_node (ENUMERAL_TYPE);
+ // SET_TYPE_MODE (enum_node, TYPE_MODE (unsigned_type_node));
+ // SET_TYPE_ALIGN (enum_node, TYPE_ALIGN (unsigned_type_node));
+ // TYPE_USER_ALIGN (enum_node) = 0;
+ // TYPE_UNSIGNED (enum_node) = 1;
+ // TYPE_PRECISION (enum_node) = TYPE_PRECISION (unsigned_type_node);
+ // TYPE_MIN_VALUE (enum_node) = TYPE_MIN_VALUE (unsigned_type_node);
+ // TYPE_MAX_VALUE (enum_node) = TYPE_MAX_VALUE (unsigned_type_node);
+
+ // // tree identifier = ctx->get_backend ()->get_identifier_node
+ // // ("enumeral"); tree enum_decl
+ // // = build_decl (BUILTINS_LOCATION, TYPE_DECL, identifier,
+ // enum_node);
+ // // TYPE_NAME (enum_node) = enum_decl;
+ // }
+ // return enum_node;
+
+ static tree enum_node = NULL_TREE;
+ if (enum_node == NULL_TREE)
+ {
+ enum_node = ctx->get_backend ()->named_type (
+ "enumeral", ctx->get_backend ()->integer_type (false, 64),
+ Linemap::predeclared_location ());
+ }
+ return enum_node;
+}
+
void
TyTyResolveCompile::visit (const TyTy::ErrorType &)
{
@@ -120,29 +159,120 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
if (ctx->lookup_compiled_types (type.get_ty_ref (), &translated, &type))
return;
- // we dont support enums yet
- rust_assert (!type.is_enum ());
- rust_assert (type.number_of_variants () == 1);
+ tree type_record = error_mark_node;
+ if (!type.is_enum ())
+ {
+ rust_assert (type.number_of_variants () == 1);
- TyTy::VariantDef &variant = *type.get_variants ().at (0);
- std::vector<Backend::typed_identifier> fields;
- for (size_t i = 0; i < variant.num_fields (); i++)
+ TyTy::VariantDef &variant = *type.get_variants ().at (0);
+ std::vector<Backend::typed_identifier> fields;
+ for (size_t i = 0; i < variant.num_fields (); i++)
+ {
+ const TyTy::StructFieldType *field = variant.get_field_at_index (i);
+ tree compiled_field_ty
+ = TyTyResolveCompile::compile (ctx, field->get_field_type ());
+
+ Backend::typed_identifier f (field->get_name (), compiled_field_ty,
+ ctx->get_mappings ()->lookup_location (
+ type.get_ty_ref ()));
+ fields.push_back (std::move (f));
+ }
+
+ type_record = type.is_union ()
+ ? ctx->get_backend ()->union_type (fields)
+ : ctx->get_backend ()->struct_type (fields);
+ }
+ else
{
- const TyTy::StructFieldType *field = variant.get_field_at_index (i);
- tree compiled_field_ty
- = TyTyResolveCompile::compile (ctx, field->get_field_type ());
+ // see:
+ // https://github.com/bminor/binutils-gdb/blob/527b8861cd472385fa9160a91dd6d65a25c41987/gdb/dwarf2/read.c#L9010-L9241
+ //
+ // enums are actually a big union so for example the rust enum:
+ //
+ // enum AnEnum {
+ // A,
+ // B,
+ // C (char),
+ // D { x: i64, y: i64 },
+ // }
+ //
+ // we actually turn this into
+ //
+ // union {
+ // struct A { int RUST$ENUM$DISR; }; <- this is a data-less variant
+ // struct B { int RUST$ENUM$DISR; }; <- this is a data-less variant
+ // struct C { int RUST$ENUM$DISR; char __0; };
+ // struct D { int RUST$ENUM$DISR; i64 x; i64 y; };
+ // }
+ //
+ // Ada, qual_union_types might still work for this but I am not 100% sure.
+ // I ran into some issues lets reuse our normal union and ask Ada people
+ // about it.
+
+ std::vector<tree> variant_records;
+ for (auto &variant : type.get_variants ())
+ {
+ std::vector<Backend::typed_identifier> fields;
+
+ // add in the qualifier field for the variant
+ tree enumeral_type
+ = TyTyResolveCompile::get_implicit_enumeral_node_type (ctx);
+ Backend::typed_identifier f (RUST_ENUM_DISR_FIELD_NAME, enumeral_type,
+ ctx->get_mappings ()->lookup_location (
+ variant->get_id ()));
+ fields.push_back (std::move (f));
+
+ // compile the rest of the fields
+ for (size_t i = 0; i < variant->num_fields (); i++)
+ {
+ const TyTy::StructFieldType *field
+ = variant->get_field_at_index (i);
+ tree compiled_field_ty
+ = TyTyResolveCompile::compile (ctx, field->get_field_type ());
+
+ std::string field_name = field->get_name ();
+ if (variant->get_variant_type ()
+ == TyTy::VariantDef::VariantType::TUPLE)
+ field_name = "__" + field->get_name ();
+
+ Backend::typed_identifier f (
+ field_name, compiled_field_ty,
+ ctx->get_mappings ()->lookup_location (type.get_ty_ref ()));
+ fields.push_back (std::move (f));
+ }
+
+ tree variant_record = ctx->get_backend ()->struct_type (fields);
+ tree named_variant_record = ctx->get_backend ()->named_type (
+ variant->get_identifier (), variant_record,
+ ctx->get_mappings ()->lookup_location (variant->get_id ()));
+
+ // set the qualifier to be a builtin
+ DECL_ARTIFICIAL (TYPE_FIELDS (variant_record)) = 1;
+
+ // add them to the list
+ variant_records.push_back (named_variant_record);
+ }
+
+ // now we need to make the actual union, but first we need to make
+ // named_type TYPE_DECL's out of the variants
+
+ size_t i = 0;
+ std::vector<Backend::typed_identifier> enum_fields;
+ for (auto &variant_record : variant_records)
+ {
+ TyTy::VariantDef *variant = type.get_variants ().at (i++);
+ std::string implicit_variant_name = variant->get_identifier ();
+
+ Backend::typed_identifier f (implicit_variant_name, variant_record,
+ ctx->get_mappings ()->lookup_location (
+ type.get_ty_ref ()));
+ enum_fields.push_back (std::move (f));
+ }
- Backend::typed_identifier f (field->get_name (), compiled_field_ty,
- ctx->get_mappings ()->lookup_location (
- type.get_ty_ref ()));
- fields.push_back (std::move (f));
+ // finally make the union or the enum
+ type_record = ctx->get_backend ()->union_type (enum_fields);
}
- tree type_record;
- if (type.is_union ())
- type_record = ctx->get_backend ()->union_type (fields);
- else
- type_record = ctx->get_backend ()->struct_type (fields);
tree named_struct
= ctx->get_backend ()->named_type (type.get_name (), type_record,
ctx->get_mappings ()->lookup_location (
diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust-compile-type.h
index f62581f..1e05e5d 100644
--- a/gcc/rust/backend/rust-compile-type.h
+++ b/gcc/rust/backend/rust-compile-type.h
@@ -35,6 +35,8 @@ public:
return compiler.translated;
}
+ static tree get_implicit_enumeral_node_type (Context *ctx);
+
void visit (const TyTy::InferType &) override;
void visit (const TyTy::ADTType &) override;
void visit (const TyTy::TupleType &) override;
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index ac3be3b..610e3aa 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -336,8 +336,8 @@ HIRCompileBase::coerce_to_dyn_object (tree compiled_ref,
}
tree constructed_trait_object
- = ctx->get_backend ()->constructor_expression (dynamic_object, vals, -1,
- locus);
+ = ctx->get_backend ()->constructor_expression (dynamic_object, false, vals,
+ -1, locus);
fncontext fnctx = ctx->peek_fn ();
tree enclosing_scope = ctx->peek_enclosing_scope ();
diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h
index 64144bc..43a81f2 100644
--- a/gcc/rust/rust-backend.h
+++ b/gcc/rust/rust-backend.h
@@ -122,6 +122,8 @@ public:
return "unknown";
}
+ virtual tree get_identifier_node (const std::string &str) = 0;
+
// Types.
// Produce an error type. Actually the backend could probably just
@@ -348,7 +350,7 @@ public:
// Return an expression that constructs BTYPE with VALS. BTYPE must be the
// backend representation a of struct. VALS must be in the same order as the
// corresponding fields in BTYPE.
- virtual tree constructor_expression (tree btype,
+ virtual tree constructor_expression (tree btype, bool is_variant,
const std::vector<tree> &vals, int,
Location)
= 0;
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 12df769..43716d9 100644
--- a/gcc/rust/rust-gcc.cc
+++ b/gcc/rust/rust-gcc.cc
@@ -110,6 +110,11 @@ public:
void debug (tree t) { debug_tree (t); };
void debug (Bvariable *t) { debug_tree (t->get_decl ()); };
+ tree get_identifier_node (const std::string &str)
+ {
+ return get_identifier_with_length (str.data (), str.length ());
+ }
+
// Types.
tree error_type () { return error_mark_node; }
@@ -288,7 +293,8 @@ public:
tree lazy_boolean_expression (LazyBooleanOperator op, tree left, tree right,
Location);
- tree constructor_expression (tree, const std::vector<tree> &, int, Location);
+ tree constructor_expression (tree, bool, const std::vector<tree> &, int,
+ Location);
tree array_constructor_expression (tree, const std::vector<unsigned long> &,
const std::vector<tree> &, Location);
@@ -1715,7 +1721,7 @@ Gcc_backend::lazy_boolean_expression (LazyBooleanOperator op, tree left_tree,
// Return an expression that constructs BTYPE with VALS.
tree
-Gcc_backend::constructor_expression (tree type_tree,
+Gcc_backend::constructor_expression (tree type_tree, bool is_variant,
const std::vector<tree> &vals,
int union_index, Location location)
{
@@ -1728,46 +1734,40 @@ Gcc_backend::constructor_expression (tree type_tree,
tree sink = NULL_TREE;
bool is_constant = true;
tree field = TYPE_FIELDS (type_tree);
- if (union_index != -1)
+
+ if (is_variant)
{
+ gcc_assert (union_index != -1);
gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
- tree val = vals.front ();
+
for (int i = 0; i < union_index; i++)
{
gcc_assert (field != NULL_TREE);
field = DECL_CHAIN (field);
}
- if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
- || TREE_TYPE (val) == error_mark_node)
- return this->error_expression ();
- if (int_size_in_bytes (TREE_TYPE (field)) == 0)
- {
- // GIMPLE cannot represent indices of zero-sized types so
- // trying to construct a map with zero-sized keys might lead
- // to errors. Instead, we evaluate each expression that
- // would have been added as a map element for its
- // side-effects and construct an empty map.
- append_to_statement_list (val, &sink);
- }
- else
- {
- constructor_elt empty = {NULL, NULL};
- constructor_elt *elt = init->quick_push (empty);
- elt->index = field;
- elt->value = this->convert_tree (TREE_TYPE (field), val, location);
- if (!TREE_CONSTANT (elt->value))
- is_constant = false;
- }
+ tree nested_ctor
+ = constructor_expression (TREE_TYPE (field), false, vals, -1, location);
+
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), nested_ctor, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
}
else
{
- gcc_assert (TREE_CODE (type_tree) == RECORD_TYPE);
- for (std::vector<tree>::const_iterator p = vals.begin ();
- p != vals.end (); ++p, field = DECL_CHAIN (field))
+ if (union_index != -1)
{
- gcc_assert (field != NULL_TREE);
- tree val = (*p);
+ gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
+ tree val = vals.front ();
+ for (int i = 0; i < union_index; i++)
+ {
+ gcc_assert (field != NULL_TREE);
+ field = DECL_CHAIN (field);
+ }
if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
|| TREE_TYPE (val) == error_mark_node)
return this->error_expression ();
@@ -1780,18 +1780,53 @@ Gcc_backend::constructor_expression (tree type_tree,
// would have been added as a map element for its
// side-effects and construct an empty map.
append_to_statement_list (val, &sink);
- continue;
}
+ else
+ {
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), val, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
+ }
+ }
+ else
+ {
+ gcc_assert (TREE_CODE (type_tree) == RECORD_TYPE);
+ for (std::vector<tree>::const_iterator p = vals.begin ();
+ p != vals.end (); ++p, field = DECL_CHAIN (field))
+ {
+ gcc_assert (field != NULL_TREE);
+ tree val = (*p);
+ if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
+ || TREE_TYPE (val) == error_mark_node)
+ return this->error_expression ();
+
+ if (int_size_in_bytes (TREE_TYPE (field)) == 0)
+ {
+ // GIMPLE cannot represent indices of zero-sized types so
+ // trying to construct a map with zero-sized keys might lead
+ // to errors. Instead, we evaluate each expression that
+ // would have been added as a map element for its
+ // side-effects and construct an empty map.
+ append_to_statement_list (val, &sink);
+ continue;
+ }
- constructor_elt empty = {NULL, NULL};
- constructor_elt *elt = init->quick_push (empty);
- elt->index = field;
- elt->value = this->convert_tree (TREE_TYPE (field), val, location);
- if (!TREE_CONSTANT (elt->value))
- is_constant = false;
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), val, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
+ }
+ gcc_assert (field == NULL_TREE);
}
- gcc_assert (field == NULL_TREE);
}
+
tree ret = build_constructor (type_tree, init);
if (is_constant)
TREE_CONSTANT (ret) = 1;
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index b2fefbb..3cedba8 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -1268,15 +1268,21 @@ public:
return false;
}
- bool lookup_variant_by_id (HirId id, VariantDef **found_variant) const
+ bool lookup_variant_by_id (HirId id, VariantDef **found_variant,
+ int *index = nullptr) const
{
+ int i = 0;
for (auto &variant : variants)
{
if (variant->get_id () == id)
{
+ if (index != nullptr)
+ *index = i;
+
*found_variant = variant;
return true;
}
+ i++;
}
return false;
}
diff --git a/gcc/testsuite/rust/compile/torture/enum1.rs b/gcc/testsuite/rust/compile/torture/enum1.rs
new file mode 100644
index 0000000..7cea48f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/enum1.rs
@@ -0,0 +1,13 @@
+enum Foo {
+ A,
+ B,
+ C(char),
+ D { x: i64, y: i64 },
+}
+
+fn main() {
+ let _a = Foo::A;
+ let _b = Foo::B;
+ let _c = Foo::C('x');
+ let _d = Foo::D { x: 20, y: 80 };
+}