Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450]

Message ID 82efe5297d61e4937eae0b1aca8eae5a97da04e3.camel@gmail.com
State New
Headers
Series Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450] |

Commit Message

Martin Uecker April 11, 2023, 6:47 p.m. UTC
  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.

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.
  

Comments

Andrew Pinski April 11, 2023, 7:01 p.m. UTC | #1
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];
>    };
>
>
>
>
  
Joseph Myers April 12, 2023, 12:32 a.m. UTC | #2
On Tue, 11 Apr 2023, Martin Uecker via Gcc-patches 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.

This wording implies this is version 2 or later of the patch, could you 
please give a reference to whatever previous patch posting / discussion 
there may have been?

> 	Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450]

108424 seems to be the wrong PR number.
  
Martin Uecker April 12, 2023, 5:02 a.m. UTC | #3
Am Mittwoch, dem 12.04.2023 um 00:32 +0000 schrieb Joseph Myers:
> On Tue, 11 Apr 2023, Martin Uecker via Gcc-patches 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.
> 
> This wording implies this is version 2 or later of the patch, could you 
> please give a reference to whatever previous patch posting / discussion 
> there may have been?

The previous one was the following for PR107557 and PR108423.

https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611562.html

While revising it I realized that recursing for parameter
when gimplifying is incorrect for the same reason as recursing in
other cases (see the comment in gimplify_type_sizes). This lead
to PR109450.

> 
> > 	Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450]
> 
> 108424 seems to be the wrong PR number.

This should be: PR108423


Martin
  

Patch

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];
   };