re PR c++/40975 (ICE in copy_tree_r on array new)
authorJason Merrill <jason@redhat.com>
Thu, 28 Apr 2011 01:53:34 +0000 (21:53 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 28 Apr 2011 01:53:34 +0000 (21:53 -0400)
PR c++/40975
* cp-tree.def (VEC_INIT_EXPR): Add third operand.
* cp-tree.h (VEC_INIT_EXPR_NELTS): New.
* cp-gimplify.c (cp_gimplify_expr) [VEC_INIT_EXPR]: Handle it.
* tree.c (build_vec_init_expr): Handle getting pointer/nelts.
(build_vec_init_elt): Don't expect an array type.
(build_array_copy): Adjust.
* init.c (perform_member_init): Adjust.
(build_new_1): Use build_vec_init_expr.

From-SVN: r173056

13 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/cp/ChangeLog
gcc/cp/cp-gimplify.c
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/init.c
gcc/cp/method.c
gcc/cp/tree.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/initlist49.C [new file with mode: 0644]
gcc/testsuite/g++.dg/init/new30.C [new file with mode: 0644]

index 6c6ca98895739bb8f8a92adfa26dc349a97bb10d..8864a3238e92cd3784c0250c25e2aec4be700b0c 100644 (file)
@@ -1,3 +1,8 @@
+2011-04-27  Jason Merrill  <jason@redhat.com>
+
+       * c-common.c (make_tree_vector_from_list): New.
+       * c-common.h: Declare it.
+
 2011-04-26  Richard Guenther  <rguenther@suse.de>
 
        PR preprocessor/48248
index 63277ca76af06d3698feca0e74c46ccc89c2155b..802040d9b0327bf342870312dafec1255e1365d5 100644 (file)
@@ -9580,6 +9580,17 @@ make_tree_vector_single (tree t)
   return ret;
 }
 
+/* Get a new tree vector of the TREE_VALUEs of a TREE_LIST chain.  */
+
+VEC(tree,gc) *
+make_tree_vector_from_list (tree list)
+{
+  VEC(tree,gc) *ret = make_tree_vector ();
+  for (; list; list = TREE_CHAIN (list))
+    VEC_safe_push (tree, gc, ret, TREE_VALUE (list));
+  return ret;
+}
+
 /* Get a new tree vector which is a copy of an existing one.  */
 
 VEC(tree,gc) *
index 09aa6000689e72dd3ee73ba7682ce6727c9c8e39..ad6da6be4a8056af7e7c4c32f4bad6d198f396f1 100644 (file)
@@ -959,6 +959,7 @@ extern void set_underlying_type (tree x);
 extern VEC(tree,gc) *make_tree_vector (void);
 extern void release_tree_vector (VEC(tree,gc) *);
 extern VEC(tree,gc) *make_tree_vector_single (tree);
+extern VEC(tree,gc) *make_tree_vector_from_list (tree);
 extern VEC(tree,gc) *make_tree_vector_copy (const VEC(tree,gc) *);
 
 /* In c-gimplify.c  */
index 349434f2fe96d3864d2485b32671e7b90dff9a99..737ba2e30ea446eaa0aed2b1dc7d2c0df4a78044 100644 (file)
@@ -1,5 +1,15 @@
 2011-04-27  Jason Merrill  <jason@redhat.com>
 
+       PR c++/40975
+       * cp-tree.def (VEC_INIT_EXPR): Add third operand.
+       * cp-tree.h (VEC_INIT_EXPR_NELTS): New.
+       * cp-gimplify.c (cp_gimplify_expr) [VEC_INIT_EXPR]: Handle it.
+       * tree.c (build_vec_init_expr): Handle getting pointer/nelts.
+       (build_vec_init_elt): Don't expect an array type.
+       (build_array_copy): Adjust.
+       * init.c (perform_member_init): Adjust.
+       (build_new_1): Use build_vec_init_expr.
+
        * class.c (resolve_address_of_overloaded_function): Don't
        change OVERLOAD to TREE_LIST.
        * pt.c (print_candidates_1): Remove nonsensical assert.
