]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix ICEs related to VM types in C 2/2 [PR109450]
authorMartin Uecker <uecker@tugraz.at>
Sun, 21 May 2023 17:32:01 +0000 (19:32 +0200)
committerMartin Uecker <uecker@tugraz.at>
Tue, 23 May 2023 20:04:56 +0000 (22:04 +0200)
Size expressions were sometimes lost and not gimplified correctly,
leading to ICEs and incorrect evaluation order.  Fix this by 1) not
recursing pointers when gimplifying parameters, which was incorrect
because it might access variables declared later for incomplete
structs, and 2) adding a decl expr for variably-modified arrays
that are pointed to by parameters declared as arrays.

PR c/109450

gcc/
* function.cc (gimplify_parm_type): Remove function.
(gimplify_parameters): Call gimplify_type_sizes.

gcc/c/
* c-decl.cc (add_decl_expr): New function.
(grokdeclarator): Add decl expr for size expression in
types pointed to by parameters declared as arrays.

gcc/testsuite/
* gcc.dg/pr109450-1.c: New test.
* gcc.dg/pr109450-2.c: New test.
* gcc.dg/vla-26.c: New test.

gcc/c/c-decl.cc
gcc/function.cc
gcc/testsuite/gcc.dg/pr109450-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr109450-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/vla-26.c [new file with mode: 0644]

index 494d3cf17476179b7780f62471b23d25a29dc4e7..1af51c4acfc5e678b15f7418fda7377198776c49 100644 (file)
@@ -6490,6 +6490,58 @@ smallest_type_quals_location (const location_t *locations,
   return loc;
 }
 
+
+/* We attach an artificial TYPE_DECL to pointed-to type
+   and arrange for it to be included in a DECL_EXPR.  This
+   forces the sizes evaluation at a safe point and ensures it
+   is not deferred until e.g. within a deeper conditional context.
+
+   PARM contexts have no enclosing statement list that
+   can hold the DECL_EXPR, so we need to use a BIND_EXPR
+   instead, and add it to the list of expressions that
+   need to be evaluated.
+
+   TYPENAME contexts do have an enclosing statement list,
+   but it would be incorrect to use it, as the size should
+   only be evaluated if the containing expression is
+   evaluated.  We might also be in the middle of an
+   expression with side effects on the pointed-to type size
+   "arguments" prior to the pointer declaration point and
+   the fake TYPE_DECL in the enclosing context would force
+   the size evaluation prior to the side effects.  We therefore
+   use BIND_EXPRs in TYPENAME contexts too.  */
+static void
+add_decl_expr (location_t loc, enum decl_context decl_context, tree type,
+              tree *expr)
+{
+  tree bind = NULL_TREE;
+  if (decl_context == TYPENAME || decl_context == PARM
+      || decl_context == FIELD)
+    {
+      bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE,
+                    NULL_TREE);
+      TREE_SIDE_EFFECTS (bind) = 1;
+      BIND_EXPR_BODY (bind) = push_stmt_list ();
+      push_scope ();
+    }
+
+  tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
+  pushdecl (decl);
+  DECL_ARTIFICIAL (decl) = 1;
+  add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
+  TYPE_NAME (type) = decl;
+
+  if (bind)
+    {
+      pop_scope ();
+      BIND_EXPR_BODY (bind) = pop_stmt_list (BIND_EXPR_BODY (bind));
+      if (*expr)
+       *expr = build2 (COMPOUND_EXPR, void_type_node, *expr, bind);
+      else
+       *expr = bind;
+    }
+}
+
 /* Given declspecs and a declarator,
    determine the name and type of the object declared
    and construct a ..._DECL node for it.
@@ -7474,58 +7526,9 @@ grokdeclarator (const struct c_declarator *declarator,
 
               This is expected to happen automatically when the pointed-to
               type has a name/declaration of it's own, but special attention
-              is required if the type is anonymous.
-
-              We attach an artificial TYPE_DECL to such pointed-to type
-              and arrange for it to be included in a DECL_EXPR.  This
-              forces the sizes evaluation at a safe point and ensures it
-              is not deferred until e.g. within a deeper conditional context.
-
-              PARM contexts have no enclosing statement list that
-              can hold the DECL_EXPR, so we need to use a BIND_EXPR
-              instead, and add it to the list of expressions that
-              need to be evaluated.
-
-              TYPENAME contexts do have an enclosing statement list,
-              but it would be incorrect to use it, as the size should
-              only be evaluated if the containing expression is
-              evaluated.  We might also be in the middle of an
-              expression with side effects on the pointed-to type size
-              "arguments" prior to the pointer declaration point and
-              the fake TYPE_DECL in the enclosing context would force
-              the size evaluation prior to the side effects.  We therefore
-              use BIND_EXPRs in TYPENAME contexts too.  */
-           if (!TYPE_NAME (type)
-               && c_type_variably_modified_p (type))
-             {
-               tree bind = NULL_TREE;
-               if (decl_context == TYPENAME || decl_context == PARM
-                   || decl_context == FIELD)
-                 {
-                   bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
-                                  NULL_TREE, NULL_TREE);
-                   TREE_SIDE_EFFECTS (bind) = 1;
-                   BIND_EXPR_BODY (bind) = push_stmt_list ();
-                   push_scope ();
-                 }
-               tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
-               pushdecl (decl);
-               DECL_ARTIFICIAL (decl) = 1;
-               add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
-               TYPE_NAME (type) = decl;
-
-               if (bind)
-                 {
-                   pop_scope ();
-                   BIND_EXPR_BODY (bind)
-                     = pop_stmt_list (BIND_EXPR_BODY (bind));
-                   if (*expr)
-                     *expr = build2 (COMPOUND_EXPR, void_type_node, *expr,
-                                     bind);
-                   else
-                     *expr = bind;
-                 }
-             }
+              is required if the type is anonymous. */
+           if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
+             add_decl_expr (loc, decl_context, type, expr);
 
            type = c_build_pointer_type (type);
 
@@ -7787,6 +7790,11 @@ grokdeclarator (const struct c_declarator *declarator,
            if (type_quals)
              type = c_build_qualified_type (type, type_quals, orig_qual_type,
                                             orig_qual_indirect);
+
+           /* The pointed-to type may need a decl expr (see above).  */
+           if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
+             add_decl_expr (loc, decl_context, type, expr);
+
            type = c_build_pointer_type (type);
            type_quals = array_ptr_quals;
            if (type_quals)
index f0ae641512d91ecf088f7c520be35e4ffcf49c2c..82102ed78d7e64241751814550296b11787eaa71 100644 (file)
@@ -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,8 +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);
+      gimplify_type_sizes (TREE_TYPE (parm), &stmts);
 
       if (TREE_CODE (DECL_SIZE_UNIT (parm)) != INTEGER_CST)
        {
diff --git a/gcc/testsuite/gcc.dg/pr109450-1.c b/gcc/testsuite/gcc.dg/pr109450-1.c
new file mode 100644 (file)
index 0000000..aec127f
--- /dev/null
@@ -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 (file)
index 0000000..06799f6
--- /dev/null
@@ -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/vla-26.c b/gcc/testsuite/gcc.dg/vla-26.c
new file mode 100644 (file)
index 0000000..5d2fa3e
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -O2" } */
+
+void ed(int n, float s[3][n])
+{
+       for (int i = 0; i < n; i++)
+               s[1][i];
+}
+
+void e(int n, float s[3][n])
+{
+       ed(n, s);       
+}
+
+