diff mbox

C++ PATCH for c++/47080 (limits on explicit conversion operators)

Message ID 4DFF558D.5040402@redhat.com
State New
Headers show

Commit Message

Jason Merrill June 20, 2011, 2:13 p.m. UTC
The PR pointed out that explicit conversion operators are more 
restricted than normal ones even in direct-initialization; the return 
type must be convertible to the target type with no more than a 
qualification conversion.

Tested x86_64-pc-linux-gnu, applying to trunk
diff mbox

Patch

commit 8f60db54d602164cda13a5f8c763f569b70c5e40
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Jun 20 00:09:37 2011 -0400

    	PR c++/47080
    	* call.c (rejection_reason_code): Add rr_explicit_conversion.
    	(print_z_candidate): Handle it.
    	(explicit_conversion_rejection): New.
    	(build_user_type_conversion_1): Reject an explicit conversion
    	function that requires more than a qualification conversion.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 09d73d0..e9d6e7e 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -429,6 +429,7 @@  struct candidate_warning {
 enum rejection_reason_code {
   rr_none,
   rr_arity,
+  rr_explicit_conversion,
   rr_arg_conversion,
   rr_bad_arg_conversion
 };
@@ -608,6 +609,16 @@  bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
   return r;
 }
 
+static struct rejection_reason *
+explicit_conversion_rejection (tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_explicit_conversion);
+  r->u.conversion.n_arg = 0;
+  r->u.conversion.from_type = from;
+  r->u.conversion.to_type = to;
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -3153,6 +3164,12 @@  print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 	case rr_bad_arg_conversion:
 	  print_conversion_rejection (loc, &r->u.bad_conversion);
 	  break;
+	case rr_explicit_conversion:
+	  inform (loc, "  return type %qT of explicit conversion function "
+		  "cannot be converted to %qT with a qualification "
+		  "conversion", r->u.conversion.from_type,
+		  r->u.conversion.to_type);
+	  break;
 	case rr_none:
 	default:
 	  /* This candidate didn't have any issues or we failed to
@@ -3429,9 +3446,10 @@  build_user_type_conversion_1 (tree totype, tree expr, int flags)
 
       for (cand = candidates; cand != old_candidates; cand = cand->next)
 	{
+	  tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
 	  conversion *ics
 	    = implicit_conversion (totype,
-				   TREE_TYPE (TREE_TYPE (cand->fn)),
+				   rettype,
 				   0,
 				   /*c_cast_p=*/false, convflags);
 
@@ -3453,14 +3471,23 @@  build_user_type_conversion_1 (tree totype, tree expr, int flags)
 
 	  if (!ics)
 	    {
-	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
 	      cand->viable = 0;
 	      cand->reason = arg_conversion_rejection (NULL_TREE, -1,
 						       rettype, totype);
 	    }
+	  else if (DECL_NONCONVERTING_P (cand->fn)
+		   && ics->rank > cr_exact)
+	    {
+	      /* 13.3.1.5: For direct-initialization, those explicit
+		 conversion functions that are not hidden within S and
+		 yield type T or a type that can be converted to type T
+		 with a qualification conversion (4.4) are also candidate
+		 functions.  */
+	      cand->viable = -1;
+	      cand->reason = explicit_conversion_rejection (rettype, totype);
+	    }
 	  else if (cand->viable == 1 && ics->bad_p)
 	    {
-	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
 	      cand->viable = -1;
 	      cand->reason
 		= bad_arg_conversion_rejection (NULL_TREE, -1,
@@ -5513,7 +5540,18 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
       for (; t; t = convs->u.next)
 	{
-	  if (t->kind == ck_user || !t->bad_p)
+	  if (t->kind == ck_user && t->cand->reason)
+	    {
+	      permerror (input_location, "invalid user-defined conversion "
+			 "from %qT to %qT", TREE_TYPE (expr), totype);
+	      print_z_candidate ("candidate is:", t->cand);
+	      expr = convert_like_real (t, expr, fn, argnum, 1,
+					/*issue_conversion_warnings=*/false,
+					/*c_cast_p=*/false,
+					complain);
+	      return cp_convert (totype, expr);
+	    }
+	  else if (t->kind == ck_user || !t->bad_p)
 	    {
 	      expr = convert_like_real (t, expr, fn, argnum, 1,
 					/*issue_conversion_warnings=*/false,
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit6.C b/gcc/testsuite/g++.dg/cpp0x/explicit6.C
new file mode 100644
index 0000000..0d620be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit6.C
@@ -0,0 +1,11 @@ 
+// PR c++/47080
+// { dg-options -std=c++0x }
+
+struct A {
+  explicit operator int();	// { dg-message "qualification conversion" }
+};
+
+int main() {
+  bool b((A()));		// { dg-error "invalid user-defined" }
+  !A();				// { dg-error "" }
+}