Our old model for handling lambdas in templates was to handle them
like any other template class, and instantiate them by normal
substitution.  This was insufficient for lambdas for two reasons: for
one, it made it impossible to get implicit captures quite right in
templates.

Also, if a lambda appears in a pack expansion, e.g.

template <class... T>
auto f() {
  int i = 42;
  return ([i]{ return T(i); }() + ...);
}

There needs to be one lambda for each element of T, not just one for
each instantiation of f.  So instantiating a LAMBDA_EXPR needs to
build up a new LAMBDA_EXPR each time.  This patch implements that,
primarily in the new tsubst_lambda_expr function.

Generating the op() decl for the new lambda is a lot like a normal
instantiation, but not quite.  I decided to do this by factoring out
tsubst_function_decl and tsubst_template_decl, and having them handle
the lambda special case appropriately: when we're dealing with the
lambda function, it isn't actually a specialization of the lambda in
the template, and it isn't a member of a specialization of the closure
in the template.

The code in process_outer_var_ref for handling generic lambdas
specifically can now go away; we now defer implicit capture until the
enclosing context is instantiated for generic and non-generic lambdas.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit bdbf060161375648283cf82d4662362ea788b298
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Jul 6 19:32:32 2017 -0400

            Reimplement handling of lambdas in templates.
    
            * cp-tree.h (LAMBDA_FUNCTION_P): Check DECL_DECLARES_FUNCTION_P.
            * decl.c (start_preparsed_function): Call start_lambda_scope.
            (finish_function): Call finish_lambda_scope.
            * init.c (get_nsdmi): Call start/finish_lambda_scope.
            * lambda.c (start_lambda_scope): Only ignore VAR_DECL in a function.
            * parser.c (cp_parser_function_definition_after_declarator): Don't
            call start/finish_lambda_scope.
            * pt.c (retrieve_specialization): Ignore lambda functions in
            templates.
            (find_parameter_packs_r): Ignore capture proxies.  Look into
            lambdas.
            (check_for_bare_parameter_packs): Allow bare packs in lambdas.
            (tsubst_default_argument): Call start/finish_lambda_scope.
            (tsubst_function_decl): Handle lambda functions differently.
            (tsubst_template_decl): Likewise.
            (tsubst_expr) [DECL_EXPR]: Skip closure declarations and capture
            proxies.
            (tsubst_lambda_expr): Create a new closure rather than instantiate
            the one from the template.
            (tsubst_copy_and_build): Don't register a specialization of a pack.
            (regenerate_decl_from_template): Call start/finish_lambda_scope.
            (instantiate_decl): Remove special lambda function handling.
            * semantics.c (process_outer_var_ref): Remove special generic lambda
            handling.  Don't implicitly capture in a lambda in a template.  Look
            for an existing proxy.
            * class.c (current_nonlambda_class_type): Use decl_type_context.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 28cf7dc..a5f1007 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7709,27 +7709,10 @@ outermost_open_class (void)
 tree
 current_nonlambda_class_type (void)
 {
-  int i;
-
-  /* We start looking from 1 because entry 0 is from global scope,
-     and has no type.  */
-  for (i = current_class_depth; i > 0; --i)
-    {
-      tree c;
-      if (i == current_class_depth)
-       c = current_class_type;
-      else
-       {
-         if (current_class_stack[i].hidden)
-           break;
-         c = current_class_stack[i].type;
-       }
-      if (!c)
-       continue;
-      if (!LAMBDA_TYPE_P (c))
-       return c;
-    }
-  return NULL_TREE;
+  tree type = current_class_type;
+  while (type && LAMBDA_TYPE_P (type))
+    type = decl_type_context (TYPE_NAME (type));
+  return type;
 }
 
 /* When entering a class scope, all enclosing class scopes' names with
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ad97be4..41c48ec 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1216,8 +1216,9 @@ struct GTY (()) tree_trait_expr {
   (CLASS_TYPE_P (NODE) && CLASSTYPE_LAMBDA_EXPR (NODE))
 
 /* Test if FUNCTION_DECL is a lambda function.  */
-#define LAMBDA_FUNCTION_P(FNDECL) \
-  (DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR \
+#define LAMBDA_FUNCTION_P(FNDECL)                      \
+  (DECL_DECLARES_FUNCTION_P (FNDECL)                   \
+   && DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR \
    && LAMBDA_TYPE_P (CP_DECL_CONTEXT (FNDECL)))
 
 enum cp_lambda_default_capture_mode_type {
@@ -6828,6 +6829,11 @@ extern bool is_lambda_ignored_entity            (tree);
 extern bool lambda_static_thunk_p              (tree);
 extern tree finish_builtin_launder             (location_t, tree,
                                                 tsubst_flags_t);
+extern void start_lambda_scope                 (tree);
+extern void record_lambda_scope                        (tree);
+extern void finish_lambda_scope                        (void);
+extern tree start_lambda_function              (tree fn, tree lambda_expr);
+extern void finish_lambda_function             (tree body);
 
 /* in tree.c */
 extern int cp_tree_operand_length              (const_tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 23829b0..d6b80c6 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -15097,6 +15097,8 @@ start_preparsed_function (tree decl1, tree attrs, int 
flags)
       && !implicit_default_ctor_p (decl1))
     cp_ubsan_maybe_initialize_vtbl_ptrs (current_class_ptr);
 
+  start_lambda_scope (decl1);
+
   return true;
 }
 
@@ -15462,6 +15464,8 @@ finish_function (int flags)
   if (fndecl == NULL_TREE)
     return error_mark_node;
 
+  finish_lambda_scope ();
+
   if (c_dialect_objc ())
     objc_finish_function ();
 
@@ -15565,11 +15569,11 @@ finish_function (int flags)
 
   /* Lambda closure members are implicitly constexpr if possible.  */
   if (cxx_dialect >= cxx1z
-      && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))
-      && (processing_template_decl
+      && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))
+    DECL_DECLARED_CONSTEXPR_P (fndecl)
+      = ((processing_template_decl
          || is_valid_constexpr_fn (fndecl, /*complain*/false))
-      && potential_constant_expression (DECL_SAVED_TREE (fndecl)))
-    DECL_DECLARED_CONSTEXPR_P (fndecl) = true;
+        && potential_constant_expression (DECL_SAVED_TREE (fndecl)));
 
   /* Save constexpr function body before it gets munged by
      the NRV transformation.   */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 56a5df8..b01d662 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -574,13 +574,17 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t 
complain)
 
          inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
 
+         start_lambda_scope (member);
+
          /* Do deferred instantiation of the NSDMI.  */
          init = (tsubst_copy_and_build
                  (init, DECL_TI_ARGS (member),
                   complain, member, /*function_p=*/false,
                   /*integral_constant_expression_p=*/false));
          init = digest_nsdmi_init (member, init, complain);
-         
+
+         finish_lambda_scope ();
+
          DECL_INSTANTIATING_NSDMI_P (member) = 0;
 
          if (init != error_mark_node)
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 55d3415..4747a72 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -1253,4 +1253,87 @@ is_lambda_ignored_entity (tree val)
   return false;
 }
 
