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];
+}

Reply via email to