Reimplement handling of lambdas in templates.
authorJason Merrill <jason@redhat.com>
Tue, 29 Aug 2017 20:37:15 +0000 (16:37 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 29 Aug 2017 20:37:15 +0000 (16:37 -0400)
* 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.

From-SVN: r251433

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/init.c
gcc/cp/lambda.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp1z/fold-lambda.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wshadow-6.C

index ef7f4292d4d551cd1cb5fb9319bdc7cb447a0f01..387a27591c4b47c82b6d5d243a75b05750e04e7d 100644 (file)
@@ -1,3 +1,33 @@
+2017-08-23  Jason Merrill  <jason@redhat.com>
+
+       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.
+
 2017-08-29  Jason Merrill  <jason@redhat.com>
 
        * cp-tree.h (LAMBDA_EXPR_CLOSURE): Use TREE_TYPE.
index 28cf7dcdb5fc0210e1ccf70e2c6041d5676efe6e..a5f1007b993a59af27e367e31193ef8b2862c8d6 100644 (file)
@@ -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
index ad97be4c1ce813e32f86046eeac7071e5f8b1528..41c48ece8a44f43d5b4b4949b75a3a67b468f4b6 100644 (file)
@@ -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);
index 23829b0f18e2968cb9089d7e1fba0202ed71db43..d6b80c604c8bcc3942ddd683f4f17f92b9a0f52a 100644 (file)
@@ -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.   */
index 56a5df87cb3222fd3d5bf76bd9ddc62e7e4a3bcb..b01d662fef286af073381f3d468b0c9dc7b8d56d 100644 (file)
@@ -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)
index 55d3415676c6c13645080f92143d06fa7a8334f3..4747a727173f4dd7a17e70f622f16f7c05e2da3a 100644 (file)
@@ -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"
index 9f62b4310e720f5b9fe960cc46500c5aed26a667..d0d71fa1dae1d5921c68e1689463a47e6639f5a0 100644 (file)
@@ -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));
index e064a11c05bd1e4ddc1317a1164714102ac2c1bd..141b4d7564a8de9d1a2c0041cdfbce5ea5bda404 100644 (file)
@@ -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,415 +12162,466 @@ tsubst_default_arguments (tree fn, tsubst_flags_t complain)
                                                    complain);
 }
 
-/* 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.  */
+/* Subroutine of tsubst_decl for the case when T is a FUNCTION_DECL.  */
 
 static tree
-tsubst_decl (tree t, tree args, tsubst_flags_t complain)
+tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
+                     tree lambda_fntype)
 {
-#define RETURN(EXP) do { r = (EXP); goto out; } while(0)
-  location_t saved_loc;
-  tree r = NULL_TREE;
-  tree in_decl = t;
+  tree gen_tmpl, argvec;
   hashval_t hash = 0;
+  tree in_decl = t;
 
-  /* Set the filename and linenumber to improve error-reporting.  */
-  saved_loc = input_location;
-  input_location = DECL_SOURCE_LOCATION (t);
+  /* Nobody should be tsubst'ing into non-template functions.  */
+  gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);
 
-  switch (TREE_CODE (t))
+  if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
     {
-    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 T is not dependent, just return it.  */
+      if (!uses_template_parms (DECL_TI_ARGS (t)))
+       return t;
 
-       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;
-         }
+      /* 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;
 
-       /* 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);
+      /* 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;
+       }
 
-       /* If this is a default template template argument,
-          tsubst might not have changed anything.  */
-       if (full_args == tmpl_args)
-         RETURN (t);
+      /* We can see more levels of arguments than parameters if
+        there was a specialization of a member template, like
+        this:
 
-       hash = hash_tmpl_and_args (t, full_args);
-       spec = retrieve_specialization (t, full_args, hash);
-       if (spec != NULL_TREE)
-         {
-           r = spec;
-           break;
-         }
+        template <class T> struct S { template <class U> void f(); }
+        template <> template <class U> void S<int>::f(U);
 
-       /* 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;
+        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.
 
-        // Build new template info linking to the original template decl.
-       DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+        We also deal with the peculiar case:
 
-       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);
+        template <class T> struct S {
+        template <class U> friend void f();
+        };
+        template <class U> void f() {}
+        template S<int>;
+        template void f<double>();
 
-           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);
+        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:
 
-           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);
-         }
+        template <class T> struct S { template <class U> void f(U); }
+        template <class T> template <> void S<T>::f(int) {}
 
-       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);
-      }
-      break;
+        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)));
 
-    case FUNCTION_DECL:
+      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)
       {
-       tree gen_tmpl, argvec;
+       ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);
+       set_constraints (r, ci);
+      }
 
-       /* Nobody should be tsubst'ing into non-template functions.  */
-       gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);
+  /* 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;
 
-       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);
+  /* 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);
+    }
 
-           /* 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;
-             }
+  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;
 
-           /* We can see more levels of arguments than parameters if
-              there was a specialization of a member template, like
-              this:
+  if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
+    SET_DECL_FRIEND_CONTEXT (r,
+                            tsubst (DECL_FRIEND_CONTEXT (t),
+                                    args, complain, in_decl));
 
-                template <class T> struct S { template <class U> void f(); }
-                template <> template <class U> void S<int>::f(U);
+  /* 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);
 
-              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.
+  apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
+                                 args, complain, in_decl);
+  return r;
+}
 
-              We also deal with the peculiar case:
+/* Subroutine of tsubst_decl for the case when T is a TEMPLATE_DECL.  */
 
