re PR c++/48446 (internal compiler error: in gimplify_var_or_parm_decl, at gimplify...
authorJason Merrill <jason@redhat.com>
Mon, 2 May 2011 18:38:44 +0000 (14:38 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 2 May 2011 18:38:44 +0000 (14:38 -0400)
PR c++/48446
* decl.c (stabilize_save_expr_r, stabilize_vla_size): New.
(compute_array_index_type): Revert earlier 48446 changes.
(grokdeclarator): Use stabilize_vla_size.

From-SVN: r173264

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/vla-1.c [new file with mode: 0644]

index fc64e7dd2363285e19168ba4d070429fd208b60d..983939e2a180aedcbb186e56a26c15eb8d8c9ca8 100644 (file)
@@ -1,3 +1,10 @@
+2011-05-02  Jason Merrill  <jason@redhat.com>
+
+       PR c++/48446
+       * decl.c (stabilize_save_expr_r, stabilize_vla_size): New.
+       (compute_array_index_type): Revert earlier 48446 changes.
+       (grokdeclarator): Use stabilize_vla_size.
+
 2011-05-02  Dmitry Gorbachev  <d.g.gorbachev@gmail.com>
            Eric Botcazou <ebotcazou@adacore.com>
 
index 0a2e1dd5cc5f5482d59b6100aa1dc15493aa05d1..f9dd6dec5f8fa038a2e5a20a518a58d773544239 100644 (file)
@@ -7576,6 +7576,38 @@ check_static_variable_definition (tree decl, tree type)
   return 0;
 }
 
+/* *expr_p is part of the TYPE_SIZE of a variably-sized array.  If any
+   SAVE_EXPRs in *expr_p wrap expressions with side-effects, break those
+   expressions out into temporary variables so that walk_tree doesn't
+   step into them (c++/15764).  */
+
+static tree
+stabilize_save_expr_r (tree *expr_p, int *walk_subtrees, void *data)
+{
+  struct pointer_set_t *pset = (struct pointer_set_t *)data;
+  tree expr = *expr_p;
+  if (TREE_CODE (expr) == SAVE_EXPR)
+    {
+      tree op = TREE_OPERAND (expr, 0);
+      cp_walk_tree (&op, stabilize_save_expr_r, data, pset);
+      if (TREE_SIDE_EFFECTS (op))
+       TREE_OPERAND (expr, 0) = get_temp_regvar (TREE_TYPE (op), op);
+    }
+  else if (!EXPR_P (expr))
+    *walk_subtrees = 0;
+  return NULL;
+}
+
+/* Entry point for the above.  */
+
+static void
+stabilize_vla_size (tree size)
+{
+  struct pointer_set_t *pset = pointer_set_create ();
+  /* Break out any function calls into temporary variables.  */
+  cp_walk_tree (&size, stabilize_save_expr_r, pset, pset);
+}
+
 /* Given the SIZE (i.e., number of elements) in an array, compute an
    appropriate index type for the array.  If non-NULL, NAME is the
    name of the thing being declared.  */
@@ -7769,16 +7801,8 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
       processing_template_decl = saved_processing_template_decl;
 
       if (!TREE_CONSTANT (itype))
-       {
-         /* A variable sized array.  */
-         if (TREE_SIDE_EFFECTS (itype))
-           /* Use get_temp_regvar rather than variable_size here so that
-              people walking expressions that use a variable of this type
-              don't walk into this expression.  */
-           itype = get_temp_regvar (TREE_TYPE (itype), itype);
-         else
-           itype = variable_size (itype);
-       }
+       /* A variable sized array.  */
+       itype = variable_size (itype);
       /* Make sure that there was no overflow when creating to a signed
         index type.  (For example, on a 32-bit machine, an array with
         size 2^32 - 1 is too big.)  */
@@ -9051,7 +9075,12 @@ grokdeclarator (const cp_declarator *declarator,
              && (decl_context == NORMAL || decl_context == FIELD)
              && at_function_scope_p ()
              && variably_modified_type_p (type, NULL_TREE))
-           finish_expr_stmt (TYPE_SIZE (type));
+           {
+             /* First break out any side-effects.  */
+             stabilize_vla_size (TYPE_SIZE (type));
+             /* And then force evaluation of the SAVE_EXPR.  */
+             finish_expr_stmt (TYPE_SIZE (type));
+           }
 
          if (declarator->kind == cdk_reference)
            {
@@ -9126,6 +9155,14 @@ grokdeclarator (const cp_declarator *declarator,
        }
     }
 
+  /* We need to stabilize side-effects in VLA sizes for regular array
+     declarations too, not just pointers to arrays.  */
+  if (type != error_mark_node && !TYPE_NAME (type)
+      && (decl_context == NORMAL || decl_context == FIELD)
+      && at_function_scope_p ()
+      && variably_modified_type_p (type, NULL_TREE))
+    stabilize_vla_size (TYPE_SIZE (type));
+
   /* A `constexpr' specifier used in an object declaration declares
      the object as `const'.  */
   if (constexpr_p && innermost_code != cdk_function)
index 02722cf34022392da90b75d59a6e8c4e7d2c530f..e6cdd3fa654a3359013334791eb7ca68e3bcacb0 100644 (file)
@@ -1,3 +1,7 @@
+2011-05-02  Jason Merrill  <jason@redhat.com>
+
+       * c-c++-common/vla-1.c: New.
+
 2011-05-02  Richard Guenther  <rguenther@suse.de>
 
        PR tree-optimization/48822
diff --git a/gcc/testsuite/c-c++-common/vla-1.c b/gcc/testsuite/c-c++-common/vla-1.c
new file mode 100644 (file)
index 0000000..401c4e0
--- /dev/null
@@ -0,0 +1,21 @@
+/* Test that changes to a variable are reflected in a VLA later in the
+   expression.  */
+/* { dg-options "" } */
+
+#ifdef __cplusplus
+extern "C"
+#endif
+void abort();
+
+int i = 4;
+int f()
+{
+  return i;
+}
+
+int main()
+{
+  if (i+=2, sizeof(*(int(*)[f()])0) != 6*sizeof(int))
+    abort();
+  return 0;
+}