diff options
author | Philip Herron <philip.herron@embecosm.com> | 2021-12-14 18:10:42 +0000 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2021-12-16 10:17:08 +0000 |
commit | e0588300adc00872b0e818477dba614348d2cb02 (patch) | |
tree | a696b3458140310c223e519b0b53d4481dc2c1de /gcc/rust/rust-gcc.cc | |
parent | 3629645386ad503606f29f95c2e16d0600df6e20 (diff) | |
download | gcc-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.cc | 111 |
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; |