index ca62df3e5858c7bd96bcd79e74c5142a3716babf..dc2e0fb4473f0ea3538e72fb657bdf952599c039 100644 (file)
@@ -530,10 +530,12 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
       {
        location_t loc = input_location;
        tree init = VEC_INIT_EXPR_INIT (*expr_p);
-       int from_array = (init && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE);
+       int from_array = (init && TREE_TYPE (init)
+                         && TREE_CODE (TREE_TYPE (init)) == ARRAY_TYPE);
        gcc_assert (EXPR_HAS_LOCATION (*expr_p));
        input_location = EXPR_LOCATION (*expr_p);
-       *expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p), NULL_TREE,
+       *expr_p = build_vec_init (VEC_INIT_EXPR_SLOT (*expr_p),
+                                 VEC_INIT_EXPR_NELTS (*expr_p),
                                  init, VEC_INIT_EXPR_VALUE_INIT (*expr_p),
                                  from_array,
                                  tf_warning_or_error);
index 7bd35e0d6b29a5fa2c1fee98d314c90b9ea0dbed..c9fc9707311de20ac8f2c5eabe01bae755bc75d7 100644 (file)
@@ -83,8 +83,8 @@ DEFTREECODE (AGGR_INIT_EXPR, "aggr_init_expr", tcc_vl_exp, 3)
 
 /* Initialization of an array from another array, expressed at a high level
    so that it works with TARGET_EXPR.  Operand 0 is the target, operand 1
-   is the initializer.  */
-DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", tcc_expression, 2)
+   is the initializer, operand 2 is the number of elements or NULL_TREE.  */
+DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", tcc_expression, 3)
 
 /* A throw expression.  operand 0 is the expression, if there was one,
    else it is NULL_TREE.  */
index 26da4b3746c10dccb7630fd8e5a5a9a8d51d2874..a65998d31006beb20dede478d985fe81a53405dc 100644 (file)
@@ -2896,8 +2896,9 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
        (arg) = next_aggr_init_expr_arg (&(iter)))
 
 /* VEC_INIT_EXPR accessors.  */
-#define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (NODE, 0)
-#define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (NODE, 1)
+#define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 0)
+#define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 1)
+#define VEC_INIT_EXPR_NELTS(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 2)
 
 /* Indicates that a VEC_INIT_EXPR is a potential constant expression.
    Only set when the current function is constexpr.  */
@@ -5022,6 +5023,7 @@ extern tree get_copy_ctor                 (tree);
 extern tree get_copy_assign                    (tree);
 extern tree get_default_ctor                   (tree);
 extern tree get_dtor                           (tree);
+extern tree get_dtor_sfinae                    (tree, tsubst_flags_t);
 extern tree locate_ctor                                (tree);
 
 /* In optimize.c */
@@ -5418,7 +5420,7 @@ extern tree get_target_expr_sfinae                (tree, tsubst_flags_t);
 extern tree build_cplus_array_type             (tree, tree);
 extern tree build_array_of_n_type              (tree, int);
 extern tree build_array_copy                   (tree);
-extern tree build_vec_init_expr                        (tree, tree);
+extern tree build_vec_init_expr                        (tree, tree, tree, tsubst_flags_t);
 extern void diagnose_non_constexpr_vec_init    (tree);
 extern tree hash_tree_cons                     (tree, tree, tree);
 extern tree hash_tree_chain                    (tree, tree);
index 25beba8bd5ea4e5e2085a5ddee26f15d89274214..883734f65f6907e589c93b7fc8623d905cb71331 100644 (file)
@@ -506,7 +506,8 @@ perform_member_init (tree member, tree init)
       /* mem() means value-initialization.  */
       if (TREE_CODE (type) == ARRAY_TYPE)
        {
-         init = build_vec_init_expr (type, init);
+         init = build_vec_init_expr (type, init, NULL_TREE,
+                                     tf_warning_or_error);
          init = build2 (INIT_EXPR, type, decl, init);
          finish_expr_stmt (init);
        }
@@ -541,7 +542,8 @@ perform_member_init (tree member, tree init)
              || same_type_ignoring_top_level_qualifiers_p (type,
                                                            TREE_TYPE (init)))
            {
-             init = build_vec_init_expr (type, init);
+             init = build_vec_init_expr (type, init, NULL_TREE,
+                                         tf_warning_or_error);
              init = build2 (INIT_EXPR, type, decl, init);
              finish_expr_stmt (init);
            }
@@ -2384,15 +2386,14 @@ build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
              vecinit = build_tree_list_vec (*init);
             }
          init_expr
