public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PING] [C PATCH]  Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]
@ 2023-05-18 12:46 Martin Uecker
  2023-05-18 21:46 ` Joseph Myers
  0 siblings, 1 reply; 4+ messages in thread
From: Martin Uecker @ 2023-05-18 12:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: joseph, richard.guenther



Ping. Ok, for trunk?

Bootstrapped and tested on x86_64-linux-gnu with no regressions.



    Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, 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 90d7cd27cd5..f63c1108ab5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5378,7 +5378,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))
@@ -7510,7 +7511,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);
@@ -7519,10 +7521,11 @@ 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);
+		DECL_ARTIFICIAL (decl) = 1;
+		add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
 		TYPE_NAME (type) = decl;
+
 		if (bind)
 		  {
 		    pop_scope ();
@@ -8721,7 +8724,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;
 
@@ -8778,7 +8781,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);
@@ -9436,13 +9439,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);
 
@@ -10068,6 +10064,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;
@@ -10079,7 +10076,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,
@@ -10088,6 +10085,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.  */
@@ -12292,10 +12294,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 c9f06930e3a..8e9948dff89 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;
@@ -11732,7 +11736,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
@@ -12871,7 +12875,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 f0ae641512d..5699b9d495d 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -3872,30 +3872,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
@@ -3931,14 +3907,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 3740a8979af..88ca2655ce4 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 *,
@@ -17467,7 +17468,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)
@@ -17575,6 +17576,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.dg/typename-vla-5.c b/gcc/testsuite/gcc.dg/typename-vla-5.c
new file mode 100644
index 00000000000..b959cb924af
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/typename-vla-5.c
@@ -0,0 +1,13 @@
+/* { dg-do run } 
+ * { dg-options "-std=gnu99" }
+ * */
+
+int
+main (void)
+{
+	int a = 1;
+	if (sizeof (*(++a, (struct { char (*x)[a]; }){ 0 }).x) != 2)
+ 		__builtin_abort ();
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/typename-vla-6.c b/gcc/testsuite/gcc.dg/typename-vla-6.c
new file mode 100644
index 00000000000..6dfb126870f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/typename-vla-6.c
@@ -0,0 +1,15 @@
+/* { dg-do run } 
+ * { dg-options "-std=gnu99" }
+ * */
+
+
+
+int
+main (void)
+{
+	int a = 1;
+	if ((++a, sizeof(*((struct { char (*x)[a]; }){ 0 }).x)) != 2)
+ 		__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];
   };



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PING] [C PATCH]  Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]
  2023-05-18 12:46 [PING] [C PATCH] Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450] Martin Uecker
@ 2023-05-18 21:46 ` Joseph Myers
  2023-05-19 11:50   ` [C PATCH v2] " Martin Uecker
  0 siblings, 1 reply; 4+ messages in thread
From: Joseph Myers @ 2023-05-18 21:46 UTC (permalink / raw)
  To: Martin Uecker; +Cc: gcc-patches, richard.guenther

On Thu, 18 May 2023, Martin Uecker via Gcc-patches wrote:

> +      /* we still have to evaluate size expressions */

Comments should start with a capital letter and end with ".  ".

> 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" } */

I'm concerned with various undefined behavior in this and other tests; 
they look very fragile, relying on some optimizations and not others 
taking place.  I think they should be adjusted to avoid undefined behavior 
if all the evaluations from the abstract machine (in particular, of sizeof 
operands with variable size) take place, and other undefined behavior from 
calling functions through function pointers with incompatible type.

> +	struct bar { char x[++n]; } (*bar2)(void) = bar;	/* { dg-warning "incompatible pointer type" } */
> +
> +	if (2 != n)
> +		__builtin_abort();
> +
> +	if (2 != sizeof((*bar2)()))
> +		__builtin_abort();

You're relying on the compiler not noticing that a function is being 
called through an incompatible type and thus not turning the call (which 
should be evaluated, because the operand of sizeof has a type with 
variable size) into a call to 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();

In this test, *bar() is evaluated, i.e. an undefined pointer is 
dereferenced; it would be better to return a valid pointer to a 
sufficiently large array to avoid that undefined behavior.

> 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();
> +	}

> +	g1(2, (void*)0);

Similarly, this is dereferencing a null pointer in the evaluated operand 
of sizeof.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [C PATCH v2]  Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]
  2023-05-18 21:46 ` Joseph Myers
