On Tue, Apr 11, 2023 at 11:47 AM Martin Uecker via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > > > Ok, here is another attempt on fixing issues with size expression. > Not all are regressions, but it does not make sense to try to split > it up.
They might be regressions still from pre gimple (3.4 and before), though I wonder how much value considering something which didn't work in GCC 4.0+ these days as a regression. Also splitting them up if possible is always welcomed to be able to review each thing separately. Thanks, Andrew > > Martin > > > > Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, > PR109450] > > Size expressions were sometimes lost and not gimplified correctly, > leading to > ICEs and incorrect evaluation order. Fix this by 1) not recursing > into > pointers when gimplifying parameters in the middle-end (the code is > merged with > gimplify_type_sizes), which is incorrect because it might access > variables > declared later for incomplete structs, and 2) tracking size > expressions for > struct/union members correctly, 3) emitting code to evaluate size > expressions > for missing cases (nested functions, empty declarations, and > structs/unions). > > PR c/106465 > PR c/107557 > PR c/108423 > PR c/109450 > > gcc/ > * c/c-decl.cc (start_decl): Make sure size expression are > evaluated only in correct context. > (grokdeclarator): Size expression in fields may need a bind > expression, make sure DECL_EXPR is always created. > (grokfield, declspecs_add_type): Pass along size expressions. > (finish_struct): Remove unneeded DECL_EXPR. > (start_function): Evaluate size expressions for nested functions. > * c/c-parser.cc (c_parser_struct_declarations, > c_parser_struct_or_union_specifier): Pass along size expressions. > (c_parser_declaration_or_fndef): Evaluate size expression. > (c_parser_objc_at_property_declaration, > c_parser_objc_class_instance_variables): Adapt. > * function.cc (gimplify_parm_type): Remove function. > (gimplify_parameters): Call gimplify_parm_sizes. > * gimplify.cc (gimplify_type_sizes): Make function static. > (gimplify_parm_sizes): New function. > > gcc/testsuite/ > * gcc.dg/nested-vla-1.c: New test. > * gcc.dg/nested-vla-2.c: New test. > * gcc.dg/nested-vla-3.c: New test. > * gcc.dg/pr106465.c: New test. > * gcc.dg/pr107557-1.c: New test. > * gcc.dg/pr107557-2.c: New test. > * gcc.dg/pr108423-1.c: New test. > * gcc.dg/pr108423-2.c: New test. > * gcc.dg/pr108423-3.c: New test. > * gcc.dg/pr108423-4.c: New test. > * gcc.dg/pr108423-5.c: New test. > * gcc.dg/pr108423-6.c: New test. > * gcc.dg/pr109450-1.c: New test. > * gcc.dg/pr109450-2.c: New test. > * gcc.dg/typename-vla-2.c: New test. > * gcc.dg/typename-vla-3.c: New test. > * gcc.dg/typename-vla-4.c: New test. > * gcc.misc-tests/gcov-pr85350.c: Adapt. > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc > index e537d33f398..c76cbb3115f 100644 > --- a/gcc/c/c-decl.cc > +++ b/gcc/c/c-decl.cc > @@ -5371,7 +5371,8 @@ start_decl (struct c_declarator *declarator, struct > c_declspecs *declspecs, > if (lastdecl != error_mark_node) > *lastloc = DECL_SOURCE_LOCATION (lastdecl); > > - if (expr) > + /* Make sure the size expression is evaluated at this point. */ > + if (expr && !current_scope->parm_flag) > add_stmt (fold_convert (void_type_node, expr)); > > if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)) > @@ -7500,7 +7501,8 @@ grokdeclarator (const struct c_declarator *declarator, > && c_type_variably_modified_p (type)) > { > tree bind = NULL_TREE; > - if (decl_context == TYPENAME || decl_context == PARM) > + if (decl_context == TYPENAME || decl_context == PARM > + || decl_context == FIELD) > { > bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, > NULL_TREE, NULL_TREE); > @@ -7509,10 +7511,9 @@ grokdeclarator (const struct c_declarator *declarator, > push_scope (); > } > tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type); > - DECL_ARTIFICIAL (decl) = 1; > - pushdecl (decl); > - finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE); > + add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, > decl)); > TYPE_NAME (type) = decl; > + > if (bind) > { > pop_scope (); > @@ -8711,7 +8712,7 @@ start_struct (location_t loc, enum tree_code code, tree > name, > tree > grokfield (location_t loc, > struct c_declarator *declarator, struct c_declspecs *declspecs, > - tree width, tree *decl_attrs) > + tree width, tree *decl_attrs, tree *expr) > { > tree value; > > @@ -8768,7 +8769,7 @@ grokfield (location_t loc, > } > > value = grokdeclarator (declarator, declspecs, FIELD, false, > - width ? &width : NULL, decl_attrs, NULL, NULL, > + width ? &width : NULL, decl_attrs, expr, NULL, > DEPRECATED_NORMAL); > > finish_decl (value, loc, NULL_TREE, NULL_TREE, NULL_TREE); > @@ -9426,13 +9427,6 @@ finish_struct (location_t loc, tree t, tree fieldlist, > tree attributes, > > finish_incomplete_vars (incomplete_vars, toplevel); > > - /* If we're inside a function proper, i.e. not file-scope and not still > - parsing parameters, then arrange for the size of a variable sized type > - to be bound now. */ > - if (building_stmt_list_p () && c_type_variably_modified_p(t)) > - add_stmt (build_stmt (loc, > - DECL_EXPR, build_decl (loc, TYPE_DECL, NULL, t))); > - > if (warn_cxx_compat) > warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc); > > @@ -10058,6 +10052,7 @@ start_function (struct c_declspecs *declspecs, struct > c_declarator *declarator, > tree restype, resdecl; > location_t loc; > location_t result_loc; > + tree expr = NULL; > > current_function_returns_value = 0; /* Assume, until we see it does. */ > current_function_returns_null = 0; > @@ -10069,7 +10064,7 @@ start_function (struct c_declspecs *declspecs, struct > c_declarator *declarator, > in_statement = 0; > > decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL, > - &attributes, NULL, NULL, DEPRECATED_NORMAL); > + &attributes, &expr, NULL, DEPRECATED_NORMAL); > invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1); > > /* If the declarator is not suitable for a function definition, > @@ -10078,6 +10073,11 @@ start_function (struct c_declspecs *declspecs, > struct c_declarator *declarator, > || TREE_CODE (decl1) != FUNCTION_DECL) > return false; > > + /* Nested functions may have variably modified (return) type. > + Make sure the size expression is evaluated at this point. */ > + if (expr && !current_scope->parm_flag) > + add_stmt (fold_convert (void_type_node, expr)); > + > loc = DECL_SOURCE_LOCATION (decl1); > > /* A nested function is not global. */ > @@ -12282,10 +12282,13 @@ declspecs_add_type (location_t loc, struct > c_declspecs *specs, > } > else > { > - if (TREE_CODE (type) != ERROR_MARK && spec.kind == ctsk_typeof) > + if (TREE_CODE (type) != ERROR_MARK) > { > - specs->typedef_p = true; > - specs->locations[cdw_typedef] = loc; > + if (spec.kind == ctsk_typeof) > + { > + specs->typedef_p = true; > + specs->locations[cdw_typedef] = loc; > + } > if (spec.expr) > { > if (specs->expr) > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc > index 21bc3167ce2..6008ca78c07 100644 > --- a/gcc/c/c-parser.cc > +++ b/gcc/c/c-parser.cc > @@ -1541,7 +1541,7 @@ static void c_parser_static_assert_declaration_no_semi > (c_parser *); > static void c_parser_static_assert_declaration (c_parser *); > static struct c_typespec c_parser_enum_specifier (c_parser *); > static struct c_typespec c_parser_struct_or_union_specifier (c_parser *); > -static tree c_parser_struct_declaration (c_parser *); > +static tree c_parser_struct_declaration (c_parser *, tree *); > static struct c_typespec c_parser_typeof_specifier (c_parser *); > static tree c_parser_alignas_specifier (c_parser *); > static struct c_declarator *c_parser_direct_declarator (c_parser *, bool, > @@ -2263,6 +2263,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool > fndef_ok, > if (!handled_assume) > pedwarn (here, 0, "empty declaration"); > } > + /* we still have to evaluate size expressions */ > + if (specs->expr) > + add_stmt (fold_convert (void_type_node, specs->expr)); > c_parser_consume_token (parser); > if (oacc_routine_data) > c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false); > @@ -3782,6 +3785,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) > so we'll be minimizing the number of node traversals required > by chainon. */ > tree contents; > + tree expr = NULL; > timevar_push (TV_PARSE_STRUCT); > contents = NULL_TREE; > c_parser_consume_token (parser); > @@ -3843,7 +3847,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) > } > /* Parse some comma-separated declarations, but not the > trailing semicolon if any. */ > - decls = c_parser_struct_declaration (parser); > + decls = c_parser_struct_declaration (parser, &expr); > contents = chainon (decls, contents); > /* If no semicolon follows, either we have a parse error or > are at the end of the struct or union and should > @@ -3874,7 +3878,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) > chainon (attrs, postfix_attrs)), > struct_info); > ret.kind = ctsk_tagdef; > - ret.expr = NULL_TREE; > + ret.expr = expr; > ret.expr_const_operands = true; > ret.has_enum_type_specifier = false; > timevar_pop (TV_PARSE_STRUCT); > @@ -3936,7 +3940,7 @@ c_parser_struct_or_union_specifier (c_parser *parser) > expressions will be diagnosed as non-constant. */ > > static tree > -c_parser_struct_declaration (c_parser *parser) > +c_parser_struct_declaration (c_parser *parser, tree *expr) > { > struct c_declspecs *specs; > tree prefix_attrs; > @@ -3949,7 +3953,7 @@ c_parser_struct_declaration (c_parser *parser) > tree decl; > ext = disable_extension_diagnostics (); > c_parser_consume_token (parser); > - decl = c_parser_struct_declaration (parser); > + decl = c_parser_struct_declaration (parser, expr); > restore_extension_diagnostics (ext); > return decl; > } > @@ -3995,7 +3999,7 @@ c_parser_struct_declaration (c_parser *parser) > > ret = grokfield (c_parser_peek_token (parser)->location, > build_id_declarator (NULL_TREE), specs, > - NULL_TREE, &attrs); > + NULL_TREE, &attrs, expr); > if (ret) > decl_attributes (&ret, attrs, 0); > } > @@ -4056,7 +4060,7 @@ c_parser_struct_declaration (c_parser *parser) > if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)) > postfix_attrs = c_parser_gnu_attributes (parser); > d = grokfield (c_parser_peek_token (parser)->location, > - declarator, specs, width, &all_prefix_attrs); > + declarator, specs, width, &all_prefix_attrs, expr); > decl_attributes (&d, chainon (postfix_attrs, > all_prefix_attrs), 0); > DECL_CHAIN (d) = decls; > @@ -11729,7 +11733,7 @@ c_parser_objc_class_instance_variables (c_parser > *parser) > } > > /* Parse some comma-separated declarations. */ > - decls = c_parser_struct_declaration (parser); > + decls = c_parser_struct_declaration (parser, NULL); > if (decls == NULL) > { > /* There is a syntax error. We want to skip the offending > @@ -12868,7 +12872,7 @@ c_parser_objc_at_property_declaration (c_parser > *parser) > /* 'properties' is the list of properties that we read. Usually a > single one, but maybe more (eg, in "@property int a, b, c;" there > are three). */ > - tree properties = c_parser_struct_declaration (parser); > + tree properties = c_parser_struct_declaration (parser, NULL); > > if (properties == error_mark_node) > c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL); > diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h > index e6b6fe9a40e..7c5234e80fd 100644 > --- a/gcc/c/c-tree.h > +++ b/gcc/c/c-tree.h > @@ -656,7 +656,7 @@ extern tree c_simulate_record_decl (location_t, const > char *, > extern struct c_arg_info *build_arg_info (void); > extern struct c_arg_info *get_parm_info (bool, tree); > extern tree grokfield (location_t, struct c_declarator *, > - struct c_declspecs *, tree, tree *); > + struct c_declspecs *, tree, tree *, tree *); > extern tree groktypename (struct c_type_name *, tree *, bool *); > extern tree grokparm (const struct c_parm *, tree *); > extern tree implicitly_declare (location_t, tree); > diff --git a/gcc/function.cc b/gcc/function.cc > index edf0b2ec6cf..e50d9601509 100644 > --- a/gcc/function.cc > +++ b/gcc/function.cc > @@ -3873,30 +3873,6 @@ assign_parms (tree fndecl) > } > } > > -/* A subroutine of gimplify_parameters, invoked via walk_tree. > - For all seen types, gimplify their sizes. */ > - > -static tree > -gimplify_parm_type (tree *tp, int *walk_subtrees, void *data) > -{ > - tree t = *tp; > - > - *walk_subtrees = 0; > - if (TYPE_P (t)) > - { > - if (POINTER_TYPE_P (t)) > - *walk_subtrees = 1; > - else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t)) > - && !TYPE_SIZES_GIMPLIFIED (t)) > - { > - gimplify_type_sizes (t, (gimple_seq *) data); > - *walk_subtrees = 1; > - } > - } > - > - return NULL; > -} > - > /* Gimplify the parameter list for current_function_decl. This involves > evaluating SAVE_EXPRs of variable sized parameters and generating code > to implement callee-copies reference parameters. Returns a sequence of > @@ -3932,14 +3908,7 @@ gimplify_parameters (gimple_seq *cleanup) > SAVE_EXPRs (amongst others) onto a pending sizes list. This > turned out to be less than manageable in the gimple world. > Now we have to hunt them down ourselves. */ > - walk_tree_without_duplicates (&data.arg.type, > - gimplify_parm_type, &stmts); > - > - if (TREE_CODE (DECL_SIZE_UNIT (parm)) != INTEGER_CST) > - { > - gimplify_one_sizepos (&DECL_SIZE (parm), &stmts); > - gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), &stmts); > - } > + gimplify_parm_sizes (parm, &stmts); > > if (data.arg.pass_by_reference) > { > diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc > index ade6e335da7..a220886d973 100644 > --- a/gcc/gimplify.cc > +++ b/gcc/gimplify.cc > @@ -242,6 +242,7 @@ static struct gimplify_omp_ctx *gimplify_omp_ctxp; > static bool in_omp_construct; > > /* Forward declaration. */ > +static void gimplify_type_sizes (tree type, gimple_seq *list_p); > static enum gimplify_status gimplify_compound_expr (tree *, gimple_seq *, > bool); > static hash_map<tree, tree> *oacc_declare_returns; > static enum gimplify_status gimplify_expr (tree *, gimple_seq *, gimple_seq > *, > @@ -17448,7 +17449,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, > gimple_seq *post_p, > /* Look through TYPE for variable-sized objects and gimplify each such > size that we find. Add to LIST_P any statements generated. */ > > -void > +static void > gimplify_type_sizes (tree type, gimple_seq *list_p) > { > if (type == NULL || type == error_mark_node) > @@ -17556,6 +17557,21 @@ gimplify_type_sizes (tree type, gimple_seq *list_p) > } > } > > +/* Gimplify sizes in parameter declarations. */ > + > +void > +gimplify_parm_sizes (tree parm, gimple_seq *list_p) > +{ > + gimplify_type_sizes (TREE_TYPE (parm), list_p); > + > + if (TREE_CODE (DECL_SIZE_UNIT (parm)) != INTEGER_CST) > + { > + gimplify_one_sizepos (&DECL_SIZE (parm), list_p); > + gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), list_p); > + } > +} > + > + > /* A subroutine of gimplify_type_sizes to make sure that *EXPR_P, > a size or position, has had all of its SAVE_EXPRs evaluated. > We add any required statements to *STMT_P. */ > diff --git a/gcc/gimplify.h b/gcc/gimplify.h > index f4a3eea2606..17ea0580647 100644 > --- a/gcc/gimplify.h > +++ b/gcc/gimplify.h > @@ -78,7 +78,7 @@ extern enum gimplify_status gimplify_expr (tree *, > gimple_seq *, gimple_seq *, > > int omp_construct_selector_matches (enum tree_code *, int, int *); > > -extern void gimplify_type_sizes (tree, gimple_seq *); > +extern void gimplify_parm_sizes (tree, gimple_seq *); > extern void gimplify_one_sizepos (tree *, gimple_seq *); > extern gbind *gimplify_body (tree, bool); > extern enum gimplify_status gimplify_arg (tree *, gimple_seq *, location_t, > diff --git a/gcc/testsuite/gcc.dg/nested-vla-1.c > b/gcc/testsuite/gcc.dg/nested-vla-1.c > new file mode 100644 > index 00000000000..408a68524d8 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/nested-vla-1.c > @@ -0,0 +1,37 @@ > +/* { dg-do run } */ > +/* { dg-options "-std=gnu99" } */ > + > + > +int main() > +{ > + int n = 1; > + > + struct foo { char x[++n]; } bar(void) { } > + > + if (2 != n) > + __builtin_abort(); > + > + if (2 != sizeof(bar())) > + __builtin_abort(); > + > + n = 1; > + > + struct bar { char x[++n]; } (*bar2)(void) = bar; /* { > dg-warning "incompatible pointer type" } */ > + > + if (2 != n) > + __builtin_abort(); > + > + if (2 != sizeof((*bar2)())) > + __builtin_abort(); > + > + n = 1; > + > + struct { char x[++n]; } *bar3(void) { } > + > + if (2 != n) > + __builtin_abort(); > + > + if (2 != sizeof(*bar3())) > + __builtin_abort(); > +} > + > diff --git a/gcc/testsuite/gcc.dg/nested-vla-2.c > b/gcc/testsuite/gcc.dg/nested-vla-2.c > new file mode 100644 > index 00000000000..504eec48c80 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/nested-vla-2.c > @@ -0,0 +1,33 @@ > +/* { dg-do run } */ > +/* { dg-options "-std=gnu99" } */ > + > + > +int main() > +{ > + int n = 1; > + > + typeof(char (*)[++n]) bar(void) { } > + > + if (2 != n) > + __builtin_abort(); > + > + if (2 != sizeof(*bar())) > + __builtin_abort(); > + > + if (2 != n) > + __builtin_abort(); > + > + n = 1; > + > + typeof(char (*)[++n]) (*bar2)(void) = bar; > + > + if (2 != n) > + __builtin_abort(); > + > + if (2 != sizeof(*(*bar2)())) > + __builtin_abort(); > + > + if (2 != n) > + __builtin_abort(); > +} > + > diff --git a/gcc/testsuite/gcc.dg/nested-vla-3.c > b/gcc/testsuite/gcc.dg/nested-vla-3.c > new file mode 100644 > index 00000000000..e0e70b651ca > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/nested-vla-3.c > @@ -0,0 +1,28 @@ > +/* { dg-do run } */ > +/* { dg-options "-std=gnu99" } */ > + > + > +int main() > +{ > + int n = 1; > + > + char (*bar(void))[++n] { } > + > + if (2 != n) > + __builtin_abort(); > + > + if (2 != sizeof(*bar())) > + __builtin_abort(); > + > + n = 1; > + > + char (*(*bar2)(void))[++n] = bar; > + > + if (2 != n) > + __builtin_abort(); > + > + if (2 != sizeof(*(*bar2)())) > + __builtin_abort(); > + > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr106465.c b/gcc/testsuite/gcc.dg/pr106465.c > new file mode 100644 > index 00000000000..b03e2442f12 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr106465.c > @@ -0,0 +1,86 @@ > +/* PR c/106465 > + * { dg-do run } > + * { dg-options "-std=gnu99" } > + * */ > + > +int main() > +{ > + int n = 3; > + > + void g1(int m, struct { char p[++m]; }* b) /* { dg-warning > "anonymous struct" } */ > + { > + if (3 != m) > + __builtin_abort(); > + > + if (3 != sizeof(b->p)) > + __builtin_abort(); > + } > + > + void g2(struct { char p[++n]; }* b) /* { dg-warning "anonymous > struct" } */ > + { > + if (4 != n) > + __builtin_abort(); > + > + if (4 != sizeof(b->p)) > + __builtin_abort(); > + } > + > + void g2b(struct { char (*p)[++n]; }* b) /* { dg-warning "anonymous > struct" } */ > + { > + if (5 != n) > + __builtin_abort(); > + > + if (5 != sizeof(*b->p)) > + __builtin_abort(); > + } > + > + if (3 != n) > + __builtin_abort(); > + > + g1(2, (void*)0); > + g2((void*)0); > + g2b((void*)0); > + n--; > + > + if (4 != n) > + __builtin_abort(); > + > + struct foo { char (*p)[++n]; } x; > + > + if (5 != n) > + __builtin_abort(); > + > + struct bar { char (*p)[++n]; }; > + > + if (6 != n) > + __builtin_abort(); > + > + auto struct z { char (*p)[++n]; } g3(void); > + > + if (7 != n) > + __builtin_abort(); > + > + struct z g3(void) { }; > + > + if (7 != n) > + __builtin_abort(); > + > + struct { char (*p)[++n]; } g4(void) { }; > + > + if (8 != n) > + __builtin_abort(); > + > + __auto_type u = g3(); > + > + if (8 != n) > + __builtin_abort(); > + > + if (5 != sizeof *x.p) > + __builtin_abort(); > + > + if (7 != sizeof *u.p) > + __builtin_abort(); > + > + return 0; > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr107557-1.c > b/gcc/testsuite/gcc.dg/pr107557-1.c > new file mode 100644 > index 00000000000..88c248b6564 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr107557-1.c > @@ -0,0 +1,24 @@ > +/* PR107557 > + * { dg-do compile } > + * { dg-options "-flto -fsanitize=undefined -fexceptions > -Wno-incompatible-pointer-types" } > + */ > + > + > +int c[1][3*2]; > +int f(int * const m, int (**v)[*m * 2]) > +{ > + return &(c[0][*m]) == &((*v)[0][*m]); > +} > +int test(int n, int (*(*fn)(void))[n]) > +{ > + return (*fn())[0]; > +} > +int main() > +{ > + int m = 3; > + int (*d)[3*2] = c; > + int (*fn[m])(void); > + return f(&m, &d) + test(m, &fn); > +} > + > + > diff --git a/gcc/testsuite/gcc.dg/pr107557-2.c > b/gcc/testsuite/gcc.dg/pr107557-2.c > new file mode 100644 > index 00000000000..2d26bb0b16a > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr107557-2.c > @@ -0,0 +1,23 @@ > +/* PR107557 > + * { dg-do compile } > + * { dg-options "-flto -fsanitize=undefined -fexceptions > -Wno-incompatible-pointer-types" } > + */ > + > + > +int c[1][3*2]; > +int f(int * const m, int (**(*v))[*m * 2]) > +{ > + return &(c[0][*m]) == &((*v)[0][*m]); /* { dg-warning "lacks a > cast" } */ > +} > +int test(int n, int (*(*(*fn))(void))[n]) > +{ > + return (*(*fn)())[0]; > +} > +int main() > +{ > + int m = 3; > + int (*d)[3*2] = c; > + int (*fn[m])(void); > + return f(&m, &d) + test(m, &fn); > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr108423-1.c > b/gcc/testsuite/gcc.dg/pr108423-1.c > new file mode 100644 > index 00000000000..0c98d1d46b9 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr108423-1.c > @@ -0,0 +1,16 @@ > +/* PR108423 > + * { dg-do compile } > + * { dg-options "-O2 -Wno-int-conversion -Wno-incompatible-pointer-types" } > + */ > +int f (int n, int (**(*a)(void))[n]) > +{ > + return (*a())[0]; > +} > +int g () > +{ > + int m = 3; > + int (*a[m])(void); > + return f(m, &a); > +} > + > + > diff --git a/gcc/testsuite/gcc.dg/pr108423-2.c > b/gcc/testsuite/gcc.dg/pr108423-2.c > new file mode 100644 > index 00000000000..006e45a9629 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr108423-2.c > @@ -0,0 +1,16 @@ > +/* PR108423 > + * { dg-do compile } > + * { dg-options "-O2" } > + */ > + > +void f(int n, int (*a(void))[n]) > +{ > + (a())[0]; > +} > + > +void g(void) > +{ > + int (*a(void))[1]; > + f(1, a); > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr108423-3.c > b/gcc/testsuite/gcc.dg/pr108423-3.c > new file mode 100644 > index 00000000000..c1987c42b40 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr108423-3.c > @@ -0,0 +1,17 @@ > +/* PR108423 > + * { dg-do compile } > + * { dg-options "-O2" } > + */ > + > +void f(int n, int (*(*b)(void))[n]) > +{ > + sizeof (*(*b)()); > +} > + > +int (*a(void))[1]; > + > +void g(void) > +{ > + f(1, &a); > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr108423-4.c > b/gcc/testsuite/gcc.dg/pr108423-4.c > new file mode 100644 > index 00000000000..91336f3f283 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr108423-4.c > @@ -0,0 +1,17 @@ > +/* PR108423 > + * { dg-do compile } > + * { dg-options "-O2" } > + */ > + > +void f(int n, int (*a(void))[n]) > +{ > + sizeof (*a()); > +} > + > +int (*a(void))[1]; > + > +void g(void) > +{ > + f(1, a); > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr108423-5.c > b/gcc/testsuite/gcc.dg/pr108423-5.c > new file mode 100644 > index 00000000000..7e4fffb2870 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr108423-5.c > @@ -0,0 +1,17 @@ > +/* PR108423 > + * { dg-do compile } > + * { dg-options "-O2" } > + */ > + > +void f(int n, int (*(*a)(void))[n]) > +{ > + sizeof ((*a)()); > +} > + > +int (*a(void))[1]; > + > +void g(void) > +{ > + f(1, a); > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr108423-6.c > b/gcc/testsuite/gcc.dg/pr108423-6.c > new file mode 100644 > index 00000000000..c36e45aaf45 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr108423-6.c > @@ -0,0 +1,16 @@ > +/* PR108423 > + * { dg-do compile } > + * { dg-options "-O2" } > + */ > + > +void f(int n, int (*a())[n]) > +{ > + (a())[0]; > +} > + > +void g(void) > +{ > + int (*a())[1]; > + f(1, a); > +} > + > diff --git a/gcc/testsuite/gcc.dg/pr109450-1.c > b/gcc/testsuite/gcc.dg/pr109450-1.c > new file mode 100644 > index 00000000000..aec127f2afc > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr109450-1.c > @@ -0,0 +1,21 @@ > +/* PR c/109450 > + * { dg-do run } > + * { dg-options "-std=gnu99" } > + * */ > + > +int bar(int n, struct foo* x) /* { dg-warning "not be visible" } */ > +{ > + int a = n; > + struct foo { char buf[n++]; }* p = x; > + return a; > +} > + > +int main() > +{ > + if (1 != bar(1, 0)) > + __builtin_abort(); > +} > + > + > + > + > diff --git a/gcc/testsuite/gcc.dg/pr109450-2.c > b/gcc/testsuite/gcc.dg/pr109450-2.c > new file mode 100644 > index 00000000000..06799f6df23 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/pr109450-2.c > @@ -0,0 +1,18 @@ > +/* PR c/109450 > + * { dg-do run } > + * { dg-options "-std=gnu99" } > + * */ > + > +int bar(int n, struct foo *x) /* { dg-warning "not be visible" } */ > +{ > + int a = n; > + struct foo { char buf[a++]; }* p = x; > + return n == a; > +} > + > +int main() > +{ > + if (bar(1, 0)) > + __builtin_abort(); > +} > + > diff --git a/gcc/testsuite/gcc.dg/typename-vla-2.c > b/gcc/testsuite/gcc.dg/typename-vla-2.c > new file mode 100644 > index 00000000000..9cdd9467544 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/typename-vla-2.c > @@ -0,0 +1,16 @@ > +/* { dg-do run } > + * { dg-options "-std=c99" } > + * */ > + > +static int f(int n, char (*x)[sizeof (*(++n, (char (*)[n])0))]) > +{ > + return sizeof *x; > +} > + > +int main (void) > +{ > + if (2 != f(1, 0)) > + __builtin_abort (); > + return 0; > +} > + > diff --git a/gcc/testsuite/gcc.dg/typename-vla-3.c > b/gcc/testsuite/gcc.dg/typename-vla-3.c > new file mode 100644 > index 00000000000..4c7c56bff8e > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/typename-vla-3.c > @@ -0,0 +1,16 @@ > +/* { dg-do run } > + * { dg-options "-std=c99" } > + * */ > + > +static int f(int n, char (*x)[sizeof *(++n, (struct { char (*x)[n]; }){ 0 > }).x]) /* { dg-warning "anonymous struct" } */ > +{ > + return sizeof *x; > +} > + > +int main (void) > +{ > + if (2 != f(1, 0)) > + __builtin_abort (); > + return 0; > +} > + > diff --git a/gcc/testsuite/gcc.dg/typename-vla-4.c > b/gcc/testsuite/gcc.dg/typename-vla-4.c > new file mode 100644 > index 00000000000..a05c782b555 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/typename-vla-4.c > @@ -0,0 +1,23 @@ > +/* { dg-do run } > + * { dg-options "-std=gnu99" } > + * */ > + > +int main() > +{ > + int n = 1; > + sizeof(int[n++]); > + typeof(int[n++]); /* { dg-warning "empty > declaration" } */ > + struct { int x[n++]; }; /* { dg-warning "no instance" > } */ > + struct foo { int x[n++]; }; > + struct { int x[n++]; } x; > + struct bar { int x[n++]; } y; > + (int(*)[n++])0; > + (typeof(int(*)[n++]))0; > + (struct { int x[n++]; }*)0; > + (struct q { int x[n++]; }*)0; > + typeof(struct { int x[n++]; }); /* { dg-warning "empty > declaration" } */ > + typeof(struct r { int x[n++]; }); /* { dg-warning "empty > declaration" } */ > + > + if (13 != n) > + __builtin_abort(); > +} > diff --git a/gcc/testsuite/gcc.misc-tests/gcov-pr85350.c > b/gcc/testsuite/gcc.misc-tests/gcov-pr85350.c > index 0383b81fdfb..a42bf1282b2 100644 > --- a/gcc/testsuite/gcc.misc-tests/gcov-pr85350.c > +++ b/gcc/testsuite/gcc.misc-tests/gcov-pr85350.c > @@ -4,7 +4,7 @@ > int main (void) > { > const int t = 2; /* count(1) */ > - struct s1 { /* count(1) */ > + struct s1 { /* count(-) */ > int x; > int g[t]; > }; > > > >