-           = build_vec_init (data_addr,
-                             cp_build_binary_op (input_location,
-                                                 MINUS_EXPR, outer_nelts,
-                                                 integer_one_node,
-                                                 complain),
-                             vecinit,
-                             explicit_value_init_p,
-                             /*from_array=*/0,
-                              complain);
+           = build_vec_init_expr (data_addr,
+                                  (explicit_value_init_p
+                                   ? void_type_node: vecinit),
+                                  cp_build_binary_op (input_location,
+                                                      MINUS_EXPR, outer_nelts,
+                                                      integer_one_node,
+                                                      complain),
+                                  complain);
 
          /* An array initialization is stable because the initialization
             of each element is a full-expression, so the temporaries don't
index 6b268067cc028ea0c00e04cd85b21efdf452f555..8b1b4dcf40c24b59c75603f55e03af01fe62b51b 100644 (file)
@@ -842,11 +842,17 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags,
 
 /* Locate the dtor of TYPE.  */
 
+tree
+get_dtor_sfinae (tree type, tsubst_flags_t complain)
+{
+  return locate_fn_flags (type, complete_dtor_identifier, NULL_TREE,
+                         LOOKUP_NORMAL, complain);
+}
+
 tree
 get_dtor (tree type)
 {
-  tree fn = locate_fn_flags (type, complete_dtor_identifier, NULL_TREE,
-                            LOOKUP_NORMAL, tf_warning_or_error);
+  tree fn = get_dtor_sfinae (type, tf_warning_or_error);
   if (fn == error_mark_node)
     return NULL_TREE;
   return fn;
index 8fe8832f7bb3095e6e43aec8999b91e8fabe6b48..2f082a6ff542d5b57167caeeaea9c911605c45dd 100644 (file)
@@ -473,45 +473,80 @@ build_cplus_new (tree type, tree init, tsubst_flags_t complain)
    another array to copy.  */
 
 static tree
-build_vec_init_elt (tree type, tree init)
+build_vec_init_elt (tree type, tree init, tsubst_flags_t complain)
 {
-  tree inner_type = strip_array_types (type);
+  tree inner_type = strip_array_types (TREE_TYPE (type));
   VEC(tree,gc) *argvec;
 
-  if (integer_zerop (array_type_nelts_total (type))
-      || !CLASS_TYPE_P (inner_type))
+  if (!CLASS_TYPE_P (inner_type))
     /* No interesting initialization to do.  */
     return integer_zero_node;
   else if (init == void_type_node)
     return build_value_init (inner_type, tf_warning_or_error);
 
-  gcc_assert (init == NULL_TREE
-             || (same_type_ignoring_top_level_qualifiers_p
-                 (type, TREE_TYPE (init))));
-
-  argvec = make_tree_vector ();
-  if (init)
+  if (init == NULL_TREE)
+    argvec = make_tree_vector ();
+  else if (TREE_CODE (init) == TREE_LIST)
+    /* Array init extension, i.e. g++.robertl/eb58.C. */
+    argvec = make_tree_vector_from_list (init);
+  else if (same_type_ignoring_top_level_qualifiers_p
+          (inner_type, strip_array_types (TREE_TYPE (init))))
     {
+      /* Array copy or list-initialization.  */
       tree dummy = build_dummy_object (inner_type);
       if (!real_lvalue_p (init))
        dummy = move (dummy);
-      VEC_quick_push (tree, argvec, dummy);
+      argvec = make_tree_vector_single (dummy);
     }
-  return build_special_member_call (NULL_TREE, complete_ctor_identifier,
+  else
+    gcc_unreachable ();
+  init = build_special_member_call (NULL_TREE, complete_ctor_identifier,
                                    &argvec, inner_type, LOOKUP_NORMAL,
-                                   tf_warning_or_error);
+                                   complain);
+  release_tree_vector (argvec);
+
+  /* For array new, also mark the destructor as used.  */
+  if (TREE_CODE (type) == POINTER_TYPE
+      && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_type))
+    {
+      tree dtor = get_dtor_sfinae (inner_type, complain);
+      if (dtor == error_mark_node)
+       return error_mark_node;
+      else if (dtor)
+       mark_used (dtor);
+    }
+  return init;
 }
 
-/* Return a TARGET_EXPR which expresses the initialization of an array to
-   be named later, either default-initialization or copy-initialization
-   from another array of the same type.  */
+/* Return a TARGET_EXPR which expresses the initialization of an array.  If
+   TARGET is an array type, the initialization is of an array to be named
+   later, and the initialization will be wrapped in a TARGET_EXPR.  If
+   TARGET is an expression, it is the array to be initialized.  INIT is the
+   initializer, or void_type_node for value-initialization.  If TARGET is
+   an expression, NELTS is the number of elements to initialize. */
 
 tree
