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 c++/40308, 40311


Both of these bugs have to do with cp_build_modify_expr (..., INIT_EXPR, ...) not handling initializer lists properly. I thought about duplicating the special handling that we have for decl initializers, but decided that it was simpler to just keep handling it as a conversion. The change to cp_build_modify_expr makes us hand it off to perform_implicit_conversion, and the change to implicit_conversion makes that conversion work in a direct-initialization situation.

The latter change removes the error from initlist13.C, but on further consideration I think that's fine. int i({0}) is a silly thing to write, but I don't think the working paper actually says it's ill-formed, and I tend to feel that it's better to err on the side of syntactic permissiveness.

I still want to prohibit excessive braces on scalar initializers, i.e. int i = {{0}}, and the bad_p and convert_like_real changes accomplish that with a useful error message.

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

	PR c++/40308
	PR c++/40311
	* typeck.c (cp_build_modify_expr): Always pass init-lists to the
	conversion code.
	* call.c (implicit_conversion): Allow init-list conversion to scalar
	during direct-initialization, too.  Mark the conversion bad if it
	has too many levels of braces.
	(convert_like_real): And give a helpful error.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 138abe0..1ab27c7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1406,21 +1406,27 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
 	return build_list_conv (to, expr, flags);
 
       /* Allow conversion from an initializer-list with one element to a
-	 scalar type if this is copy-initialization.  Direct-initialization
-	 would be something like int i({1}), which is invalid.  */
-      if (SCALAR_TYPE_P (to) && CONSTRUCTOR_NELTS (expr) <= 1
-	  && (flags & LOOKUP_ONLYCONVERTING))
+	 scalar type.  */
+      if (SCALAR_TYPE_P (to))
 	{
+	  int nelts = CONSTRUCTOR_NELTS (expr);
 	  tree elt;
-	  if (CONSTRUCTOR_NELTS (expr) == 1)
+
+	  if (nelts == 0)
+	    elt = integer_zero_node;
+	  else if (nelts == 1)
 	    elt = CONSTRUCTOR_ELT (expr, 0)->value;
 	  else
-	    elt = integer_zero_node;
+	    elt = error_mark_node;
+
 	  conv = implicit_conversion (to, TREE_TYPE (elt), elt,
 				      c_cast_p, flags);
 	  if (conv)
 	    {
 	      conv->check_narrowing = true;
+	      if (BRACE_ENCLOSED_INITIALIZER_P (elt))
+		/* Too many levels of braces, i.e. '{{1}}'.  */
+		conv->bad_p = true;
 	      return conv;
 	    }
 	}
@@ -4698,6 +4704,14 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
       && convs->kind != ck_base)
     {
       conversion *t = convs;
+
+      /* Give a helpful error if this is bad because of excess braces.  */
+      if (BRACE_ENCLOSED_INITIALIZER_P (expr)
+	  && SCALAR_TYPE_P (totype)
+	  && CONSTRUCTOR_NELTS (expr) > 0
+	  && BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (expr, 0)->value))
+	permerror (input_location, "too many braces around initializer for %qT", totype);
+
       for (; t; t = convs->u.next)
 	{
 	  if (t->kind == ck_user || !t->bad_p)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 6f6bd39..b384fea 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -6081,8 +6081,11 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
 
   if (modifycode == INIT_EXPR)
     {
-      if (TREE_CODE (rhs) == CONSTRUCTOR)
+      if (BRACE_ENCLOSED_INITIALIZER_P (rhs))
+	/* Do the default thing.  */;
+      else if (TREE_CODE (rhs) == CONSTRUCTOR)
 	{
+	  /* Compound literal.  */
 	  if (! same_type_p (TREE_TYPE (rhs), lhstype))
 	    /* Call convert to generate an error; see PR 11063.  */
 	    rhs = convert (lhstype, rhs);
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist13.C b/gcc/testsuite/g++.dg/cpp0x/initlist13.C
index 98af92b..9ed6c74 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist13.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist13.C
@@ -2,4 +2,7 @@
 // { dg-do compile }
 // { dg-options "-std=gnu++0x" }
 
-__complex__ int i ({0});	// { dg-error "cannot convert" }
+#include <complex>
+
+__complex__ int i ({0});
+std::complex<int> i2 ({0});
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist18.C b/gcc/testsuite/g++.dg/cpp0x/initlist18.C
new file mode 100644
index 0000000..c9a9bcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist18.C
@@ -0,0 +1,19 @@
+// PR c++/40308, 40311
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+
+template< typename T >
+struct test {
+   test() : data{} {}
+
+   T data;
+};
+
+int main()
+{
+   test<int> x;
+   test<int*> y;
+   int * a = new int{};
+   int * b = new int{5};
+   return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist19.C b/gcc/testsuite/g++.dg/cpp0x/initlist19.C
new file mode 100644
index 0000000..418cddc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist19.C
@@ -0,0 +1,8 @@
+// { dg-options "-std=c++0x" }
+
+void f(double);
+int main()
+{
+  f({{1}});			// { dg-error "too many braces" }
+  // { dg-error "" "" { target *-*-* } 6 } allow other errors, too
+}

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