The code I put in back when I implemented list-initialization rejects
additional user-defined conversions when considering the copy parm of a
copy/move constructor, in order to avoid ambiguity when a nested
braced-init-list could initialize either the copy parm or the parm of
another constructor. But this testcase shows that this is too broad; we
only want to suppress the copy constructor when the argument is another
braced-init-list.
That change fixes most of the testcase, but then we incorrectly accept
the declaration of 'c'. To fix that, we need to separate the handling
of explicit constructors from explicit conversion operators in
list-initialization.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 47859b1cf1ddd04ced45922eb1011bf4dc516f75
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Dec 19 11:32:55 2011 -0500
PR c++/51553
* call.c (add_function_candidate): Allow conversions for the copy
parm in list-initialization unless the argument is an init-list.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index dd716a4..3e6db51 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1964,8 +1964,10 @@ add_function_candidate (struct z_candidate **candidates,
{
lflags |= LOOKUP_COPY_PARM;
/* We allow user-defined conversions within init-lists, but
- not for the copy constructor. */
- if (flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
+ don't list-initialize the copy parm, as that would mean
+ using two levels of braces for the same type. */
+ if ((flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
+ && BRACE_ENCLOSED_INITIALIZER_P (arg))
lflags |= LOOKUP_NO_CONVERSION;
}
else
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist64.C b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
new file mode 100644
index 0000000..337e89b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
@@ -0,0 +1,29 @@
+// PR c++/51553
+// { dg-options -std=c++0x }
+
+struct X
+{
+ X();
+};
+
+struct Y
+{
+ operator X() const;
+};
+
+struct Z
+{
+ explicit operator X() const;
+};
+
+X a = { Y() };
+X aa = Y();
+
+X b{ Y() };
+X bb(Y());
+
+X c = { Z() }; // { dg-error "" "" { xfail *-*-* } }
+X cc = Z(); // { dg-error "" }
+
+X d{ Z() };
+X dd( Z() );
commit 7186017c5f76e0673483df849965fe705e45dcf3
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Dec 19 14:01:11 2011 -0500
PR c++/51553
* cp-tree.h (LOOKUP_LIST_INIT_CTOR): Rename from
LOOKUP_NO_COPY_CTOR_CONVERSION.
(add_list_candidates): Set it earlier.
(add_candidates): Don't check explicit on ctors when it's set.
(add_function_candidate): Check it even when LOOKUP_ONLYCONVERTING
is set.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3e6db51..29aed98 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1956,17 +1956,17 @@ add_function_candidate (struct z_candidate **candidates,
to handle move constructors and template constructors as well;
the standardese should soon be updated similarly. */
if (ctype && i == 0 && (len-skip == 1)
- && !(flags & LOOKUP_ONLYCONVERTING)
&& DECL_CONSTRUCTOR_P (fn)
&& parmtype != error_mark_node
&& (same_type_ignoring_top_level_qualifiers_p
(non_reference (parmtype), ctype)))
{
- lflags |= LOOKUP_COPY_PARM;
+ if (!(flags & LOOKUP_ONLYCONVERTING))
+ lflags |= LOOKUP_COPY_PARM;
/* We allow user-defined conversions within init-lists, but
don't list-initialize the copy parm, as that would mean
using two levels of braces for the same type. */
- if ((flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
+ if ((flags & LOOKUP_LIST_INIT_CTOR)
&& BRACE_ENCLOSED_INITIALIZER_P (arg))
lflags |= LOOKUP_NO_CONVERSION;
}
@@ -3344,9 +3344,8 @@ add_list_candidates (tree fns, tree first_arg,
gcc_assert (*candidates == NULL);
- /* For list-initialization we consider explicit constructors, but
- give an error if one is selected. */
- flags &= ~LOOKUP_ONLYCONVERTING;
+ /* We're looking for a ctor for list-initialization. */
+ flags |= LOOKUP_LIST_INIT_CTOR;
/* And we don't allow narrowing conversions. We also use this flag to
avoid the copy constructor call for copy-list-initialization. */
flags |= LOOKUP_NO_NARROWING;
@@ -3374,8 +3373,6 @@ add_list_candidates (tree fns, tree first_arg,
flags &= ~LOOKUP_LIST_ONLY;
/* We allow more user-defined conversions within an init-list. */
flags &= ~LOOKUP_NO_CONVERSION;
- /* But not for the copy ctor. */
- flags |= LOOKUP_NO_COPY_CTOR_CONVERSION;
add_candidates (fns, first_arg, args, NULL_TREE,
explicit_targs, template_only, conversion_path,
@@ -4801,7 +4798,11 @@ add_candidates (tree fns, tree first_arg, const VEC(tree,gc) *args,
if (DECL_CONSTRUCTOR_P (fn))
{
check_list_ctor = !!(flags & LOOKUP_LIST_ONLY);
- check_converting = !!(flags & LOOKUP_ONLYCONVERTING);
+ /* For list-initialization we consider explicit constructors
+ and complain if one is chosen. */
+ check_converting
+ = ((flags & (LOOKUP_ONLYCONVERTING|LOOKUP_LIST_INIT_CTOR))
+ == LOOKUP_ONLYCONVERTING);
}
else
{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 42a9ced..633b6b4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4384,11 +4384,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
#define LOOKUP_PREFER_RVALUE (LOOKUP_HIDDEN << 1)
/* We're inside an init-list, so narrowing conversions are ill-formed. */
#define LOOKUP_NO_NARROWING (LOOKUP_PREFER_RVALUE << 1)
-/* Avoid user-defined conversions for the first parameter of a copy
- constructor (or move constructor). */
-#define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1)
+/* We're looking up a constructor for list-initialization. */
+#define LOOKUP_LIST_INIT_CTOR (LOOKUP_NO_NARROWING << 1)
/* This is the first parameter of a copy constructor. */
-#define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
+#define LOOKUP_COPY_PARM (LOOKUP_LIST_INIT_CTOR << 1)
/* We only want to consider list constructors. */
#define LOOKUP_LIST_ONLY (LOOKUP_COPY_PARM << 1)
/* Return after determining which function to call and checking access.
diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist64.C b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
index 337e89b..bcf1658 100644
--- a/gcc/testsuite/g++.dg/cpp0x/initlist64.C
+++ b/gcc/testsuite/g++.dg/cpp0x/initlist64.C
@@ -22,7 +22,7 @@ X aa = Y();
X b{ Y() };
X bb(Y());
-X c = { Z() }; // { dg-error "" "" { xfail *-*-* } }
+X c = { Z() }; // { dg-error "" }
X cc = Z(); // { dg-error "" }
X d{ Z() };