This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++0x PATCH to explicit conversion handling
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Sat, 26 Jun 2010 17:33:58 -0400
- Subject: C++0x PATCH to explicit conversion handling
In my earlier implementation of explicit conversion ops, I treated
initialization of a reference temp for the argument of the copy
constructor as direct-initialization. This was later adopted as core DR
899. In my recent work on implicit move constructors (to be committed
soon) I noticed that we need the same handling of move constructors, and
indeed any other constructor used to initialize a class from an object
of the same type.
The BAD_CONVERSION_RANK change is to fix comparison of bad conversions
in order to keep the useful error ("bad conversion") on
20_util/unique_ptr/cons/pointer_array_convertible.cc; without that
change the error changes to "no match".
Tested x86_64-pc-linux-gnu, applying to trunk.
commit bad8ef8482a6bd5ecc0450f791a5aff768dc6b80
Author: Jason Merrill <jason@redhat.com>
Date: Fri Jun 25 15:20:17 2010 -0400
* call.c (add_function_candidate): Set LOOKUP_COPY_PARM for any
constructor called with a single argument that takes a reference
to the constructor's class.
(BAD_CONVERSION_RANK): New.
(compare_ics): Use it to compare bad ICSes.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 55089ed..faaab10 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -122,6 +122,11 @@ struct conversion {
: (NODE)->user_conv_p ? cr_user \
: (NODE)->rank)
+#define BAD_CONVERSION_RANK(NODE) \
+ ((NODE)->ellipsis_p ? cr_ellipsis \
+ : (NODE)->user_conv_p ? cr_user \
+ : (NODE)->rank)
+
static struct obstack conversion_obstack;
static bool conversion_obstack_initialized;
@@ -1386,9 +1391,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
conversion operator). */
flags |= LOOKUP_NO_TEMP_BIND;
- /* Temporaries are copy-initialized, except for this hack to allow
- explicit conversion ops to the copy ctor. See also
- add_function_candidate. */
+ /* Core issue 899: When [copy-]initializing a temporary to be bound
+ to the first parameter of a copy constructor (12.8) called with
+ a single argument in the context of direct-initialization,
+ explicit conversion functions are also considered.
+
+ So don't set LOOKUP_ONLYCONVERTING in that case. */
if (!(flags & LOOKUP_COPY_PARM))
flags |= LOOKUP_ONLYCONVERTING;
@@ -1618,6 +1626,8 @@ add_function_candidate (struct z_candidate **candidates,
tree parmtype = TREE_VALUE (parmnode);
int lflags = flags;
+ parmnode = TREE_CHAIN (parmnode);
+
/* The type of the implicit object parameter ('this') for
overload resolution is not always the same as for the
function itself; conversion functions are considered to
@@ -1634,13 +1644,25 @@ add_function_candidate (struct z_candidate **candidates,
parmtype = build_pointer_type (parmtype);
}
- if (ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn)
- && (len-skip == 1))
+ /* Core issue 899: When [copy-]initializing a temporary to be bound
+ to the first parameter of a copy constructor (12.8) called with
+ a single argument in the context of direct-initialization,
+ explicit conversion functions are also considered.
+
+ So set LOOKUP_COPY_PARM to let reference_binding know that
+ it's being called in that context. We generalize the above
+ 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)))
{
- /* Hack: Direct-initialize copy parm (i.e. suppress
- LOOKUP_ONLYCONVERTING) to make explicit conversion ops
- work. See also reference_binding. */
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)
lflags |= LOOKUP_NO_CONVERSION;
}
@@ -1668,9 +1690,6 @@ add_function_candidate (struct z_candidate **candidates,
if (t->bad_p)
viable = -1;
-
- if (parmnode)
- parmnode = TREE_CHAIN (parmnode);
}
out:
@@ -6741,14 +6760,16 @@ compare_ics (conversion *ics1, conversion *ics2)
if (rank1 == cr_bad)
{
- /* XXX Isn't this an extension? */
- /* Both ICS are bad. We try to make a decision based on what
- would have happened if they'd been good. */
- if (ics1->user_conv_p > ics2->user_conv_p
- || ics1->rank > ics2->rank)
+ /* Both ICS are bad. We try to make a decision based on what would
+ have happened if they'd been good. This is not an extension,
+ we'll still give an error when we build up the call; this just
+ helps us give a more helpful error message. */
+ rank1 = BAD_CONVERSION_RANK (ics1);
+ rank2 = BAD_CONVERSION_RANK (ics2);
+
+ if (rank1 > rank2)
return -1;
- else if (ics1->user_conv_p < ics2->user_conv_p
- || ics1->rank < ics2->rank)
+ else if (rank1 < rank2)
return 1;
/* We couldn't make up our minds; try to figure it out below. */
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit5.C b/gcc/testsuite/g++.dg/cpp0x/explicit5.C
new file mode 100644
index 0000000..88a4707
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit5.C
@@ -0,0 +1,25 @@
+// test for extension of DR 899 to handle template ctors
+// { dg-options "-std=c++0x" }
+// { dg-do run }
+
+int r = 1;
+
+struct C {
+ C() { }
+ template <class T = int> C(C&, T = 0) { r = 0; }
+};
+
+C c;
+
+struct A
+{
+ explicit operator C&() const { return c; }
+};
+
+int main()
+{
+ A a;
+ C c2 (a);
+
+ return r;
+}