https://gcc.gnu.org/g:99b548951fe68ffe999a96e1123faec6bfda5fa6
commit r16-4543-g99b548951fe68ffe999a96e1123faec6bfda5fa6 Author: Martin Uecker <[email protected]> Date: Sun Oct 12 20:00:22 2025 +0200 c2y: Allow unspecified arrays in generic association. To allow unspecified arrays in generic association add a new declaration context GENERIC_ASSOC for grokdeclarator and new function grokgenassoc to be used by the parser. The error about unspecified array is moved from build_array_declarator to grokdeclarator to be able to check for this. gcc/c/ChangeLog: * c-decl.cc (build_array_declarator): Remove error. (grokgenassoc): New function. (grokdeclarator): Add error. * c-parser.cc (c_parser_generic_selection): Use grokgenassoc. * c-tree.h (grokgenassoc): Add prototype. gcc/testsuite/ChangeLog: * gcc.dg/c2y-generic-6.c: New test. * gcc.dg/c2y-generic-7.c: New test. Diff: --- gcc/c/c-decl.cc | 70 ++++++++++++++++++++++++------------ gcc/c/c-parser.cc | 2 +- gcc/c/c-tree.h | 1 + gcc/testsuite/gcc.dg/c2y-generic-6.c | 11 ++++++ gcc/testsuite/gcc.dg/c2y-generic-7.c | 15 ++++++++ 5 files changed, 76 insertions(+), 23 deletions(-) diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 4a940d5eec33..061892ac95b8 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -71,7 +71,8 @@ enum decl_context FUNCDEF, /* Function definition */ PARM, /* Declaration of parm before function body */ FIELD, /* Declaration inside struct or union */ - TYPENAME}; /* Typename (inside cast or sizeof) */ + TYPENAME, /* Typename (inside cast or sizeof) */ + GENERIC_ASSOC }; /* Typename in generic association */ /* States indicating how grokdeclarator() should handle declspecs marked with __attribute__((deprecated)) or __attribute__((unavailable)). @@ -5455,20 +5456,12 @@ build_array_declarator (location_t loc, pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support %<static%> or type " "qualifiers in parameter array declarators"); - if (vla_unspec_p) - pedwarn_c90 (loc, OPT_Wpedantic, - "ISO C90 does not support %<[*]%> array declarators"); if (vla_unspec_p) { - if (!current_scope->parm_flag) - { - /* C99 6.7.5.2p4 */ - error_at (loc, "%<[*]%> not allowed in other than " - "function prototype scope"); - declarator->u.array.vla_unspec_p = false; - return NULL; - } - current_scope->had_vla_unspec = true; + pedwarn_c90 (loc, OPT_Wpedantic, + "ISO C90 does not support %<[*]%> array declarators"); + if (current_scope->parm_flag) + current_scope->had_vla_unspec = true; } return declarator; } @@ -5574,6 +5567,29 @@ groktypename (struct c_type_name *type_name, tree *expr, return type; } + +/* Decode a "typename", such as "int **", returning a ..._TYPE node, + as for groktypename but setting the context to GENERIC_ASSOC. */ + +tree +grokgenassoc (struct c_type_name *type_name) +{ + tree type; + tree attrs = type_name->specs->attrs; + + type_name->specs->attrs = NULL_TREE; + + type = grokdeclarator (type_name->declarator, type_name->specs, GENERIC_ASSOC, + false, NULL, &attrs, NULL, NULL, DEPRECATED_NORMAL); + + /* Apply attributes. */ + attrs = c_warn_type_attributes (type, attrs); + decl_attributes (&type, attrs, 0); + + return type; +} + + /* Looks up the most recent pushed declaration corresponding to DECL. */ static tree @@ -6772,6 +6788,7 @@ build_arg_spec_attribute (tree type, bool static_p, tree attrs) or before a function body). Make a PARM_DECL, or return void_type_node. TYPENAME if for a typename (in a cast or sizeof). Don't make a DECL node; just return the ..._TYPE node. + GENERIC_ASSOC for typenames in a generic association. FIELD for a struct or union field; make a FIELD_DECL. INITIALIZED is true if the decl has an initializer. WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node @@ -6908,6 +6925,7 @@ grokdeclarator (const struct c_declarator *declarator, { gcc_assert (decl_context == PARM || decl_context == TYPENAME + || decl_context == GENERIC_ASSOC || (decl_context == FIELD && declarator->kind == cdk_id)); gcc_assert (!initialized); @@ -7481,14 +7499,6 @@ grokdeclarator (const struct c_declarator *declarator, itype = build_index_type (NULL_TREE); } - if (array_parm_vla_unspec_p) - { - /* C99 6.7.5.2p4 */ - if (decl_context == TYPENAME) - warning (0, "%<[*]%> not in a declaration"); - size_varies = true; - } - /* Complain about arrays of incomplete types. */ if (!COMPLETE_TYPE_P (type)) { @@ -7527,6 +7537,22 @@ grokdeclarator (const struct c_declarator *declarator, type = c_build_array_type (type, itype); } + if (array_parm_vla_unspec_p) + { + /* C99 6.7.5.2p4 */ + if (decl_context == TYPENAME) + warning (0, "%<[*]%> not in a declaration"); + else if (decl_context != GENERIC_ASSOC + && decl_context != PARM + && decl_context != FIELD) + { + error ("%<[*]%> not allowed in other than function prototype scope " + "or generic association"); + type = error_mark_node; + } + size_varies = true; + } + if (type != error_mark_node) { /* The GCC extension for zero-length arrays differs from @@ -7898,7 +7924,7 @@ grokdeclarator (const struct c_declarator *declarator, /* If this is a type name (such as, in a cast or sizeof), compute the type and return it now. */ - if (decl_context == TYPENAME) + if (decl_context == TYPENAME || decl_context == GENERIC_ASSOC) { /* Note that the grammar rejects storage classes in typenames and fields. */ diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 1d212b51fcda..56fb0be25b53 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -11240,7 +11240,7 @@ c_parser_generic_selection (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); return error_expr; } - assoc.type = groktypename (type_name, NULL, NULL); + assoc.type = grokgenassoc (type_name); if (assoc.type == error_mark_node) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 162add0522ac..f367cda35d7c 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -713,6 +713,7 @@ extern struct c_arg_info *get_parm_info (bool, tree); extern tree grokfield (location_t, struct c_declarator *, struct c_declspecs *, tree, tree *, tree *); extern tree groktypename (struct c_type_name *, tree *, bool *); +extern tree grokgenassoc (struct c_type_name *); extern tree grokparm (const struct c_parm *, tree *); extern tree implicitly_declare (location_t, tree); extern void keep_next_level (void); diff --git a/gcc/testsuite/gcc.dg/c2y-generic-6.c b/gcc/testsuite/gcc.dg/c2y-generic-6.c new file mode 100644 index 000000000000..7220d9401449 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-generic-6.c @@ -0,0 +1,11 @@ +/* { dg-do "compile" } */ +/* { dg-options "-std=c2y -Wpedantic" } */ + +void f() +{ + _Generic(1, int[*]: 1, default: 0); + _Generic(1, int(*)[*]: 1, default: 0); + _Generic(1, int[sizeof(int[*])]: 1, default: 0); /* { dg-warning "not in a declaration" } */ + _Generic(1, struct { int a[*]; }: 1, default: 0); /* { dg-warning "variably modified" } */ +} + diff --git a/gcc/testsuite/gcc.dg/c2y-generic-7.c b/gcc/testsuite/gcc.dg/c2y-generic-7.c new file mode 100644 index 000000000000..6ca046c90a89 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2y-generic-7.c @@ -0,0 +1,15 @@ +/* { dg-do "run" } */ +/* { dg-options "-std=c2y" } */ + +int main() +{ + int n = 1; + int a[1]; + _Generic(typeof(a), int[n++]: 0); + float b[1]; + _Generic(typeof(b), int[n++]: 0, default: 1); + if (n != 1) + __builtin_abort(); + return 0; +} +
