diff options
Diffstat (limited to 'gcc')
| -rw-r--r-- | gcc/gcc/elna-builtins.cc | 37 |
1 files changed, 25 insertions, 12 deletions
diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index c728a00..3d10c44 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -170,7 +170,8 @@ namespace elna::gcc static_cast<int>(procedure.parameters.size()), parameter_types.data()); } - tree get_inner_alias(const boot::type& type, const std::shared_ptr<symbol_table>& symbols) + tree get_inner_alias(const boot::type& type, const std::shared_ptr<symbol_table>& symbols, + tree placeholder) { if (auto reference = type.get<boot::primitive_type>()) { @@ -181,7 +182,7 @@ namespace elna::gcc } else if (auto reference = type.get<boot::record_type>()) { - tree composite_type_node = make_node(RECORD_TYPE); + tree composite_type_node = placeholder != NULL_TREE ? placeholder : make_node(RECORD_TYPE); if (!reference->base.empty()) { @@ -217,17 +218,17 @@ namespace elna::gcc } else if (auto reference = type.get<boot::pointer_type>()) { - return build_pointer_type(get_inner_alias(reference->base, symbols)); + return build_pointer_type(get_inner_alias(reference->base, symbols, placeholder)); } else if (auto reference = type.get<boot::array_type>()) { - tree base = get_inner_alias(reference->base, symbols); + tree base = get_inner_alias(reference->base, symbols, placeholder); return build_static_array_type(base, reference->size); } else if (auto reference = type.get<boot::slice_type>()) { - tree base_type = get_inner_alias(reference->base, symbols); + tree base_type = get_inner_alias(reference->base, symbols, placeholder); tree slice_record = make_node(RECORD_TYPE); tree ptr_field = build_field(UNKNOWN_LOCATION, slice_record, "ptr", build_pointer_type(base_type)); @@ -246,7 +247,7 @@ namespace elna::gcc } else if (auto reference = type.get<boot::constant_type>()) { - tree unqualified = get_inner_alias(reference->unqualified, symbols); + tree unqualified = get_inner_alias(reference->unqualified, symbols, placeholder); return build_qualified_type(unqualified, TYPE_QUAL_CONST); } else if (auto reference = type.get<boot::alias_type>()) @@ -264,15 +265,28 @@ namespace elna::gcc if (looked_up == NULL_TREE) { - tree type_tree = get_inner_alias(reference->referent, symbols); + /* + * Enter a placeholder before converting the referent: a + * self-reference through a pointer or a slice then finds the + * in-progress declaration and breaks the conversion recursion. + */ + tree placeholder = make_node(RECORD_TYPE); + looked_up = build_decl(UNKNOWN_LOCATION, TYPE_DECL, + get_identifier(symbol_name.c_str()), placeholder); + + TREE_PUBLIC(looked_up) = 1; + TYPE_NAME(placeholder) = DECL_NAME(looked_up); + symbols->enter(symbol_name, looked_up); + + tree type_tree = get_inner_alias(reference->referent, symbols, placeholder); if (type_tree == error_mark_node) { return error_mark_node; } - looked_up = build_decl(UNKNOWN_LOCATION, TYPE_DECL, - get_identifier(symbol_name.c_str()), type_tree); - - TREE_PUBLIC(looked_up) = 1; + if (type_tree != placeholder) + { + TREE_TYPE(looked_up) = type_tree; + } if (is_unique_type(type_tree)) { TYPE_NAME(type_tree) = DECL_NAME(looked_up); @@ -282,7 +296,6 @@ namespace elna::gcc { TYPE_NAME(type_tree) = looked_up; } - symbols->enter(symbol_name, looked_up); } return looked_up; } |
