aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-08-30 02:08:45 +0200
committerEugen Wissner <belka@caraus.de>2026-08-30 02:08:45 +0200
commit491e62664394a8689a3f8904fbe8dbc3dea05524 (patch)
tree7142cf8d94fc6f9cf953d42d9c136b77f65d8034 /gcc
parent08d9c4292ebba3e320c1dbaca4fa06c83f6fc7fb (diff)
downloadelna-491e62664394a8689a3f8904fbe8dbc3dea05524.tar.gz
Fix ICEs with recursive type declarations
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gcc/elna-builtins.cc37
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;
}