Patchwork C++ PATCH for c++/49216 (problems with new T[1]{})

login
register
mail settings
Submitter Jason Merrill
Date June 29, 2011, 10:25 p.m.
Message ID <4E0BA665.5040105@redhat.com>
Download mbox | patch
Permalink /patch/102685/
State New
Headers show

Comments

Jason Merrill - June 29, 2011, 10:25 p.m.
As reported, this still wasn't working properly for an array of scalar 
type.  We still need to handle {} in the case of iterating over all the 
elements.

While I was poking at related code, I fixed a wrong-code bug with the 
ancient and permerrored new T[n](init) extension because it was easy.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit dd6c8f64eec3752e9a7cf63b8ef2e46627fb5af1
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jun 29 17:13:49 2011 -0400

    	PR c++/49216
    	* init.c (build_new_1): Pass {} down to build_vec_init.
    	(build_vec_init): Handle it.

diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index ac2b733..f80c475 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2396,24 +2396,31 @@  build_new_1 (VEC(tree,gc) **placement, tree type, tree nelts,
 	      && BRACE_ENCLOSED_INITIALIZER_P (VEC_index (tree, *init, 0))
 	      && CONSTRUCTOR_IS_DIRECT_INIT (VEC_index (tree, *init, 0)))
 	    {
-	      tree arraytype, domain;
 	      vecinit = VEC_index (tree, *init, 0);
-	      if (TREE_CONSTANT (nelts))
-		domain = compute_array_index_type (NULL_TREE, nelts, complain);
+	      if (CONSTRUCTOR_NELTS (vecinit) == 0)
+		/* List-value-initialization, leave it alone.  */;
 	      else
 		{
-		  domain = NULL_TREE;
-		  if (CONSTRUCTOR_NELTS (vecinit) > 0)
-		    warning (0, "non-constant array size in new, unable to "
-			     "verify length of initializer-list");
+		  tree arraytype, domain;
+		  if (TREE_CONSTANT (nelts))
+		    domain = compute_array_index_type (NULL_TREE, nelts,
+						       complain);
+		  else
+		    {
+		      domain = NULL_TREE;
+		      if (CONSTRUCTOR_NELTS (vecinit) > 0)
+			warning (0, "non-constant array size in new, unable "
+				 "to verify length of initializer-list");
+		    }
+		  arraytype = build_cplus_array_type (type, domain);
+		  vecinit = digest_init (arraytype, vecinit, complain);
 		}
-	      arraytype = build_cplus_array_type (type, domain);
-	      vecinit = digest_init (arraytype, vecinit, complain);
 	    }
 	  else if (*init)
             {
               if (complain & tf_error)
-                permerror (input_location, "ISO C++ forbids initialization in array new");
+                permerror (input_location,
+			   "parenthesized initializer in array new");
               else
                 return error_mark_node;
 	      vecinit = build_tree_list_vec (*init);
@@ -3090,9 +3097,23 @@  build_vec_init (tree base, tree maxindex, tree init,
       try_block = begin_try_block ();
     }
 
+  /* If the initializer is {}, then all elements are initialized from {}.
+     But for non-classes, that's the same as value-initialization.  */
+  if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
+      && CONSTRUCTOR_NELTS (init) == 0)
+    {
+      if (CLASS_TYPE_P (type))
+	/* Leave init alone.  */;
+      else
+	{
+	  init = NULL_TREE;
+	  explicit_value_init_p = true;
+	}
+    }
+
   /* Maybe pull out constant value when from_array? */
 
-  if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
+  else if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR)
     {
       /* Do non-default initialization of non-trivial arrays resulting from
 	 brace-enclosed initializers.  */
@@ -3210,7 +3231,7 @@  build_vec_init (tree base, tree maxindex, tree init,
      We do need to keep going if we're copying an array.  */
 
   if (from_array
-      || ((type_build_ctor_call (type) || explicit_value_init_p)
+      || ((type_build_ctor_call (type) || init || explicit_value_init_p)
 	  && ! (host_integerp (maxindex, 0)
 		&& (num_initialized_elts
 		    == tree_low_cst (maxindex, 0) + 1))))
@@ -3276,8 +3297,16 @@  build_vec_init (tree base, tree maxindex, tree init,
 	}
       else
 	{
-	  gcc_assert (type_build_ctor_call (type));
-	  elt_init = build_aggr_init (to, init, 0, complain);
+	  gcc_assert (type_build_ctor_call (type) || init);
+	  if (CLASS_TYPE_P (type))
+	    elt_init = build_aggr_init (to, init, 0, complain);
+	  else
+	    {
+	      if (TREE_CODE (init) == TREE_LIST)
+		init = build_x_compound_expr_from_list (init, ELK_INIT,
+							complain);
+	      elt_init = build2 (INIT_EXPR, type, to, init);
+	    }
 	}
 
       if (elt_init == error_mark_node)
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-value.C b/gcc/testsuite/g++.dg/cpp0x/initlist-value.C
index 25a3373..215bb90 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist-value.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist-value.C
@@ -2,6 +2,9 @@ 
 // { dg-options -std=c++0x }
 // { dg-do run }
 
+void * operator new (__SIZE_TYPE__, void *p) { return p; }
+void * operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
 // Empty base so A isn't an aggregate
 struct B {};
 struct A: B {
@@ -18,8 +21,14 @@  int main()
 {
   A a{};
   C c;
+  int space = 42;
+  A* ap = new (&space) A{};
+  int space1[1] = { 42 };
+  A* a1p = new (space1) A[1]{};
   if (a.i != 0
       || c.i != 0
+      || ap->i != 0
+      || a1p[0].i != 0
       || A{}.i != 0
       || f({}) != 0)
     return 1;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist53.C b/gcc/testsuite/g++.dg/cpp0x/initlist53.C
index 750ebba..22633f9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist53.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist53.C
@@ -4,6 +4,7 @@ 
 
 #include <initializer_list>
 extern "C" void abort();
+void * operator new[] (__SIZE_TYPE__, void *p) { return p; }
 
 bool constructed;
 
@@ -14,7 +15,8 @@  struct A
 
 int main() {
   new A[1]{};
-  int *p = new int[1]{};
+  int space[1] = { 42 };
+  int *p = new (space) int[1]{};
   if (p[0] != 0 || !constructed)
     abort();
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C b/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C
index 93d15d0..5bd113f 100644
--- a/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C
+++ b/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C
@@ -1,4 +1,3 @@ 
-// { dg-do run { xfail *-*-* } }
 // { dg-options "-w -fpermissive" }
 
 int *foo = new int[1](42); // { dg-bogus "" }