This bug has accumulated a lot of duplicates over the years. The issue
is that the standard says that
"Implicit conversions (Clause 4) will be performed on a function
argument to convert it to the type of the corresponding function
parameter if the parameter type contains no template-parameters that
participate in template argument deduction."
We were doing this for types that contain no template-parameters at all,
but not for types that contain template-parameters that only appear in
non-deduced locations.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 1af65c13d382c9ce0ec26b9d79fa68517343a844
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Apr 9 17:24:30 2013 -0400
PR c++/23055
* pt.c (uses_deducible_template_parms): New.
(deducible_array_bound, deducible_expression): New.
(deducible_template_args): New.
(unify_one_argument): Call uses_deducible_template_parms.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7367a3a..1c0b3ec 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15390,6 +15390,135 @@ check_non_deducible_conversion (tree parm, tree arg, int strict,
return unify_arg_conversion (explain_p, parm, type, arg);
}
+static bool uses_deducible_template_parms (tree type);
+
+/* Returns true iff the expression EXPR is one from which a template
+ argument can be deduced. In other words, if it's an undecorated
+ use of a template non-type parameter. */
+
+static bool
+deducible_expression (tree expr)
+{
+ return (TREE_CODE (expr) == TEMPLATE_PARM_INDEX);
+}
+
+/* Returns true iff the array domain DOMAIN uses a template parameter in a
+ deducible way; that is, if it has a max value of <PARM> - 1. */
+
+static bool
+deducible_array_bound (tree domain)
+{
+ if (domain == NULL_TREE)
+ return false;
+
+ tree max = TYPE_MAX_VALUE (domain);
+ if (TREE_CODE (max) != MINUS_EXPR)
+ return false;
+
+ return deducible_expression (TREE_OPERAND (max, 0));
+}
+
+/* Returns true iff the template arguments ARGS use a template parameter
+ in a deducible way. */
+
+static bool
+deducible_template_args (tree args)
+{
+ for (int i = 0; i < TREE_VEC_LENGTH (args); ++i)
+ {
+ bool deducible;
+ tree elt = TREE_VEC_ELT (args, i);
+ if (ARGUMENT_PACK_P (elt))
+ deducible = deducible_template_args (ARGUMENT_PACK_ARGS (elt));
+ else
+ {
+ if (PACK_EXPANSION_P (elt))
+ elt = PACK_EXPANSION_PATTERN (elt);
+ if (TREE_CODE (elt) == TEMPLATE_TEMPLATE_PARM)
+ deducible = true;
+ else if (TYPE_P (elt))
+ deducible = uses_deducible_template_parms (elt);
+ else
+ deducible = deducible_expression (elt);
+ }
+ if (deducible)
+ return true;
+ }
+ return false;
+}
+
+/* Returns true iff TYPE contains any deducible references to template
+ parameters, as per 14.8.2.5. */
+
+static bool
+uses_deducible_template_parms (tree type)
+{
+ if (PACK_EXPANSION_P (type))
+ type = PACK_EXPANSION_PATTERN (type);
+
+ /* T
+ cv-list T
+ TT<T>
+ TT<i>
+ TT<> */
+ if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ return true;
+
+ /* T*
+ T&
+ T&& */
+ if (POINTER_TYPE_P (type))
+ return uses_deducible_template_parms (TREE_TYPE (type));
+
+ /* T[integer-constant ]
+ type [i] */
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return (uses_deducible_template_parms (TREE_TYPE (type))
+ || deducible_array_bound (TYPE_DOMAIN (type)));
+
+ /* T type ::*
+ type T::*
+ T T::*
+ T (type ::*)()
+ type (T::*)()
+ type (type ::*)(T)
+ type (T::*)(T)
+ T (type ::*)(T)
+ T (T::*)()
+ T (T::*)(T) */
+ if (TYPE_PTRMEM_P (type))
+ return (uses_deducible_template_parms (TYPE_PTRMEM_CLASS_TYPE (type))
+ || (uses_deducible_template_parms
+ (TYPE_PTRMEM_POINTED_TO_TYPE (type))));
+
+ /* template-name <T> (where template-name refers to a class template)
+ template-name <i> (where template-name refers to a class template) */
+ if (CLASS_TYPE_P (type)
+ && CLASSTYPE_TEMPLATE_INFO (type)
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)))
+ return deducible_template_args (INNERMOST_TEMPLATE_ARGS
+ (CLASSTYPE_TI_ARGS (type)));
+
+ /* type (T)
+ T()
+ T(T) */
+ if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE)
+ {
+ if (uses_deducible_template_parms (TREE_TYPE (type)))
+ return true;
+ tree parm = TYPE_ARG_TYPES (type);
+ if (TREE_CODE (type) == METHOD_TYPE)
+ parm = TREE_CHAIN (parm);
+ for (; parm; parm = TREE_CHAIN (parm))
+ if (uses_deducible_template_parms (TREE_VALUE (parm)))
+ return true;
+ }
+
+ return false;
+}
+
/* Subroutine of type_unification_real and unify_pack_expansion to
handle unification of a single P/A pair. Parameters are as
for those functions. */
@@ -15409,10 +15538,21 @@ unify_one_argument (tree tparms, tree targs, tree parm, tree arg,
template args from other function args. */
return unify_success (explain_p);
- /* FIXME uses_deducible_template_parms */
+ /* Implicit conversions (Clause 4) will be performed on a function
+ argument to convert it to the type of the corresponding function
+ parameter if the parameter type contains no template-parameters that
+ participate in template argument deduction. */
if (TYPE_P (parm) && !uses_template_parms (parm))
+ /* For function parameters that contain no template-parameters at all,
+ we have historically checked for convertibility in order to shortcut
+ consideration of this candidate. */
return check_non_deducible_conversion (parm, arg, strict, flags,
explain_p);
+ else if (strict == DEDUCE_CALL
+ && TYPE_P (parm) && !uses_deducible_template_parms (parm))
+ /* For function parameters with only non-deducible template parameters,
+ just return. */
+ return unify_success (explain_p);
switch (strict)
{
diff --git a/gcc/testsuite/g++.dg/template/non-deducible1.C b/gcc/testsuite/g++.dg/template/non-deducible1.C
new file mode 100644
index 0000000..4213524
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-deducible1.C
@@ -0,0 +1,8 @@
+// PR c++/23055
+
+template <class> struct S { typedef int type; };
+
+template <class T>
+int foo(T, typename S<T>::type * ret);
+
+int j = foo(1, 0);
diff --git a/gcc/testsuite/g++.dg/template/nontype25.C b/gcc/testsuite/g++.dg/template/nontype25.C
index bcdcce5..f399408 100644
--- a/gcc/testsuite/g++.dg/template/nontype25.C
+++ b/gcc/testsuite/g++.dg/template/nontype25.C
@@ -7,7 +7,7 @@ template<const A* a> class C {};
template<const B* b> class D {};
template<B* b> class E {};
-template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" "" { target c++98 } }
+template<const B* b> void f(D<b> &, C<static_cast<const A*>(b)> &) {} // { dg-error "" "" }
template<const B* b> void g(D<b> &, E<const_cast<B*>(b)> &) {} // { dg-error "" "" { target c++98 } }
B b;