After looking a bit more at this, it turns out that it is still possible to trigger the assertion that checks that the composite type is compatible to the original types when using self-referential types where it then sees composite types which are still under construction.
This patch now moves the checking assertion out of the recursion, which seems better anyhow. I could not do the check unconditionally for all types. because we sometimes call composite_type for with mismatching qualifiers. There is also still a remaining issue with setting C_VARIABLY_MODIFIED_TYPE_P correctly for composite types for such self-referential types. Bootstrapped and regression tested for x86_64. Martin c: Move checking assertions from recursion when forming composite types to avoid ICE. The checking assertion in composite_type_internal for structures and unions may fail if there are self-referential types. To avoid this, we move them out of the recursion. This should also be more efficient and covers other types. We have to ignore some cases where we form composite types despite qualifiers not matching. gcc/c/ChangeLog: * c-typeck.cc (composite_type_internal,composite_type): Move checking assertions. gcc/testsuite/ChangeLog: * gcc.dg/gnu23-tag-composite-6.c: Update. diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 2f243cab8da..417db8795c5 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -846,12 +846,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache) n = finish_struct (input_location, n, fields, attributes, NULL, &expr); - n = qualify_type (n, t1); - - gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t1)); - gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t2)); - - return n; + return qualify_type (n, t1); } /* FALLTHRU */ case ENUMERAL_TYPE: @@ -1004,7 +999,15 @@ tree composite_type (tree t1, tree t2) { struct composite_cache cache = { }; - return composite_type_internal (t1, t2, &cache); + tree n = composite_type_internal (t1, t2, &cache); + /* For function and arrays there are some exceptions where + qualifiers do not match. */ + if (FUNCTION_TYPE != TREE_CODE (n) && ARRAY_TYPE != TREE_CODE (n)) + { + gcc_checking_assert (comptypes (n, t1)); + gcc_checking_assert (comptypes (n, t2)); + } + return n; } /* Return the type of a conditional expression between pointers to diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c b/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c index 2411b04d388..076c066f9c8 100644 --- a/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c +++ b/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c @@ -1,11 +1,31 @@ /* { dg-do compile } */ /* { dg-options "-std=gnu23" } */ +#define NEST(...) typeof(({ (__VA_ARGS__){ }; })) + int f() { typedef struct foo bar; - struct foo { typeof(({ (struct foo { bar * x; }){ }; })) * x; } *q; - typeof(q->x) p; - 1 ? p : q; + struct foo { NEST(struct foo { bar *x; }) *x; } *q; + typeof(q->x) p0; + typeof(q->x) p1; + 1 ? p0 : q; + 1 ? p1 : q; + 1 ? p0 : p1; +} + +int g() +{ + typedef struct fo2 bar; + struct fo2 { NEST(struct fo2 { NEST(struct fo2 { bar *x; }) * x; }) *x; } *q; + typeof(q->x) p0; + typeof(q->x->x) p1; + typeof(q->x->x->x) p2; + 1 ? p0 : q; + 1 ? p1 : q; + 1 ? p2 : q; + 1 ? p0 : p1; + 1 ? p2 : p1; + 1 ? p0 : p2; }