OSDN Git Service

PR c++/48446
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 May 2011 21:58:30 +0000 (21:58 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 6 May 2011 21:58:30 +0000 (21:58 +0000)
* decl.c (stabilize_save_expr_r, stabilize_vla_size): New.
(grokdeclarator): Use stabilize_vla_size.
* init.c (get_temp_regvar): No longer static.
* cp-tree.h: Declare it.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_6-branch@173514 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/init.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/vla-1.c [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/vla10.C [new file with mode: 0644]

index 3457ac5..e2be641 100644 (file)
@@ -1,5 +1,11 @@
 2011-05-06  Jason Merrill  <jason@redhat.com>
 
+       PR c++/48446
+       * decl.c (stabilize_save_expr_r, stabilize_vla_size): New.
+       (grokdeclarator): Use stabilize_vla_size.
+       * init.c (get_temp_regvar): No longer static.
+       * cp-tree.h: Declare it.
+
        PR c++/48089
        * semantics.c (potential_constant_expression_1): Don't allow *this
        in a constructor.
index 9fbca57..be61dad 100644 (file)
@@ -4958,6 +4958,7 @@ extern tree build_offset_ref                      (tree, tree, bool);
 extern tree build_new                          (VEC(tree,gc) **, tree, tree,
                                                 VEC(tree,gc) **, int,
                                                  tsubst_flags_t);
+extern tree get_temp_regvar                    (tree, tree);
 extern tree build_vec_init                     (tree, tree, tree, bool, int,
                                                  tsubst_flags_t);
 extern tree build_delete                       (tree, tree,
index 6f8bb9f..74bae0b 100644 (file)
@@ -7499,6 +7499,39 @@ 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);
+      *walk_subtrees = 0;
+    }
+  else if (!EXPR_P (expr) || !TREE_SIDE_EFFECTS (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.  */
@@ -8951,7 +8984,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)
            {
@@ -9026,6 +9064,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 4798257..ff94b71 100644 (file)
@@ -45,7 +45,6 @@ static void expand_virtual_init (tree, tree);
 static tree sort_mem_initializers (tree, tree);
 static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
-static tree get_temp_regvar (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
 static tree build_dtor_call (tree, special_function_kind, int);
 static tree build_field_list (tree, tree, int *);
@@ -2871,7 +2870,7 @@ create_temporary_var (tree type)
    things when it comes time to do final cleanups (which take place
    "outside" the binding contour of the function).  */
 
-static tree
+tree
 get_temp_regvar (tree type, tree init)
 {
   tree decl;
index 3e7cb22..f77596c 100644 (file)
@@ -1,5 +1,8 @@
 2011-05-06  Jason Merrill  <jason@redhat.com>
 
+       * g++.dg/ext/vla10.C: New.
+       * c-c++-common/vla-1.c: New.
+
        * g++.dg/cpp0x/constexpr-48089.C: New.
 
 2011-05-06  Dodji Seketeli  <dodji@redhat.com>
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;
+}
diff --git a/gcc/testsuite/g++.dg/ext/vla10.C b/gcc/testsuite/g++.dg/ext/vla10.C
new file mode 100644 (file)
index 0000000..17cdb2f
--- /dev/null
@@ -0,0 +1,32 @@
+// PR c++/48446
+// { dg-options "" }
+
+template<typename T>
+struct A
+{
+  ~A ();
+  T *operator-> () const;
+};
+
+struct B
+{
+  typedef A <B> P;
+  static P foo (int);
+};
+
+struct C
+{
+  typedef A<C> P;
+  static const int c = 80;
+};
+
+C::P bar ();
+
+void
+baz ()
+{
+  char z[bar ()->c];
+  {
+    B::P m = B::foo (sizeof (z));
+  }
+}