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 for initializing references with initializer lists


Core issue 934 deals with using an initializer list to initialize a reference variable; to my surprise, g++ rejected such a declaration with an error "ISO C++ forbids use of initializer list to initialize reference." I wondered what I was thinking when I wrote that error; further investigation discovered that the error dates back to the dawn of SVN time, it just happens to use the same terminology. Anyway, this patch implements the semantics that we agreed on.

The reshape_init_r hunk is something I noticed while I was looking at this: we were improperly treating { a } as a valid aggregate initializer for A, which it isn't.

Tested x86_64-pc-linux-gnu, applied to trunk.
2009-07-21  Jason Merrill  <jason@redhat.com>

	Core issue 934
	* call.c (reference_binding): Implement binding to { }.
	(initialize_reference): Binding temporary to non-const && is fine.
	* decl.c (grok_reference_init): Remove error for CONSTRUCTOR.

	* decl.c (reshape_init_r): { T } is not an aggregate initializer
	for class T.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index f4b5b02..845fa56 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1221,7 +1221,21 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
       lvalue_p = clk_ordinary;
       from = TREE_TYPE (from);
     }
-  else if (expr)
+
+  if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr))
+    {
+      maybe_warn_cpp0x ("extended initializer lists");
+      conv = implicit_conversion (to, from, expr, c_cast_p,
+				  flags);
+      if (!CLASS_TYPE_P (to)
+	  && CONSTRUCTOR_NELTS (expr) == 1)
+	{
+	  expr = CONSTRUCTOR_ELT (expr, 0)->value;
+	  from = TREE_TYPE (expr);
+	}
+    }
+
+  if (lvalue_p == clk_none && expr)
     lvalue_p = real_lvalue_p (expr);
 
   tfrom = from;
@@ -1363,8 +1377,9 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
   if (!(flags & LOOKUP_COPY_PARM))
     flags |= LOOKUP_ONLYCONVERTING;
 
-  conv = implicit_conversion (to, from, expr, c_cast_p,
-			      flags);
+  if (!conv)
+    conv = implicit_conversion (to, from, expr, c_cast_p,
+				flags);
   if (!conv)
     return NULL;
 
@@ -7541,6 +7556,7 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
   if (!conv || conv->bad_p)
     {
       if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
+	  && !TYPE_REF_IS_RVALUE (type)
 	  && !real_lvalue_p (expr))
 	error ("invalid initialization of non-const reference of "
 	       "type %qT from a temporary of type %qT",
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 251d0a3..7f4509e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4370,13 +4370,6 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup)
       return NULL_TREE;
     }
 
-  if (TREE_CODE (init) == CONSTRUCTOR)
-    {
-      error ("ISO C++ forbids use of initializer list to "
-	     "initialize reference %qD", decl);
-      return NULL_TREE;
-    }
-
   if (TREE_CODE (init) == TREE_LIST)
     init = build_x_compound_expr_from_list (init, "initializer");
 
@@ -4885,7 +4878,7 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p)
    a CONSTRUCTOR). TYPE is the type of the variable being initialized, D is the
    iterator within the CONSTRUCTOR which points to the initializer to process.
    FIRST_INITIALIZER_P is true if this is the first initializer of the
-   CONSTRUCTOR node.  */
+   outermost CONSTRUCTOR node.  */
 
 static tree
 reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p)
@@ -4930,6 +4923,10 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p)
      initializer is considered for the initialization of the first
      member of the subaggregate.  */
   if (TREE_CODE (init) != CONSTRUCTOR
+      /* But don't try this for the first initializer, since that would be
+	 looking through the outermost braces; A a2 = { a1 }; is not a
+	 valid aggregate initialization.  */
+      && !first_initializer_p
       && can_convert_arg (type, TREE_TYPE (init), init, LOOKUP_NORMAL))
     {
       d->cur++;
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist22.C b/gcc/testsuite/g++.dg/cpp0x/initlist22.C
new file mode 100644
index 0000000..bf1c554
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist22.C
@@ -0,0 +1,24 @@
+// Core issue 934
+// { dg-options "-std=c++0x" }
+
+int i;
+
+int& r1{ i };			// OK, direct binding
+int&& r2{ i };			// OK, direct binding
+
+int& r3{ };			// { dg-error "" } reference to temporary
+int&& r4{ };			// OK, reference to temporary
+
+struct A { int i; } a;
+
+A& r5 { i };			// { dg-error "" } reference to temporary
+A&& r6 { i };			// OK, aggregate initialization of temporary
+A& r7 { a };			// { dg-error "" } invalid aggregate initializer for A
+A&& r8 { a };			// { dg-error "" } invalid aggregate initializer for A
+
+struct B { B(int); int i; } b(0);
+
+B& r9 { i };			// { dg-error "" } reference to temporary
+B&& r10 { i };			// OK, make temporary with B(int) constructor
+B& r11 { b };			// { dg-error "" } reference to temporary
+B&& r12 { b };			// OK, make temporary with copy constructor
diff --git a/gcc/testsuite/g++.dg/init/aggr4.C b/gcc/testsuite/g++.dg/init/aggr4.C
new file mode 100644
index 0000000..7120e68
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/aggr4.C
@@ -0,0 +1,7 @@
+struct A
+{
+  int i;
+};
+
+A a1 = { 1 };			// ok
+A a2 = { a1 };			// { dg-error "cannot convert" }
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/init4.C b/gcc/testsuite/g++.old-deja/g++.brendan/init4.C
index 71e7cd6..aa2bfb6 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/init4.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/init4.C
@@ -2,4 +2,4 @@
 // GROUPS passed initialization
 struct CharList { int i; };
 
-const CharList& terminals = { 1 };// { dg-error "" } .*
+const CharList& terminals = { 1 }; // { dg-error "initializer lists" } c++0x

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