* union support
@ 2021-07-22 23:19 Mark Wielaard
2021-07-22 23:19 ` [PATCH 1/2] Better union support in the parser Mark Wielaard
2021-07-22 23:19 ` [PATCH 2/2] WIP union hir-lowering and type support Mark Wielaard
0 siblings, 2 replies; 9+ messages in thread
From: Mark Wielaard @ 2021-07-22 23:19 UTC (permalink / raw)
To: gcc-rust
Hi,
I have been playing with union support which was mostly missing. union
is slightly odd because it is a weak keyword, so it can be used as a
"normal" identifier and is only special when defining a union
type. Which means you can have programs like:
union union { union: u32, funion: f32 }
pub fn main ()
{
let union = union { union: 1 };
let _u = unsafe { union.union };
let _f = unsafe { union.funion; };
}
Here are two patches to support the above (partially).
Also on https://code.wildebeest.org/git/user/mjw/gccrs/log/?h=union
The first fixes up the parser and should be good to go.
[PATCH 1/2] Better union support in the parser
The second provides lowering to HIR and type checking support. This
is mostly cargo culting existing code for structs and tuple struct. It
seems to work, but I cannot say I fully understand what I am doing.
[PATCH 2/2] WIP union hir-lowering and type support
Currently this will eventually crash when trying to generate code in
Gcc_backend::constructor_expression because we try to emit code for a
struct with multiple fields, but the union doesn't have real fields,
just multiple variants.
Hopefully this is somewhat useful. Feedback on how to proceed and/or
how to get a better design (it seems a good idea to treat a union as
much as possible as a struct/tuple variant, but maybe there is a
better way) is very welcome.
Thanks,
Mark
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/2] Better union support in the parser
2021-07-22 23:19 union support Mark Wielaard
@ 2021-07-22 23:19 ` Mark Wielaard
2021-07-23 11:19 ` Philip Herron
2021-07-22 23:19 ` [PATCH 2/2] WIP union hir-lowering and type support Mark Wielaard
1 sibling, 1 reply; 9+ messages in thread
From: Mark Wielaard @ 2021-07-22 23:19 UTC (permalink / raw)
To: gcc-rust; +Cc: Mark Wielaard
union is a weak keyword which means it isn't reserved and can be used
as a generic identifier. When we see an identifier where a union could
be declared we check whether the identifier is "union", but only when
the next token is also an identifier. In parse_union we shouldn't skip
the first identifier token, because it is already skipped when we call
expect_token.
---
gcc/rust/parse/rust-parse-impl.h | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index bdf1e09a029..3996ef21672 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -1083,7 +1083,8 @@ Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
// crappy hack to do union "keyword"
case IDENTIFIER:
// TODO: ensure std::string and literal comparison works
- if (t->get_str () == "union")
+ if (t->get_str () == "union"
+ && lexer.peek_token (1)->get_id () == IDENTIFIER)
{
return parse_vis_item (std::move (outer_attrs));
// or should this go straight to parsing union?
@@ -1274,8 +1275,8 @@ Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
// TODO: implement union keyword but not really because of
// context-dependence case UNION: crappy hack to do union "keyword"
case IDENTIFIER:
- // TODO: ensure std::string and literal comparison works
- if (t->get_str () == "union")
+ if (t->get_str () == "union"
+ && lexer.peek_token (1)->get_id () == IDENTIFIER)
{
return parse_union (std::move (vis), std::move (outer_attrs));
// or should item switch go straight to parsing union?
@@ -4524,7 +4525,6 @@ Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
const_TokenPtr union_keyword = expect_token (IDENTIFIER);
rust_assert (union_keyword->get_str () == "union");
Location locus = union_keyword->get_locus ();
- lexer.skip_token ();
// parse actual union name
const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
@@ -6054,8 +6054,8 @@ Parser<ManagedTokenSource>::parse_stmt ()
break;
// crappy hack to do union "keyword"
case IDENTIFIER:
- // TODO: ensure std::string and literal comparison works
- if (t->get_str () == "union")
+ if (t->get_str () == "union"
+ && lexer.peek_token (1)->get_id () == IDENTIFIER)
{
return parse_vis_item (std::move (outer_attrs));
// or should this go straight to parsing union?
@@ -11674,8 +11674,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
}
// crappy hack to do union "keyword"
case IDENTIFIER:
- // TODO: ensure std::string and literal comparison works
- if (t->get_str () == "union")
+ if (t->get_str () == "union"
+ && lexer.peek_token (1)->get_id () == IDENTIFIER)
{
std::unique_ptr<AST::VisItem> item (
parse_vis_item (std::move (outer_attrs)));
--
2.32.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/2] WIP union hir-lowering and type support
2021-07-22 23:19 union support Mark Wielaard
2021-07-22 23:19 ` [PATCH 1/2] Better union support in the parser Mark Wielaard
@ 2021-07-22 23:19 ` Mark Wielaard
2021-07-23 11:19 ` Philip Herron
1 sibling, 1 reply; 9+ messages in thread
From: Mark Wielaard @ 2021-07-22 23:19 UTC (permalink / raw)
To: gcc-rust; +Cc: Mark Wielaard
Treat a union as a Struct variant like a tuple struct. Add an
iterator and get_identifier functions to the AST Union class. Same
for the HIR Union class, plus a get_generics_params method. Add a
get_is_union method tot the ADTType.
---
gcc/rust/ast/rust-item.h | 11 ++++
gcc/rust/hir/rust-ast-lower-item.h | 51 +++++++++++++++++
gcc/rust/hir/rust-ast-lower-stmt.h | 53 ++++++++++++++++++
gcc/rust/hir/tree/rust-hir-item.h | 16 ++++++
gcc/rust/resolve/rust-ast-resolve-item.h | 22 ++++++++
gcc/rust/resolve/rust-ast-resolve-stmt.h | 32 +++++++++++
gcc/rust/resolve/rust-ast-resolve-toplevel.h | 14 +++++
gcc/rust/typecheck/rust-hir-type-check-stmt.h | 55 ++++++++++++++++++-
.../typecheck/rust-hir-type-check-toplevel.h | 54 +++++++++++++++++-
gcc/rust/typecheck/rust-hir-type-check.cc | 12 +++-
gcc/rust/typecheck/rust-tycheck-dump.h | 6 ++
gcc/rust/typecheck/rust-tyty.cc | 4 +-
gcc/rust/typecheck/rust-tyty.h | 12 ++--
13 files changed, 331 insertions(+), 11 deletions(-)
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index 30cab0ed900..1e928e8111a 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -2489,6 +2489,15 @@ public:
std::vector<StructField> &get_variants () { return variants; }
const std::vector<StructField> &get_variants () const { return variants; }
+ void iterate (std::function<bool (StructField &)> cb)
+ {
+ for (auto &variant : variants)
+ {
+ if (!cb (variant))
+ return;
+ }
+ }
+
std::vector<std::unique_ptr<GenericParam> > &get_generic_params ()
{
return generic_params;
@@ -2505,6 +2514,8 @@ public:
return where_clause;
}
+ Identifier get_identifier () const { return union_name; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
index 5ba59183179..b6af00f6b54 100644
--- a/gcc/rust/hir/rust-ast-lower-item.h
+++ b/gcc/rust/hir/rust-ast-lower-item.h
@@ -192,6 +192,57 @@ public:
struct_decl.get_locus ());
}
+ void visit (AST::Union &union_decl) override
+ {
+ std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+ if (union_decl.has_generics ())
+ {
+ generic_params
+ = lower_generic_params (union_decl.get_generic_params ());
+ }
+
+ std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+ HIR::WhereClause where_clause (std::move (where_clause_items));
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+
+ std::vector<HIR::StructField> variants;
+ union_decl.iterate ([&] (AST::StructField &variant) mutable -> bool {
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+ HIR::Type *type
+ = ASTLoweringType::translate (variant.get_field_type ().get ());
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (
+ crate_num));
+
+ HIR::StructField translated_variant (mapping, variant.get_field_name (),
+ std::unique_ptr<HIR::Type> (type),
+ vis, variant.get_locus (),
+ variant.get_outer_attrs ());
+ variants.push_back (std::move (translated_variant));
+ return true;
+ });
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (crate_num));
+
+ translated
+ = new HIR::Union (mapping, union_decl.get_identifier (), vis,
+ std::move (generic_params), std::move (where_clause),
+ std::move (variants), union_decl.get_outer_attrs (),
+ union_decl.get_locus ());
+
+ mappings->insert_defid_mapping (mapping.get_defid (), translated);
+ mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (),
+ translated);
+ mappings->insert_location (crate_num, mapping.get_hirid (),
+ union_decl.get_locus ());
+ }
+
void visit (AST::StaticItem &var) override
{
HIR::Visibility vis = HIR::Visibility::create_public ();
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
index 9df6b746bb7..2e97ca63a13 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.h
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -215,6 +215,59 @@ public:
struct_decl.get_locus ());
}
+ void visit (AST::Union &union_decl) override
+ {
+ std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+ if (union_decl.has_generics ())
+ {
+ generic_params
+ = lower_generic_params (union_decl.get_generic_params ());
+ }
+
+ std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+ HIR::WhereClause where_clause (std::move (where_clause_items));
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+
+ std::vector<HIR::StructField> variants;
+ union_decl.iterate ([&] (AST::StructField &variant) mutable -> bool {
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+ HIR::Type *type
+ = ASTLoweringType::translate (variant.get_field_type ().get ());
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (
+ crate_num));
+
+ // FIXME
+ // AST::StructField is missing Location info
+ Location variant_locus;
+ HIR::StructField translated_variant (mapping, variant.get_field_name (),
+ std::unique_ptr<HIR::Type> (type),
+ vis, variant_locus,
+ variant.get_outer_attrs ());
+ variants.push_back (std::move (translated_variant));
+ return true;
+ });
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (crate_num));
+
+ translated
+ = new HIR::Union (mapping, union_decl.get_identifier (), vis,
+ std::move (generic_params), std::move (where_clause),
+ std::move (variants), union_decl.get_outer_attrs (),
+ union_decl.get_locus ());
+
+ mappings->insert_hir_stmt (mapping.get_crate_num (), mapping.get_hirid (),
+ translated);
+ mappings->insert_location (crate_num, mapping.get_hirid (),
+ union_decl.get_locus ());
+ }
+
void visit (AST::EmptyStmt &empty) override
{
auto crate_num = mappings->get_current_crate ();
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index e7e110fda92..cfe45d73d85 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -1989,10 +1989,26 @@ public:
Union (Union &&other) = default;
Union &operator= (Union &&other) = default;
+ std::vector<std::unique_ptr<GenericParam> > &get_generic_params ()
+ {
+ return generic_params;
+ }
+
+ Identifier get_identifier () const { return union_name; }
+
Location get_locus () const { return locus; }
void accept_vis (HIRVisitor &vis) override;
+ void iterate (std::function<bool (StructField &)> cb)
+ {
+ for (auto &variant : variants)
+ {
+ if (!cb (variant))
+ return;
+ }
+ }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 0714f5d5706..54f1fe15533 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -260,6 +260,28 @@ public:
resolver->get_type_scope ().pop ();
}
+ void visit (AST::Union &union_decl) override
+ {
+ NodeId scope_node_id = union_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic : union_decl.get_generic_params ())
+ {
+ ResolveGenericParam::go (generic.get (), union_decl.get_node_id ());
+ }
+ }
+
+ union_decl.iterate ([&] (AST::StructField &field) mutable -> bool {
+ ResolveType::go (field.get_field_type ().get (),
+ union_decl.get_node_id ());
+ return true;
+ });
+
+ resolver->get_type_scope ().pop ();
+ }
+
void visit (AST::StaticItem &var) override
{
ResolveType::go (var.get_type ().get (), var.get_node_id ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 210a9fc047d..b6044327b27 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -131,6 +131,38 @@ public:
resolver->get_type_scope ().pop ();
}
+ void visit (AST::Union &union_decl) override
+ {
+ auto path = CanonicalPath::new_seg (union_decl.get_node_id (),
+ union_decl.get_identifier ());
+ resolver->get_type_scope ().insert (
+ path, union_decl.get_node_id (), union_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (union_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId scope_node_id = union_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic : union_decl.get_generic_params ())
+ {
+ ResolveGenericParam::go (generic.get (), union_decl.get_node_id ());
+ }
+ }
+
+ union_decl.iterate ([&] (AST::StructField &field) mutable -> bool {
+ ResolveType::go (field.get_field_type ().get (),
+ union_decl.get_node_id ());
+ return true;
+ });
+
+ resolver->get_type_scope ().pop ();
+ }
+
void visit (AST::Function &function) override
{
auto path = ResolveFunctionItemToCanonicalPath::resolve (function);
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index 9abbb18e080..4df0467b994 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -81,6 +81,20 @@ public:
});
}
+ void visit (AST::Union &union_decl) override
+ {
+ auto path
+ = prefix.append (CanonicalPath::new_seg (union_decl.get_node_id (),
+ union_decl.get_identifier ()));
+ resolver->get_type_scope ().insert (
+ path, union_decl.get_node_id (), union_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (union_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+ }
+
void visit (AST::StaticItem &var) override
{
auto path = prefix.append (
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
index 1b6f47c1595..fad2b7183df 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
@@ -159,7 +159,7 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), true,
+ struct_decl.get_identifier (), true, false,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
@@ -209,13 +209,64 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), false,
+ struct_decl.get_identifier (), false, false,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
infered = type;
}
+ void visit (HIR::Union &union_decl) override
+ {
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic_param : union_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ // Skipping Lifetime completely until better handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::StructFieldType *> variants;
+ union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ variants.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ return true;
+ });
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ union_decl.get_identifier (), false, true,
+ std::move (variants), std::move (substitutions));
+
+ context->insert_type (union_decl.get_mappings (), type);
+ infered = type;
+ }
+
void visit (HIR::Function &function) override
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
index dd3dd751ad6..a723e7e679f 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
@@ -94,7 +94,7 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), true,
+ struct_decl.get_identifier (), true, false,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
@@ -143,12 +143,62 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), false,
+ struct_decl.get_identifier (), false, false,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
}
+ void visit (HIR::Union &union_decl) override
+ {
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic_param : union_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ // Skipping Lifetime completely until better handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::StructFieldType *> variants;
+ union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ variants.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ return true;
+ });
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ union_decl.get_identifier (), false, true,
+ std::move (variants), std::move (substitutions));
+
+ context->insert_type (union_decl.get_mappings (), type);
+ }
+
void visit (HIR::StaticItem &var) override
{
TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index cb2896c0bb4..da528d7878a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -180,7 +180,17 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
// check the arguments are all assigned and fix up the ordering
if (fields_assigned.size () != struct_path_resolved->num_fields ())
{
- if (!struct_expr.has_struct_base ())
+ if (struct_def->get_is_union ())
+ {
+ if (fields_assigned.size () != 1)
+ {
+ rust_error_at (
+ struct_expr.get_locus (),
+ "union must have exactly one field variant assigned");
+ return;
+ }
+ }
+ else if (!struct_expr.has_struct_base ())
{
rust_error_at (struct_expr.get_locus (),
"constructor is missing fields");
diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
index b80372b2a9c..cc2e3c01110 100644
--- a/gcc/rust/typecheck/rust-tycheck-dump.h
+++ b/gcc/rust/typecheck/rust-tycheck-dump.h
@@ -48,6 +48,12 @@ public:
+ "\n";
}
+ void visit (HIR::Union &union_decl) override
+ {
+ dump
+ += indent () + "union " + type_string (union_decl.get_mappings ()) + "\n";
+ }
+
void visit (HIR::ImplBlock &impl_block) override
{
dump += indent () + "impl "
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index f043c7eabda..d059134f8a0 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -517,8 +517,8 @@ ADTType::clone ()
cloned_fields.push_back ((StructFieldType *) f->clone ());
return new ADTType (get_ref (), get_ty_ref (), identifier, get_is_tuple (),
- cloned_fields, clone_substs (), used_arguments,
- get_combined_refs ());
+ get_is_union (), cloned_fields, clone_substs (),
+ used_arguments, get_combined_refs ());
}
ADTType *
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 2152c1b6d76..b7cf46bb783 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -848,7 +848,7 @@ protected:
class ADTType : public BaseType, public SubstitutionRef
{
public:
- ADTType (HirId ref, std::string identifier, bool is_tuple,
+ ADTType (HirId ref, std::string identifier, bool is_tuple, bool is_union,
std::vector<StructFieldType *> fields,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
@@ -856,21 +856,24 @@ public:
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ref, TypeKind::ADT, refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
- identifier (identifier), fields (fields), is_tuple (is_tuple)
+ identifier (identifier), fields (fields), is_tuple (is_tuple),
+ is_union (is_union)
{}
ADTType (HirId ref, HirId ty_ref, std::string identifier, bool is_tuple,
- std::vector<StructFieldType *> fields,
+ bool is_union, std::vector<StructFieldType *> fields,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
= SubstitutionArgumentMappings::error (),
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ty_ref, TypeKind::ADT, refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
- identifier (identifier), fields (fields), is_tuple (is_tuple)
+ identifier (identifier), fields (fields), is_tuple (is_tuple),
+ is_union (is_union)
{}
bool get_is_tuple () { return is_tuple; }
+ bool get_is_union () { return is_union; }
bool is_unit () const override { return this->fields.empty (); }
@@ -957,6 +960,7 @@ private:
std::string identifier;
std::vector<StructFieldType *> fields;
bool is_tuple;
+ bool is_union;
};
class FnType : public BaseType, public SubstitutionRef
--
2.32.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/2] WIP union hir-lowering and type support
2021-07-22 23:19 ` [PATCH 2/2] WIP union hir-lowering and type support Mark Wielaard
@ 2021-07-23 11:19 ` Philip Herron
2021-08-01 11:29 ` Mark Wielaard
0 siblings, 1 reply; 9+ messages in thread
From: Philip Herron @ 2021-07-23 11:19 UTC (permalink / raw)
To: gcc-rust
[-- Attachment #1.1: Type: text/plain, Size: 24182 bytes --]
On 23/07/2021 00:19, Mark Wielaard wrote:
> Treat a union as a Struct variant like a tuple struct. Add an
> iterator and get_identifier functions to the AST Union class. Same
> for the HIR Union class, plus a get_generics_params method. Add a
> get_is_union method tot the ADTType.
> ---
> gcc/rust/ast/rust-item.h | 11 ++++
> gcc/rust/hir/rust-ast-lower-item.h | 51 +++++++++++++++++
> gcc/rust/hir/rust-ast-lower-stmt.h | 53 ++++++++++++++++++
> gcc/rust/hir/tree/rust-hir-item.h | 16 ++++++
> gcc/rust/resolve/rust-ast-resolve-item.h | 22 ++++++++
> gcc/rust/resolve/rust-ast-resolve-stmt.h | 32 +++++++++++
> gcc/rust/resolve/rust-ast-resolve-toplevel.h | 14 +++++
> gcc/rust/typecheck/rust-hir-type-check-stmt.h | 55 ++++++++++++++++++-
> .../typecheck/rust-hir-type-check-toplevel.h | 54 +++++++++++++++++-
> gcc/rust/typecheck/rust-hir-type-check.cc | 12 +++-
> gcc/rust/typecheck/rust-tycheck-dump.h | 6 ++
> gcc/rust/typecheck/rust-tyty.cc | 4 +-
> gcc/rust/typecheck/rust-tyty.h | 12 ++--
> 13 files changed, 331 insertions(+), 11 deletions(-)
>
> diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
> index 30cab0ed900..1e928e8111a 100644
> --- a/gcc/rust/ast/rust-item.h
> +++ b/gcc/rust/ast/rust-item.h
> @@ -2489,6 +2489,15 @@ public:
> std::vector<StructField> &get_variants () { return variants; }
> const std::vector<StructField> &get_variants () const { return variants; }
>
> + void iterate (std::function<bool (StructField &)> cb)
> + {
> + for (auto &variant : variants)
> + {
> + if (!cb (variant))
> + return;
> + }
> + }
> +
> std::vector<std::unique_ptr<GenericParam> > &get_generic_params ()
> {
> return generic_params;
> @@ -2505,6 +2514,8 @@ public:
> return where_clause;
> }
>
> + Identifier get_identifier () const { return union_name; }
> +
> protected:
> /* Use covariance to implement clone function as returning this object
> * rather than base */
> diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
> index 5ba59183179..b6af00f6b54 100644
> --- a/gcc/rust/hir/rust-ast-lower-item.h
> +++ b/gcc/rust/hir/rust-ast-lower-item.h
> @@ -192,6 +192,57 @@ public:
> struct_decl.get_locus ());
> }
>
> + void visit (AST::Union &union_decl) override
> + {
> + std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
> + if (union_decl.has_generics ())
> + {
> + generic_params
> + = lower_generic_params (union_decl.get_generic_params ());
> + }
> +
> + std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
> + HIR::WhereClause where_clause (std::move (where_clause_items));
> + HIR::Visibility vis = HIR::Visibility::create_public ();
> +
> + std::vector<HIR::StructField> variants;
> + union_decl.iterate ([&] (AST::StructField &variant) mutable -> bool {
> + HIR::Visibility vis = HIR::Visibility::create_public ();
> + HIR::Type *type
> + = ASTLoweringType::translate (variant.get_field_type ().get ());
> +
> + auto crate_num = mappings->get_current_crate ();
> + Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
> + mappings->get_next_hir_id (crate_num),
> + mappings->get_next_localdef_id (
> + crate_num));
> +
> + HIR::StructField translated_variant (mapping, variant.get_field_name (),
> + std::unique_ptr<HIR::Type> (type),
> + vis, variant.get_locus (),
> + variant.get_outer_attrs ());
> + variants.push_back (std::move (translated_variant));
> + return true;
> + });
> +
> + auto crate_num = mappings->get_current_crate ();
> + Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
> + mappings->get_next_hir_id (crate_num),
> + mappings->get_next_localdef_id (crate_num));
> +
> + translated
> + = new HIR::Union (mapping, union_decl.get_identifier (), vis,
> + std::move (generic_params), std::move (where_clause),
> + std::move (variants), union_decl.get_outer_attrs (),
> + union_decl.get_locus ());
> +
> + mappings->insert_defid_mapping (mapping.get_defid (), translated);
> + mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (),
> + translated);
> + mappings->insert_location (crate_num, mapping.get_hirid (),
> + union_decl.get_locus ());
> + }
> +
> void visit (AST::StaticItem &var) override
> {
> HIR::Visibility vis = HIR::Visibility::create_public ();
> diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
> index 9df6b746bb7..2e97ca63a13 100644
> --- a/gcc/rust/hir/rust-ast-lower-stmt.h
> +++ b/gcc/rust/hir/rust-ast-lower-stmt.h
> @@ -215,6 +215,59 @@ public:
> struct_decl.get_locus ());
> }
>
> + void visit (AST::Union &union_decl) override
> + {
> + std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
> + if (union_decl.has_generics ())
> + {
> + generic_params
> + = lower_generic_params (union_decl.get_generic_params ());
> + }
> +
> + std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
> + HIR::WhereClause where_clause (std::move (where_clause_items));
> + HIR::Visibility vis = HIR::Visibility::create_public ();
> +
> + std::vector<HIR::StructField> variants;
> + union_decl.iterate ([&] (AST::StructField &variant) mutable -> bool {
> + HIR::Visibility vis = HIR::Visibility::create_public ();
> + HIR::Type *type
> + = ASTLoweringType::translate (variant.get_field_type ().get ());
> +
> + auto crate_num = mappings->get_current_crate ();
> + Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
> + mappings->get_next_hir_id (crate_num),
> + mappings->get_next_localdef_id (
> + crate_num));
> +
> + // FIXME
> + // AST::StructField is missing Location info
> + Location variant_locus;
> + HIR::StructField translated_variant (mapping, variant.get_field_name (),
> + std::unique_ptr<HIR::Type> (type),
> + vis, variant_locus,
> + variant.get_outer_attrs ());
> + variants.push_back (std::move (translated_variant));
> + return true;
> + });
> +
> + auto crate_num = mappings->get_current_crate ();
> + Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
> + mappings->get_next_hir_id (crate_num),
> + mappings->get_next_localdef_id (crate_num));
> +
> + translated
> + = new HIR::Union (mapping, union_decl.get_identifier (), vis,
> + std::move (generic_params), std::move (where_clause),
> + std::move (variants), union_decl.get_outer_attrs (),
> + union_decl.get_locus ());
> +
> + mappings->insert_hir_stmt (mapping.get_crate_num (), mapping.get_hirid (),
> + translated);
> + mappings->insert_location (crate_num, mapping.get_hirid (),
> + union_decl.get_locus ());
> + }
> +
> void visit (AST::EmptyStmt &empty) override
> {
> auto crate_num = mappings->get_current_crate ();
> diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
> index e7e110fda92..cfe45d73d85 100644
> --- a/gcc/rust/hir/tree/rust-hir-item.h
> +++ b/gcc/rust/hir/tree/rust-hir-item.h
> @@ -1989,10 +1989,26 @@ public:
> Union (Union &&other) = default;
> Union &operator= (Union &&other) = default;
>
> + std::vector<std::unique_ptr<GenericParam> > &get_generic_params ()
> + {
> + return generic_params;
> + }
> +
> + Identifier get_identifier () const { return union_name; }
> +
> Location get_locus () const { return locus; }
>
> void accept_vis (HIRVisitor &vis) override;
>
> + void iterate (std::function<bool (StructField &)> cb)
> + {
> + for (auto &variant : variants)
> + {
> + if (!cb (variant))
> + return;
> + }
> + }
> +
> protected:
> /* Use covariance to implement clone function as returning this object
> * rather than base */
> diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
> index 0714f5d5706..54f1fe15533 100644
> --- a/gcc/rust/resolve/rust-ast-resolve-item.h
> +++ b/gcc/rust/resolve/rust-ast-resolve-item.h
> @@ -260,6 +260,28 @@ public:
> resolver->get_type_scope ().pop ();
> }
>
> + void visit (AST::Union &union_decl) override
> + {
> + NodeId scope_node_id = union_decl.get_node_id ();
> + resolver->get_type_scope ().push (scope_node_id);
> +
> + if (union_decl.has_generics ())
> + {
> + for (auto &generic : union_decl.get_generic_params ())
> + {
> + ResolveGenericParam::go (generic.get (), union_decl.get_node_id ());
> + }
> + }
> +
> + union_decl.iterate ([&] (AST::StructField &field) mutable -> bool {
> + ResolveType::go (field.get_field_type ().get (),
> + union_decl.get_node_id ());
> + return true;
> + });
> +
> + resolver->get_type_scope ().pop ();
> + }
> +
> void visit (AST::StaticItem &var) override
> {
> ResolveType::go (var.get_type ().get (), var.get_node_id ());
> diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
> index 210a9fc047d..b6044327b27 100644
> --- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
> +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
> @@ -131,6 +131,38 @@ public:
> resolver->get_type_scope ().pop ();
> }
>
> + void visit (AST::Union &union_decl) override
> + {
> + auto path = CanonicalPath::new_seg (union_decl.get_node_id (),
> + union_decl.get_identifier ());
> + resolver->get_type_scope ().insert (
> + path, union_decl.get_node_id (), union_decl.get_locus (), false,
> + [&] (const CanonicalPath &, NodeId, Location locus) -> void {
> + RichLocation r (union_decl.get_locus ());
> + r.add_range (locus);
> + rust_error_at (r, "redefined multiple times");
> + });
> +
> + NodeId scope_node_id = union_decl.get_node_id ();
> + resolver->get_type_scope ().push (scope_node_id);
> +
> + if (union_decl.has_generics ())
> + {
> + for (auto &generic : union_decl.get_generic_params ())
> + {
> + ResolveGenericParam::go (generic.get (), union_decl.get_node_id ());
> + }
> + }
> +
> + union_decl.iterate ([&] (AST::StructField &field) mutable -> bool {
> + ResolveType::go (field.get_field_type ().get (),
> + union_decl.get_node_id ());
> + return true;
> + });
> +
> + resolver->get_type_scope ().pop ();
> + }
> +
> void visit (AST::Function &function) override
> {
> auto path = ResolveFunctionItemToCanonicalPath::resolve (function);
> diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
> index 9abbb18e080..4df0467b994 100644
> --- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
> +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
> @@ -81,6 +81,20 @@ public:
> });
> }
>
> + void visit (AST::Union &union_decl) override
> + {
> + auto path
> + = prefix.append (CanonicalPath::new_seg (union_decl.get_node_id (),
> + union_decl.get_identifier ()));
> + resolver->get_type_scope ().insert (
> + path, union_decl.get_node_id (), union_decl.get_locus (), false,
> + [&] (const CanonicalPath &, NodeId, Location locus) -> void {
> + RichLocation r (union_decl.get_locus ());
> + r.add_range (locus);
> + rust_error_at (r, "redefined multiple times");
> + });
> + }
> +
> void visit (AST::StaticItem &var) override
> {
> auto path = prefix.append (
> diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
> index 1b6f47c1595..fad2b7183df 100644
> --- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h
> +++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
> @@ -159,7 +159,7 @@ public:
> TyTy::BaseType *type
> = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
> mappings->get_next_hir_id (),
> - struct_decl.get_identifier (), true,
> + struct_decl.get_identifier (), true, false,
> std::move (fields), std::move (substitutions));
>
> context->insert_type (struct_decl.get_mappings (), type);
> @@ -209,13 +209,64 @@ public:
> TyTy::BaseType *type
> = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
> mappings->get_next_hir_id (),
> - struct_decl.get_identifier (), false,
> + struct_decl.get_identifier (), false, false,
> std::move (fields), std::move (substitutions));
>
> context->insert_type (struct_decl.get_mappings (), type);
> infered = type;
> }
>
> + void visit (HIR::Union &union_decl) override
> + {
> + std::vector<TyTy::SubstitutionParamMapping> substitutions;
> + if (union_decl.has_generics ())
> + {
> + for (auto &generic_param : union_decl.get_generic_params ())
> + {
> + switch (generic_param.get ()->get_kind ())
> + {
> + case HIR::GenericParam::GenericKind::LIFETIME:
> + // Skipping Lifetime completely until better handling.
> + break;
> +
> + case HIR::GenericParam::GenericKind::TYPE: {
> + auto param_type
> + = TypeResolveGenericParam::Resolve (generic_param.get ());
> + context->insert_type (generic_param->get_mappings (),
> + param_type);
> +
> + substitutions.push_back (TyTy::SubstitutionParamMapping (
> + static_cast<HIR::TypeParam &> (*generic_param),
> + param_type));
> + }
> + break;
> + }
> + }
> + }
> +
> + std::vector<TyTy::StructFieldType *> variants;
> + union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
> + TyTy::BaseType *variant_type
> + = TypeCheckType::Resolve (variant.get_field_type ().get ());
> + TyTy::StructFieldType *ty_variant
> + = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
> + variant.get_field_name (), variant_type);
> + variants.push_back (ty_variant);
> + context->insert_type (variant.get_mappings (),
> + ty_variant->get_field_type ());
> + return true;
> + });
> +
> + TyTy::BaseType *type
> + = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
> + mappings->get_next_hir_id (),
> + union_decl.get_identifier (), false, true,
> + std::move (variants), std::move (substitutions));
> +
> + context->insert_type (union_decl.get_mappings (), type);
> + infered = type;
> + }
> +
> void visit (HIR::Function &function) override
> {
> std::vector<TyTy::SubstitutionParamMapping> substitutions;
> diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
> index dd3dd751ad6..a723e7e679f 100644
> --- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
> +++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
> @@ -94,7 +94,7 @@ public:
> TyTy::BaseType *type
> = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
> mappings->get_next_hir_id (),
> - struct_decl.get_identifier (), true,
> + struct_decl.get_identifier (), true, false,
> std::move (fields), std::move (substitutions));
>
> context->insert_type (struct_decl.get_mappings (), type);
> @@ -143,12 +143,62 @@ public:
> TyTy::BaseType *type
> = new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
> mappings->get_next_hir_id (),
> - struct_decl.get_identifier (), false,
> + struct_decl.get_identifier (), false, false,
> std::move (fields), std::move (substitutions));
>
> context->insert_type (struct_decl.get_mappings (), type);
> }
>
> + void visit (HIR::Union &union_decl) override
> + {
> + std::vector<TyTy::SubstitutionParamMapping> substitutions;
> + if (union_decl.has_generics ())
> + {
> + for (auto &generic_param : union_decl.get_generic_params ())
> + {
> + switch (generic_param.get ()->get_kind ())
> + {
> + case HIR::GenericParam::GenericKind::LIFETIME:
> + // Skipping Lifetime completely until better handling.
> + break;
> +
> + case HIR::GenericParam::GenericKind::TYPE: {
> + auto param_type
> + = TypeResolveGenericParam::Resolve (generic_param.get ());
> + context->insert_type (generic_param->get_mappings (),
> + param_type);
> +
> + substitutions.push_back (TyTy::SubstitutionParamMapping (
> + static_cast<HIR::TypeParam &> (*generic_param),
> + param_type));
> + }
> + break;
> + }
> + }
> + }
> +
> + std::vector<TyTy::StructFieldType *> variants;
> + union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
> + TyTy::BaseType *variant_type
> + = TypeCheckType::Resolve (variant.get_field_type ().get ());
> + TyTy::StructFieldType *ty_variant
> + = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
> + variant.get_field_name (), variant_type);
> + variants.push_back (ty_variant);
> + context->insert_type (variant.get_mappings (),
> + ty_variant->get_field_type ());
> + return true;
> + });
> +
> + TyTy::BaseType *type
> + = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
> + mappings->get_next_hir_id (),
> + union_decl.get_identifier (), false, true,
> + std::move (variants), std::move (substitutions));
> +
> + context->insert_type (union_decl.get_mappings (), type);
> + }
> +
> void visit (HIR::StaticItem &var) override
> {
> TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
> diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
> index cb2896c0bb4..da528d7878a 100644
> --- a/gcc/rust/typecheck/rust-hir-type-check.cc
> +++ b/gcc/rust/typecheck/rust-hir-type-check.cc
> @@ -180,7 +180,17 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
> // check the arguments are all assigned and fix up the ordering
> if (fields_assigned.size () != struct_path_resolved->num_fields ())
> {
> - if (!struct_expr.has_struct_base ())
> + if (struct_def->get_is_union ())
> + {
> + if (fields_assigned.size () != 1)
> + {
> + rust_error_at (
> + struct_expr.get_locus (),
> + "union must have exactly one field variant assigned");
> + return;
> + }
> + }
> + else if (!struct_expr.has_struct_base ())
> {
> rust_error_at (struct_expr.get_locus (),
> "constructor is missing fields");
> diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
> index b80372b2a9c..cc2e3c01110 100644
> --- a/gcc/rust/typecheck/rust-tycheck-dump.h
> +++ b/gcc/rust/typecheck/rust-tycheck-dump.h
> @@ -48,6 +48,12 @@ public:
> + "\n";
> }
>
> + void visit (HIR::Union &union_decl) override
> + {
> + dump
> + += indent () + "union " + type_string (union_decl.get_mappings ()) + "\n";
> + }
> +
> void visit (HIR::ImplBlock &impl_block) override
> {
> dump += indent () + "impl "
> diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
> index f043c7eabda..d059134f8a0 100644
> --- a/gcc/rust/typecheck/rust-tyty.cc
> +++ b/gcc/rust/typecheck/rust-tyty.cc
> @@ -517,8 +517,8 @@ ADTType::clone ()
> cloned_fields.push_back ((StructFieldType *) f->clone ());
>
> return new ADTType (get_ref (), get_ty_ref (), identifier, get_is_tuple (),
> - cloned_fields, clone_substs (), used_arguments,
> - get_combined_refs ());
> + get_is_union (), cloned_fields, clone_substs (),
> + used_arguments, get_combined_refs ());
> }
>
> ADTType *
> diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
> index 2152c1b6d76..b7cf46bb783 100644
> --- a/gcc/rust/typecheck/rust-tyty.h
> +++ b/gcc/rust/typecheck/rust-tyty.h
> @@ -848,7 +848,7 @@ protected:
> class ADTType : public BaseType, public SubstitutionRef
> {
> public:
> - ADTType (HirId ref, std::string identifier, bool is_tuple,
> + ADTType (HirId ref, std::string identifier, bool is_tuple, bool is_union,
> std::vector<StructFieldType *> fields,
> std::vector<SubstitutionParamMapping> subst_refs,
> SubstitutionArgumentMappings generic_arguments
> @@ -856,21 +856,24 @@ public:
> std::set<HirId> refs = std::set<HirId> ())
> : BaseType (ref, ref, TypeKind::ADT, refs),
> SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
> - identifier (identifier), fields (fields), is_tuple (is_tuple)
> + identifier (identifier), fields (fields), is_tuple (is_tuple),
> + is_union (is_union)
> {}
>
> ADTType (HirId ref, HirId ty_ref, std::string identifier, bool is_tuple,
> - std::vector<StructFieldType *> fields,
> + bool is_union, std::vector<StructFieldType *> fields,
> std::vector<SubstitutionParamMapping> subst_refs,
> SubstitutionArgumentMappings generic_arguments
> = SubstitutionArgumentMappings::error (),
> std::set<HirId> refs = std::set<HirId> ())
> : BaseType (ref, ty_ref, TypeKind::ADT, refs),
> SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
> - identifier (identifier), fields (fields), is_tuple (is_tuple)
> + identifier (identifier), fields (fields), is_tuple (is_tuple),
> + is_union (is_union)
> {}
>
> bool get_is_tuple () { return is_tuple; }
> + bool get_is_union () { return is_union; }
>
> bool is_unit () const override { return this->fields.empty (); }
>
> @@ -957,6 +960,7 @@ private:
> std::string identifier;
> std::vector<StructFieldType *> fields;
> bool is_tuple;
> + bool is_union;
> };
>
> class FnType : public BaseType, public SubstitutionRef
Hi Mark
Nice work Mark, I think this is nearly there. As far as i can tell there
is potentially 1 change to make in the ADTType and 1 more change to the
rust-gcc.cc backend stuff to finish it.
The ADTType is going to be used to represent not just structs and unions
but also enums.
https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html
has a field called flags which looks like a u32 bitfield to have
IS_ENUM, IS_UNION etc it might make sense to turn your is_union flag
into a bitmask now as part of this patch.
The other missing piece is that we need to have another function in
rust-gcc.cc to create the GCC's union_type_node since this will
currently be creating a RECORD_TYPE at the moment.
https://github.com/Rust-GCC/gccrs/blob/44472c580cedd836081c82e621482e479a69729c/gcc/rust/rust-gcc.cc#L1085
I am slightly stuck though since I don't understand the difference
between UNION_TYPE and QUAL_UNION_TYPE:
https://github.com/Rust-GCC/gccrs/blob/master/gcc/tree.def#L216-L222
Maybe someone on the list can give an example between those union types.
When we are able to create the GCC union type we should be able to
create an if statement over inside:
https://github.com/Rust-GCC/gccrs/blob/44472c580cedd836081c82e621482e479a69729c/gcc/rust/backend/rust-compile-context.h#L415
to call union_type or something similar instead of the struct_type.
Moving forward I think this patch looks pretty good to be merged and you
can make another patch to change the is_union flag into a bitmask with
just the IS_UNION piece for now. Then once that's done i would suggest
looking into how the GENERIC part to create the union_type.
I hope some of this makes sense. Nice work.
--Phil
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 665 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 1/2] Better union support in the parser
2021-07-22 23:19 ` [PATCH 1/2] Better union support in the parser Mark Wielaard
@ 2021-07-23 11:19 ` Philip Herron
0 siblings, 0 replies; 9+ messages in thread
From: Philip Herron @ 2021-07-23 11:19 UTC (permalink / raw)
To: gcc-rust
[-- Attachment #1.1: Type: text/plain, Size: 3245 bytes --]
On 23/07/2021 00:19, Mark Wielaard wrote:
> union is a weak keyword which means it isn't reserved and can be used
> as a generic identifier. When we see an identifier where a union could
> be declared we check whether the identifier is "union", but only when
> the next token is also an identifier. In parse_union we shouldn't skip
> the first identifier token, because it is already skipped when we call
> expect_token.
> ---
> gcc/rust/parse/rust-parse-impl.h | 16 ++++++++--------
> 1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
> index bdf1e09a029..3996ef21672 100644
> --- a/gcc/rust/parse/rust-parse-impl.h
> +++ b/gcc/rust/parse/rust-parse-impl.h
> @@ -1083,7 +1083,8 @@ Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
> // crappy hack to do union "keyword"
> case IDENTIFIER:
> // TODO: ensure std::string and literal comparison works
> - if (t->get_str () == "union")
> + if (t->get_str () == "union"
> + && lexer.peek_token (1)->get_id () == IDENTIFIER)
> {
> return parse_vis_item (std::move (outer_attrs));
> // or should this go straight to parsing union?
> @@ -1274,8 +1275,8 @@ Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
> // TODO: implement union keyword but not really because of
> // context-dependence case UNION: crappy hack to do union "keyword"
> case IDENTIFIER:
> - // TODO: ensure std::string and literal comparison works
> - if (t->get_str () == "union")
> + if (t->get_str () == "union"
> + && lexer.peek_token (1)->get_id () == IDENTIFIER)
> {
> return parse_union (std::move (vis), std::move (outer_attrs));
> // or should item switch go straight to parsing union?
> @@ -4524,7 +4525,6 @@ Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
> const_TokenPtr union_keyword = expect_token (IDENTIFIER);
> rust_assert (union_keyword->get_str () == "union");
> Location locus = union_keyword->get_locus ();
> - lexer.skip_token ();
>
> // parse actual union name
> const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
> @@ -6054,8 +6054,8 @@ Parser<ManagedTokenSource>::parse_stmt ()
> break;
> // crappy hack to do union "keyword"
> case IDENTIFIER:
> - // TODO: ensure std::string and literal comparison works
> - if (t->get_str () == "union")
> + if (t->get_str () == "union"
> + && lexer.peek_token (1)->get_id () == IDENTIFIER)
> {
> return parse_vis_item (std::move (outer_attrs));
> // or should this go straight to parsing union?
> @@ -11674,8 +11674,8 @@ Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
> }
> // crappy hack to do union "keyword"
> case IDENTIFIER:
> - // TODO: ensure std::string and literal comparison works
> - if (t->get_str () == "union")
> + if (t->get_str () == "union"
> + && lexer.peek_token (1)->get_id () == IDENTIFIER)
> {
> std::unique_ptr<AST::VisItem> item (
> parse_vis_item (std::move (outer_attrs)));
Looks great, I will merge this now.
--Phil
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 665 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/2] WIP union hir-lowering and type support
2021-07-23 11:19 ` Philip Herron
@ 2021-08-01 11:29 ` Mark Wielaard
2021-08-01 22:37 ` Mark Wielaard
2021-08-04 21:04 ` Mark Wielaard
0 siblings, 2 replies; 9+ messages in thread
From: Mark Wielaard @ 2021-08-01 11:29 UTC (permalink / raw)
To: Philip Herron; +Cc: gcc-rust
[-- Attachment #1: Type: text/plain, Size: 5116 bytes --]
Hi Philip,
On Fri, Jul 23, 2021 at 12:19:18PM +0100, Philip Herron wrote:
> On 23/07/2021 00:19, Mark Wielaard wrote:
> > Treat a union as a Struct variant like a tuple struct. Add an
> > iterator and get_identifier functions to the AST Union class. Same
> > for the HIR Union class, plus a get_generics_params method. Add a
> > get_is_union method tot the ADTType.
> > ---
> [...]
> Nice work Mark, I think this is nearly there. As far as i can tell there
> is potentially 1 change to make in the ADTType and 1 more change to the
> rust-gcc.cc backend stuff to finish it.
Turned out that there was a bit more work to make constructor
expressions (StructExprStruct) work correctly, but it seems the basics
for union support are ok now. Not every pass (type checking) seems to
handle unions yet though. See below.
> The ADTType is going to be used to represent not just structs and unions
> but also enums.
> https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html
> has a field called flags which looks like a u32 bitfield to have
> IS_ENUM, IS_UNION etc it might make sense to turn your is_union flag
> into a bitmask now as part of this patch.
I did add a enum field to distinquish between regular structs, tuple
structs and unions. But I am not sure this abstraction is the easiest
to work with. We will see when we add enum support. structs and tuple
structs are fairly similar and unions and enums also, but they don't
easily combine imho. And if you are treating all abstract data types
the same, then why are tuples separate?
> The other missing piece is that we need to have another function in
> rust-gcc.cc to create the GCC's union_type_node since this will
> currently be creating a RECORD_TYPE at the moment.
>
> https://github.com/Rust-GCC/gccrs/blob/44472c580cedd836081c82e621482e479a69729c/gcc/rust/rust-gcc.cc#L1085
>
> I am slightly stuck though since I don't understand the difference
> between UNION_TYPE and QUAL_UNION_TYPE:
> https://github.com/Rust-GCC/gccrs/blob/master/gcc/tree.def#L216-L222
According to https://gcc.gnu.org/onlinedocs/gccint/Types.html
QUAL_UNION_TYPE is for Ada variant records. Which may be somewhat
similar to Rust enums, but Rust unions seem to be like UNION_TYPEs.
> When we are able to create the GCC union type we should be able to
> create an if statement over inside:
> https://github.com/Rust-GCC/gccrs/blob/44472c580cedd836081c82e621482e479a69729c/gcc/rust/backend/rust-compile-context.h#L415
> to call union_type or something similar instead of the struct_type.
I renamed fill_in_struct to fill_in_fields and handle structs
(RECORD_TYPE) and unions (UNION_TYPE) separately now.
The other thing I needed was to handle constructors in Gcc backend
constructor_expression differently for structs and unions. Unions only
initialize one field. For that I added a union_index to
StructExprStruct to indicate which whether the contructor is for a
union and which field (index) is being initialized. The
TypeCheckStructExpr visitor sets this (and also checks the constructor
only mentions one field and doesn't have a base expression for
unions).
I added two simple testcases to show the basic support for unions
works now. But there are a couple of things that don't work correctly
for unions yet. In particular when enabling warnings for the new
union.rs testcase you'll get:
$ gcc/gccrs -Bgcc -g union.rs
union.rs:18:3: warning: field is never read: ‘f1’
18 | f1: U,
| ^
union.rs:19:3: warning: field is never read: ‘f2’
19 | f2: V
| ^
But those (union) fields in the struct are read. Similarly unused
union fields aren't detected.
And you cannot use unions as function arguments or return values.
This example (sorry for the funny naming, union isn't a keyword, so
you can call basically anything a union, including a union, a union
field, function argument, etc.) doesn't pass the type checker:
union union { union: u32, funion: f32 }
fn funion (union: &union) -> union
{
let v = unsafe { union.union };
union { union: v }
}
pub fn main ()
{
let union = union { union: 1 };
let u = unsafe { union.union };
let f = unsafe { union.funion };
let r = funion (&union);
let _r3 = unsafe { r.union } + unsafe { union.union } + u;
let _f2 = f + unsafe { r.funion };
}
$ gcc/gccrs -Bgcc -g fn_union.rs
fn_union.rs:5:20: error: expected algebraic data type got: [& union{union:Uint:u32:(Ref: 20 TyRef: 3[3,]), funion:Float:f32:(Ref: 23 TyRef: 12[12,])}]
5 | let v = unsafe { union.union };
| ^
fn_union.rs:5:20: error: failed to type resolve expression
fn_union.rs:6:3: error: expected an ADT type for constructor
6 | union { union: v }
| ^
fn_union.rs:3:1: error: expected [union{union:Uint:u32:(Ref: 20 TyRef: 3[3,]), funion:Float:f32:(Ref: 23 TyRef: 12[12,])}] got [<tyty::error>]
3 | fn funion (union: &union) -> union
| ^ ~
But I hope the patch is still useful as basic union support.
Attached and also at
https://code.wildebeest.org/git/user/mjw/gccrs/commit/?h=union
Cheers,
Mark
[-- Attachment #2: 0001-union-support-for-hir-type-checking-and-gcc-backend.patch --]
[-- Type: text/x-diff, Size: 36839 bytes --]
From 389fd74a3f3e9422a965263b6961b51295c55976 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Sun, 1 Aug 2021 12:57:33 +0200
Subject: [PATCH] union support for hir type checking and gcc backend
Treat a union as a Struct variant like a tuple struct. Add an
iterator and get_identifier functions to the AST Union class. Same
for the HIR Union class, plus a get_generics_params method. Add a new
ADTKind enum and adt_kind field to the ADTType to select the
underlying abstract data type (struct struct, tuple struct or union,
with enum as possible future variant).
An union constructor can have only one field. Add an union_index field
to StructExprStruct which is set during type checking in the
TypeCheckStructExpr HIR StructExprStructFields visitor.
For the Gcc_backend class rename fill_in_struct to fill_in_fields and
use it from a new union_type method. Handle union_index in
constructor_expression (so only one field is initialized).
---
gcc/rust/ast/rust-item.h | 11 +++
gcc/rust/backend/rust-compile-context.h | 8 +-
gcc/rust/backend/rust-compile-expr.h | 3 +-
gcc/rust/backend/rust-compile.cc | 2 +-
gcc/rust/hir/rust-ast-lower-item.h | 51 +++++++++++
gcc/rust/hir/rust-ast-lower-stmt.h | 53 +++++++++++
gcc/rust/hir/tree/rust-hir-expr.h | 8 +-
gcc/rust/hir/tree/rust-hir-item.h | 16 ++++
gcc/rust/resolve/rust-ast-resolve-item.h | 22 +++++
gcc/rust/resolve/rust-ast-resolve-stmt.h | 32 +++++++
gcc/rust/resolve/rust-ast-resolve-toplevel.h | 14 +++
gcc/rust/rust-backend.h | 5 +-
gcc/rust/rust-gcc.cc | 91 ++++++++++++++-----
gcc/rust/typecheck/rust-hir-type-check-stmt.h | 58 +++++++++++-
.../typecheck/rust-hir-type-check-toplevel.h | 57 +++++++++++-
gcc/rust/typecheck/rust-hir-type-check.cc | 59 ++++++++----
gcc/rust/typecheck/rust-tycheck-dump.h | 6 ++
gcc/rust/typecheck/rust-tyty.cc | 4 +-
gcc/rust/typecheck/rust-tyty.h | 22 +++--
gcc/testsuite/rust/compile/torture/union.rs | 35 +++++++
.../rust/compile/torture/union_union.rs | 27 ++++++
21 files changed, 529 insertions(+), 55 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/torture/union.rs
create mode 100644 gcc/testsuite/rust/compile/torture/union_union.rs
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index 6d29c5b2e22..5605b0bb79c 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -2489,6 +2489,15 @@ public:
std::vector<StructField> &get_variants () { return variants; }
const std::vector<StructField> &get_variants () const { return variants; }
+ void iterate (std::function<bool (StructField &)> cb)
+ {
+ for (auto &variant : variants)
+ {
+ if (!cb (variant))
+ return;
+ }
+ }
+
std::vector<std::unique_ptr<GenericParam> > &get_generic_params ()
{
return generic_params;
@@ -2505,6 +2514,8 @@ public:
return where_clause;
}
+ Identifier get_identifier () const { return union_name; }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 0aaf084f04f..8007c2fa00d 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -417,9 +417,13 @@ public:
fields.push_back (std::move (f));
}
- Btype *struct_type_record = ctx->get_backend ()->struct_type (fields);
+ Btype *type_record;
+ if (type.is_union ())
+ type_record = ctx->get_backend ()->union_type (fields);
+ else
+ type_record = ctx->get_backend ()->struct_type (fields);
Btype *named_struct
- = ctx->get_backend ()->named_type (type.get_name (), struct_type_record,
+ = ctx->get_backend ()->named_type (type.get_name (), type_record,
ctx->get_mappings ()->lookup_location (
type.get_ty_ref ()));
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index 2a147abcf09..46582954895 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -80,7 +80,7 @@ public:
}
translated
- = ctx->get_backend ()->constructor_expression (tuple_type, vals,
+ = ctx->get_backend ()->constructor_expression (tuple_type, vals, -1,
expr.get_locus ());
}
@@ -595,6 +595,7 @@ public:
translated
= ctx->get_backend ()->constructor_expression (type, vals,
+ struct_expr.union_index,
struct_expr.get_locus ());
}
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index 5ffd11a422c..aa9aa2d90ab 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -79,7 +79,7 @@ CompileExpr::visit (HIR::CallExpr &expr)
});
translated
- = ctx->get_backend ()->constructor_expression (type, vals,
+ = ctx->get_backend ()->constructor_expression (type, vals, -1,
expr.get_locus ());
}
else
diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
index 80ca29859fb..f168c7d3e88 100644
--- a/gcc/rust/hir/rust-ast-lower-item.h
+++ b/gcc/rust/hir/rust-ast-lower-item.h
@@ -193,6 +193,57 @@ public:
struct_decl.get_locus ());
}
+ void visit (AST::Union &union_decl) override
+ {
+ std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+ if (union_decl.has_generics ())
+ {
+ generic_params
+ = lower_generic_params (union_decl.get_generic_params ());
+ }
+
+ std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+ HIR::WhereClause where_clause (std::move (where_clause_items));
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+
+ std::vector<HIR::StructField> variants;
+ union_decl.iterate ([&] (AST::StructField &variant) mutable -> bool {
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+ HIR::Type *type
+ = ASTLoweringType::translate (variant.get_field_type ().get ());
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (
+ crate_num));
+
+ HIR::StructField translated_variant (mapping, variant.get_field_name (),
+ std::unique_ptr<HIR::Type> (type),
+ vis, variant.get_locus (),
+ variant.get_outer_attrs ());
+ variants.push_back (std::move (translated_variant));
+ return true;
+ });
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (crate_num));
+
+ translated
+ = new HIR::Union (mapping, union_decl.get_identifier (), vis,
+ std::move (generic_params), std::move (where_clause),
+ std::move (variants), union_decl.get_outer_attrs (),
+ union_decl.get_locus ());
+
+ mappings->insert_defid_mapping (mapping.get_defid (), translated);
+ mappings->insert_hir_item (mapping.get_crate_num (), mapping.get_hirid (),
+ translated);
+ mappings->insert_location (crate_num, mapping.get_hirid (),
+ union_decl.get_locus ());
+ }
+
void visit (AST::StaticItem &var) override
{
HIR::Visibility vis = HIR::Visibility::create_public ();
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
index 9df6b746bb7..2e97ca63a13 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.h
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -215,6 +215,59 @@ public:
struct_decl.get_locus ());
}
+ void visit (AST::Union &union_decl) override
+ {
+ std::vector<std::unique_ptr<HIR::GenericParam> > generic_params;
+ if (union_decl.has_generics ())
+ {
+ generic_params
+ = lower_generic_params (union_decl.get_generic_params ());
+ }
+
+ std::vector<std::unique_ptr<HIR::WhereClauseItem> > where_clause_items;
+ HIR::WhereClause where_clause (std::move (where_clause_items));
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+
+ std::vector<HIR::StructField> variants;
+ union_decl.iterate ([&] (AST::StructField &variant) mutable -> bool {
+ HIR::Visibility vis = HIR::Visibility::create_public ();
+ HIR::Type *type
+ = ASTLoweringType::translate (variant.get_field_type ().get ());
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, variant.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (
+ crate_num));
+
+ // FIXME
+ // AST::StructField is missing Location info
+ Location variant_locus;
+ HIR::StructField translated_variant (mapping, variant.get_field_name (),
+ std::unique_ptr<HIR::Type> (type),
+ vis, variant_locus,
+ variant.get_outer_attrs ());
+ variants.push_back (std::move (translated_variant));
+ return true;
+ });
+
+ auto crate_num = mappings->get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (),
+ mappings->get_next_hir_id (crate_num),
+ mappings->get_next_localdef_id (crate_num));
+
+ translated
+ = new HIR::Union (mapping, union_decl.get_identifier (), vis,
+ std::move (generic_params), std::move (where_clause),
+ std::move (variants), union_decl.get_outer_attrs (),
+ union_decl.get_locus ());
+
+ mappings->insert_hir_stmt (mapping.get_crate_num (), mapping.get_hirid (),
+ translated);
+ mappings->insert_location (crate_num, mapping.get_hirid (),
+ union_decl.get_locus ());
+ }
+
void visit (AST::EmptyStmt &empty) override
{
auto crate_num = mappings->get_current_crate ();
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index 65c40d60bdf..8d815c5adc6 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -1449,6 +1449,10 @@ public:
// FIXME make unique_ptr
StructBase *struct_base;
+ // For unions there is just one field, the index
+ // is set when type checking
+ int union_index = -1;
+
std::string as_string () const override;
bool has_struct_base () const { return struct_base != nullptr; }
@@ -1467,7 +1471,8 @@ public:
// copy constructor with vector clone
StructExprStructFields (StructExprStructFields const &other)
- : StructExprStruct (other), struct_base (other.struct_base)
+ : StructExprStruct (other), struct_base (other.struct_base),
+ union_index (other.union_index)
{
fields.reserve (other.fields.size ());
for (const auto &e : other.fields)
@@ -1479,6 +1484,7 @@ public:
{
StructExprStruct::operator= (other);
struct_base = other.struct_base;
+ union_index = other.union_index;
fields.reserve (other.fields.size ());
for (const auto &e : other.fields)
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 7d976c5c991..182fe87a6b9 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -1989,10 +1989,26 @@ public:
Union (Union &&other) = default;
Union &operator= (Union &&other) = default;
+ std::vector<std::unique_ptr<GenericParam> > &get_generic_params ()
+ {
+ return generic_params;
+ }
+
+ Identifier get_identifier () const { return union_name; }
+
Location get_locus () const { return locus; }
void accept_vis (HIRVisitor &vis) override;
+ void iterate (std::function<bool (StructField &)> cb)
+ {
+ for (auto &variant : variants)
+ {
+ if (!cb (variant))
+ return;
+ }
+ }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h
index 539229d60fa..c67121d72f9 100644
--- a/gcc/rust/resolve/rust-ast-resolve-item.h
+++ b/gcc/rust/resolve/rust-ast-resolve-item.h
@@ -260,6 +260,28 @@ public:
resolver->get_type_scope ().pop ();
}
+ void visit (AST::Union &union_decl) override
+ {
+ NodeId scope_node_id = union_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic : union_decl.get_generic_params ())
+ {
+ ResolveGenericParam::go (generic.get (), union_decl.get_node_id ());
+ }
+ }
+
+ union_decl.iterate ([&] (AST::StructField &field) mutable -> bool {
+ ResolveType::go (field.get_field_type ().get (),
+ union_decl.get_node_id ());
+ return true;
+ });
+
+ resolver->get_type_scope ().pop ();
+ }
+
void visit (AST::StaticItem &var) override
{
ResolveType::go (var.get_type ().get (), var.get_node_id ());
diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h
index 210a9fc047d..b6044327b27 100644
--- a/gcc/rust/resolve/rust-ast-resolve-stmt.h
+++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h
@@ -131,6 +131,38 @@ public:
resolver->get_type_scope ().pop ();
}
+ void visit (AST::Union &union_decl) override
+ {
+ auto path = CanonicalPath::new_seg (union_decl.get_node_id (),
+ union_decl.get_identifier ());
+ resolver->get_type_scope ().insert (
+ path, union_decl.get_node_id (), union_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (union_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId scope_node_id = union_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic : union_decl.get_generic_params ())
+ {
+ ResolveGenericParam::go (generic.get (), union_decl.get_node_id ());
+ }
+ }
+
+ union_decl.iterate ([&] (AST::StructField &field) mutable -> bool {
+ ResolveType::go (field.get_field_type ().get (),
+ union_decl.get_node_id ());
+ return true;
+ });
+
+ resolver->get_type_scope ().pop ();
+ }
+
void visit (AST::Function &function) override
{
auto path = ResolveFunctionItemToCanonicalPath::resolve (function);
diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
index a042f5c3dcb..57a0534de48 100644
--- a/gcc/rust/resolve/rust-ast-resolve-toplevel.h
+++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h
@@ -81,6 +81,20 @@ public:
});
}
+ void visit (AST::Union &union_decl) override
+ {
+ auto path
+ = prefix.append (CanonicalPath::new_seg (union_decl.get_node_id (),
+ union_decl.get_identifier ()));
+ resolver->get_type_scope ().insert (
+ path, union_decl.get_node_id (), union_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (union_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+ }
+
void visit (AST::StaticItem &var) override
{
auto path = prefix.append (
diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h
index be23fd3d852..4635796e953 100644
--- a/gcc/rust/rust-backend.h
+++ b/gcc/rust/rust-backend.h
@@ -178,6 +178,9 @@ public:
// Get a struct type.
virtual Btype *struct_type (const std::vector<Btyped_identifier> &fields) = 0;
+ // Get a union type.
+ virtual Btype *union_type (const std::vector<Btyped_identifier> &fields) = 0;
+
// Get an array type.
virtual Btype *array_type (Btype *element_type, Bexpression *length) = 0;
@@ -424,7 +427,7 @@ public:
// corresponding fields in BTYPE.
virtual Bexpression *
constructor_expression (Btype *btype, const std::vector<Bexpression *> &vals,
- Location)
+ int, Location)
= 0;
// Return an expression that constructs an array of BTYPE with INDEXES and
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 44617a68d2a..3e47a7cba7a 100644
--- a/gcc/rust/rust-gcc.cc
+++ b/gcc/rust/rust-gcc.cc
@@ -265,6 +265,8 @@ public:
Btype *struct_type (const std::vector<Btyped_identifier> &);
+ Btype *union_type (const std::vector<Btyped_identifier> &);
+
Btype *array_type (Btype *, Bexpression *);
Btype *placeholder_pointer_type (const std::string &, Location, bool);
@@ -377,7 +379,7 @@ public:
Location);
Bexpression *constructor_expression (Btype *,
- const std::vector<Bexpression *> &,
+ const std::vector<Bexpression *> &, int,
Location);
Bexpression *array_constructor_expression (Btype *,
@@ -531,7 +533,7 @@ private:
Bfunction *make_function (tree t) { return new Bfunction (t); }
- Btype *fill_in_struct (Btype *, const std::vector<Btyped_identifier> &);
+ Btype *fill_in_fields (Btype *, const std::vector<Btyped_identifier> &);
Btype *fill_in_array (Btype *, Btype *, Bexpression *);
@@ -1145,14 +1147,23 @@ Gcc_backend::function_ptr_type (Btype *result_type,
Btype *
Gcc_backend::struct_type (const std::vector<Btyped_identifier> &fields)
{
- return this->fill_in_struct (this->make_type (make_node (RECORD_TYPE)),
+ return this->fill_in_fields (this->make_type (make_node (RECORD_TYPE)),
+ fields);
+}
+
+// Make a union type.
+
+Btype *
+Gcc_backend::union_type (const std::vector<Btyped_identifier> &fields)
+{
+ return this->fill_in_fields (this->make_type (make_node (UNION_TYPE)),
fields);
}
-// Fill in the fields of a struct type.
+// Fill in the fields of a struct or union type.
Btype *
-Gcc_backend::fill_in_struct (Btype *fill,
+Gcc_backend::fill_in_fields (Btype *fill,
const std::vector<Btyped_identifier> &fields)
{
tree fill_tree = fill->get_tree ();
@@ -1311,7 +1322,7 @@ Gcc_backend::set_placeholder_struct_type (
{
tree t = placeholder->get_tree ();
gcc_assert (TREE_CODE (t) == RECORD_TYPE && TYPE_FIELDS (t) == NULL_TREE);
- Btype *r = this->fill_in_struct (placeholder, fields);
+ Btype *r = this->fill_in_fields (placeholder, fields);
if (TYPE_NAME (t) != NULL_TREE)
{
@@ -1321,7 +1332,7 @@ Gcc_backend::set_placeholder_struct_type (
DECL_ORIGINAL_TYPE (TYPE_NAME (t)) = copy;
TYPE_SIZE (copy) = NULL_TREE;
Btype *bc = this->make_type (copy);
- this->fill_in_struct (bc, fields);
+ this->fill_in_fields (bc, fields);
delete bc;
}
@@ -1758,7 +1769,8 @@ Gcc_backend::struct_field_expression (Bexpression *bstruct, size_t index,
if (struct_tree == error_mark_node
|| TREE_TYPE (struct_tree) == error_mark_node)
return this->error_expression ();
- gcc_assert (TREE_CODE (TREE_TYPE (struct_tree)) == RECORD_TYPE);
+ gcc_assert (TREE_CODE (TREE_TYPE (struct_tree)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (struct_tree)) == UNION_TYPE);
tree field = TYPE_FIELDS (TREE_TYPE (struct_tree));
if (field == NULL_TREE)
{
@@ -2041,7 +2053,7 @@ Gcc_backend::lazy_boolean_expression (LazyBooleanOperator op, Bexpression *left,
Bexpression *
Gcc_backend::constructor_expression (Btype *btype,
const std::vector<Bexpression *> &vals,
- Location location)
+ int union_index, Location location)
{
tree type_tree = btype->get_tree ();
if (type_tree == error_mark_node)
@@ -2053,11 +2065,15 @@ Gcc_backend::constructor_expression (Btype *btype,
tree sink = NULL_TREE;
bool is_constant = true;
tree field = TYPE_FIELDS (type_tree);
- for (std::vector<Bexpression *>::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)->get_tree ();
+ gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
+ tree val = vals.front ()->get_tree ();
+ 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 ();
@@ -2070,17 +2086,49 @@ Gcc_backend::constructor_expression (Btype *btype,
// 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<Bexpression *>::const_iterator p = vals.begin ();
+ p != vals.end (); ++p, field = DECL_CHAIN (field))
+ {
+ gcc_assert (field != NULL_TREE);
+ tree val = (*p)->get_tree ();
+ if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
+ || TREE_TYPE (val) == error_mark_node)
+ return this->error_expression ();
- 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;
+ 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;
+ }
+ gcc_assert (field == NULL_TREE);
}
- gcc_assert (field == NULL_TREE);
tree ret = build_constructor (type_tree, init);
if (is_constant)
TREE_CONSTANT (ret) = 1;
@@ -2781,6 +2829,7 @@ Gcc_backend::convert_tree (tree type_tree, tree expr_tree, Location location)
|| SCALAR_FLOAT_TYPE_P (type_tree) || COMPLEX_FLOAT_TYPE_P (type_tree))
return fold_convert_loc (location.gcc_location (), type_tree, expr_tree);
else if (TREE_CODE (type_tree) == RECORD_TYPE
+ || TREE_CODE (type_tree) == UNION_TYPE
|| TREE_CODE (type_tree) == ARRAY_TYPE)
{
gcc_assert (int_size_in_bytes (type_tree)
diff --git a/gcc/rust/typecheck/rust-hir-type-check-stmt.h b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
index 1b6f47c1595..77cbc0628ef 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-stmt.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-stmt.h
@@ -159,7 +159,8 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), true,
+ struct_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::TUPLE_STRUCT,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
@@ -209,13 +210,66 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), false,
+ struct_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::STRUCT_STRUCT,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
infered = type;
}
+ void visit (HIR::Union &union_decl) override
+ {
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic_param : union_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ // Skipping Lifetime completely until better handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::StructFieldType *> variants;
+ union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ variants.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ return true;
+ });
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ union_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::UNION, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (union_decl.get_mappings (), type);
+ infered = type;
+ }
+
void visit (HIR::Function &function) override
{
std::vector<TyTy::SubstitutionParamMapping> substitutions;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
index 18f3e725416..5b9757f6519 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-toplevel.h
@@ -94,7 +94,8 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), true,
+ struct_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::TUPLE_STRUCT,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
@@ -143,12 +144,64 @@ public:
TyTy::BaseType *type
= new TyTy::ADTType (struct_decl.get_mappings ().get_hirid (),
mappings->get_next_hir_id (),
- struct_decl.get_identifier (), false,
+ struct_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::STRUCT_STRUCT,
std::move (fields), std::move (substitutions));
context->insert_type (struct_decl.get_mappings (), type);
}
+ void visit (HIR::Union &union_decl) override
+ {
+ std::vector<TyTy::SubstitutionParamMapping> substitutions;
+ if (union_decl.has_generics ())
+ {
+ for (auto &generic_param : union_decl.get_generic_params ())
+ {
+ switch (generic_param.get ()->get_kind ())
+ {
+ case HIR::GenericParam::GenericKind::LIFETIME:
+ // Skipping Lifetime completely until better handling.
+ break;
+
+ case HIR::GenericParam::GenericKind::TYPE: {
+ auto param_type
+ = TypeResolveGenericParam::Resolve (generic_param.get ());
+ context->insert_type (generic_param->get_mappings (),
+ param_type);
+
+ substitutions.push_back (TyTy::SubstitutionParamMapping (
+ static_cast<HIR::TypeParam &> (*generic_param),
+ param_type));
+ }
+ break;
+ }
+ }
+ }
+
+ std::vector<TyTy::StructFieldType *> variants;
+ union_decl.iterate ([&] (HIR::StructField &variant) mutable -> bool {
+ TyTy::BaseType *variant_type
+ = TypeCheckType::Resolve (variant.get_field_type ().get ());
+ TyTy::StructFieldType *ty_variant
+ = new TyTy::StructFieldType (variant.get_mappings ().get_hirid (),
+ variant.get_field_name (), variant_type);
+ variants.push_back (ty_variant);
+ context->insert_type (variant.get_mappings (),
+ ty_variant->get_field_type ());
+ return true;
+ });
+
+ TyTy::BaseType *type
+ = new TyTy::ADTType (union_decl.get_mappings ().get_hirid (),
+ mappings->get_next_hir_id (),
+ union_decl.get_identifier (),
+ TyTy::ADTType::ADTKind::UNION, std::move (variants),
+ std::move (substitutions));
+
+ context->insert_type (union_decl.get_mappings (), type);
+ }
+
void visit (HIR::StaticItem &var) override
{
TyTy::BaseType *type = TypeCheckType::Resolve (var.get_type ());
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index cb2896c0bb4..66adfcb5131 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -180,7 +180,17 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
// check the arguments are all assigned and fix up the ordering
if (fields_assigned.size () != struct_path_resolved->num_fields ())
{
- if (!struct_expr.has_struct_base ())
+ if (struct_def->is_union ())
+ {
+ if (fields_assigned.size () != 1 || struct_expr.has_struct_base ())
+ {
+ rust_error_at (
+ struct_expr.get_locus (),
+ "union must have exactly one field variant assigned");
+ return;
+ }
+ }
+ else if (!struct_expr.has_struct_base ())
{
rust_error_at (struct_expr.get_locus (),
"constructor is missing fields");
@@ -236,23 +246,40 @@ TypeCheckStructExpr::visit (HIR::StructExprStructFields &struct_expr)
}
}
- // everything is ok, now we need to ensure all field values are ordered
- // correctly. The GIMPLE backend uses a simple algorithm that assumes each
- // assigned field in the constructor is in the same order as the field in
- // the type
-
- std::vector<std::unique_ptr<HIR::StructExprField> > expr_fields
- = struct_expr.get_fields_as_owner ();
- for (auto &f : expr_fields)
- f.release ();
-
- std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
- for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
+ if (struct_def->is_union ())
+ {
+ // There is exactly one field in this constructor, we need to
+ // figure out the field index to make sure we initialize the
+ // right union field.
+ for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
+ {
+ if (adtFieldIndexToField[i])
+ {
+ struct_expr.union_index = i;
+ break;
+ }
+ }
+ rust_assert (struct_expr.union_index != -1);
+ }
+ else
{
- ordered_fields.push_back (
- std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
+ // everything is ok, now we need to ensure all field values are ordered
+ // correctly. The GIMPLE backend uses a simple algorithm that assumes each
+ // assigned field in the constructor is in the same order as the field in
+ // the type
+ std::vector<std::unique_ptr<HIR::StructExprField> > expr_fields
+ = struct_expr.get_fields_as_owner ();
+ for (auto &f : expr_fields)
+ f.release ();
+
+ std::vector<std::unique_ptr<HIR::StructExprField> > ordered_fields;
+ for (size_t i = 0; i < adtFieldIndexToField.size (); i++)
+ {
+ ordered_fields.push_back (
+ std::unique_ptr<HIR::StructExprField> (adtFieldIndexToField[i]));
+ }
+ struct_expr.set_fields_as_owner (std::move (ordered_fields));
}
- struct_expr.set_fields_as_owner (std::move (ordered_fields));
resolved = struct_def;
}
diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h
index b80372b2a9c..cc2e3c01110 100644
--- a/gcc/rust/typecheck/rust-tycheck-dump.h
+++ b/gcc/rust/typecheck/rust-tycheck-dump.h
@@ -48,6 +48,12 @@ public:
+ "\n";
}
+ void visit (HIR::Union &union_decl) override
+ {
+ dump
+ += indent () + "union " + type_string (union_decl.get_mappings ()) + "\n";
+ }
+
void visit (HIR::ImplBlock &impl_block) override
{
dump += indent () + "impl "
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 1ca28fae061..6bac7647ec6 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -537,7 +537,7 @@ ADTType::clone ()
for (auto &f : fields)
cloned_fields.push_back ((StructFieldType *) f->clone ());
- return new ADTType (get_ref (), get_ty_ref (), identifier, get_is_tuple (),
+ return new ADTType (get_ref (), get_ty_ref (), identifier, get_adt_kind (),
cloned_fields, clone_substs (), used_arguments,
get_combined_refs ());
}
@@ -1999,7 +1999,7 @@ PlaceholderType::clone ()
void
TypeCheckCallExpr::visit (ADTType &type)
{
- if (!type.get_is_tuple ())
+ if (!type.is_tuple_struct ())
{
rust_error_at (
call.get_locus (),
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index 336d42b15f9..46110e4a9a7 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -855,7 +855,15 @@ protected:
class ADTType : public BaseType, public SubstitutionRef
{
public:
- ADTType (HirId ref, std::string identifier, bool is_tuple,
+ enum ADTKind
+ {
+ STRUCT_STRUCT,
+ TUPLE_STRUCT,
+ UNION,
+ // ENUM ?
+ };
+
+ ADTType (HirId ref, std::string identifier, ADTKind adt_kind,
std::vector<StructFieldType *> fields,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
@@ -863,10 +871,10 @@ public:
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ref, TypeKind::ADT, refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
- identifier (identifier), fields (fields), is_tuple (is_tuple)
+ identifier (identifier), fields (fields), adt_kind (adt_kind)
{}
- ADTType (HirId ref, HirId ty_ref, std::string identifier, bool is_tuple,
+ ADTType (HirId ref, HirId ty_ref, std::string identifier, ADTKind adt_kind,
std::vector<StructFieldType *> fields,
std::vector<SubstitutionParamMapping> subst_refs,
SubstitutionArgumentMappings generic_arguments
@@ -874,10 +882,12 @@ public:
std::set<HirId> refs = std::set<HirId> ())
: BaseType (ref, ty_ref, TypeKind::ADT, refs),
SubstitutionRef (std::move (subst_refs), std::move (generic_arguments)),
- identifier (identifier), fields (fields), is_tuple (is_tuple)
+ identifier (identifier), fields (fields), adt_kind (adt_kind)
{}
- bool get_is_tuple () { return is_tuple; }
+ ADTKind get_adt_kind () { return adt_kind; }
+ bool is_tuple_struct () { return adt_kind == TUPLE_STRUCT; }
+ bool is_union () { return adt_kind == UNION; }
bool is_unit () const override { return this->fields.empty (); }
@@ -964,7 +974,7 @@ public:
private:
std::string identifier;
std::vector<StructFieldType *> fields;
- bool is_tuple;
+ ADTType::ADTKind adt_kind;
};
class FnType : public BaseType, public SubstitutionRef
diff --git a/gcc/testsuite/rust/compile/torture/union.rs b/gcc/testsuite/rust/compile/torture/union.rs
new file mode 100644
index 00000000000..393e59115a7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/union.rs
@@ -0,0 +1,35 @@
+// { dg-do compile }
+// { dg-options "-w" }
+
+union U
+{
+ f1: u8
+}
+
+union V
+{
+ f1: u8,
+ f2: u16,
+ f3: i32,
+}
+
+struct S
+{
+ f1: U,
+ f2: V
+}
+
+fn main ()
+{
+ let u = U { f1: 16 };
+ let v = V { f2: 365 };
+ let s = S { f1: u, f2: v };
+ let _v125 = unsafe
+ { let mut uv: u64;
+ uv = s.f1.f1 as u64;
+ uv += s.f2.f1 as u64;
+ uv += s.f2.f2 as u64;
+ uv -= s.f2.f3 as u64;
+ uv
+ };
+}
diff --git a/gcc/testsuite/rust/compile/torture/union_union.rs b/gcc/testsuite/rust/compile/torture/union_union.rs
new file mode 100644
index 00000000000..9feb145a692
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/union_union.rs
@@ -0,0 +1,27 @@
+union union
+{
+ union: u32,
+ inion: i32,
+ u8ion: u8,
+ i64on: i64,
+ u64on: u64
+}
+
+pub fn main ()
+{
+ let union = union { union: 2 };
+ let inion = union { inion: -2 };
+ let mut mnion = union { inion: -16 };
+ let m1 = unsafe { mnion.union };
+ unsafe { mnion.union = union.union };
+ let m2 = unsafe { mnion.inion };
+ let u1 = unsafe { union.union };
+ let i1 = unsafe { union.inion };
+ let u2 = unsafe { inion.union };
+ let i2 = unsafe { inion.inion };
+ let _r1 = u2 - u1 - m1;
+ let _r2 = i1 + i2 + m2;
+ let _u8 = unsafe { union.u8ion };
+ let _i64 = unsafe { union.i64on };
+ let _u64 = unsafe { union.u64on };
+}
--
2.32.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/2] WIP union hir-lowering and type support
2021-08-01 11:29 ` Mark Wielaard
@ 2021-08-01 22:37 ` Mark Wielaard
2021-08-02 12:33 ` Thomas Schwinge
2021-08-04 21:04 ` Mark Wielaard
1 sibling, 1 reply; 9+ messages in thread
From: Mark Wielaard @ 2021-08-01 22:37 UTC (permalink / raw)
To: Philip Herron; +Cc: gcc-rust
[-- Attachment #1: Type: text/plain, Size: 1122 bytes --]
On Sun, Aug 01, 2021 at 01:29:16PM +0200, Mark Wielaard wrote:
> I added two simple testcases to show the basic support for unions
> works now. But there are a couple of things that don't work correctly
> for unions yet. In particular when enabling warnings for the new
> union.rs testcase you'll get:
>
> $ gcc/gccrs -Bgcc -g union.rs
> union.rs:18:3: warning: field is never read: ‘f1’
> 18 | f1: U,
> | ^
> union.rs:19:3: warning: field is never read: ‘f2’
> 19 | f2: V
> | ^
>
> But those (union) fields in the struct are read. Similarly unused
> union fields aren't detected.
This is why the testcase uses { dg-options "-w" } to suppress all
warnings.
Attached is a small followup patch to resolve two FIXMEs to add the
correct locus for the Union variant fields (the actual fixme was fixed
by Thomas Young in commit 6d7b87f9dd92 "make struct field carry the
location info"). But it was missing TupleField and (obviously)
Union variants since those weren't implemented yet.
Also on
https://code.wildebeest.org/git/user/mjw/gccrs/commit/?h=tuple-union-field-locus
Cheers,
Mark
[-- Attachment #2: 0001-Add-locus-to-TupleField-and-pass-it-and-union-varian.patch --]
[-- Type: text/x-diff, Size: 5635 bytes --]
From cd67e5d5f138dbdff4ec859e4020e8091cb03aa7 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <mark@klomp.org>
Date: Mon, 2 Aug 2021 00:33:02 +0200
Subject: [PATCH] Add locus to TupleField and pass it and union variants to HIR
class
TupleField was missing a Location field and we dropped to locus when
lowering Union fields to HIR.
---
gcc/rust/ast/rust-item.h | 16 ++++++++++------
gcc/rust/hir/rust-ast-lower-item.h | 6 ++----
gcc/rust/hir/rust-ast-lower-stmt.h | 11 +++--------
gcc/rust/parse/rust-parse-impl.h | 4 +++-
4 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index 5605b0bb79c..6b0021a8b11 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -2002,9 +2002,10 @@ private:
std::unique_ptr<Type> field_type;
- // should this store location info?
NodeId node_id;
+ Location locus;
+
public:
// Returns whether tuple field has outer attributes.
bool has_outer_attributes () const { return !outer_attrs.empty (); }
@@ -2014,17 +2015,17 @@ public:
bool has_visibility () const { return !visibility.is_error (); }
// Complete constructor
- TupleField (std::unique_ptr<Type> field_type, Visibility vis,
+ TupleField (std::unique_ptr<Type> field_type, Visibility vis, Location locus,
std::vector<Attribute> outer_attrs = std::vector<Attribute> ())
: outer_attrs (std::move (outer_attrs)), visibility (std::move (vis)),
field_type (std::move (field_type)),
- node_id (Analysis::Mappings::get ()->get_next_node_id ())
+ node_id (Analysis::Mappings::get ()->get_next_node_id ()), locus (locus)
{}
// Copy constructor with clone
TupleField (TupleField const &other)
: outer_attrs (other.outer_attrs), visibility (other.visibility),
- node_id (other.node_id)
+ node_id (other.node_id), locus (other.locus)
{
// guard to prevent null dereference (only required if error)
if (other.field_type != nullptr)
@@ -2039,6 +2040,7 @@ public:
visibility = other.visibility;
outer_attrs = other.outer_attrs;
node_id = other.node_id;
+ locus = other.locus;
// guard to prevent null dereference (only required if error)
if (other.field_type != nullptr)
@@ -2059,12 +2061,14 @@ public:
// Creates an error state tuple field.
static TupleField create_error ()
{
- return TupleField (nullptr, Visibility::create_error ());
+ return TupleField (nullptr, Visibility::create_error (), Location ());
}
std::string as_string () const;
- NodeId get_node_id () const { return node_id; };
+ NodeId get_node_id () const { return node_id; }
+
+ Location get_locus () const { return locus; }
// TODO: this mutable getter seems really dodgy. Think up better way.
std::vector<Attribute> &get_outer_attrs () { return outer_attrs; }
diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h
index f168c7d3e88..d49d2b22bf0 100644
--- a/gcc/rust/hir/rust-ast-lower-item.h
+++ b/gcc/rust/hir/rust-ast-lower-item.h
@@ -111,12 +111,10 @@ public:
mappings->get_next_localdef_id (
crate_num));
- // FIXME
- // AST::TupleField is missing Location info
- Location field_locus;
HIR::TupleField translated_field (mapping,
std::unique_ptr<HIR::Type> (type), vis,
- field_locus, field.get_outer_attrs ());
+ field.get_locus (),
+ field.get_outer_attrs ());
fields.push_back (std::move (translated_field));
return true;
});
diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h
index 2e97ca63a13..c4c00ac0bee 100644
--- a/gcc/rust/hir/rust-ast-lower-stmt.h
+++ b/gcc/rust/hir/rust-ast-lower-stmt.h
@@ -187,12 +187,10 @@ public:
mappings->get_next_localdef_id (
crate_num));
- // FIXME
- // AST::StructField is missing Location info
- Location field_locus;
HIR::StructField translated_field (mapping, field.get_field_name (),
std::unique_ptr<HIR::Type> (type), vis,
- field_locus, field.get_outer_attrs ());
+ field.get_locus (),
+ field.get_outer_attrs ());
fields.push_back (std::move (translated_field));
return true;
});
@@ -240,12 +238,9 @@ public:
mappings->get_next_localdef_id (
crate_num));
- // FIXME
- // AST::StructField is missing Location info
- Location variant_locus;
HIR::StructField translated_variant (mapping, variant.get_field_name (),
std::unique_ptr<HIR::Type> (type),
- vis, variant_locus,
+ vis, variant.get_locus (),
variant.get_outer_attrs ());
variants.push_back (std::move (translated_variant));
return true;
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index 122a3c361b0..9eb212b4e72 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -4295,6 +4295,8 @@ Parser<ManagedTokenSource>::parse_tuple_field ()
// parse visibility if it exists
AST::Visibility vis = parse_visibility ();
+ Location locus = lexer.peek_token ()->get_locus ();
+
// parse type, which is required
std::unique_ptr<AST::Type> field_type = parse_type ();
if (field_type == nullptr)
@@ -4308,7 +4310,7 @@ Parser<ManagedTokenSource>::parse_tuple_field ()
return AST::TupleField::create_error ();
}
- return AST::TupleField (std::move (field_type), std::move (vis),
+ return AST::TupleField (std::move (field_type), std::move (vis), locus,
std::move (outer_attrs));
}
--
2.32.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/2] WIP union hir-lowering and type support
2021-08-01 22:37 ` Mark Wielaard
@ 2021-08-02 12:33 ` Thomas Schwinge
0 siblings, 0 replies; 9+ messages in thread
From: Thomas Schwinge @ 2021-08-02 12:33 UTC (permalink / raw)
To: Mark Wielaard, gcc-rust; +Cc: dkm, wenzhang5800, Philip Herron
Hi!
On 2021-08-02T00:37:37+0200, Mark Wielaard <mark@klomp.org> wrote:
> On Sun, Aug 01, 2021 at 01:29:16PM +0200, Mark Wielaard wrote:
>> I added two simple testcases to show the basic support for unions
>> works now. But there are a couple of things that don't work correctly
>> for unions yet. In particular when enabling warnings for the new
>> union.rs testcase you'll get:
>>
>> $ gcc/gccrs -Bgcc -g union.rs
>> union.rs:18:3: warning: field is never read: ‘f1’
>> 18 | f1: U,
>> | ^
>> union.rs:19:3: warning: field is never read: ‘f2’
>> 19 | f2: V
>> | ^
>>
>> But those (union) fields in the struct are read. Similarly unused
>> union fields aren't detected.
>
> This is why the testcase uses { dg-options "-w" } to suppress all
> warnings.
For that one, I've put in <https://github.com/Rust-GCC/gccrs/pull/604>
"Handle 'UnsafeBlockExpr' in liveness analysis". Hope I got that right;
someone please review.
> Attached is a small followup patch to resolve two FIXMEs to add the
> correct locus for the Union variant fields (the actual fixme was fixed
> by Thomas Young in commit 6d7b87f9dd92 "make struct field carry the
> location info"). But it was missing TupleField and (obviously)
> Union variants since those weren't implemented yet.
>
> Also on
> https://code.wildebeest.org/git/user/mjw/gccrs/commit/?h=tuple-union-field-locus
For that one, Marc P. filed <https://github.com/Rust-GCC/gccrs/pull/602>
"Add locus to TupleField and pass it and union variants to HIR class".
Grüße
thomas
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 2/2] WIP union hir-lowering and type support
2021-08-01 11:29 ` Mark Wielaard
2021-08-01 22:37 ` Mark Wielaard
@ 2021-08-04 21:04 ` Mark Wielaard
1 sibling, 0 replies; 9+ messages in thread
From: Mark Wielaard @ 2021-08-04 21:04 UTC (permalink / raw)
To: Philip Herron; +Cc: gcc-rust
Hi,
On Sun, Aug 01, 2021 at 01:29:16PM +0200, Mark Wielaard wrote:
> And you cannot use unions as function arguments or return values.
> This example (sorry for the funny naming, union isn't a keyword, so
> you can call basically anything a union, including a union, a union
> field, function argument, etc.) doesn't pass the type checker:
>
> union union { union: u32, funion: f32 }
>
> fn funion (union: &union) -> union
> {
> let v = unsafe { union.union };
> union { union: v }
> }
>
> pub fn main ()
> {
> let union = union { union: 1 };
> let u = unsafe { union.union };
> let f = unsafe { union.funion };
> let r = funion (&union);
> let _r3 = unsafe { r.union } + unsafe { union.union } + u;
> let _f2 = f + unsafe { r.funion };
> }
>
> $ gcc/gccrs -Bgcc -g fn_union.rs
> fn_union.rs:5:20: error: expected algebraic data type got: [& union{union:Uint:u32:(Ref: 20 TyRef: 3[3,]), funion:Float:f32:(Ref: 23 TyRef: 12[12,])}]
> 5 | let v = unsafe { union.union };
> | ^
> fn_union.rs:5:20: error: failed to type resolve expression
> fn_union.rs:6:3: error: expected an ADT type for constructor
> 6 | union { union: v }
> | ^
> fn_union.rs:3:1: error: expected [union{union:Uint:u32:(Ref: 20 TyRef: 3[3,]), funion:Float:f32:(Ref: 23 TyRef: 12[12,])}] got [<tyty::error>]
> 3 | fn funion (union: &union) -> union
> | ^ ~
This example might be slightly hard to read because it uses "union"
also as identifier for things that aren't unions (which is allowed
since union is a weak keyword). So here is a simpler hopefully more
clear example to show the issue:
union U
{
v1: u64,
v2: i8
}
fn f (u: &U) -> U
{
let v = unsafe { u.v2 };
U { v2: v }
}
pub fn main ()
{
let u = U { v1: 356 };
let r = f (u);
let _v100 = unsafe { r.v1 };
}
$ gcc/gccrs -Bgcc -g union_call.rs
union_call.rs:9:20: error: expected algebraic data type got: [& U{v1:Uint:u64:(Ref: 20 TyRef: 4[4,]), v2:Int:i8:(Ref: 23 TyRef: 6[6,])}]
9 | let v = unsafe { u.v2 };
| ^
union_call.rs:9:20: error: failed to type resolve expression
union_call.rs:9:3: error: Failed to resolve IdentifierExpr type: ( v ([C: 0 Nid: 42 Hid: 40]))
9 | let v = unsafe { u.v2 };
| ^
union_call.rs:10:11: error: failed to type resolve expression
10 | U { v2: v }
| ^
union_call.rs:10:11: error: expected [i8] got [<tyty::error>]
I am a little lost where the typechecking goes wrong.
Could someone give me a hint?
Thanks,
Mark
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2021-08-04 21:04 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-22 23:19 union support Mark Wielaard
2021-07-22 23:19 ` [PATCH 1/2] Better union support in the parser Mark Wielaard
2021-07-23 11:19 ` Philip Herron
2021-07-22 23:19 ` [PATCH 2/2] WIP union hir-lowering and type support Mark Wielaard
2021-07-23 11:19 ` Philip Herron
2021-08-01 11:29 ` Mark Wielaard
2021-08-01 22:37 ` Mark Wielaard
2021-08-02 12:33 ` Thomas Schwinge
2021-08-04 21:04 ` Mark Wielaard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).