+/* Lambdas that appear in variable initializer or default argument scope
+   get that in their mangling, so we need to record it.  We might as well
+   use the count for function and namespace scopes as well.  */
+static GTY(()) tree lambda_scope;
+static GTY(()) int lambda_count;
+struct GTY(()) tree_int
+{
+  tree t;
+  int i;
+};
+static GTY(()) vec<tree_int, va_gc> *lambda_scope_stack;
+
+void
+start_lambda_scope (tree decl)
+{
+  tree_int ti;
+  gcc_assert (decl);
+  /* Once we're inside a function, we ignore variable scope and just push
+     the function again so that popping works properly.  */
+  if (current_function_decl && TREE_CODE (decl) == VAR_DECL)
+    decl = current_function_decl;
+  ti.t = lambda_scope;
+  ti.i = lambda_count;
+  vec_safe_push (lambda_scope_stack, ti);
+  if (lambda_scope != decl)
+    {
+      /* Don't reset the count if we're still in the same function.  */
+      lambda_scope = decl;
+      lambda_count = 0;
+    }
+}
+
+void
+record_lambda_scope (tree lambda)
+{
+  LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;
+  LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
+}
+
+void
+finish_lambda_scope (void)
+{
+  tree_int *p = &lambda_scope_stack->last ();
+  if (lambda_scope != p->t)
+    {
+      lambda_scope = p->t;
+      lambda_count = p->i;
+    }
+  lambda_scope_stack->pop ();
+}
+
+tree
+start_lambda_function (tree fco, tree lambda_expr)
+{
+  /* Let the front end know that we are going to be defining this
+     function.  */
+  start_preparsed_function (fco,
+                           NULL_TREE,
+                           SF_PRE_PARSED | SF_INCLASS_INLINE);
+
+  tree body = begin_function_body ();
+
+  /* Push the proxies for any explicit captures.  */
+  for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
+       cap = TREE_CHAIN (cap))
+    build_capture_proxy (TREE_PURPOSE (cap));
+
+  return body;
+}
+
+void
+finish_lambda_function (tree body)
+{
+  finish_function_body (body);
+
+  /* Finish the function and generate code for it if necessary.  */
+  tree fn = finish_function (/*inline*/2);
+
+  /* Only expand if the call op is not a template.  */
+  if (!DECL_TEMPLATE_INFO (fn))
+    expand_or_defer_fn (fn);
+}
+
 #include "gt-cp-lambda.h"
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 9f62b43..d0d71fa 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -9982,57 +9982,6 @@ cp_parser_trait_expr (cp_parser* parser, enum rid 
keyword)
     }
 }
 
-/* Lambdas that appear in variable initializer or default argument scope
-   get that in their mangling, so we need to record it.  We might as well
-   use the count for function and namespace scopes as well.  */
-static GTY(()) tree lambda_scope;
-static GTY(()) int lambda_count;
-struct GTY(()) tree_int
-{
-  tree t;
-  int i;
-};
-static GTY(()) vec<tree_int, va_gc> *lambda_scope_stack;
-
-static void
-start_lambda_scope (tree decl)
-{
-  tree_int ti;
-  gcc_assert (decl);
-  /* Once we're inside a function, we ignore other scopes and just push
-     the function again so that popping works properly.  */
-  if (current_function_decl && TREE_CODE (decl) != FUNCTION_DECL)
-    decl = current_function_decl;
-  ti.t = lambda_scope;
-  ti.i = lambda_count;
-  vec_safe_push (lambda_scope_stack, ti);
-  if (lambda_scope != decl)
-    {
-      /* Don't reset the count if we're still in the same function.  */
-      lambda_scope = decl;
-      lambda_count = 0;
-    }
-}
-
-static void
-record_lambda_scope (tree lambda)
-{
-  LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;
-  LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
-}
-
-static void
-finish_lambda_scope (void)
-{
-  tree_int *p = &lambda_scope_stack->last ();
-  if (lambda_scope != p->t)
-    {
-      lambda_scope = p->t;
-      lambda_count = p->i;
-    }
-  lambda_scope_stack->pop ();
-}
-
 /* Parse a lambda expression.
 
    lambda-expression:
@@ -10605,29 +10554,14 @@ cp_parser_lambda_body (cp_parser* parser, tree 
lambda_expr)
      + ctor_initializer_opt_and_function_body  */
   {
     tree fco = lambda_function (lambda_expr);
-    tree body;
+    tree body = start_lambda_function (fco, lambda_expr);
     bool done = false;
     tree compound_stmt;
-    tree cap;
-
-    /* Let the front end know that we are going to be defining this
-       function.  */
-    start_preparsed_function (fco,
-                             NULL_TREE,
-                             SF_PRE_PARSED | SF_INCLASS_INLINE);
-
-    start_lambda_scope (fco);
-    body = begin_function_body ();
 
     matching_braces braces;
     if (!braces.require_open (parser))
       goto out;
 
-    /* Push the proxies for any explicit captures.  */
-    for (cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
-        cap = TREE_CHAIN (cap))
-      build_capture_proxy (TREE_PURPOSE (cap));
-
     compound_stmt = begin_compound_stmt (0);
 
     /* 5.1.1.4 of the standard says:
@@ -10691,15 +10625,7 @@ cp_parser_lambda_body (cp_parser* parser, tree 
lambda_expr)
     finish_compound_stmt (compound_stmt);
 
   out:
-    finish_function_body (body);
-    finish_lambda_scope ();
-
-    /* Finish the function and generate code for it if necessary.  */
-    tree fn = finish_function (/*inline*/2);
-
-    /* Only expand if the call op is not a template.  */
-    if (!DECL_TEMPLATE_INFO (fco))
-      expand_or_defer_fn (fn);
+    finish_lambda_function (body);
   }
 
   restore_omp_privatization_clauses (omp_privatization_save);
@@ -26577,8 +26503,6 @@ cp_parser_function_definition_after_declarator 
(cp_parser* parser,
     = parser->num_template_parameter_lists;
   parser->num_template_parameter_lists = 0;
 
-  start_lambda_scope (current_function_decl);
-
   /* If the next token is `try', `__transaction_atomic', or
      `__transaction_relaxed`, then we are looking at either function-try-block
      or function-transaction-block.  Note that all of these include the
@@ -26596,8 +26520,6 @@ cp_parser_function_definition_after_declarator 
(cp_parser* parser,
     ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body
       (parser, /*in_function_try_block=*/false);
 
-  finish_lambda_scope ();
-
   /* Finish the function.  */
   fn = finish_function ((ctor_initializer_p ? 1 : 0) |
                        (inline_p ? 2 : 0));
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e064a11..141b4d7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -220,6 +220,7 @@ static bool complex_alias_template_p (const_tree tmpl);
 static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
 static tree canonicalize_expr_argument (tree, tsubst_flags_t);
 static tree make_argument_pack (tree);
+static void register_parameter_specializations (tree, tree);
 
 /* Make the current scope suitable for access checking when we are
    processing T.  T can be FUNCTION_DECL for instantiated function
@@ -1190,6 +1191,19 @@ retrieve_specialization (tree tmpl, tree args, hashval_t 
hash)
   if (flag_checking)
     verify_unstripped_args (args);
 
+  /* Lambda functions in templates aren't instantiated normally, but through
+     tsubst_lambda_expr.  */
+  if (LAMBDA_FUNCTION_P (tmpl))
+    {
+      bool generic = PRIMARY_TEMPLATE_P (tmpl);
+      if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)) > generic)
+       return NULL_TREE;
+
+      /* But generic lambda functions are instantiated normally, once their
+        containing context is fully instantiated.  */
+      gcc_assert (generic);
+    }
+
   if (optimize_specialization_lookup_p (tmpl))
     {
       /* The template arguments actually apply to the containing
@@ -3615,6 +3629,12 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
void* data)
     case PARM_DECL:
       return NULL_TREE;
 
+    case DECL_EXPR:
+      /* Ignore the declaration of a capture proxy for a parameter pack.  */
+      if (is_capture_proxy (DECL_EXPR_DECL (t)))
+       *walk_subtrees = 0;
+      return NULL_TREE;
+
     case RECORD_TYPE:
       if (TYPE_PTRMEMFUNC_P (t))
        return NULL_TREE;
@@ -3662,6 +3682,15 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, 
void* data)
       *walk_subtrees = 0;
       return NULL_TREE;
 
+    case LAMBDA_EXPR:
+      {
+       tree fn = lambda_function (t);
+       cp_walk_tree (&DECL_SAVED_TREE (fn), &find_parameter_packs_r, ppd,
+                     ppd->visited);
+       *walk_subtrees = 0;
+       return NULL_TREE;
+      }
+
     case DECLTYPE_TYPE:
       {
        /* When traversing a DECLTYPE_TYPE_EXPR, we need to set
@@ -3849,6 +3878,10 @@ check_for_bare_parameter_packs (tree t)
   if (!processing_template_decl || !t || t == error_mark_node)
     return false;
 
+  /* A lambda might use a parameter pack from the containing context.  */
+  if (current_function_decl && LAMBDA_FUNCTION_P (current_function_decl))
+    return false;
+
   if (TREE_CODE (t) == TYPE_DECL)
     t = TREE_TYPE (t);
 
@@ -12056,6 +12089,8 @@ tsubst_default_argument (tree fn, int parmnum, tree 
type, tree arg,
       cp_function_chain->x_current_class_ref = NULL_TREE;
     }
 
+  start_lambda_scope (parm);
+
   push_deferring_access_checks(dk_no_deferred);
   /* The default argument expression may cause implicitly defined
      member functions to be synthesized, which will result in garbage
@@ -12069,6 +12104,8 @@ tsubst_default_argument (tree fn, int parmnum, tree 
type, tree arg,
   --function_depth;
   pop_deferring_access_checks();
 
+  finish_lambda_scope ();
+
   /* Restore the "this" pointer.  */
   if (cfun)
     {
@@ -12125,6 +12162,441 @@ tsubst_default_arguments (tree fn, tsubst_flags_t 
complain)
                                                    complain);
 }
 
