diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 10182fcdd1b2491c3e2d353af938263389eee20f..b025fa7e623847506f7633366a7042c03ca402a5 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,11 @@
 2011-12-23  Jason Merrill  <jason@redhat.com>
 
+	PR c++/51507
+	* search.c (at_function_scope_p): Also check cfun.
+	* pt.c (tsubst_pack_expansion): Check it instead of
+	cp_unevaluated_operand.
+	(instantiate_template_1): Use push_to_top_level.
+
 	* tree.c (dependent_name): OFFSET_REF and BASELINK
 	are not dependent names.
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 820b1ff755240758a20cb95efb98d633e400a24f..20f67aa6edf0ad0774e1714c984b6513d90c4e78 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -9297,6 +9297,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   int i, len = -1;
   tree result;
   htab_t saved_local_specializations = NULL;
+  bool need_local_specializations = false;
   int levels;
 
   gcc_assert (PACK_EXPANSION_P (t));
@@ -9330,7 +9331,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
        }
       if (TREE_CODE (parm_pack) == PARM_DECL)
 	{
-	  if (!cp_unevaluated_operand)
+	  if (at_function_scope_p ())
 	    arg_pack = retrieve_local_specialization (parm_pack);
 	  else
 	    {
@@ -9346,6 +9347,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
 		arg_pack = NULL_TREE;
 	      else
 		arg_pack = make_fnparm_pack (arg_pack);
+	      need_local_specializations = true;
 	    }
 	}
       else
@@ -9476,7 +9478,7 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,
   if (len < 0)
     return error_mark_node;
 
-  if (cp_unevaluated_operand)
+  if (need_local_specializations)
     {
       /* We're in a late-specified return type, so create our own local
 	 specializations table; the current table is either NULL or (in the
@@ -14524,7 +14526,6 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
   tree fndecl;
   tree gen_tmpl;
   tree spec;
-  HOST_WIDE_INT saved_processing_template_decl;
 
   if (tmpl == error_mark_node)
     return error_mark_node;
@@ -14585,18 +14586,22 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
      deferring all checks until we have the FUNCTION_DECL.  */
   push_deferring_access_checks (dk_deferred);
 
-  /* Although PROCESSING_TEMPLATE_DECL may be true at this point
-     (because, for example, we have encountered a non-dependent
-     function call in the body of a template function and must now
-     determine which of several overloaded functions will be called),
-     within the instantiation itself we are not processing a
-     template.  */  
-  saved_processing_template_decl = processing_template_decl;
-  processing_template_decl = 0;
+  /* Instantiation of the function happens in the context of the function
+     template, not the context of the overload resolution we're doing.  */
+  push_to_top_level ();
+  if (DECL_CLASS_SCOPE_P (gen_tmpl))
+    {
+      tree ctx = tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr,
+			 complain, gen_tmpl);
+      push_nested_class (ctx);
+    }
   /* Substitute template parameters to obtain the specialization.  */
   fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
 		   targ_ptr, complain, gen_tmpl);
-  processing_template_decl = saved_processing_template_decl;
+  if (DECL_CLASS_SCOPE_P (gen_tmpl))
+    pop_nested_class ();
+  pop_from_top_level ();
+
   if (fndecl == error_mark_node)
     return error_mark_node;
 
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 0ceb5bc14f8d16abc0d3f820a047619cfeb305bf..45fdafc37237f7e4977aea4d28451a68dd740d7e 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -539,7 +539,11 @@ int
 at_function_scope_p (void)
 {
   tree cs = current_scope ();
-  return cs && TREE_CODE (cs) == FUNCTION_DECL;
+  /* Also check cfun to make sure that we're really compiling
+     this function (as opposed to having set current_function_decl
+     for access checking or some such).  */
+  return (cs && TREE_CODE (cs) == FUNCTION_DECL
+	  && cfun && cfun->decl == current_function_decl);
 }
 
 /* Returns true if the innermost active scope is a class scope.  */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index dac74c38c67a47b48a9a65bc8d5d8a628ecada4f..c2ca72bfa16522f8cab4e138ddb17fdcfc75719f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2011-12-23  Jason Merrill  <jason@redhat.com>
+
+	PR c++/51507
+	* g++.dg/cpp0x/variadic121.C: New.
+
 2011-12-23  Uros Bizjak  <ubizjak@gmail.com>
 
 	* gcc.dg/vect/fast-math-pr35982.c: Fix parenthesis in target selectors.
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic121.C b/gcc/testsuite/g++.dg/cpp0x/variadic121.C
new file mode 100644
index 0000000000000000000000000000000000000000..805c0065fe9270d09d24cd2ff801c2333e3b7356
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic121.C
@@ -0,0 +1,12 @@
+// PR c++/51507
+// { dg-options -std=c++0x }
+
+template<typename ...>
+struct foo { typedef void type; };
+template<typename ...Ts>
+auto g(Ts ...ts)->
+  typename foo<decltype(ts)...>::type
+{}
+int main() {
+  g(42);
+}