-                template <class T> struct S {
-                  template <class U> friend void f();
-                };
-                template <class U> void f() {}
-                template S<int>;
-                template void f<double>();
+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;
 
-              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:
+  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;
+    }
 
-                template <class T> struct S { template <class U> void f(U); }
-                template <class T> template <> void S<T>::f(int) {}
+  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;
 
-              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 this is a default template template argument,
+        tsubst might not have changed anything.  */
+      if (full_args == tmpl_args)
+       return 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;
-         }
+      hash = hash_tmpl_and_args (t, full_args);
+      spec = retrieve_specialization (t, full_args, hash);
+      if (spec != NULL_TREE)
+       return spec;
+    }
 
-       tree ctx = DECL_CONTEXT (t);
-       bool member = ctx && TYPE_P (ctx);
+  /* 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;
 
-       if (member)
-         ctx = tsubst_aggr_type (ctx, args,
-                                 complain, t, /*entering_scope=*/1);
+  // 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;
 
-       tree type = tsubst (TREE_TYPE (t), args,
-                           complain | tf_fndecl_type, in_decl);
-       if (type == error_mark_node)
-         RETURN (error_mark_node);
+  /* 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 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);
+  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;
 
-       /* 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;
+      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;
 
-       /* 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);
-         }
+      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);
+       }
+    }
 
-       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);
+  DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
+  DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
 
-        /* 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);
-            }
+  if (PRIMARY_TEMPLATE_P (t))
+    DECL_PRIMARY_TEMPLATE (r) = r;
 
-       /* 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);
+  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);
 
-           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;
+  return r;
+}
 
-       /* 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);
-         }
+/* 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.  */
 
-       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);
+static tree
+tsubst_decl (tree t, tree args, tsubst_flags_t complain)
+{
+#define RETURN(EXP) do { r = (EXP); goto out; } while(0)
+  location_t saved_loc;
+  tree r = NULL_TREE;
+  tree in_decl = t;
+  hashval_t hash = 0;
 
-       if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
-         SET_DECL_FRIEND_CONTEXT (r,
-                                  tsubst (DECL_FRIEND_CONTEXT (t),
-                                           args, complain, in_decl));
+  /* Set the filename and linenumber to improve error-reporting.  */
+  saved_loc = input_location;
+  input_location = DECL_SOURCE_LOCATION (t);
 
-       /* 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);
+  switch (TREE_CODE (t))
+    {
+    case TEMPLATE_DECL:
+      r = tsubst_template_decl (t, args, complain, /*lambda*/NULL_TREE);
+      break;
 
-       apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
-                                       args, complain, in_decl);
-      }
+    case FUNCTION_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);
index fe118cd97af231b508d469d7b18cbee9e6b8e90a..8f2822107d630f149daea695c6aa21445ae43e87 100644 (file)
@@ -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 (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;
-       }
+  if (decl_constant_var_p (decl))
+    {
+      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 (file)
index 0000000..5eaed4a
--- /dev/null
@@ -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();
+}
index 9c2e8b894606fb10d1e881d124f898e82cf32f37..1d8d21b9b6f17925c5180faf042eb31b497365c5 100644 (file)
@@ -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;
  };
 }