+/* Subroutine of tsubst_decl for the case when T is a FUNCTION_DECL.  */
+
+static tree
+tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
+                     tree lambda_fntype)
+{
+  tree gen_tmpl, argvec;
+  hashval_t hash = 0;
+  tree in_decl = t;
+
+  /* Nobody should be tsubst'ing into non-template functions.  */
+  gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);
+
+  if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
+    {
+      /* If T is not dependent, just return it.  */
+      if (!uses_template_parms (DECL_TI_ARGS (t)))
+       return t;
+
+      /* Calculate the most general template of which R is a
+        specialization, and the complete set of arguments used to
+        specialize R.  */
+      gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
+      argvec = tsubst_template_args (DECL_TI_ARGS
+                                    (DECL_TEMPLATE_RESULT
+                                     (DECL_TI_TEMPLATE (t))),
+                                    args, complain, in_decl);
+      if (argvec == error_mark_node)
+       return error_mark_node;
+
+      /* Check to see if we already have this specialization.  */
+      if (!lambda_fntype)
+       {
+         hash = hash_tmpl_and_args (gen_tmpl, argvec);
+         if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
+           return spec;
+       }
+
+      /* We can see more levels of arguments than parameters if
+        there was a specialization of a member template, like
+        this:
+
+        template <class T> struct S { template <class U> void f(); }
+        template <> template <class U> void S<int>::f(U);
+
+        Here, we'll be substituting into the specialization,
+        because that's where we can find the code we actually
+        want to generate, but we'll have enough arguments for
+        the most general template.
+
+        We also deal with the peculiar case:
+
+        template <class T> struct S {
+        template <class U> friend void f();
+        };
+        template <class U> void f() {}
+        template S<int>;
+        template void f<double>();
+
+        Here, the ARGS for the instantiation of will be {int,
+        double}.  But, we only need as many ARGS as there are
+        levels of template parameters in CODE_PATTERN.  We are
+        careful not to get fooled into reducing the ARGS in
+        situations like:
+
+        template <class T> struct S { template <class U> void f(U); }
+        template <class T> template <> void S<T>::f(int) {}
+
+        which we can spot because the pattern will be a
+        specialization in this case.  */
+      int args_depth = TMPL_ARGS_DEPTH (args);
+      int parms_depth =
+       TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t)));
+
+      if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t))
+       args = get_innermost_template_args (args, parms_depth);
+    }
+  else
+    {
+      /* This special case arises when we have something like this:
+
+        template <class T> struct S {
+        friend void f<int>(int, double);
+        };
+
+        Here, the DECL_TI_TEMPLATE for the friend declaration
+        will be an IDENTIFIER_NODE.  We are being called from
+        tsubst_friend_function, and we want only to create a
+        new decl (R) with appropriate types so that we can call
+        determine_specialization.  */
+      gen_tmpl = NULL_TREE;
+      argvec = NULL_TREE;
+    }
+
+  tree closure = (lambda_fntype ? TYPE_METHOD_BASETYPE (lambda_fntype)
+                 : NULL_TREE);
+  tree ctx = closure ? closure : DECL_CONTEXT (t);
+  bool member = ctx && TYPE_P (ctx);
+
+  if (member && !closure)
+    ctx = tsubst_aggr_type (ctx, args,
+                           complain, t, /*entering_scope=*/1);
+
+  tree type = (lambda_fntype ? lambda_fntype
+              : tsubst (TREE_TYPE (t), args,
+                        complain | tf_fndecl_type, in_decl));
+  if (type == error_mark_node)
+    return error_mark_node;
+
+  /* If we hit excessive deduction depth, the type is bogus even if
+     it isn't error_mark_node, so don't build a decl.  */
+  if (excessive_deduction_depth)
+    return error_mark_node;
+
+  /* We do NOT check for matching decls pushed separately at this
+     point, as they may not represent instantiations of this
+     template, and in any case are considered separate under the
+     discrete model.  */
+  tree r = copy_decl (t);
+  DECL_USE_TEMPLATE (r) = 0;
+  TREE_TYPE (r) = type;
+  /* Clear out the mangled name and RTL for the instantiation.  */
+  SET_DECL_ASSEMBLER_NAME (r, NULL_TREE);
+  SET_DECL_RTL (r, NULL);
+  /* Leave DECL_INITIAL set on deleted instantiations.  */
+  if (!DECL_DELETED_FN (r))
+    DECL_INITIAL (r) = NULL_TREE;
+  DECL_CONTEXT (r) = ctx;
+
+  /* OpenMP UDRs have the only argument a reference to the declared
+     type.  We want to diagnose if the declared type is a reference,
+     which is invalid, but as references to references are usually
+     quietly merged, diagnose it here.  */
+  if (DECL_OMP_DECLARE_REDUCTION_P (t))
+    {
+      tree argtype
+       = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t))));
+      argtype = tsubst (argtype, args, complain, in_decl);
+      if (TREE_CODE (argtype) == REFERENCE_TYPE)
+       error_at (DECL_SOURCE_LOCATION (t),
+                 "reference type %qT in "
+                 "%<#pragma omp declare reduction%>", argtype);
+      if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)
+       DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),
+                                         argtype);
+    }
+
+  if (member && DECL_CONV_FN_P (r))
+    /* Type-conversion operator.  Reconstruct the name, in
+       case it's the name of one of the template's parameters.  */
+    DECL_NAME (r) = make_conv_op_name (TREE_TYPE (type));
+
+  tree parms = DECL_ARGUMENTS (t);
+  if (closure)
+    parms = DECL_CHAIN (parms);
+  parms = tsubst (parms, args, complain, t);
+  for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
+    DECL_CONTEXT (parm) = r;
+  if (closure)
+    {
+      tree tparm = build_this_parm (r, closure, type_memfn_quals (type));
+      DECL_CHAIN (tparm) = parms;
+      parms = tparm;
+    }
+  DECL_ARGUMENTS (r) = parms;
+  DECL_RESULT (r) = NULL_TREE;
+
+  TREE_STATIC (r) = 0;
+  TREE_PUBLIC (r) = TREE_PUBLIC (t);
+  DECL_EXTERNAL (r) = 1;
+  /* If this is an instantiation of a function with internal
+     linkage, we already know what object file linkage will be
+     assigned to the instantiation.  */
+  DECL_INTERFACE_KNOWN (r) = !TREE_PUBLIC (r);
+  DECL_DEFER_OUTPUT (r) = 0;
+  DECL_CHAIN (r) = NULL_TREE;
+  DECL_PENDING_INLINE_INFO (r) = 0;
+  DECL_PENDING_INLINE_P (r) = 0;
+  DECL_SAVED_TREE (r) = NULL_TREE;
+  DECL_STRUCT_FUNCTION (r) = NULL;
+  TREE_USED (r) = 0;
+  /* We'll re-clone as appropriate in instantiate_template.  */
+  DECL_CLONED_FUNCTION (r) = NULL_TREE;
+
+  /* If we aren't complaining now, return on error before we register
+     the specialization so that we'll complain eventually.  */
+  if ((complain & tf_error) == 0
+      && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
+      && !grok_op_properties (r, /*complain=*/false))
+    return error_mark_node;
+
+  /* When instantiating a constrained member, substitute
+     into the constraints to create a new constraint.  */
+  if (tree ci = get_constraints (t))
+    if (member)
+      {
+       ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);
+       set_constraints (r, ci);
+      }
+
+  /* Set up the DECL_TEMPLATE_INFO for R.  There's no need to do
+     this in the special friend case mentioned above where
+     GEN_TMPL is NULL.  */
+  if (gen_tmpl && !closure)
+    {
+      DECL_TEMPLATE_INFO (r)
+       = build_template_info (gen_tmpl, argvec);
+      SET_DECL_IMPLICIT_INSTANTIATION (r);
+
+      tree new_r
+       = register_specialization (r, gen_tmpl, argvec, false, hash);
+      if (new_r != r)
+       /* We instantiated this while substituting into
+          the type earlier (template/friend54.C).  */
+       return new_r;
+
+      /* We're not supposed to instantiate default arguments
+        until they are called, for a template.  But, for a
+        declaration like:
+
+        template <class T> void f ()
+        { extern void g(int i = T()); }
+
+        we should do the substitution when the template is
+        instantiated.  We handle the member function case in
+        instantiate_class_template since the default arguments
+        might refer to other members of the class.  */
+      if (!member
+         && !PRIMARY_TEMPLATE_P (gen_tmpl)
+         && !uses_template_parms (argvec))
+       tsubst_default_arguments (r, complain);
+    }
+  else
+    DECL_TEMPLATE_INFO (r) = NULL_TREE;
+
+  /* Copy the list of befriending classes.  */
+  for (tree *friends = &DECL_BEFRIENDING_CLASSES (r);
+       *friends;
+       friends = &TREE_CHAIN (*friends))
+    {
+      *friends = copy_node (*friends);
+      TREE_VALUE (*friends)
+       = tsubst (TREE_VALUE (*friends), args, complain, in_decl);
+    }
+
+  if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))
+    {
+      maybe_retrofit_in_chrg (r);
+      if (DECL_CONSTRUCTOR_P (r) && !grok_ctor_properties (ctx, r))
+       return error_mark_node;
+      /* If this is an instantiation of a member template, clone it.
+        If it isn't, that'll be handled by
+        clone_constructors_and_destructors.  */
+      if (PRIMARY_TEMPLATE_P (gen_tmpl))
+       clone_function_decl (r, /*update_methods=*/false);
+    }
+  else if ((complain & tf_error) != 0
+          && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
+          && !grok_op_properties (r, /*complain=*/true))
+    return error_mark_node;
+
+  if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
+    SET_DECL_FRIEND_CONTEXT (r,
+                            tsubst (DECL_FRIEND_CONTEXT (t),
+                                    args, complain, in_decl));
+
+  /* Possibly limit visibility based on template args.  */
+  DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
+  if (DECL_VISIBILITY_SPECIFIED (t))
+    {
+      DECL_VISIBILITY_SPECIFIED (r) = 0;
+      DECL_ATTRIBUTES (r)
+       = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
+    }
+  determine_visibility (r);
+  if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
+      && !processing_template_decl)
+    defaulted_late_check (r);
+
+  apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
+                                 args, complain, in_decl);
+  return r;
+}
+
+/* Subroutine of tsubst_decl for the case when T is a TEMPLATE_DECL.  */
+
+static tree
+tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
+                     tree lambda_fntype)
+{
+  /* We can get here when processing a member function template,
+     member class template, or template template parameter.  */
+  tree decl = DECL_TEMPLATE_RESULT (t);
+  tree in_decl = t;
+  tree spec;
+  tree tmpl_args;
+  tree full_args;
+  tree r;
+  hashval_t hash = 0;
+
+  if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+    {
+      /* Template template parameter is treated here.  */
+      tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+      if (new_type == error_mark_node)
+       r = error_mark_node;
+      /* If we get a real template back, return it.  This can happen in
+        the context of most_specialized_partial_spec.  */
+      else if (TREE_CODE (new_type) == TEMPLATE_DECL)
+       r = new_type;
+      else
+       /* The new TEMPLATE_DECL was built in
+          reduce_template_parm_level.  */
+       r = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (new_type);
+      return r;
+    }
+
+  if (!lambda_fntype)
+    {
+      /* We might already have an instance of this template.
+        The ARGS are for the surrounding class type, so the
+        full args contain the tsubst'd args for the context,
+        plus the innermost args from the template decl.  */
+      tmpl_args = DECL_CLASS_TEMPLATE_P (t)
+       ? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
+       : DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t));
+      /* Because this is a template, the arguments will still be
+        dependent, even after substitution.  If
+        PROCESSING_TEMPLATE_DECL is not set, the dependency
+        predicates will short-circuit.  */
+      ++processing_template_decl;
+      full_args = tsubst_template_args (tmpl_args, args,
+                                       complain, in_decl);
+      --processing_template_decl;
+      if (full_args == error_mark_node)
+       return error_mark_node;
+
+      /* If this is a default template template argument,
+        tsubst might not have changed anything.  */
+      if (full_args == tmpl_args)
+       return t;
+
+      hash = hash_tmpl_and_args (t, full_args);
+      spec = retrieve_specialization (t, full_args, hash);
+      if (spec != NULL_TREE)
+       return spec;
+    }
+
+  /* Make a new template decl.  It will be similar to the
+     original, but will record the current template arguments.
+     We also create a new function declaration, which is just
+     like the old one, but points to this new template, rather
+     than the old one.  */
+  r = copy_decl (t);
+  gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
+  DECL_CHAIN (r) = NULL_TREE;
+
+  // Build new template info linking to the original template decl.
+  if (!lambda_fntype)
+    {
+      DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+      SET_DECL_IMPLICIT_INSTANTIATION (r);
+    }
+  else
+    DECL_TEMPLATE_INFO (r) = NULL_TREE;
+
+  /* The template parameters for this new template are all the
+     template parameters for the old template, except the
+     outermost level of parameters.  */
+  DECL_TEMPLATE_PARMS (r)
+    = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
+                            complain);
+
+  if (TREE_CODE (decl) == TYPE_DECL
+      && !TYPE_DECL_ALIAS_P (decl))
+    {
+      tree new_type;
+      ++processing_template_decl;
+      new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+      --processing_template_decl;
+      if (new_type == error_mark_node)
+       return error_mark_node;
+
+      TREE_TYPE (r) = new_type;
+      /* For a partial specialization, we need to keep pointing to
+        the primary template.  */
+      if (!DECL_TEMPLATE_SPECIALIZATION (t))
+       CLASSTYPE_TI_TEMPLATE (new_type) = r;
+      DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
+      DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
+      DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
+    }
+  else
+    {
+      tree new_decl;
+      ++processing_template_decl;
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       new_decl = tsubst_function_decl (decl, args, complain, lambda_fntype);
+      else
+       new_decl = tsubst (decl, args, complain, in_decl);
+      --processing_template_decl;
+      if (new_decl == error_mark_node)
+       return error_mark_node;
+
+      DECL_TEMPLATE_RESULT (r) = new_decl;
+      TREE_TYPE (r) = TREE_TYPE (new_decl);
+      DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
+      if (lambda_fntype)
+       {
+         tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r));
+         DECL_TEMPLATE_INFO (new_decl) = build_template_info (r, args);
+       }
+      else
+       {
+         DECL_TI_TEMPLATE (new_decl) = r;
+         DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
+       }
+    }
+
+  DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
+  DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
+
+  if (PRIMARY_TEMPLATE_P (t))
+    DECL_PRIMARY_TEMPLATE (r) = r;
+
+  if (TREE_CODE (decl) != TYPE_DECL && !VAR_P (decl)
+      && !lambda_fntype)
+    /* Record this non-type partial instantiation.  */
+    register_specialization (r, t,
+                            DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
+                            false, hash);
+
+  return r;
+}
+
 /* Substitute the ARGS into the T, which is a _DECL.  Return the
    result of the substitution.  Issue error and warning messages under
    control of COMPLAIN.  */
