diff mbox

C++ PATCH to handling of template conversion functions

Message ID 4E6E4910.9070701@redhat.com
State New
Headers show

Commit Message

Jason Merrill Sept. 12, 2011, 6:01 p.m. UTC
This was another change that I needed to make to fix the deduction issue 
mentioned in my previous mail, and brought my attention to an existing 
bug.  When considering a template conversion function we don't want to 
allow derived-to-base conversions, but we should still allow 
qualification conversions.  This patch fixes the latter, and gives a 
more helpful diagnostic for the former.

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

Patch

commit eeb8627ed5d62c93d015c58e6e0e2958fe833f47
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Sep 9 15:14:54 2011 -0400

    	* pt.c (type_unification_real): Fix handling of DEDUCE_CONV
    	with no deducible template parameters.
    	* call.c (rejection_reason_code): Add rr_template_conversion.
    	(print_z_candidate): Handle it.
    	(template_conversion_rejection): New.
    	(build_user_type_conversion_1): Use it.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a97e8c7..81df80e 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -432,6 +432,7 @@  enum rejection_reason_code {
   rr_none,
   rr_arity,
   rr_explicit_conversion,
+  rr_template_conversion,
   rr_arg_conversion,
   rr_bad_arg_conversion,
   rr_template_unification,
@@ -654,6 +655,16 @@  explicit_conversion_rejection (tree from, tree to)
 }
 
 static struct rejection_reason *
+template_conversion_rejection (tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_template_conversion);
+  r->u.conversion.n_arg = 0;
+  r->u.conversion.from_type = from;
+  r->u.conversion.to_type = to;
+  return r;
+}
+
+static struct rejection_reason *
 template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
 				const tree *args, unsigned int nargs,
 				tree return_type, unification_kind_t strict,
@@ -3135,6 +3146,12 @@  print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 		  "conversion", r->u.conversion.from_type,
 		  r->u.conversion.to_type);
 	  break;
+	case rr_template_conversion:
+	  inform (loc, "  conversion from return type %qT of template "
+		  "conversion function specialization to %qT is not an "
+		  "exact match", r->u.conversion.from_type,
+		  r->u.conversion.to_type);
+	  break;
 	case rr_template_unification:
 	  /* We use template_unification_error_rejection if unification caused
 	     actual non-SFINAE errors, in which case we don't need to repeat
@@ -3495,6 +3512,16 @@  build_user_type_conversion_1 (tree totype, tree expr, int flags)
 		= bad_arg_conversion_rejection (NULL_TREE, -1,
 						rettype, totype);
 	    }
+	  else if (primary_template_instantiation_p (cand->fn)
+		   && ics->rank > cr_exact)
+	    {
+	      /* 13.3.3.1.2: If the user-defined conversion is specified by
+		 a specialization of a conversion function template, the
+		 second standard conversion sequence shall have exact match
+		 rank.  */
+	      cand->viable = -1;
+	      cand->reason = template_conversion_rejection (rettype, totype);
+	    }
 	}
     }
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d326c84..9a5e3dd 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14709,10 +14709,18 @@  type_unification_real (tree tparms,
 
 	  if (same_type_p (parm, type))
 	    continue;
-	  if (strict != DEDUCE_EXACT
-	      && can_convert_arg (parm, type, TYPE_P (arg) ? NULL_TREE : arg,
-				  flags))
-	    continue;
+	  if (strict == DEDUCE_CONV)
+	    {
+	      if (can_convert_arg (type, parm, NULL_TREE, flags))
+		continue;
+	    }
+	  else if (strict != DEDUCE_EXACT)
+	    {
+	      if (can_convert_arg (parm, type,
+				   TYPE_P (arg) ? NULL_TREE : arg,
+				   flags))
+		continue;
+	    }
 
 	  if (strict == DEDUCE_EXACT)
 	    return unify_type_mismatch (explain_p, parm, arg);
diff --git a/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg2.C b/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg2.C
index 12cc836..d94843c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/fntmpdefarg2.C
@@ -4,11 +4,21 @@ 
 struct B { };
 struct D : B { };
 struct A {
-  template<typename T = void> operator D&();
+  template<typename T = void> operator D&(); // { dg-message "template conversion" }
   operator long();
 };
 
 void f(long);
 void f(B&);
 
-int main() { f(A()); }
+struct A2 {
+  template<typename T = void> operator B&();
+};
+
+void f2(const B&);
+
+int main() {
+  f(A());
+  f2(A2());
+  f2(A());			// { dg-error "" }
+}