aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/rust-gcc.cc
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2021-08-01 12:57:33 +0200
committerMark Wielaard <mark@klomp.org>2021-08-01 12:57:33 +0200
commit389fd74a3f3e9422a965263b6961b51295c55976 (patch)
treed815a7d24660b24da5fcf7d05b5f2b3e8de99ae1 /gcc/rust/rust-gcc.cc
parent06a65591eb09fbec25e4ee38c1cf751b416af5bf (diff)
downloadgcc-389fd74a3f3e9422a965263b6961b51295c55976.zip
gcc-389fd74a3f3e9422a965263b6961b51295c55976.tar.gz
gcc-389fd74a3f3e9422a965263b6961b51295c55976.tar.bz2
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).
Diffstat (limited to 'gcc/rust/rust-gcc.cc')
-rw-r--r--gcc/rust/rust-gcc.cc91
1 files changed, 70 insertions, 21 deletions
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 44617a6..3e47a7c 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)