This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/40308, 40311
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Tue, 02 Jun 2009 12:59:29 -0400
- Subject: 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
+}