@@ -12145,395 +12617,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
   switch (TREE_CODE (t))
     {
     case TEMPLATE_DECL:
-      {
-       /* We can get here when processing a member function template,
-          member class template, or template template parameter.  */
-       tree decl = DECL_TEMPLATE_RESULT (t);
-       tree spec;
-       tree tmpl_args;
-       tree full_args;
-
-       if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
-         {
-           /* Template template parameter is treated here.  */
-           tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-           if (new_type == error_mark_node)
-             r = error_mark_node;
-           /* If we get a real template back, return it.  This can happen in
-              the context of most_specialized_partial_spec.  */
-           else if (TREE_CODE (new_type) == TEMPLATE_DECL)
-             r = new_type;
-           else
-             /* The new TEMPLATE_DECL was built in
-                reduce_template_parm_level.  */
-             r = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (new_type);
-           break;
-         }
-
-       /* We might already have an instance of this template.
-          The ARGS are for the surrounding class type, so the
-          full args contain the tsubst'd args for the context,
-          plus the innermost args from the template decl.  */
-       tmpl_args = DECL_CLASS_TEMPLATE_P (t)
-         ? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
-         : DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t));
-       /* Because this is a template, the arguments will still be
-          dependent, even after substitution.  If
-          PROCESSING_TEMPLATE_DECL is not set, the dependency
-          predicates will short-circuit.  */
-       ++processing_template_decl;
-       full_args = tsubst_template_args (tmpl_args, args,
-                                         complain, in_decl);
-       --processing_template_decl;
-       if (full_args == error_mark_node)
-         RETURN (error_mark_node);
-
-       /* If this is a default template template argument,
-          tsubst might not have changed anything.  */
-       if (full_args == tmpl_args)
-         RETURN (t);
-
-       hash = hash_tmpl_and_args (t, full_args);
-       spec = retrieve_specialization (t, full_args, hash);
-       if (spec != NULL_TREE)
-         {
-           r = spec;
-           break;
-         }
-
-       /* Make a new template decl.  It will be similar to the
-          original, but will record the current template arguments.
-          We also create a new function declaration, which is just
-          like the old one, but points to this new template, rather
-          than the old one.  */
-       r = copy_decl (t);
-       gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
-       DECL_CHAIN (r) = NULL_TREE;
-
-        // Build new template info linking to the original template decl.
-       DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
-
-       if (TREE_CODE (decl) == TYPE_DECL
-           && !TYPE_DECL_ALIAS_P (decl))
-         {
-           tree new_type;
-           ++processing_template_decl;
-           new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
-           --processing_template_decl;
-           if (new_type == error_mark_node)
-             RETURN (error_mark_node);
-
-           TREE_TYPE (r) = new_type;
-           /* For a partial specialization, we need to keep pointing to
-              the primary template.  */
-           if (!DECL_TEMPLATE_SPECIALIZATION (t))
-             CLASSTYPE_TI_TEMPLATE (new_type) = r;
-           DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
-           DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
-           DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
-         }
-       else
-         {
-           tree new_decl;
-           ++processing_template_decl;
-           new_decl = tsubst (decl, args, complain, in_decl);
-           --processing_template_decl;
-           if (new_decl == error_mark_node)
-             RETURN (error_mark_node);
-
-           DECL_TEMPLATE_RESULT (r) = new_decl;
-           DECL_TI_TEMPLATE (new_decl) = r;
-           TREE_TYPE (r) = TREE_TYPE (new_decl);
-           DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
-           DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
-         }
-
-       SET_DECL_IMPLICIT_INSTANTIATION (r);
-       DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
-       DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
-
-       /* The template parameters for this new template are all the
-          template parameters for the old template, except the
-          outermost level of parameters.  */
-       DECL_TEMPLATE_PARMS (r)
-         = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
-                                  complain);
-
-       if (PRIMARY_TEMPLATE_P (t))
-         DECL_PRIMARY_TEMPLATE (r) = r;
-
-       if (TREE_CODE (decl) != TYPE_DECL && !VAR_P (decl))
-         /* Record this non-type partial instantiation.  */
-         register_specialization (r, t,
-                                  DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
-                                  false, hash);
-      }
+      r = tsubst_template_decl (t, args, complain, /*lambda*/NULL_TREE);
       break;
 
     case FUNCTION_DECL:
