This paper corrected a defect in the language whereby we were
prematurely rejecting as ambiguous a conversion required by a context,
such as a delete-expression that wants some pointer type, when the class
has multiple conversion operators to similar types. In many cases, we
can resolve that using normal overload resolution; the only time we need
to give up is when the conversion operators convert to different types.
This paper was accepted after C++11, but it seems like a defect fix to
me, so I'm not limiting it to C++1y mode.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 7e137f36fd739df81bc59fee16cc5548d3cb6207
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Apr 22 14:03:58 2013 -0400
N3323
* cvt.c (build_expr_type_conversion): Two conversions that return
the same type aren't necessarily ambiguous.
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index a3b7358..93be76a 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1630,17 +1630,24 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
{
if (winner)
{
- if (complain)
+ tree winner_type
+ = non_reference (TREE_TYPE (TREE_TYPE (winner)));
+
+ if (!same_type_ignoring_top_level_qualifiers_p (winner_type,
+ candidate))
{
- error ("ambiguous default type conversion from %qT",
- basetype);
- error (" candidate conversions include %qD and %qD",
- winner, cand);
+ if (complain)
+ {
+ error ("ambiguous default type conversion from %qT",
+ basetype);
+ error (" candidate conversions include %qD and %qD",
+ winner, cand);
+ }
+ return error_mark_node;
}
- return error_mark_node;
}
- else
- winner = cand;
+
+ winner = cand;
}
}
diff --git a/gcc/testsuite/g++.dg/cpp1y/context-conv1.C b/gcc/testsuite/g++.dg/cpp1y/context-conv1.C
new file mode 100644
index 0000000..fe20cab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/context-conv1.C
@@ -0,0 +1,32 @@
+// N3323
+
+#define assert(E) if(!(E))__builtin_abort();
+
+template<class T>
+class zero_init
+{
+public:
+ zero_init( )
+ : val( static_cast<T>(0) ) { }
+ zero_init( T val ) : val( val )
+ { }
+ operator T & ( ) { return val; }
+ operator T ( ) const { return val; }
+private:
+ T val;
+};
+
+void f()
+{
+ zero_init<int*> p; assert( p == 0 );
+ p = new int(7);
+ assert( *p == 7 );
+ delete p; // error!
+
+ zero_init<int> i; assert( i == 0 );
+ i = 7;
+ assert( i == 7 );
+ switch( i ) { } // error!
+
+ int *vp = new int[i];
+}