2014-01-30  Jason Merrill  <jason@redhat.com>

	PR c++/57899
gcc/
	* pointer-set.c (pointer_map_copy): New.
	* pointer-set.h: Declare it.
gcc/cp/
	* cp-tree.h (struct saved_scope): Add x_local_specializations.
	(local_specializations): New macro.
	* pt.c (local_specializations): Remove variable.
	(instantiate_decl): Only create new local_specializations if
	we did push_to_top_level.

diff --git a/gcc/pointer-set.c b/gcc/pointer-set.c
index 8b6a732..fdd9275 100644
--- a/gcc/pointer-set.c
+++ b/gcc/pointer-set.c
@@ -192,6 +192,19 @@ pointer_map_create (void)
   return result;
 }
 
+/* Duplicate an existing pointer map.  */
+struct pointer_map_t *
+pointer_map_copy (pointer_map_t *p)
+{
+  struct pointer_map_t *result = XNEW (struct pointer_map_t);
+  result->pset.n_elements = p->pset.n_elements;
+  result->pset.log_slots = p->pset.log_slots;
+  result->pset.n_slots = p->pset.n_slots;
+  result->pset.slots = XDUPVEC (const void *, p->pset.slots, p->pset.n_slots);
+  result->values = XDUPVEC (void *, p->values, p->pset.n_slots);
+  return result;
+}
+
 /* Reclaims all memory associated with PMAP.  */
 void pointer_map_destroy (struct pointer_map_t *pmap)
 {
diff --git a/gcc/pointer-set.h b/gcc/pointer-set.h
index a426534..67f6527 100644
--- a/gcc/pointer-set.h
+++ b/gcc/pointer-set.h
@@ -159,6 +159,7 @@ pointer_map<T>::traverse (bool (*fn) (const void *, T *, void *), void *data)
 
 struct pointer_map_t;
 pointer_map_t *pointer_map_create (void);
+pointer_map_t *pointer_map_copy (pointer_map_t *);
 void pointer_map_destroy (pointer_map_t *pmap);
 
 void **pointer_map_contains (const pointer_map_t *pmap, const void *p);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7f46499..7681b27 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1049,6 +1049,8 @@ struct GTY(()) saved_scope {
   cp_binding_level *class_bindings;
   cp_binding_level *bindings;
 
+  struct pointer_map_t *x_local_specializations;
+
   struct saved_scope *prev;
 };
 
@@ -1098,6 +1100,12 @@ struct GTY(()) saved_scope {
 
 #define previous_class_level scope_chain->x_previous_class_level
 
+/* A map from local variable declarations in the body of the template
+   presently being instantiated to the corresponding instantiated
+   local variables.  */
+
+#define local_specializations scope_chain->x_local_specializations
+
 /* A list of private types mentioned, for deferred access checking.  */
 
 extern GTY(()) struct saved_scope *scope_chain;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 4a5b6cc..43aeaa0 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -78,11 +78,6 @@ static GTY(()) tree saved_access_scope;
    to the EXPR_STMT that is its result.  */
 static tree cur_stmt_expr;
 
-/* A map from local variable declarations in the body of the template
-   presently being instantiated to the corresponding instantiated
-   local variables.  */
-static struct pointer_map_t *local_specializations;
-
 /* True if we've recursed into fn_type_unification too many times.  */
 static bool excessive_deduction_depth;
 
@@ -19637,7 +19632,15 @@ instantiate_decl (tree d, int defer_ok,
       saved_local_specializations = local_specializations;
 
       /* Set up the list of local specializations.  */
-      local_specializations = pointer_map_create ();
+      if (fn_context
+	  && !(DECL_CLASS_SCOPE_P (d) && LAMBDA_TYPE_P (DECL_CONTEXT (d))))
+	/* Normally in a nested function we want to be able to look up
+	   variables from the enclosing function.  But in a lambda we've
+	   already remapped everything to refer to the closure, and we
+	   might be instantiating from outside the enclosing function.  */
+	local_specializations = pointer_map_copy (local_specializations);
+      else
+	local_specializations = pointer_map_create ();
 
       /* Set up context.  */
       if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
diff --git a/libstdc++-v3/testsuite/20_util/bind/57899.cc b/libstdc++-v3/testsuite/20_util/bind/57899.cc
new file mode 100644
index 0000000..d46d53e
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bind/57899.cc
@@ -0,0 +1,48 @@
+// Copyright (C) 2010-2014 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// 20.7.11 Function template bind
+
+// PR c++/57899
+// { dg-do compile }
+// { dg-options -std=c++11 }
+
+#include <functional>
+using std::bind;
+using std::placeholders::_1;
+
+struct S { int i; };
+
+struct P { S s; };
+
+struct get_s
+{
+  const S& operator()(const P& p) const { return p.s; }
+} gs;
+
+int gi(const S& s) { return s.i; }
+
+bool cmp(int, int) { return true; }
+
+int main()
+{
+  P p{};
+  auto f1 = bind(gs, _1);
+  auto f2 = bind(gi, f1);
+  auto f3 = bind(cmp, f2, 5);
+  f3(p);
+}