-      {
-       tree gen_tmpl, argvec;
-
-       /* Nobody should be tsubst'ing into non-template functions.  */
-       gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);
-
-       if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
-         {
-           /* If T is not dependent, just return it.  */
-           if (!uses_template_parms (DECL_TI_ARGS (t)))
-             RETURN (t);
-
-           /* Calculate the most general template of which R is a
-              specialization, and the complete set of arguments used to
-              specialize R.  */
-           gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
-           argvec = tsubst_template_args (DECL_TI_ARGS
-                                          (DECL_TEMPLATE_RESULT
-                                                 (DECL_TI_TEMPLATE (t))),
-                                          args, complain, in_decl);
-           if (argvec == error_mark_node)
-             RETURN (error_mark_node);
-
-           /* Check to see if we already have this specialization.  */
-           hash = hash_tmpl_and_args (gen_tmpl, argvec);
-           if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
-             {
-               r = spec;
-               break;
-             }
-
-           /* We can see more levels of arguments than parameters if
-              there was a specialization of a member template, like
-              this:
-
-                template <class T> struct S { template <class U> void f(); }
-                template <> template <class U> void S<int>::f(U);
-
-              Here, we'll be substituting into the specialization,
-              because that's where we can find the code we actually
-              want to generate, but we'll have enough arguments for
-              the most general template.
-
-              We also deal with the peculiar case:
-
-                template <class T> struct S {
-                  template <class U> friend void f();
-                };
-                template <class U> void f() {}
-                template S<int>;
-                template void f<double>();
-
-              Here, the ARGS for the instantiation of will be {int,
-              double}.  But, we only need as many ARGS as there are
-              levels of template parameters in CODE_PATTERN.  We are
-              careful not to get fooled into reducing the ARGS in
-              situations like:
-
-                template <class T> struct S { template <class U> void f(U); }
-                template <class T> template <> void S<T>::f(int) {}
-
-              which we can spot because the pattern will be a
-              specialization in this case.  */
-           int args_depth = TMPL_ARGS_DEPTH (args);
-           int parms_depth =
-             TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t)));
-
-           if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t))
-             args = get_innermost_template_args (args, parms_depth);
-         }
-       else
-         {
-           /* This special case arises when we have something like this:
-
-                template <class T> struct S {
-                  friend void f<int>(int, double);
-                };
-
-              Here, the DECL_TI_TEMPLATE for the friend declaration
-              will be an IDENTIFIER_NODE.  We are being called from
-              tsubst_friend_function, and we want only to create a
-              new decl (R) with appropriate types so that we can call
-              determine_specialization.  */
-           gen_tmpl = NULL_TREE;
-           argvec = NULL_TREE;
-         }
-
-       tree ctx = DECL_CONTEXT (t);
-       bool member = ctx && TYPE_P (ctx);
-
-       if (member)
-         ctx = tsubst_aggr_type (ctx, args,
-                                 complain, t, /*entering_scope=*/1);
-
-       tree type = tsubst (TREE_TYPE (t), args,
-                           complain | tf_fndecl_type, in_decl);
-       if (type == error_mark_node)
-         RETURN (error_mark_node);
-
-       /* If we hit excessive deduction depth, the type is bogus even if
-          it isn't error_mark_node, so don't build a decl.  */
-       if (excessive_deduction_depth)
-         RETURN (error_mark_node);
-
-       /* We do NOT check for matching decls pushed separately at this
-          point, as they may not represent instantiations of this
-          template, and in any case are considered separate under the
-          discrete model.  */
-       r = copy_decl (t);
-       DECL_USE_TEMPLATE (r) = 0;
-       TREE_TYPE (r) = type;
-       /* Clear out the mangled name and RTL for the instantiation.  */
-       SET_DECL_ASSEMBLER_NAME (r, NULL_TREE);
-       SET_DECL_RTL (r, NULL);
-       /* Leave DECL_INITIAL set on deleted instantiations.  */
-       if (!DECL_DELETED_FN (r))
-         DECL_INITIAL (r) = NULL_TREE;
-       DECL_CONTEXT (r) = ctx;
-
-       /* OpenMP UDRs have the only argument a reference to the declared
-          type.  We want to diagnose if the declared type is a reference,
-          which is invalid, but as references to references are usually
-          quietly merged, diagnose it here.  */
-       if (DECL_OMP_DECLARE_REDUCTION_P (t))
-         {
-           tree argtype
-             = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t))));
-           argtype = tsubst (argtype, args, complain, in_decl);
-           if (TREE_CODE (argtype) == REFERENCE_TYPE)
-             error_at (DECL_SOURCE_LOCATION (t),
-                       "reference type %qT in "
-                       "%<#pragma omp declare reduction%>", argtype);
-           if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)
-             DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),
-                                               argtype);
-         }
-
-       if (member && DECL_CONV_FN_P (r))
-         /* Type-conversion operator.  Reconstruct the name, in
-            case it's the name of one of the template's parameters.  */
-         DECL_NAME (r) = make_conv_op_name (TREE_TYPE (type));
-
-       DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args,
-                                    complain, t);
-       for (tree parm = DECL_ARGUMENTS (r); parm; parm = DECL_CHAIN (parm))
-         DECL_CONTEXT (parm) = r;
-       DECL_RESULT (r) = NULL_TREE;
-
-       TREE_STATIC (r) = 0;
-       TREE_PUBLIC (r) = TREE_PUBLIC (t);
-       DECL_EXTERNAL (r) = 1;
-       /* If this is an instantiation of a function with internal
-          linkage, we already know what object file linkage will be
-          assigned to the instantiation.  */
-       DECL_INTERFACE_KNOWN (r) = !TREE_PUBLIC (r);
-       DECL_DEFER_OUTPUT (r) = 0;
-       DECL_CHAIN (r) = NULL_TREE;
-       DECL_PENDING_INLINE_INFO (r) = 0;
-       DECL_PENDING_INLINE_P (r) = 0;
-       DECL_SAVED_TREE (r) = NULL_TREE;
-       DECL_STRUCT_FUNCTION (r) = NULL;
-       TREE_USED (r) = 0;
-       /* We'll re-clone as appropriate in instantiate_template.  */
-       DECL_CLONED_FUNCTION (r) = NULL_TREE;
-
-       /* If we aren't complaining now, return on error before we register
-          the specialization so that we'll complain eventually.  */
-       if ((complain & tf_error) == 0
-           && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
-           && !grok_op_properties (r, /*complain=*/false))
-         RETURN (error_mark_node);
-
-        /* When instantiating a constrained member, substitute
-           into the constraints to create a new constraint.  */
-        if (tree ci = get_constraints (t))
-          if (member)
-            {
-              ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);
-              set_constraints (r, ci);
-            }
-
-       /* Set up the DECL_TEMPLATE_INFO for R.  There's no need to do
-          this in the special friend case mentioned above where
-          GEN_TMPL is NULL.  */
-       if (gen_tmpl)
-         {
-           DECL_TEMPLATE_INFO (r)
-             = build_template_info (gen_tmpl, argvec);
-           SET_DECL_IMPLICIT_INSTANTIATION (r);
-
-           tree new_r
-             = register_specialization (r, gen_tmpl, argvec, false, hash);
-           if (new_r != r)
-             /* We instantiated this while substituting into
-                the type earlier (template/friend54.C).  */
-             RETURN (new_r);
-
-           /* We're not supposed to instantiate default arguments
-              until they are called, for a template.  But, for a
-              declaration like:
-
-                template <class T> void f ()
-                { extern void g(int i = T()); }
-
-              we should do the substitution when the template is
-              instantiated.  We handle the member function case in
-              instantiate_class_template since the default arguments
-              might refer to other members of the class.  */
-           if (!member
-               && !PRIMARY_TEMPLATE_P (gen_tmpl)
-               && !uses_template_parms (argvec))
-             tsubst_default_arguments (r, complain);
-         }
-       else
-         DECL_TEMPLATE_INFO (r) = NULL_TREE;
-
-       /* Copy the list of befriending classes.  */
-       for (tree *friends = &DECL_BEFRIENDING_CLASSES (r);
-            *friends;
-            friends = &TREE_CHAIN (*friends))
-         {
-           *friends = copy_node (*friends);
-           TREE_VALUE (*friends)
-             = tsubst (TREE_VALUE (*friends), args, complain, in_decl);
-         }
-
-       if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))
-         {
-           maybe_retrofit_in_chrg (r);
-           if (DECL_CONSTRUCTOR_P (r) && !grok_ctor_properties (ctx, r))
-             RETURN (error_mark_node);
-           /* If this is an instantiation of a member template, clone it.
-              If it isn't, that'll be handled by
-              clone_constructors_and_destructors.  */
-           if (PRIMARY_TEMPLATE_P (gen_tmpl))
-             clone_function_decl (r, /*update_methods=*/false);
-         }
-       else if ((complain & tf_error) != 0
-                && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
-                && !grok_op_properties (r, /*complain=*/true))
-         RETURN (error_mark_node);
-
-       if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
-         SET_DECL_FRIEND_CONTEXT (r,
-                                  tsubst (DECL_FRIEND_CONTEXT (t),
-                                           args, complain, in_decl));
-
-       /* Possibly limit visibility based on template args.  */
-       DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
-       if (DECL_VISIBILITY_SPECIFIED (t))
-         {
-           DECL_VISIBILITY_SPECIFIED (r) = 0;
-           DECL_ATTRIBUTES (r)
-             = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
-         }
-       determine_visibility (r);
-       if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
-           && !processing_template_decl)
-         defaulted_late_check (r);
-
-       apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
-                                       args, complain, in_decl);
-      }
+      r = tsubst_function_decl (t, args, complain, /*lambda*/NULL_TREE);
       break;
 
     case PARM_DECL:
