We've previously tweaked a few rules to avoid creating builtin
candidates with dependent types, but things keep slipping through the
cracks. This should be a more complete solution.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit aca790abae74da31099bcfb3ceb1459b6c2b6f05
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Jan 29 17:09:04 2014 -0500
PR c++/59707
* call.c (add_builtin_candidate): Catch dependent types.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index f6566cf..f572bc1 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2329,7 +2329,6 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code,
case INDIRECT_REF:
if (TYPE_PTR_P (type1)
- && !uses_template_parms (TREE_TYPE (type1))
&& (TYPE_PTROB_P (type1)
|| TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE))
break;
@@ -2467,15 +2466,13 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code,
&& TREE_CODE (type2) == ENUMERAL_TYPE)
break;
if (TYPE_PTR_P (type1)
- && null_ptr_cst_p (args[1])
- && !uses_template_parms (type1))
+ && null_ptr_cst_p (args[1]))
{
type2 = type1;
break;
}
if (null_ptr_cst_p (args[0])
- && TYPE_PTR_P (type2)
- && !uses_template_parms (type2))
+ && TYPE_PTR_P (type2))
{
type1 = type2;
break;
@@ -2642,6 +2639,28 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code,
gcc_unreachable ();
}
+ /* Make sure we don't create builtin candidates with dependent types. */
+ bool u1 = uses_template_parms (type1);
+ bool u2 = type2 ? uses_template_parms (type2) : false;
+ if (u1 || u2)
+ {
+ /* Try to recover if one of the types is non-dependent. But if
+ there's only one type, there's nothing we can do. */
+ if (!type2)
+ return;
+ /* And we lose if both are dependent. */
+ if (u1 && u2)
+ return;
+ /* Or if they have different forms. */
+ if (TREE_CODE (type1) != TREE_CODE (type2))
+ return;
+
+ if (u1 && !u2)
+ type1 = type2;
+ else if (u2 && !u1)
+ type2 = type1;
+ }
+
/* If we're dealing with two pointer types or two enumeral types,
we need candidates for both of them. */
if (type2 && !same_type_p (type1, type2)
diff --git a/gcc/testsuite/g++.dg/template/operator12.C b/gcc/testsuite/g++.dg/template/operator12.C
new file mode 100644
index 0000000..bc8e91d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/operator12.C
@@ -0,0 +1,9 @@
+// PR c++/59707
+
+struct T {
+ template<class D> operator D*() const;
+};
+
+void f(T x) {
+ x < x; // { dg-error "no match" }
+}