This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] Fix PR c++/32597 (value initialization and variadic templates)


This patch fixes two related bugs regarding initialization via pack
expansions. The first bug involves an initialization like the
following, where "args" is a parameter pack:

new T(args...)

If "args" is an empty parameter pack, GCC was not initializing the
object, essentially performing the equivalent of:

new T

rather than the expected

new T()

The same issue occurs with

T result(args...);

If "args" is an empty parameter pack, GCC is treating it as

T result;

and not initializing "result", rather than default-initializing it.
I've tweaked the template argument substitution code to do the right
thing when an initializer pack expansion instantiates to an empty
initializer, forcing value initialization in both cases.

Testing on i686-pc-linux-gnu; all G++ tests passed. Assuming all
libstdc++ tests pass, okay to commit to mainline?

- Doug

:ADDPATCH c++:

2007-07-02 Douglas Gregor <doug.gregor@gmail.com>

	PR c++/32597
	* init.c (build_default_init): Make extern.
	* cp-tree.h (build_default_init): Declare here.
	* pt.c (tsubst_expr): When the instantiation of the initializer of
	a variable results in an empty list, default-initialize the
	variable.
	(tsubst_copy_and_build): When the instantiation of the initializer
	in a new expression results in an empty initializer list,
	default-initialize it.

2007-07-02 Douglas Gregor <doug.gregor@gmail.com>

	PR c++/32597
	* gcc/testsuite/g++.dg/cpp0x/variadic-new2.C: New.
	* gcc/testsuite/g++.dg/cpp0x/variadic-new.C: New.
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 126078)
+++ cp/cp-tree.h	(working copy)
@@ -4333,6 +4333,7 @@ extern tree build_zero_init			(tree, tre
 extern tree build_offset_ref			(tree, tree, bool);
 extern tree build_new				(tree, tree, tree, tree, int);
 extern tree build_vec_init			(tree, tree, tree, bool, int);
+extern tree build_default_init                  (tree, tree);
 extern tree build_delete			(tree, tree,
 						 special_function_kind,
 						 int, int);
Index: cp/init.c
===================================================================
--- cp/init.c	(revision 126078)
+++ cp/init.c	(working copy)
@@ -52,7 +52,6 @@ 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_default_init (tree, tree);
 static tree build_dtor_call (tree, special_function_kind, int);
 static tree build_field_list (tree, tree, int *);
 static tree build_vtbl_address (tree);
@@ -276,7 +275,7 @@ build_zero_init (tree type, tree nelts, 
    returns NULL_TREE; the caller is responsible for arranging for the
    constructors to be called.  */
 
-static tree
+tree
 build_default_init (tree type, tree nelts)
 {
   /* [dcl.init]:
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 126078)
+++ cp/pt.c	(working copy)
@@ -9857,7 +9857,23 @@ tsubst_expr (tree t, tree args, tsubst_f
 			init = cp_fname_init (name, &TREE_TYPE (decl));
 		      }
 		    else
-		      init = RECUR (init);
+		      {
+			tree t = RECUR (init);
+
+			if (init && !t)
+			  /* If we had an initializer but it
+			     instantiated to nothing,
+			     value-initialize the object.  This will
+			     only occur when the initializer was a
+			     pack expansion where the parameter packs
+			     used in that expansion were of length
+			     zero.  */
+			  init = build_default_init (TREE_TYPE (decl), 
+						     integer_one_node);
+			else
+			  init = t;
+		      }
+
 		    finish_decl (decl, init, NULL_TREE);
 		  }
 	      }
@@ -10461,12 +10477,25 @@ tsubst_copy_and_build (tree t,
       return build_x_arrow (op1);
 
     case NEW_EXPR:
-      return build_new
-	(RECUR (TREE_OPERAND (t, 0)),
-	 RECUR (TREE_OPERAND (t, 1)),
-	 RECUR (TREE_OPERAND (t, 2)),
-	 RECUR (TREE_OPERAND (t, 3)),
-	 NEW_EXPR_USE_GLOBAL (t));
+      {
+	tree init = RECUR (TREE_OPERAND (t, 3));
+
+	if (TREE_OPERAND (t, 3) && !init)
+	  /* If there was an initializer in the the original tree, but
+	     it instantiated to an empty list, then we should pass on
+	     VOID_ZERO_NODE to tell build_new that it was an empty
+	     initializer () rather than no initializer.  This can only
+	     happen when the initializer is a pack expansion whose
+	     parameter packs are of length zero.  */
+	  init = void_zero_node;
+
+	return build_new
+	  (RECUR (TREE_OPERAND (t, 0)),
+	   RECUR (TREE_OPERAND (t, 1)),
+	   RECUR (TREE_OPERAND (t, 2)),
+	   init,
+	   NEW_EXPR_USE_GLOBAL (t));
+      }
 
     case DELETE_EXPR:
      return delete_sanity
Index: testsuite/g++.dg/cpp0x/variadic-new2.C
===================================================================
--- testsuite/g++.dg/cpp0x/variadic-new2.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/variadic-new2.C	(revision 0)
@@ -0,0 +1,24 @@
+// { dg-do "run" }
+// { dg-options "-std=c++0x" }
+// PR c++/32597
+#include <assert.h>
+#include <new>
+
+template< class... Args > void f( Args... args )
+{
+  { 
+    int x = 17;
+    (void)x;
+  }
+
+  {
+    int y(args...);
+    assert(y == 0);
+  }
+
+}
+
+int main()
+{
+   f();
+}
Index: testsuite/g++.dg/cpp0x/variadic-new.C
===================================================================
--- testsuite/g++.dg/cpp0x/variadic-new.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/variadic-new.C	(revision 0)
@@ -0,0 +1,19 @@
+// { dg-do "run" }
+// { dg-options "-std=c++0x" }
+// Contributed by Peter Dimov
+// PR c++/32597
+#include <assert.h>
+#include <new>
+
+int k = 5;
+
+template< class... Args > void f( Args... args )
+{
+   new( &k ) int( args... );
+}
+
+int main()
+{
+   f();
+   assert( k == 0 );
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]