-build_vec_init_expr (tree type, tree init)
+build_vec_init_expr (tree target, tree init, tree nelts,
+                    tsubst_flags_t complain)
 {
-  tree slot;
+  tree slot, type;
   bool value_init = false;
-  tree elt_init = build_vec_init_elt (type, init);
+  tree elt_init;
+  tree real_nelts;
+
+  if (TYPE_P (target))
+    {
+      gcc_assert (TREE_CODE (target) == ARRAY_TYPE && nelts == NULL_TREE);
+      type = target;
+      slot = build_local_temp (type);
+    }
+  else
+    {
+      gcc_assert (EXPR_P (target));
+      slot = target;
+      type = TREE_TYPE (slot);
+      gcc_assert (TREE_CODE (type) == POINTER_TYPE && nelts != NULL_TREE);
+    }
 
   if (init == void_type_node)
     {
@@ -519,8 +554,14 @@ build_vec_init_expr (tree type, tree init)
       init = NULL_TREE;
     }
 
-  slot = build_local_temp (type);
-  init = build2 (VEC_INIT_EXPR, type, slot, init);
+  real_nelts = nelts ? nelts : array_type_nelts_total (type);
+  if (integer_zerop (real_nelts))
+    /* No elements to initialize.  */
+    elt_init = integer_zero_node;
+  else
+    elt_init = build_vec_init_elt (type, init, complain);
+
+  init = build3 (VEC_INIT_EXPR, type, slot, init, nelts);
   SET_EXPR_LOCATION (init, input_location);
 
   if (cxx_dialect >= cxx0x
@@ -528,8 +569,11 @@ build_vec_init_expr (tree type, tree init)
     VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
   VEC_INIT_EXPR_VALUE_INIT (init) = value_init;
 
-  init = build_target_expr (slot, init, tf_warning_or_error);
-  TARGET_EXPR_IMPLICIT_P (init) = 1;
+  if (slot != target)
+    {
+      init = build_target_expr (slot, init, complain);
+      TARGET_EXPR_IMPLICIT_P (init) = 1;
+    }
 
   return init;
 }
@@ -547,14 +591,15 @@ diagnose_non_constexpr_vec_init (tree expr)
   else
     init = VEC_INIT_EXPR_INIT (expr);
 
-  elt_init = build_vec_init_elt (type, init);
+  elt_init = build_vec_init_elt (type, init, tf_warning_or_error);
   require_potential_constant_expression (elt_init);
 }
 
 tree
 build_array_copy (tree init)
 {
-  return build_vec_init_expr (TREE_TYPE (init), init);
+  return build_vec_init_expr (TREE_TYPE (init), init, NULL_TREE,
+                             tf_warning_or_error);
 }
 
 /* Build a TARGET_EXPR using INIT to initialize a new temporary of the
index d61af1b2568dab33746cb34d084ff7036c59ddf9..73060c0a9b4a8db34358cde5e15cfe3514272e6a 100644 (file)
@@ -1,3 +1,8 @@
+2011-04-27  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/initlist49.C: New.
+       * g++.dg/init/new30.C: New.
+
 2011-04-27  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/48788
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist49.C b/gcc/testsuite/g++.dg/cpp0x/initlist49.C
new file mode 100644 (file)
index 0000000..752c433
--- /dev/null
@@ -0,0 +1,18 @@
+// Test for non-trivial list-initialization with array new.
+// { dg-options -std=c++0x }
+// { dg-do run }
+
+struct A
+{
+  enum E { c_string, number } e;
+  A(const char *): e(c_string) {}
+  A(int): e(number) {}
+};
+
+int main()
+{
+  A* ap = new A[2]{1, ""};
+  if (ap[0].e != A::number || ap[1].e != A::c_string)
+    return 1;
+  delete[] ap;
+}
diff --git a/gcc/testsuite/g++.dg/init/new30.C b/gcc/testsuite/g++.dg/init/new30.C
new file mode 100644 (file)
index 0000000..24582d8
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/40975
+
+struct data_type
+{
+    // constructor required to reproduce compiler bug
+    data_type() {}
+};
+
+struct ptr_type
+{
+    // array new as default argument required to reproduce compiler bug
+    ptr_type (data_type* ptr = new data_type[1]) { delete[] ptr; }
+};
+
+ptr_type obj;