Here, the problem was that we were resolving the address of an
overloaded function in the context of the template being called (which
doesn't have access to the function) rather than the caller (which
does). We need to massage explicit template arguments before we enter
the callee's context.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit c17767b10d05c0ea47107a3b7f067da76cc5ad8d
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Sep 4 11:27:03 2012 -0400
PR c++/54437
PR c++/51213
* pt.c (fn_type_unification): Call coerce_template_parms before
entering substitution context.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4a39427..6f6235c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14591,11 +14591,22 @@ fn_type_unification (tree fn,
static int deduction_depth;
struct pending_template *old_last_pend = last_pending_template;
struct tinst_level *old_error_tinst = last_error_tinst_level;
+ tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
tree tinst;
tree r = error_mark_node;
- if (excessive_deduction_depth)
- return error_mark_node;
+ /* Adjust any explicit template arguments before entering the
+ substitution context. */
+ if (explicit_targs)
+ {
+ explicit_targs
+ = (coerce_template_parms (tparms, explicit_targs, NULL_TREE,
+ complain,
+ /*require_all_args=*/false,
+ /*use_default_args=*/false));
+ if (explicit_targs == error_mark_node)
+ return error_mark_node;
+ }
/* In C++0x, it's possible to have a function template whose type depends
on itself recursively. This is most obvious with decltype, but can also
@@ -14608,6 +14619,8 @@ fn_type_unification (tree fn,
substitutions back up to the initial one.
This is, of course, not reentrant. */
+ if (excessive_deduction_depth)
+ return error_mark_node;
tinst = build_tree_list (fn, targs);
if (!push_tinst_level (tinst))
{
@@ -14640,23 +14653,10 @@ fn_type_unification (tree fn,
specified template argument values. If a substitution in a
template parameter or in the function type of the function
template results in an invalid type, type deduction fails. */
- tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (fn);
int i, len = TREE_VEC_LENGTH (tparms);
location_t loc = input_location;
- tree converted_args;
bool incomplete = false;
- if (explicit_targs == error_mark_node)
- goto fail;
-
- converted_args
- = (coerce_template_parms (tparms, explicit_targs, NULL_TREE,
- complain,
- /*require_all_args=*/false,
- /*use_default_args=*/false));
- if (converted_args == error_mark_node)
- goto fail;
-
/* Substitute the explicit args into the function type. This is
necessary so that, for instance, explicitly declared function
arguments can match null pointed constants. If we were given
@@ -14667,7 +14667,7 @@ fn_type_unification (tree fn,
{
tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
bool parameter_pack = false;
- tree targ = TREE_VEC_ELT (converted_args, i);
+ tree targ = TREE_VEC_ELT (explicit_targs, i);
/* Dig out the actual parm. */
if (TREE_CODE (parm) == TYPE_DECL
@@ -14705,7 +14705,7 @@ fn_type_unification (tree fn,
processing_template_decl += incomplete;
input_location = DECL_SOURCE_LOCATION (fn);
- fntype = tsubst (TREE_TYPE (fn), converted_args,
+ fntype = tsubst (TREE_TYPE (fn), explicit_targs,
complain | tf_partial, NULL_TREE);
input_location = loc;
processing_template_decl -= incomplete;
@@ -14714,8 +14714,8 @@ fn_type_unification (tree fn,
goto fail;
/* Place the explicitly specified arguments in TARGS. */
- for (i = NUM_TMPL_ARGS (converted_args); i--;)
- TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (converted_args, i);
+ for (i = NUM_TMPL_ARGS (explicit_targs); i--;)
+ TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (explicit_targs, i);
}
/* Never do unification on the 'this' parameter. */
diff --git a/gcc/testsuite/g++.dg/template/access24.C b/gcc/testsuite/g++.dg/template/access24.C
new file mode 100644
index 0000000..9f19226
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/access24.C
@@ -0,0 +1,8 @@
+// PR c++/54437
+
+template <void (*P)()> void f();
+class A {
+ template <class T> static void g();
+ template <class T> static void h () { f<g<T> >(); }
+ static void i() { h<int>(); }
+};