aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/rust-gcc.cc
diff options
context:
space:
mode:
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)