@@ -15862,6 +15950,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl,
               instantiate the elements directly as needed.  */
            break;
          }
+       else if (is_capture_proxy (decl)
+                && !DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+         {
+           /* We're in tsubst_lambda_expr, we've already inserted new capture
+              proxies, and uses will find them with lookup_name.  */
+           break;
+         }
+       else if (DECL_IMPLICIT_TYPEDEF_P (decl)
+                && LAMBDA_TYPE_P (TREE_TYPE (decl)))
+         /* Don't copy the old closure; we'll create a new one in
+            tsubst_lambda_expr.  */
+         break;
        else
          {
            init = DECL_INITIAL (decl);
@@ -16659,6 +16759,149 @@ tsubst_non_call_postfix_expression (tree t, tree args,
   return t;
 }
 
+/* T is a LAMBDA_EXPR.  Generate a new LAMBDA_EXPR for the current
+   instantiation context.  Instantiating a pack expansion containing a lambda
+   might result in multiple lambdas all based on the same lambda in the
+   template.  */
+
+tree
+tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+  tree oldfn = lambda_function (t);
+  in_decl = oldfn;
+
+  tree r = build_lambda_expr ();
+
+  LAMBDA_EXPR_LOCATION (r)
+    = LAMBDA_EXPR_LOCATION (t);
+  LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
+    = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
+  LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
+
+  if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE)
+    LAMBDA_EXPR_EXTRA_SCOPE (r) = NULL_TREE;
+  else
+    record_lambda_scope (r);
+
+  gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
+             && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
+
+  for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap;
+       cap = TREE_CHAIN (cap))
+    {
+      tree field = TREE_PURPOSE (cap);
+      if (PACK_EXPANSION_P (field))
+       field = PACK_EXPANSION_PATTERN (field);
+      field = tsubst_decl (field, args, complain);
+
+      if (field == error_mark_node)
+       return error_mark_node;
+
+      tree init = TREE_VALUE (cap);
+      if (PACK_EXPANSION_P (init))
+       init = tsubst_pack_expansion (init, args, complain, in_decl);
+      else
+       init = tsubst_copy_and_build (init, args, complain, in_decl,
+                                     /*fn*/false, /*constexpr*/false);
+
+      if (TREE_CODE (field) == TREE_VEC)
+       {
+         int len = TREE_VEC_LENGTH (field);
+         gcc_assert (TREE_CODE (init) == TREE_VEC
+                     && TREE_VEC_LENGTH (init) == len);
+         for (int i = 0; i < len; ++i)
+           LAMBDA_EXPR_CAPTURE_LIST (r)
+             = tree_cons (TREE_VEC_ELT (field, i),
+                          TREE_VEC_ELT (init, i),
+                          LAMBDA_EXPR_CAPTURE_LIST (r));
+       }
+      else
+       {
+         LAMBDA_EXPR_CAPTURE_LIST (r)
+           = tree_cons (field, init, LAMBDA_EXPR_CAPTURE_LIST (r));
+
+         if (id_equal (DECL_NAME (field), "__this"))
+           LAMBDA_EXPR_THIS_CAPTURE (r) = field;
+       }
+    }
+
+  tree type = begin_lambda_type (r);
+
+  /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set.  */
+  determine_visibility (TYPE_NAME (type));
+
+  register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (r));
+
+  tree oldtmpl = (generic_lambda_fn_p (oldfn)
+                 ? DECL_TI_TEMPLATE (oldfn)
+                 : NULL_TREE);
+
+  tree fntype = static_fn_type (oldfn);
+  if (oldtmpl)
+    ++processing_template_decl;
+  fntype = tsubst (fntype, args, complain, in_decl);
+  if (oldtmpl)
+    --processing_template_decl;
+
+  if (fntype == error_mark_node)
+    r = error_mark_node;
+  else
+    {
+      /* Fix the type of 'this'.  */
+      fntype = build_memfn_type (fntype, type,
+                                type_memfn_quals (fntype),
+                                type_memfn_rqual (fntype));
+      tree fn, tmpl;
+      if (oldtmpl)
+       {
+         tmpl = tsubst_template_decl (oldtmpl, args, complain, fntype);
+         fn = DECL_TEMPLATE_RESULT (tmpl);
+         finish_member_declaration (tmpl);
+       }
+      else
+       {
+         tmpl = NULL_TREE;
+         fn = tsubst_function_decl (oldfn, args, complain, fntype);
+         finish_member_declaration (fn);
+       }
+
+      /* Let finish_function set this.  */
+      DECL_DECLARED_CONSTEXPR_P (fn) = false;
+
+      bool nested = cfun;
+      if (nested)
+       push_function_context ();
+
+      tree body = start_lambda_function (fn, r);
+
+      local_specialization_stack s (lss_copy);
+
+      register_parameter_specializations (oldfn, fn);
+
+      tsubst_expr (DECL_SAVED_TREE (oldfn), args, complain, r,
+                  /*constexpr*/false);
+
+      finish_lambda_function (body);
+
+      if (nested)
+       pop_function_context ();
+
+      /* The capture list was built up in reverse order; fix that now.  */
+      LAMBDA_EXPR_CAPTURE_LIST (r)
+       = nreverse (LAMBDA_EXPR_CAPTURE_LIST (r));
+
+      LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;
+
+      maybe_add_lambda_conv_op (type);
+    }
+
+  finish_struct (type, /*attr*/NULL_TREE);
+
+  insert_pending_capture_proxies ();
+
+  return r;
+}
+
 /* Like tsubst but deals with expressions and performs semantic
    analysis.  FUNCTION_P is true if T is the "F" in "F (ARGS)".  */
 