@ 2023-05-19 11:50   ` Martin Uecker
  2023-05-19 20:54     ` Joseph Myers
  0 siblings, 1 reply; 4+ messages in thread
From: Martin Uecker @ 2023-05-19 11:50 UTC (permalink / raw)
  To: Joseph Myers; +Cc: gcc-patches, richard.guenther


Thanks Joseph! 

Revised version attached. Ok?


But I wonder whether we generally need to do something 
about

  sizeof *x

when x is NULL or not initialized. This is quite commonly
used in C code and if the type is not of variable size,
it is also unproblematic.  So the UB for variable size is
unfortunate and certainly also affects existing code in
the wild.  In practice it does not seem to cause
problems because there is no lvalue conversion and this
then seems to work.  Maybe we document this as an 
extension?  (and make sure in the C FE that it
works)  This would also make this idiom valid:

char (*buf)[n] = malloc(sizeof *buf);

Or if we do not want to do this, then I think we should
add some warnings (and UBSan check for null pointer)
which currently do not exist:

https://godbolt.org/z/fhWMKvYc8

Martin




Am Donnerstag, dem 18.05.2023 um 21:46 +0000 schrieb Joseph Myers:
> On Thu, 18 May 2023, Martin Uecker via Gcc-patches wrote:
> 
> > +      /* we still have to evaluate size expressions */
> 
> Comments should start with a capital letter and end with ".  ".
> 
> > 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" } */
> 
> I'm concerned with various undefined behavior in this and other tests; 
> they look very fragile, relying on some optimizations and not others 
> taking place.  I think they should be adjusted to avoid undefined behavior 
> if all the evaluations from the abstract machine (in particular, of sizeof 
> operands with variable size) take place, and other undefined behavior from 
> calling functions through function pointers with incompatible type.
> 
> > +	struct bar { char x[++n]; } (*bar2)(void) = bar;	/* { dg-warning "incompatible pointer type" } */
> > +
> > +	if (2 != n)
> > +		__builtin_abort();
> > +
> > +	if (2 != sizeof((*bar2)()))
> > +		__builtin_abort();
> 
> You're relying on the compiler not noticing that a function is being 
> called through an incompatible type and thus not turning the call (which 
> should be evaluated, because the operand of sizeof has a type with 
> variable size) into a call to 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();
> 
> In this test, *bar() is evaluated, i.e. an undefined pointer is 
> dereferenced; it would be better to return a valid pointer to a 
> sufficiently large array to avoid that undefined behavior.
> 
> > 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();
> > +	}
> 
> > +	g1(2, (void*)0);
> 
> Similarly, this is dereferencing a null pointer in the evaluated operand 
> of sizeof.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 90d7cd27cd5..f63c1108ab5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5378,7 +5378,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))
@@ -7510,7 +7511,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);
@@ -7519,10 +7521,11 @@ 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);
+		DECL_ARTIFICIAL (decl) = 1;
+		add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
 		TYPE_NAME (type) = decl;
+
 		if (bind)
 		  {
 		    pop_scope ();
@@ -8721,7 +8724,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;
 
@@ -8778,7 +8781,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);
@@ -9436,13 +9439,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);
 
