commit c17767b10d05c0ea47107a3b7f067da76cc5ad8d
Author: Jason Merrill <jason@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>(); }
+};
