aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/rust-gcc.cc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-12-14 18:10:42 +0000
committerPhilip Herron <philip.herron@embecosm.com>2021-12-16 10:17:08 +0000
commite0588300adc00872b0e818477dba614348d2cb02 (patch)
treea696b3458140310c223e519b0b53d4481dc2c1de /gcc/rust/rust-gcc.cc
parent3629645386ad503606f29f95c2e16d0600df6e20 (diff)
downloadgcc-e0588300adc00872b0e818477dba614348d2cb02.zip
gcc-e0588300adc00872b0e818477dba614348d2cb02.tar.gz
gcc-e0588300adc00872b0e818477dba614348d2cb02.tar.bz2
Add enum code generation
This adds a naieve first pass approach to enum type code generation. The original idea was to use GCC's QUAL_UNION_TYPE but I have ran into issues with the DECL_QUALIFIER as my understanding of how this works is incorrect. This takes an enum such as: ```rust enum AnEnum { A, B, C (char), D (x: i64, y: i64), } ``` And turns this into one big union consisting of all fields as RECORD_TYPES. ```c union AnEnum { record A { RUST$ENUM$DISR }; record B { RUST$ENUM$DISR }; record C { RUST$ENUM$DISR, char }; record D { RUST$ENUM$DISR, i64, i64}; } ``` see: https://github.com/bminor/binutils-gdb/blob/527b8861cd472385fa9160a91dd6d65a25c41987/gdb/dwarf2/read.c#L9010-L9241 With the RUST$ENUM$DISR being the first field in all of the records this means the alignment allows for indirect memory access of the struct to use it as a qualifier field to figure out which variant is currently in use. The data-less varients use their generated discriminat value during type-checking the data variants use their HIR ID for their discriminant. This will likely get redone to get improved GDB integration/updated to use the QUAL_UNION_TYPE when we learn how to do this properly. Fixes #79
Diffstat (limited to 'gcc/rust/rust-gcc.cc')
-rw-r--r--gcc/rust/rust-gcc.cc111
1 files changed, 73 insertions, 38 deletions
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 12df769..43716d9 100644
--- a/gcc/rust/rust-gcc.cc
+++ b/gcc/rust/rust-gcc.cc
@@ -110,6 +110,11 @@ public:
void debug (tree t) { debug_tree (t); };
void debug (Bvariable *t) { debug_tree (t->get_decl ()); };
+ tree get_identifier_node (const std::string &str)
+ {
+ return get_identifier_with_length (str.data (), str.length ());
+ }
+
// Types.
tree error_type () { return error_mark_node; }
@@ -288,7 +293,8 @@ public:
tree lazy_boolean_expression (LazyBooleanOperator op, tree left, tree right,
Location);
- tree constructor_expression (tree, const std::vector<tree> &, int, Location);
+ tree constructor_expression (tree, bool, const std::vector<tree> &, int,
+ Location);
tree array_constructor_expression (tree, const std::vector<unsigned long> &,
const std::vector<tree> &, Location);
@@ -1715,7 +1721,7 @@ Gcc_backend::lazy_boolean_expression (LazyBooleanOperator op, tree left_tree,
// Return an expression that constructs BTYPE with VALS.
tree
-Gcc_backend::constructor_expression (tree type_tree,
+Gcc_backend::constructor_expression (tree type_tree, bool is_variant,
const std::vector<tree> &vals,
int union_index, Location location)
{
@@ -1728,46 +1734,40 @@ Gcc_backend::constructor_expression (tree type_tree,
tree sink = NULL_TREE;
bool is_constant = true;
tree field = TYPE_FIELDS (type_tree);
- if (union_index != -1)
+
+ if (is_variant)
{
+ gcc_assert (union_index != -1);
gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
- tree val = vals.front ();
+
for (int i = 0; i < union_index; i++)
{
gcc_assert (field != NULL_TREE);
field = DECL_CHAIN (field);
}
- if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
- || TREE_TYPE (val) == error_mark_node)
- return this->error_expression ();
- if (int_size_in_bytes (TREE_TYPE (field)) == 0)
- {
- // GIMPLE cannot represent indices of zero-sized types so
- // trying to construct a map with zero-sized keys might lead
- // to errors. Instead, we evaluate each expression that
- // would have been added as a map element for its
- // side-effects and construct an empty map.
- append_to_statement_list (val, &sink);
- }
- else
- {
- constructor_elt empty = {NULL, NULL};
- constructor_elt *elt = init->quick_push (empty);
- elt->index = field;
- elt->value = this->convert_tree (TREE_TYPE (field), val, location);
- if (!TREE_CONSTANT (elt->value))
- is_constant = false;
- }
+ tree nested_ctor
+ = constructor_expression (TREE_TYPE (field), false, vals, -1, location);
+
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), nested_ctor, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
}
else
{
- gcc_assert (TREE_CODE (type_tree) == RECORD_TYPE);
- for (std::vector<tree>::const_iterator p = vals.begin ();
- p != vals.end (); ++p, field = DECL_CHAIN (field))
+ if (union_index != -1)
{
- gcc_assert (field != NULL_TREE);
- tree val = (*p);
+ gcc_assert (TREE_CODE (type_tree) == UNION_TYPE);
+ tree val = vals.front ();
+ for (int i = 0; i < union_index; i++)
+ {
+ gcc_assert (field != NULL_TREE);
+ field = DECL_CHAIN (field);
+ }
if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
|| TREE_TYPE (val) == error_mark_node)
return this->error_expression ();
@@ -1780,18 +1780,53 @@ Gcc_backend::constructor_expression (tree type_tree,
// would have been added as a map element for its
// side-effects and construct an empty map.
append_to_statement_list (val, &sink);
- continue;
}
+ else
+ {
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), val, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
+ }
+ }
+ else
+ {
+ gcc_assert (TREE_CODE (type_tree) == RECORD_TYPE);
+ for (std::vector<tree>::const_iterator p = vals.begin ();
+ p != vals.end (); ++p, field = DECL_CHAIN (field))
+ {
+ gcc_assert (field != NULL_TREE);
+ tree val = (*p);
+ if (TREE_TYPE (field) == error_mark_node || val == error_mark_node
+ || TREE_TYPE (val) == error_mark_node)
+ return this->error_expression ();
+
+ if (int_size_in_bytes (TREE_TYPE (field)) == 0)
+ {
+ // GIMPLE cannot represent indices of zero-sized types so
+ // trying to construct a map with zero-sized keys might lead
+ // to errors. Instead, we evaluate each expression that
+ // would have been added as a map element for its
+ // side-effects and construct an empty map.
+ append_to_statement_list (val, &sink);
+ continue;
+ }
- constructor_elt empty = {NULL, NULL};
- constructor_elt *elt = init->quick_push (empty);
- elt->index = field;
- elt->value = this->convert_tree (TREE_TYPE (field), val, location);
- if (!TREE_CONSTANT (elt->value))
- is_constant = false;
+ constructor_elt empty = {NULL, NULL};
+ constructor_elt *elt = init->quick_push (empty);
+ elt->index = field;
+ elt->value
+ = this->convert_tree (TREE_TYPE (field), val, location);
+ if (!TREE_CONSTANT (elt->value))
+ is_constant = false;
+ }
+ gcc_assert (field == NULL_TREE);
}
- gcc_assert (field == NULL_TREE);
}
+
tree ret = build_constructor (type_tree, init);
if (is_constant)
TREE_CONSTANT (ret) = 1;