@@ -10068,6 +10064,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;
@@ -10079,7 +10076,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,
@@ -10088,6 +10085,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.  */
@@ -12292,10 +12294,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 c9f06930e3a..a6009dfb878 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;
@@ -11732,7 +11736,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
@@ -12871,7 +12875,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 f0ae641512d..5699b9d495d 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -3872,30 +3872,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
@@ -3931,14 +3907,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 3740a8979af..88ca2655ce4 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 *,
@@ -17467,7 +17468,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)
@@ -17575,6 +17576,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..5b62c2c213a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nested-vla-1.c
@@ -0,0 +1,63 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+
+int main()
+{
+	int n = 1;
+
+	struct foo { char x[++n]; } bar(void) { struct foo r; return r; }
+
+	if (2 != n)
+		__builtin_abort();
+
+	if (2 != sizeof(bar()))
+		__builtin_abort();
+
+	n = 1;
+
+	struct bar { char x[++n]; } (*bar2p)(void);
+	struct bar bar2(void) { struct bar r; return r; }
+	bar2p = &bar2;
+
+	if (2 != n)
+		__builtin_abort();
+
+	if (2 != sizeof((*bar2p)()))
+		__builtin_abort();
+
+	n = 1;
+
+	struct str { char x[++n]; } *bar3(void)
+	{ 
+		struct str* s = __builtin_malloc(sizeof(struct str));
+		if (!s)
+			__builtin_abort();
+		struct str t;
+		*s = t;
+		return s;
+	}
+
+	if (2 != n)
+		__builtin_abort();
+
+	struct str* p;
+
+	if (2 != sizeof(*(p = bar3())))
+		__builtin_abort();
+
+	__builtin_free(p);
+
+	n = 1;
+
+	struct { char x[++n]; } *bar4(void) { }
+
+	if (2 != n)
+		__builtin_abort();
+#if 0
+	// UB
+	if (2 != sizeof(*bar4()))
+		__builtin_abort();
+#endif
+}
+
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..d83c90a0b16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nested-vla-2.c
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+
+int main()
+{
+	int n = 1;
+
+	char tmp[2] = { 0 };
+	typeof(char (*)[++n]) bar(void) { return &tmp; }
+
+	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..1ffb482da3b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nested-vla-3.c
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" } */
+
+
+int main()
+{
+	int n = 1;
+
+	char tmp[2] = { 0 };
+	char (*bar(void))[++n] { return &tmp; }
+
+	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..0c351a513a1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr106465.c
@@ -0,0 +1,109 @@
+/* PR c/106465
+ * { dg-do run }
+ * { dg-options "-std=gnu99" }
+ * */
+
+int main()
+{
+	int n = 3;
+
+	void* p = __builtin_malloc(sizeof(struct { char p[16]; }));
+
+	if (!p)
+		return 0;
+	
+	void g1(int m, struct foo { char p[++m]; }* b)	/* { dg-warning "struct" } */
+	{
+		if (3 != m)
+			__builtin_abort();
+
+		struct foo t;
+		*b = t;
+
+		if (3 != sizeof(b->p))
+			__builtin_abort();
+	}
+
+	void g2(struct { char p[++n]; }* b)	/* { dg-warning "anonymous struct" } */
+	{ 
+		if (4 != n)
+			__builtin_abort();
+
+		typeof(*b) t;
+		*b = t;
+
+		if (4 != sizeof(b->p))
+			__builtin_abort();
+	}
+
+	void g2b(struct { char (*p)[++n]; }* b)	/* { dg-warning "anonymous struct" } */
+	{ 
+		if (5 != n)
+			__builtin_abort();
+
+		char tmp[5];
+		typeof(*b) t = { &tmp };
+		*b = t;
+
+		if (5 != sizeof(*b->p))
+			__builtin_abort();
+	}
+
+	if (3 != n)
+		__builtin_abort();
+
+	g1(2, p);
+	g2(p);
+	g2b(p);
+	n--;
+
+	__builtin_free(p);
+
+	if (4 != n)
+		__builtin_abort();
+
+	struct foo { char (*p)[++n]; } x;
+
+	if (5 != n)
+		__builtin_abort();
+
+	char tmp1[5];
+	x.p = &tmp1;
+
+	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();
+
+	char tmp2[7];
+	u.p = &tmp2;
+
+	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..24d3db8f58b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/typename-vla-2.c
@@ -0,0 +1,19 @@
+/* { dg-do run } 
+ * { dg-options "-std=c99" }
+ * */
+
+
+static char tmp[2];
+
+static int f(int n, char (*x)[sizeof (*(++n, (char (*)[n])&tmp))])
+{
+  return sizeof *x;
+}
+
+int main (void)
+{
+  if (2 != f(1, &tmp))
+    __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..2bd683e1b97
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/typename-vla-3.c
@@ -0,0 +1,18 @@
+/* { dg-do run } 
+ * { dg-options "-std=c99" }
+ * */
+
+static char tmp[2];
+
+static int f(int n, char (*x)[sizeof *(++n, (struct { char (*x)[n]; }){ &tmp }).x]) /* { dg-warning "anonymous struct" } */
+{
+  return sizeof *x;
+}
+
+int main (void)
+{
+  if (2 != f(1, &tmp))
+    __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.dg/typename-vla-5.c b/gcc/testsuite/gcc.dg/typename-vla-5.c
new file mode 100644
index 00000000000..4644d25df13
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/typename-vla-5.c
@@ -0,0 +1,14 @@
+/* { dg-do run } 
+ * { dg-options "-std=gnu99" }
+ * */
+
+int
+main (void)
+{
+	int a = 1;
+	char tmp[2];
+	if (sizeof (*(++a, (struct { char (*x)[a]; }){ &tmp }).x) != 2)
+ 		__builtin_abort ();
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/typename-vla-6.c b/gcc/testsuite/gcc.dg/typename-vla-6.c
new file mode 100644
index 00000000000..58831df5492
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/typename-vla-6.c
@@ -0,0 +1,16 @@
+/* { dg-do run } 
+ * { dg-options "-std=gnu99" }
+ * */
+
+
+
+int
+main (void)
+{
+	int a = 1;
+	char tmp[2];
+	if ((++a, sizeof(*((struct { char (*x)[a]; }){ &tmp }).x)) != 2)
+ 		__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];
   };


> 



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [C PATCH v2]  Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]
  2023-05-19 11:50   ` [C PATCH v2] " Martin Uecker
@ 2023-05-19 20:54     ` Joseph Myers
  0 siblings, 0 replies; 4+ messages in thread
From: Joseph Myers @ 2023-05-19 20:54 UTC (permalink / raw)
  To: Martin Uecker; +Cc: gcc-patches, richard.guenther

[-- Attachment #1: Type: text/plain, Size: 1446 bytes --]

On Fri, 19 May 2023, Martin Uecker via Gcc-patches wrote:

> Thanks Joseph! 
> 
> Revised version attached. Ok?

The C front-end changes and tests are OK.

> But I wonder whether we generally need to do something 
> about
> 
>   sizeof *x
> 
> when x is NULL or not initialized. This is quite commonly
> used in C code and if the type is not of variable size,
> it is also unproblematic.  So the UB for variable size is
> unfortunate and certainly also affects existing code in
> the wild.  In practice it does not seem to cause
> problems because there is no lvalue conversion and this
> then seems to work.  Maybe we document this as an 
> extension?  (and make sure in the C FE that it
> works)  This would also make this idiom valid:

There's certainly a tricky question of what exactly it means to evaluate 
*x as far as producing an lvalue but without converting it to an rvalue - 
but right now the C standard wording on unary '*' is clear that "if it 
points to an object, the result is an lvalue designating the object" and 
"If an invalid value has been assigned to the pointer, the behavior of the 
unary * operator is undefined.", i.e. it's the evaluation as far as 
producing an lvalue that produces undefined behavior, rather than the 
lvalue conversion (that doesn't happen in sizeof) that does so.  And 
indeed we probably would be able to define semantics that avoid UB if 
desired.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-05-19 20:54 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-18 12:46 [PING] [C PATCH] Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450] Martin Uecker
2023-05-18 21:46 ` Joseph Myers
2023-05-19 11:50   ` [C PATCH v2] " Martin Uecker
2023-05-19 20:54     ` Joseph Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).