https://gcc.gnu.org/g:ca19686a6b87696c0ecea5e9fce825b5e5e10144
commit r16-5681-gca19686a6b87696c0ecea5e9fce825b5e5e10144 Author: Jakub Jelinek <[email protected]> Date: Thu Nov 27 20:18:57 2025 +0100 c: Fix ICE in c_type_tag on va_list [PR121506] The C and C++ FEs disagree on what TYPE_NAME on RECORD_TYPE for structure/class definition is (rather than typedef/using, for those both have TYPE_NAME of TYPE_DECL with DECL_ORIGINAL_TYPE), the C FE just uses IDENTIFIER_NODE as TYPE_NAME on RECORD_TYPE, while the C++ FE uses TYPE_DECL as TYPENAME on RECORD_TYPE and only DECL_NAME on the TYPE_DECL provides the IDENTIFIER_NODE. The reason for the C++ FE way is that there can be type definitions at class scope (rather than just typedefs) and those need to be among TYPE_FIELDS (so the corresponding TYPE_DECL is in that chain) etc. The middle-end can cope with it, e.g. if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) pp_tree_identifier (pp, TYPE_NAME (node)); else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL && DECL_NAME (TYPE_NAME (node))) dump_decl_name (pp, TYPE_NAME (node), flags); and many other places. Now, the backends on various targets create artificial structure definitions for va_list, e.g. x86 creates struct __va_list_tag and they do it the C++ FE way so that the C++ FE can cope with those. Except the new c_type_tag can't deal with that and ICEs. The following patch fixes it so that it can handle it too. 2025-11-27 Jakub Jelinek <[email protected]> PR c/121506 * c-typeck.cc (c_type_tag): If TYPE_NAME is TYPE_DECL with non-NULL DECL_NAME, return that. * gcc.dg/pr121506.c: New test. Diff: --- gcc/c/c-typeck.cc | 6 +++--- gcc/testsuite/gcc.dg/pr121506.c | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7eb413885b87..a34ca2ab97c4 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -610,9 +610,9 @@ c_type_tag (const_tree t) return NULL_TREE; if (TREE_CODE (name) == TYPE_DECL) { - /* A TYPE_DECL added by add_decl_expr. */ - gcc_checking_assert (!DECL_NAME (name)); - return NULL_TREE; + if (!DECL_NAME (name)) + return NULL_TREE; + name = DECL_NAME (name); } gcc_checking_assert (TREE_CODE (name) == IDENTIFIER_NODE); return name; diff --git a/gcc/testsuite/gcc.dg/pr121506.c b/gcc/testsuite/gcc.dg/pr121506.c new file mode 100644 index 000000000000..0d0664739aca --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr121506.c @@ -0,0 +1,8 @@ +/* PR c/121506 */ +/* { dg-do compile } */ + +#include <stdarg.h> + +struct A; +void foo (struct A *); /* { dg-message "previous declaration of 'foo' with type 'void\\\(struct A \\\*\\\)'" } */ +void foo (va_list); /* { dg-error "conflicting types for 'foo'; have" } */