@@ -17861,7 +18104,7 @@ tsubst_copy_and_build (tree t,
        else if (outer_automatic_var_p (r))
          {
            r = process_outer_var_ref (r, complain);
-           if (is_capture_proxy (r))
+           if (is_capture_proxy (r) && !DECL_PACK_P (t))
              register_local_specialization (r, t);
          }
 
@@ -17929,59 +18172,7 @@ tsubst_copy_and_build (tree t,
 
     case LAMBDA_EXPR:
       {
-       tree r = build_lambda_expr ();
-
-       tree type = tsubst (LAMBDA_EXPR_CLOSURE (t), args, complain, NULL_TREE);
-       LAMBDA_EXPR_CLOSURE (r) = type;
-       CLASSTYPE_LAMBDA_EXPR (type) = r;
-
-       LAMBDA_EXPR_LOCATION (r)
-         = LAMBDA_EXPR_LOCATION (t);
-       LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
-         = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
-       LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
-       LAMBDA_EXPR_DISCRIMINATOR (r)
-         = (LAMBDA_EXPR_DISCRIMINATOR (t));
-       tree scope = LAMBDA_EXPR_EXTRA_SCOPE (t);
-       if (!scope)
-         /* No substitution needed.  */;
-       else if (VAR_OR_FUNCTION_DECL_P (scope))
-         /* For a function or variable scope, we want to use tsubst so that we
-            don't complain about referring to an auto before deduction.  */
-         scope = tsubst (scope, args, complain, in_decl);
-       else if (TREE_CODE (scope) == PARM_DECL)
-         {
-           /* Look up the parameter we want directly, as tsubst_copy
-              doesn't do what we need.  */
-           tree fn = tsubst (DECL_CONTEXT (scope), args, complain, in_decl);
-           tree parm = FUNCTION_FIRST_USER_PARM (fn);
-           while (DECL_PARM_INDEX (parm) != DECL_PARM_INDEX (scope))
-             parm = DECL_CHAIN (parm);
-           scope = parm;
-           /* FIXME Work around the parm not having DECL_CONTEXT set.  */
-           if (DECL_CONTEXT (scope) == NULL_TREE)
-             DECL_CONTEXT (scope) = fn;
-         }
-       else if (TREE_CODE (scope) == FIELD_DECL)
-         /* For a field, use tsubst_copy so that we look up the existing field
-            rather than build a new one.  */
-         scope = RECUR (scope);
-       else
-         gcc_unreachable ();
-       LAMBDA_EXPR_EXTRA_SCOPE (r) = scope;
-
-       gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
-                   && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
-
-       /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set.  */
-       determine_visibility (TYPE_NAME (type));
-       /* Now that we know visibility, instantiate the type so we have a
-          declaration of the op() for later calls to lambda_function.  */
-       complete_type (type);
-
-       LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;
-
-       insert_pending_capture_proxies ();
+       tree r = tsubst_lambda_expr (t, args, complain, in_decl);
 
        RETURN (build_lambda_object (r));
       }
@@ -22434,10 +22625,12 @@ regenerate_decl_from_template (tree decl, tree tmpl, 
tree args)
     }
   else if (VAR_P (decl))
     {
+      start_lambda_scope (decl);
       DECL_INITIAL (decl) =
        tsubst_expr (DECL_INITIAL (code_pattern), args,
                     tf_error, DECL_TI_TEMPLATE (decl),
                     /*integral_constant_expression_p=*/false);
+      finish_lambda_scope ();
       if (VAR_HAD_UNKNOWN_BOUND (decl))
        TREE_TYPE (decl) = tsubst (TREE_TYPE (code_pattern), args,
                                   tf_error, DECL_TI_TEMPLATE (decl));
@@ -22605,6 +22798,38 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t 
complain)
   return true;
 }
 
+/* We're starting to process the function INST, an instantiation of PATTERN;
+   add their parameters to local_specializations.  */
+
+static void
+register_parameter_specializations (tree pattern, tree inst)
+{
+  tree tmpl_parm = DECL_ARGUMENTS (pattern);
+  tree spec_parm = DECL_ARGUMENTS (inst);
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (inst))
+    {
+      register_local_specialization (spec_parm, tmpl_parm);
+      spec_parm = skip_artificial_parms_for (inst, spec_parm);
+      tmpl_parm = skip_artificial_parms_for (pattern, tmpl_parm);
+    }
+  for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
+    {
+      if (!DECL_PACK_P (tmpl_parm))
+       {
+         register_local_specialization (spec_parm, tmpl_parm);
+         spec_parm = DECL_CHAIN (spec_parm);
+       }
+      else
+       {
+         /* Register the (value) argument pack as a specialization of
+            TMPL_PARM, then move on.  */
+         tree argpack = extract_fnparm_pack (tmpl_parm, &spec_parm);
+         register_local_specialization (argpack, tmpl_parm);
+       }
+    }
+  gcc_assert (!spec_parm);
+}
+
 /* Produce the definition of D, a _DECL generated from a template.  If
    DEFER_OK is true, then we don't have to actually do the
    instantiation now; we just have to do it sometime.  Normally it is
@@ -22939,10 +23164,7 @@ instantiate_decl (tree d, bool defer_ok, bool 
expl_inst_class_mem_p)
   else if (TREE_CODE (d) == FUNCTION_DECL)
     {
       hash_map<tree, tree> *saved_local_specializations;
-      tree tmpl_parm;
-      tree spec_parm;
       tree block = NULL_TREE;
-      tree lambda_ctx = NULL_TREE;
 
       /* Save away the current list, in case we are instantiating one
         template from within the body of another.  */
