diff options
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.cc | 187 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-expr.h | 86 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-resolve-path.cc | 49 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-type.cc | 166 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile-type.h | 2 | ||||
-rw-r--r-- | gcc/rust/backend/rust-compile.cc | 4 | ||||
-rw-r--r-- | gcc/rust/rust-backend.h | 4 | ||||
-rw-r--r-- | gcc/rust/rust-gcc.cc | 111 | ||||
-rw-r--r-- | gcc/rust/typecheck/rust-tyty.h | 8 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/torture/enum1.rs | 13 |
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 }; +} |