@@ -22956,23 +23178,7 @@ instantiate_decl (tree d, bool defer_ok, bool 
expl_inst_class_mem_p)
          && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
        block = push_stmt_list ();
       else
-       {
-         if (push_to_top && LAMBDA_FUNCTION_P (d))
-           {
-             /* When instantiating a lambda's templated function
-                operator, we need to push the non-lambda class scope
-                of the lambda itself so that the nested function
-                stack is sufficiently correct to deal with this
-                capture.  */
-             lambda_ctx = DECL_CONTEXT (d);
-             do 
-               lambda_ctx = decl_type_context (TYPE_NAME (lambda_ctx));
-             while (lambda_ctx && LAMBDA_TYPE_P (lambda_ctx));
-             if (lambda_ctx)
-               push_nested_class (lambda_ctx);
-           }
-         start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
-       }
+       start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
 
       /* Some typedefs referenced from within the template code need to be
         access checked at template instantiation time, i.e now. These
@@ -22982,30 +23188,7 @@ instantiate_decl (tree d, bool defer_ok, bool 
expl_inst_class_mem_p)
                                     args);
 
       /* Create substitution entries for the parameters.  */
-      tmpl_parm = DECL_ARGUMENTS (code_pattern);
-      spec_parm = DECL_ARGUMENTS (d);
-      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (d))
-       {
-         register_local_specialization (spec_parm, tmpl_parm);
-         spec_parm = skip_artificial_parms_for (d, spec_parm);
-         tmpl_parm = skip_artificial_parms_for (code_pattern, tmpl_parm);
-       }
-      for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
-       {
-         if (!DECL_PACK_P (tmpl_parm))
-           {
-             register_local_specialization (spec_parm, tmpl_parm);
-             spec_parm = DECL_CHAIN (spec_parm);
-           }
-         else
-           {
-             /* Register the (value) argument pack as a specialization of
-                TMPL_PARM, then move on.  */
-             tree argpack = extract_fnparm_pack (tmpl_parm, &spec_parm);
-             register_local_specialization (argpack, tmpl_parm);
-           }
-       }
-      gcc_assert (!spec_parm);
+      register_parameter_specializations (code_pattern, d);
 
       /* Substitute into the body of the function.  */
       if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
@@ -23040,8 +23223,6 @@ instantiate_decl (tree d, bool defer_ok, bool 
expl_inst_class_mem_p)
          d = finish_function (0);
          expand_or_defer_fn (d);
        }
-      if (lambda_ctx)
-       pop_nested_class ();
 
       if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
        cp_check_omp_declare_reduction (d);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fe118cd..8f28221 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3301,40 +3301,56 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain)
   if (!mark_used (decl, complain))
     return error_mark_node;
 
-  bool saw_generic_lambda = false;
   if (parsing_nsdmi ())
     containing_function = NULL_TREE;
-  else
-    /* If we are in a lambda function, we can move out until we hit
-       1. the context,
-       2. a non-lambda function, or
-       3. a non-default capturing lambda function.  */
-    while (context != containing_function
-          /* containing_function can be null with invalid generic lambdas.  */
-          && containing_function
-          && LAMBDA_FUNCTION_P (containing_function))
-      {
-       tree closure = DECL_CONTEXT (containing_function);
-       lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure);
 
-       if (generic_lambda_fn_p (containing_function))
-         saw_generic_lambda = true;
+  if (containing_function && DECL_TEMPLATE_INFO (context)
+      && LAMBDA_FUNCTION_P (containing_function))
+    {
+      /* Check whether we've already built a proxy;
+        insert_pending_capture_proxies doesn't update
+        local_specializations.  */
+      tree d = lookup_name (DECL_NAME (decl));
+      if (d && is_capture_proxy (d)
+         && DECL_CONTEXT (d) == containing_function)
+       return d;
+    }
 
-       if (TYPE_CLASS_SCOPE_P (closure))
-         /* A lambda in an NSDMI (c++/64496).  */
-         break;
+  /* If we are in a lambda function, we can move out until we hit
+     1. the context,
+     2. a non-lambda function, or
+     3. a non-default capturing lambda function.  */
+  while (context != containing_function
+        /* containing_function can be null with invalid generic lambdas.  */
+        && containing_function
+        && LAMBDA_FUNCTION_P (containing_function))
+    {
+      tree closure = DECL_CONTEXT (containing_function);
+      lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure);
 
-       if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
-           == CPLD_NONE)
-         break;
+      if (TYPE_CLASS_SCOPE_P (closure))
+       /* A lambda in an NSDMI (c++/64496).  */
+       break;
 
-       lambda_stack = tree_cons (NULL_TREE,
-                                 lambda_expr,
-                                 lambda_stack);
+      if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
+         == CPLD_NONE)
+       break;
 
-       containing_function
-         = decl_function_context (containing_function);
-      }
+      lambda_stack = tree_cons (NULL_TREE,
+                               lambda_expr,
+                               lambda_stack);
+
+      containing_function
+       = decl_function_context (containing_function);
+    }
+
+  /* In a lambda within a template, wait until instantiation
+     time to implicitly capture.  */
+  if (context == containing_function
+      && DECL_TEMPLATE_INFO (containing_function)
+      && any_dependent_template_arguments_p (DECL_TI_ARGS
+                                            (containing_function)))
+    return decl;
 
   /* Core issue 696: "[At the July 2009 meeting] the CWG expressed
      support for an approach in which a reference to a local
@@ -3343,26 +3359,11 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain)
      the complexity of the problem"
 
      FIXME update for final resolution of core issue 696.  */
-  if (decl_maybe_constant_var_p (decl))
+  if (decl_constant_var_p (decl))
     {
-      if (processing_template_decl && !saw_generic_lambda)
-       /* In a non-generic lambda within a template, wait until instantiation
-          time to decide whether to capture.  For a generic lambda, we can't
-          wait until we instantiate the op() because the closure class is
-          already defined at that point.  FIXME to get the semantics exactly
-          right we need to partially-instantiate the lambda body so the only
-          dependencies left are on the generic parameters themselves.  This
-          probably means moving away from our current model of lambdas in
-          templates (instantiating the closure type) to one based on creating
-          the closure type when instantiating the lambda context.  That is
-          probably also the way to handle lambdas within pack expansions.  */
-       return decl;
-      else if (decl_constant_var_p (decl))
-       {
-         tree t = maybe_constant_value (convert_from_reference (decl));
-         if (TREE_CONSTANT (t))
-           return t;
-       }
+      tree t = maybe_constant_value (convert_from_reference (decl));
+      if (TREE_CONSTANT (t))
+       return t;
     }
 
   if (lambda_expr && VAR_P (decl)
diff --git a/gcc/testsuite/g++.dg/cpp1z/fold-lambda.C 
b/gcc/testsuite/g++.dg/cpp1z/fold-lambda.C
new file mode 100644
index 0000000..5eaed4a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/fold-lambda.C
@@ -0,0 +1,14 @@
+// { dg-do run }
+// { dg-options -std=c++17 }
+
+template <class... T>
+auto f() {
+  int i = 42;
+  return ([i]{ return T(i); }() + ...);
+}
+
+int main()
+{
+  if (f<int,double>() != 84)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wshadow-6.C 
b/gcc/testsuite/g++.dg/warn/Wshadow-6.C
index 9c2e8b8..1d8d21b 100644
--- a/gcc/testsuite/g++.dg/warn/Wshadow-6.C
+++ b/gcc/testsuite/g++.dg/warn/Wshadow-6.C
@@ -43,7 +43,7 @@ template <class T>
 void f4(int i) {
  [=]{
    int j = i;                  // { dg-message "shadowed declaration" }
-   int i;                      // { dg-warning "shadows a lambda capture" }
+   int i;                      // { dg-warning "shadows a " }
    i = 1;
  };
 }

Reply via email to