Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/807291/?format=api
{ "id": 807291, "url": "http://patchwork.ozlabs.org/api/patches/807291/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/CADzB+2nk9ggOUZ-EZBs=6074RfRUckT68YyyaDNgh2x0P_YHjw@mail.gmail.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<CADzB+2nk9ggOUZ-EZBs=6074RfRUckT68YyyaDNgh2x0P_YHjw@mail.gmail.com>", "list_archive_url": null, "date": "2017-08-29T20:36:57", "name": "C++ PATCH to overhaul lambdas in templates", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "d1dc843e0f2adfe80aac7b005d6e0eb46cd9c618", "submitter": { "id": 4337, "url": "http://patchwork.ozlabs.org/api/people/4337/?format=api", "name": "Jason Merrill", "email": "jason@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/CADzB+2nk9ggOUZ-EZBs=6074RfRUckT68YyyaDNgh2x0P_YHjw@mail.gmail.com/mbox/", "series": [ { "id": 468, "url": "http://patchwork.ozlabs.org/api/series/468/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=468", "date": "2017-08-29T20:36:57", "name": "C++ PATCH to overhaul lambdas in templates", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/468/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/807291/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/807291/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-return-461119-incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "mailing list gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org\n\t(client-ip=209.132.180.131; helo=sourceware.org;\n\tenvelope-from=gcc-patches-return-461119-incoming=patchwork.ozlabs.org@gcc.gnu.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org\n\theader.b=\"j/mGIBVO\"; dkim-atps=neutral", "sourceware.org; auth=none" ], "Received": [ "from sourceware.org (server1.sourceware.org [209.132.180.131])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xhgS351hQz9s9Y\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 30 Aug 2017 06:37:38 +1000 (AEST)", "(qmail 124742 invoked by alias); 29 Aug 2017 20:37:29 -0000", "(qmail 124731 invoked by uid 89); 29 Aug 2017 20:37:28 -0000", "from mail-it0-f54.google.com (HELO mail-it0-f54.google.com)\n\t(209.85.214.54) by sourceware.org\n\t(qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP;\n\tTue, 29 Aug 2017 20:37:21 +0000", "by mail-it0-f54.google.com with SMTP id w191so637107itc.1 for\n\t<gcc-patches@gcc.gnu.org>; Tue, 29 Aug 2017 13:37:20 -0700 (PDT)", "by 10.107.181.23 with HTTP; Tue, 29 Aug 2017 13:36:57 -0700 (PDT)" ], "DomainKey-Signature": "a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender\n\t:mime-version:from:date:message-id:subject:to:content-type; q=\n\tdns; s=default; b=pvJrKRoULQtcfXfpPu+t0eOheFgmcS2s44jgEx+dmGhhv6\n\t4oiw2PtduUKVVtWb6KSxEDfNyfMrJoHfrpHi7GjWjiQ3nXnoAw3FKBACWOMY98wG\n\tcMuTho/vxt3xXsuHOKDITSSTnjrE1FeMYPzrtMLu7nO974KOvTc4MS5GvLhxY=", "DKIM-Signature": "v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id\n\t:list-unsubscribe:list-archive:list-post:list-help:sender\n\t:mime-version:from:date:message-id:subject:to:content-type; s=\n\tdefault; bh=TNiJKVN/gmB933U8VXVKndBDIXA=; b=j/mGIBVO67Sz3tP1v8Dt\n\tD+JboTk1xWYWxRbp4+1V3pz/WvZlF19NcgHVWiBwyS2T6NOT4yzlZatwGnlYIRP0\n\tWdWS18PWOjHCcv1HzjpTkn+t84D7OvAUyX2JcGonULg1p18c2UdQ3SNuHAwTsd+O\n\tkDY9g+FaUbjS/HjcUcYrL18=", "Mailing-List": "contact gcc-patches-help@gcc.gnu.org; run by ezmlm", "Precedence": "bulk", "List-Id": "<gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<mailto:gcc-patches-unsubscribe-incoming=patchwork.ozlabs.org@gcc.gnu.org>", "List-Archive": "<http://gcc.gnu.org/ml/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-help@gcc.gnu.org>", "Sender": "gcc-patches-owner@gcc.gnu.org", "X-Virus-Found": "No", "X-Spam-SWARE-Status": "No, score=-24.5 required=5.0 tests=AWL, BAYES_00,\n\tGIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3,\n\tKAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_LOW,\n\tRCVD_IN_SORBS_SPAM autolearn=ham version=3.3.2 spammy=", "X-HELO": "mail-it0-f54.google.com", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net;\n\ts=20161025;\n\th=x-gm-message-state:mime-version:from:date:message-id:subject:to;\n\tbh=uxvxhaNErvqksxstG+bEc831hmU5wrqk9bHDoMwUpiQ=;\n\tb=KN0fPmw0f0dRKyAh10JRjtamHsPEMWWFV6QlkNpOs0QDWjCjlN/EvCRbqjIyZxZyyG\n\t64GdxdMdDgP4zt6E/uWXxO0rVyQQVy8m53yuzQL7Rvu9OqHiEIoau0au9vGE68b5oRy2\n\t740m2DKQve9Ohj12sn9VFG2MynyWmoTrJX+4KPozqRmMXuRQc0WCx2xAsbzs1zs5avMI\n\tL1rYfejEi7N42e3GWAjY5DVQ1N3y2rk3/05ssK9vuJsdjp+tlrCjDzhvli8pUPJkB7dd\n\tGFPwt/SIMmzNmffiAGzilrACpIImE5wtqvhhxDiGNlXWMi9yx83dQGW1hGn4yrsRuQls\n\t8RxQ==", "X-Gm-Message-State": "AHYfb5hXLWIbAKft5RoJatiwX3hR7hA2DXqJxRsNp2K4S3QBPDJ8ZPYn\tr/kTskIq1Vz3oTj/dpLJWwHmttPyAnR9/J4J3w==", "X-Received": "by 10.36.159.194 with SMTP id c185mr6271708ite.181.1504039038571;\n\tTue, 29 Aug 2017 13:37:18 -0700 (PDT)", "MIME-Version": "1.0", "From": "Jason Merrill <jason@redhat.com>", "Date": "Tue, 29 Aug 2017 16:36:57 -0400", "Message-ID": "<CADzB+2nk9ggOUZ-EZBs=6074RfRUckT68YyyaDNgh2x0P_YHjw@mail.gmail.com>", "Subject": "C++ PATCH to overhaul lambdas in templates", "To": "gcc-patches List <gcc-patches@gcc.gnu.org>", "Content-Type": "multipart/mixed; boundary=\"94eb2c08e5509fde0d0557ea6018\"", "X-IsSubscribed": "yes" }, "content": "Our old model for handling lambdas in templates was to handle them\nlike any other template class, and instantiate them by normal\nsubstitution. This was insufficient for lambdas for two reasons: for\none, it made it impossible to get implicit captures quite right in\ntemplates.\n\nAlso, if a lambda appears in a pack expansion, e.g.\n\ntemplate <class... T>\nauto f() {\n int i = 42;\n return ([i]{ return T(i); }() + ...);\n}\n\nThere needs to be one lambda for each element of T, not just one for\neach instantiation of f. So instantiating a LAMBDA_EXPR needs to\nbuild up a new LAMBDA_EXPR each time. This patch implements that,\nprimarily in the new tsubst_lambda_expr function.\n\nGenerating the op() decl for the new lambda is a lot like a normal\ninstantiation, but not quite. I decided to do this by factoring out\ntsubst_function_decl and tsubst_template_decl, and having them handle\nthe lambda special case appropriately: when we're dealing with the\nlambda function, it isn't actually a specialization of the lambda in\nthe template, and it isn't a member of a specialization of the closure\nin the template.\n\nThe code in process_outer_var_ref for handling generic lambdas\nspecifically can now go away; we now defer implicit capture until the\nenclosing context is instantiated for generic and non-generic lambdas.\n\nTested x86_64-pc-linux-gnu, applying to trunk.\ncommit bdbf060161375648283cf82d4662362ea788b298\nAuthor: Jason Merrill <jason@redhat.com>\nDate: Thu Jul 6 19:32:32 2017 -0400\n\n Reimplement handling of lambdas in templates.\n \n * cp-tree.h (LAMBDA_FUNCTION_P): Check DECL_DECLARES_FUNCTION_P.\n * decl.c (start_preparsed_function): Call start_lambda_scope.\n (finish_function): Call finish_lambda_scope.\n * init.c (get_nsdmi): Call start/finish_lambda_scope.\n * lambda.c (start_lambda_scope): Only ignore VAR_DECL in a function.\n * parser.c (cp_parser_function_definition_after_declarator): Don't\n call start/finish_lambda_scope.\n * pt.c (retrieve_specialization): Ignore lambda functions in\n templates.\n (find_parameter_packs_r): Ignore capture proxies. Look into\n lambdas.\n (check_for_bare_parameter_packs): Allow bare packs in lambdas.\n (tsubst_default_argument): Call start/finish_lambda_scope.\n (tsubst_function_decl): Handle lambda functions differently.\n (tsubst_template_decl): Likewise.\n (tsubst_expr) [DECL_EXPR]: Skip closure declarations and capture\n proxies.\n (tsubst_lambda_expr): Create a new closure rather than instantiate\n the one from the template.\n (tsubst_copy_and_build): Don't register a specialization of a pack.\n (regenerate_decl_from_template): Call start/finish_lambda_scope.\n (instantiate_decl): Remove special lambda function handling.\n * semantics.c (process_outer_var_ref): Remove special generic lambda\n handling. Don't implicitly capture in a lambda in a template. Look\n for an existing proxy.\n * class.c (current_nonlambda_class_type): Use decl_type_context.", "diff": "diff --git a/gcc/cp/class.c b/gcc/cp/class.c\nindex 28cf7dc..a5f1007 100644\n--- a/gcc/cp/class.c\n+++ b/gcc/cp/class.c\n@@ -7709,27 +7709,10 @@ outermost_open_class (void)\n tree\n current_nonlambda_class_type (void)\n {\n- int i;\n-\n- /* We start looking from 1 because entry 0 is from global scope,\n- and has no type. */\n- for (i = current_class_depth; i > 0; --i)\n- {\n- tree c;\n- if (i == current_class_depth)\n-\tc = current_class_type;\n- else\n-\t{\n-\t if (current_class_stack[i].hidden)\n-\t break;\n-\t c = current_class_stack[i].type;\n-\t}\n- if (!c)\n-\tcontinue;\n- if (!LAMBDA_TYPE_P (c))\n-\treturn c;\n- }\n- return NULL_TREE;\n+ tree type = current_class_type;\n+ while (type && LAMBDA_TYPE_P (type))\n+ type = decl_type_context (TYPE_NAME (type));\n+ return type;\n }\n \n /* When entering a class scope, all enclosing class scopes' names with\ndiff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h\nindex ad97be4..41c48ec 100644\n--- a/gcc/cp/cp-tree.h\n+++ b/gcc/cp/cp-tree.h\n@@ -1216,8 +1216,9 @@ struct GTY (()) tree_trait_expr {\n (CLASS_TYPE_P (NODE) && CLASSTYPE_LAMBDA_EXPR (NODE))\n \n /* Test if FUNCTION_DECL is a lambda function. */\n-#define LAMBDA_FUNCTION_P(FNDECL) \\\n- (DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR \\\n+#define LAMBDA_FUNCTION_P(FNDECL)\t\t\t\\\n+ (DECL_DECLARES_FUNCTION_P (FNDECL)\t\t\t\\\n+ && DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR\t\\\n && LAMBDA_TYPE_P (CP_DECL_CONTEXT (FNDECL)))\n \n enum cp_lambda_default_capture_mode_type {\n@@ -6828,6 +6829,11 @@ extern bool is_lambda_ignored_entity (tree);\n extern bool lambda_static_thunk_p\t\t(tree);\n extern tree finish_builtin_launder\t\t(location_t, tree,\n \t\t\t\t\t\t tsubst_flags_t);\n+extern void start_lambda_scope\t\t\t(tree);\n+extern void record_lambda_scope\t\t\t(tree);\n+extern void finish_lambda_scope\t\t\t(void);\n+extern tree start_lambda_function\t\t(tree fn, tree lambda_expr);\n+extern void finish_lambda_function\t\t(tree body);\n \n /* in tree.c */\n extern int cp_tree_operand_length\t\t(const_tree);\ndiff --git a/gcc/cp/decl.c b/gcc/cp/decl.c\nindex 23829b0..d6b80c6 100644\n--- a/gcc/cp/decl.c\n+++ b/gcc/cp/decl.c\n@@ -15097,6 +15097,8 @@ start_preparsed_function (tree decl1, tree attrs, int flags)\n && !implicit_default_ctor_p (decl1))\n cp_ubsan_maybe_initialize_vtbl_ptrs (current_class_ptr);\n \n+ start_lambda_scope (decl1);\n+\n return true;\n }\n \n@@ -15462,6 +15464,8 @@ finish_function (int flags)\n if (fndecl == NULL_TREE)\n return error_mark_node;\n \n+ finish_lambda_scope ();\n+\n if (c_dialect_objc ())\n objc_finish_function ();\n \n@@ -15565,11 +15569,11 @@ finish_function (int flags)\n \n /* Lambda closure members are implicitly constexpr if possible. */\n if (cxx_dialect >= cxx1z\n- && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))\n- && (processing_template_decl\n+ && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))\n+ DECL_DECLARED_CONSTEXPR_P (fndecl)\n+ = ((processing_template_decl\n \t || is_valid_constexpr_fn (fndecl, /*complain*/false))\n- && potential_constant_expression (DECL_SAVED_TREE (fndecl)))\n- DECL_DECLARED_CONSTEXPR_P (fndecl) = true;\n+\t && potential_constant_expression (DECL_SAVED_TREE (fndecl)));\n \n /* Save constexpr function body before it gets munged by\n the NRV transformation. */\ndiff --git a/gcc/cp/init.c b/gcc/cp/init.c\nindex 56a5df8..b01d662 100644\n--- a/gcc/cp/init.c\n+++ b/gcc/cp/init.c\n@@ -574,13 +574,17 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain)\n \n \t inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);\n \n+\t start_lambda_scope (member);\n+\n \t /* Do deferred instantiation of the NSDMI. */\n \t init = (tsubst_copy_and_build\n \t\t (init, DECL_TI_ARGS (member),\n \t\t complain, member, /*function_p=*/false,\n \t\t /*integral_constant_expression_p=*/false));\n \t init = digest_nsdmi_init (member, init, complain);\n-\t \n+\n+\t finish_lambda_scope ();\n+\n \t DECL_INSTANTIATING_NSDMI_P (member) = 0;\n \n \t if (init != error_mark_node)\ndiff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c\nindex 55d3415..4747a72 100644\n--- a/gcc/cp/lambda.c\n+++ b/gcc/cp/lambda.c\n@@ -1253,4 +1253,87 @@ is_lambda_ignored_entity (tree val)\n return false;\n }\n \n+/* Lambdas that appear in variable initializer or default argument scope\n+ get that in their mangling, so we need to record it. We might as well\n+ use the count for function and namespace scopes as well. */\n+static GTY(()) tree lambda_scope;\n+static GTY(()) int lambda_count;\n+struct GTY(()) tree_int\n+{\n+ tree t;\n+ int i;\n+};\n+static GTY(()) vec<tree_int, va_gc> *lambda_scope_stack;\n+\n+void\n+start_lambda_scope (tree decl)\n+{\n+ tree_int ti;\n+ gcc_assert (decl);\n+ /* Once we're inside a function, we ignore variable scope and just push\n+ the function again so that popping works properly. */\n+ if (current_function_decl && TREE_CODE (decl) == VAR_DECL)\n+ decl = current_function_decl;\n+ ti.t = lambda_scope;\n+ ti.i = lambda_count;\n+ vec_safe_push (lambda_scope_stack, ti);\n+ if (lambda_scope != decl)\n+ {\n+ /* Don't reset the count if we're still in the same function. */\n+ lambda_scope = decl;\n+ lambda_count = 0;\n+ }\n+}\n+\n+void\n+record_lambda_scope (tree lambda)\n+{\n+ LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;\n+ LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;\n+}\n+\n+void\n+finish_lambda_scope (void)\n+{\n+ tree_int *p = &lambda_scope_stack->last ();\n+ if (lambda_scope != p->t)\n+ {\n+ lambda_scope = p->t;\n+ lambda_count = p->i;\n+ }\n+ lambda_scope_stack->pop ();\n+}\n+\n+tree\n+start_lambda_function (tree fco, tree lambda_expr)\n+{\n+ /* Let the front end know that we are going to be defining this\n+ function. */\n+ start_preparsed_function (fco,\n+\t\t\t NULL_TREE,\n+\t\t\t SF_PRE_PARSED | SF_INCLASS_INLINE);\n+\n+ tree body = begin_function_body ();\n+\n+ /* Push the proxies for any explicit captures. */\n+ for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;\n+ cap = TREE_CHAIN (cap))\n+ build_capture_proxy (TREE_PURPOSE (cap));\n+\n+ return body;\n+}\n+\n+void\n+finish_lambda_function (tree body)\n+{\n+ finish_function_body (body);\n+\n+ /* Finish the function and generate code for it if necessary. */\n+ tree fn = finish_function (/*inline*/2);\n+\n+ /* Only expand if the call op is not a template. */\n+ if (!DECL_TEMPLATE_INFO (fn))\n+ expand_or_defer_fn (fn);\n+}\n+\n #include \"gt-cp-lambda.h\"\ndiff --git a/gcc/cp/parser.c b/gcc/cp/parser.c\nindex 9f62b43..d0d71fa 100644\n--- a/gcc/cp/parser.c\n+++ b/gcc/cp/parser.c\n@@ -9982,57 +9982,6 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)\n }\n }\n \n-/* Lambdas that appear in variable initializer or default argument scope\n- get that in their mangling, so we need to record it. We might as well\n- use the count for function and namespace scopes as well. */\n-static GTY(()) tree lambda_scope;\n-static GTY(()) int lambda_count;\n-struct GTY(()) tree_int\n-{\n- tree t;\n- int i;\n-};\n-static GTY(()) vec<tree_int, va_gc> *lambda_scope_stack;\n-\n-static void\n-start_lambda_scope (tree decl)\n-{\n- tree_int ti;\n- gcc_assert (decl);\n- /* Once we're inside a function, we ignore other scopes and just push\n- the function again so that popping works properly. */\n- if (current_function_decl && TREE_CODE (decl) != FUNCTION_DECL)\n- decl = current_function_decl;\n- ti.t = lambda_scope;\n- ti.i = lambda_count;\n- vec_safe_push (lambda_scope_stack, ti);\n- if (lambda_scope != decl)\n- {\n- /* Don't reset the count if we're still in the same function. */\n- lambda_scope = decl;\n- lambda_count = 0;\n- }\n-}\n-\n-static void\n-record_lambda_scope (tree lambda)\n-{\n- LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;\n- LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;\n-}\n-\n-static void\n-finish_lambda_scope (void)\n-{\n- tree_int *p = &lambda_scope_stack->last ();\n- if (lambda_scope != p->t)\n- {\n- lambda_scope = p->t;\n- lambda_count = p->i;\n- }\n- lambda_scope_stack->pop ();\n-}\n-\n /* Parse a lambda expression.\n \n lambda-expression:\n@@ -10605,29 +10554,14 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)\n + ctor_initializer_opt_and_function_body */\n {\n tree fco = lambda_function (lambda_expr);\n- tree body;\n+ tree body = start_lambda_function (fco, lambda_expr);\n bool done = false;\n tree compound_stmt;\n- tree cap;\n-\n- /* Let the front end know that we are going to be defining this\n- function. */\n- start_preparsed_function (fco,\n-\t\t\t NULL_TREE,\n-\t\t\t SF_PRE_PARSED | SF_INCLASS_INLINE);\n-\n- start_lambda_scope (fco);\n- body = begin_function_body ();\n \n matching_braces braces;\n if (!braces.require_open (parser))\n goto out;\n \n- /* Push the proxies for any explicit captures. */\n- for (cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;\n-\t cap = TREE_CHAIN (cap))\n- build_capture_proxy (TREE_PURPOSE (cap));\n-\n compound_stmt = begin_compound_stmt (0);\n \n /* 5.1.1.4 of the standard says:\n@@ -10691,15 +10625,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)\n finish_compound_stmt (compound_stmt);\n \n out:\n- finish_function_body (body);\n- finish_lambda_scope ();\n-\n- /* Finish the function and generate code for it if necessary. */\n- tree fn = finish_function (/*inline*/2);\n-\n- /* Only expand if the call op is not a template. */\n- if (!DECL_TEMPLATE_INFO (fco))\n- expand_or_defer_fn (fn);\n+ finish_lambda_function (body);\n }\n \n restore_omp_privatization_clauses (omp_privatization_save);\n@@ -26577,8 +26503,6 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,\n = parser->num_template_parameter_lists;\n parser->num_template_parameter_lists = 0;\n \n- start_lambda_scope (current_function_decl);\n-\n /* If the next token is `try', `__transaction_atomic', or\n `__transaction_relaxed`, then we are looking at either function-try-block\n or function-transaction-block. Note that all of these include the\n@@ -26596,8 +26520,6 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,\n ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body\n (parser, /*in_function_try_block=*/false);\n \n- finish_lambda_scope ();\n-\n /* Finish the function. */\n fn = finish_function ((ctor_initializer_p ? 1 : 0) |\n \t\t\t(inline_p ? 2 : 0));\ndiff --git a/gcc/cp/pt.c b/gcc/cp/pt.c\nindex e064a11..141b4d7 100644\n--- a/gcc/cp/pt.c\n+++ b/gcc/cp/pt.c\n@@ -220,6 +220,7 @@ static bool complex_alias_template_p (const_tree tmpl);\n static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);\n static tree canonicalize_expr_argument (tree, tsubst_flags_t);\n static tree make_argument_pack (tree);\n+static void register_parameter_specializations (tree, tree);\n \n /* Make the current scope suitable for access checking when we are\n processing T. T can be FUNCTION_DECL for instantiated function\n@@ -1190,6 +1191,19 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash)\n if (flag_checking)\n verify_unstripped_args (args);\n \n+ /* Lambda functions in templates aren't instantiated normally, but through\n+ tsubst_lambda_expr. */\n+ if (LAMBDA_FUNCTION_P (tmpl))\n+ {\n+ bool generic = PRIMARY_TEMPLATE_P (tmpl);\n+ if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)) > generic)\n+\treturn NULL_TREE;\n+\n+ /* But generic lambda functions are instantiated normally, once their\n+\t containing context is fully instantiated. */\n+ gcc_assert (generic);\n+ }\n+\n if (optimize_specialization_lookup_p (tmpl))\n {\n /* The template arguments actually apply to the containing\n@@ -3615,6 +3629,12 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)\n case PARM_DECL:\n return NULL_TREE;\n \n+ case DECL_EXPR:\n+ /* Ignore the declaration of a capture proxy for a parameter pack. */\n+ if (is_capture_proxy (DECL_EXPR_DECL (t)))\n+\t*walk_subtrees = 0;\n+ return NULL_TREE;\n+\n case RECORD_TYPE:\n if (TYPE_PTRMEMFUNC_P (t))\n \treturn NULL_TREE;\n@@ -3662,6 +3682,15 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)\n *walk_subtrees = 0;\n return NULL_TREE;\n \n+ case LAMBDA_EXPR:\n+ {\n+\ttree fn = lambda_function (t);\n+\tcp_walk_tree (&DECL_SAVED_TREE (fn), &find_parameter_packs_r, ppd,\n+\t\t ppd->visited);\n+\t*walk_subtrees = 0;\n+\treturn NULL_TREE;\n+ }\n+\n case DECLTYPE_TYPE:\n {\n \t/* When traversing a DECLTYPE_TYPE_EXPR, we need to set\n@@ -3849,6 +3878,10 @@ check_for_bare_parameter_packs (tree t)\n if (!processing_template_decl || !t || t == error_mark_node)\n return false;\n \n+ /* A lambda might use a parameter pack from the containing context. */\n+ if (current_function_decl && LAMBDA_FUNCTION_P (current_function_decl))\n+ return false;\n+\n if (TREE_CODE (t) == TYPE_DECL)\n t = TREE_TYPE (t);\n \n@@ -12056,6 +12089,8 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,\n cp_function_chain->x_current_class_ref = NULL_TREE;\n }\n \n+ start_lambda_scope (parm);\n+\n push_deferring_access_checks(dk_no_deferred);\n /* The default argument expression may cause implicitly defined\n member functions to be synthesized, which will result in garbage\n@@ -12069,6 +12104,8 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,\n --function_depth;\n pop_deferring_access_checks();\n \n+ finish_lambda_scope ();\n+\n /* Restore the \"this\" pointer. */\n if (cfun)\n {\n@@ -12125,6 +12162,441 @@ tsubst_default_arguments (tree fn, tsubst_flags_t complain)\n \t\t\t\t\t\t complain);\n }\n \n+/* Subroutine of tsubst_decl for the case when T is a FUNCTION_DECL. */\n+\n+static tree\n+tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,\n+\t\t tree lambda_fntype)\n+{\n+ tree gen_tmpl, argvec;\n+ hashval_t hash = 0;\n+ tree in_decl = t;\n+\n+ /* Nobody should be tsubst'ing into non-template functions. */\n+ gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);\n+\n+ if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)\n+ {\n+ /* If T is not dependent, just return it. */\n+ if (!uses_template_parms (DECL_TI_ARGS (t)))\n+\treturn t;\n+\n+ /* Calculate the most general template of which R is a\n+\t specialization, and the complete set of arguments used to\n+\t specialize R. */\n+ gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));\n+ argvec = tsubst_template_args (DECL_TI_ARGS\n+\t\t\t\t (DECL_TEMPLATE_RESULT\n+\t\t\t\t (DECL_TI_TEMPLATE (t))),\n+\t\t\t\t args, complain, in_decl);\n+ if (argvec == error_mark_node)\n+\treturn error_mark_node;\n+\n+ /* Check to see if we already have this specialization. */\n+ if (!lambda_fntype)\n+\t{\n+\t hash = hash_tmpl_and_args (gen_tmpl, argvec);\n+\t if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))\n+\t return spec;\n+\t}\n+\n+ /* We can see more levels of arguments than parameters if\n+\t there was a specialization of a member template, like\n+\t this:\n+\n+\t template <class T> struct S { template <class U> void f(); }\n+\t template <> template <class U> void S<int>::f(U);\n+\n+\t Here, we'll be substituting into the specialization,\n+\t because that's where we can find the code we actually\n+\t want to generate, but we'll have enough arguments for\n+\t the most general template.\n+\n+\t We also deal with the peculiar case:\n+\n+\t template <class T> struct S {\n+\t template <class U> friend void f();\n+\t };\n+\t template <class U> void f() {}\n+\t template S<int>;\n+\t template void f<double>();\n+\n+\t Here, the ARGS for the instantiation of will be {int,\n+\t double}. But, we only need as many ARGS as there are\n+\t levels of template parameters in CODE_PATTERN. We are\n+\t careful not to get fooled into reducing the ARGS in\n+\t situations like:\n+\n+\t template <class T> struct S { template <class U> void f(U); }\n+\t template <class T> template <> void S<T>::f(int) {}\n+\n+\t which we can spot because the pattern will be a\n+\t specialization in this case. */\n+ int args_depth = TMPL_ARGS_DEPTH (args);\n+ int parms_depth =\n+\tTMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t)));\n+\n+ if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t))\n+\targs = get_innermost_template_args (args, parms_depth);\n+ }\n+ else\n+ {\n+ /* This special case arises when we have something like this:\n+\n+\t template <class T> struct S {\n+\t friend void f<int>(int, double);\n+\t };\n+\n+\t Here, the DECL_TI_TEMPLATE for the friend declaration\n+\t will be an IDENTIFIER_NODE. We are being called from\n+\t tsubst_friend_function, and we want only to create a\n+\t new decl (R) with appropriate types so that we can call\n+\t determine_specialization. */\n+ gen_tmpl = NULL_TREE;\n+ argvec = NULL_TREE;\n+ }\n+\n+ tree closure = (lambda_fntype ? TYPE_METHOD_BASETYPE (lambda_fntype)\n+\t\t : NULL_TREE);\n+ tree ctx = closure ? closure : DECL_CONTEXT (t);\n+ bool member = ctx && TYPE_P (ctx);\n+\n+ if (member && !closure)\n+ ctx = tsubst_aggr_type (ctx, args,\n+\t\t\t complain, t, /*entering_scope=*/1);\n+\n+ tree type = (lambda_fntype ? lambda_fntype\n+\t : tsubst (TREE_TYPE (t), args,\n+\t\t\t complain | tf_fndecl_type, in_decl));\n+ if (type == error_mark_node)\n+ return error_mark_node;\n+\n+ /* If we hit excessive deduction depth, the type is bogus even if\n+ it isn't error_mark_node, so don't build a decl. */\n+ if (excessive_deduction_depth)\n+ return error_mark_node;\n+\n+ /* We do NOT check for matching decls pushed separately at this\n+ point, as they may not represent instantiations of this\n+ template, and in any case are considered separate under the\n+ discrete model. */\n+ tree r = copy_decl (t);\n+ DECL_USE_TEMPLATE (r) = 0;\n+ TREE_TYPE (r) = type;\n+ /* Clear out the mangled name and RTL for the instantiation. */\n+ SET_DECL_ASSEMBLER_NAME (r, NULL_TREE);\n+ SET_DECL_RTL (r, NULL);\n+ /* Leave DECL_INITIAL set on deleted instantiations. */\n+ if (!DECL_DELETED_FN (r))\n+ DECL_INITIAL (r) = NULL_TREE;\n+ DECL_CONTEXT (r) = ctx;\n+\n+ /* OpenMP UDRs have the only argument a reference to the declared\n+ type. We want to diagnose if the declared type is a reference,\n+ which is invalid, but as references to references are usually\n+ quietly merged, diagnose it here. */\n+ if (DECL_OMP_DECLARE_REDUCTION_P (t))\n+ {\n+ tree argtype\n+\t= TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t))));\n+ argtype = tsubst (argtype, args, complain, in_decl);\n+ if (TREE_CODE (argtype) == REFERENCE_TYPE)\n+\terror_at (DECL_SOURCE_LOCATION (t),\n+\t\t \"reference type %qT in \"\n+\t\t \"%<#pragma omp declare reduction%>\", argtype);\n+ if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)\n+\tDECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),\n+\t\t\t\t\t argtype);\n+ }\n+\n+ if (member && DECL_CONV_FN_P (r))\n+ /* Type-conversion operator. Reconstruct the name, in\n+ case it's the name of one of the template's parameters. */\n+ DECL_NAME (r) = make_conv_op_name (TREE_TYPE (type));\n+\n+ tree parms = DECL_ARGUMENTS (t);\n+ if (closure)\n+ parms = DECL_CHAIN (parms);\n+ parms = tsubst (parms, args, complain, t);\n+ for (tree parm = parms; parm; parm = DECL_CHAIN (parm))\n+ DECL_CONTEXT (parm) = r;\n+ if (closure)\n+ {\n+ tree tparm = build_this_parm (r, closure, type_memfn_quals (type));\n+ DECL_CHAIN (tparm) = parms;\n+ parms = tparm;\n+ }\n+ DECL_ARGUMENTS (r) = parms;\n+ DECL_RESULT (r) = NULL_TREE;\n+\n+ TREE_STATIC (r) = 0;\n+ TREE_PUBLIC (r) = TREE_PUBLIC (t);\n+ DECL_EXTERNAL (r) = 1;\n+ /* If this is an instantiation of a function with internal\n+ linkage, we already know what object file linkage will be\n+ assigned to the instantiation. */\n+ DECL_INTERFACE_KNOWN (r) = !TREE_PUBLIC (r);\n+ DECL_DEFER_OUTPUT (r) = 0;\n+ DECL_CHAIN (r) = NULL_TREE;\n+ DECL_PENDING_INLINE_INFO (r) = 0;\n+ DECL_PENDING_INLINE_P (r) = 0;\n+ DECL_SAVED_TREE (r) = NULL_TREE;\n+ DECL_STRUCT_FUNCTION (r) = NULL;\n+ TREE_USED (r) = 0;\n+ /* We'll re-clone as appropriate in instantiate_template. */\n+ DECL_CLONED_FUNCTION (r) = NULL_TREE;\n+\n+ /* If we aren't complaining now, return on error before we register\n+ the specialization so that we'll complain eventually. */\n+ if ((complain & tf_error) == 0\n+ && IDENTIFIER_ANY_OP_P (DECL_NAME (r))\n+ && !grok_op_properties (r, /*complain=*/false))\n+ return error_mark_node;\n+\n+ /* When instantiating a constrained member, substitute\n+ into the constraints to create a new constraint. */\n+ if (tree ci = get_constraints (t))\n+ if (member)\n+ {\n+\tci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);\n+\tset_constraints (r, ci);\n+ }\n+\n+ /* Set up the DECL_TEMPLATE_INFO for R. There's no need to do\n+ this in the special friend case mentioned above where\n+ GEN_TMPL is NULL. */\n+ if (gen_tmpl && !closure)\n+ {\n+ DECL_TEMPLATE_INFO (r)\n+\t= build_template_info (gen_tmpl, argvec);\n+ SET_DECL_IMPLICIT_INSTANTIATION (r);\n+\n+ tree new_r\n+\t= register_specialization (r, gen_tmpl, argvec, false, hash);\n+ if (new_r != r)\n+\t/* We instantiated this while substituting into\n+\t the type earlier (template/friend54.C). */\n+\treturn new_r;\n+\n+ /* We're not supposed to instantiate default arguments\n+\t until they are called, for a template. But, for a\n+\t declaration like:\n+\n+\t template <class T> void f ()\n+\t { extern void g(int i = T()); }\n+\n+\t we should do the substitution when the template is\n+\t instantiated. We handle the member function case in\n+\t instantiate_class_template since the default arguments\n+\t might refer to other members of the class. */\n+ if (!member\n+\t && !PRIMARY_TEMPLATE_P (gen_tmpl)\n+\t && !uses_template_parms (argvec))\n+\ttsubst_default_arguments (r, complain);\n+ }\n+ else\n+ DECL_TEMPLATE_INFO (r) = NULL_TREE;\n+\n+ /* Copy the list of befriending classes. */\n+ for (tree *friends = &DECL_BEFRIENDING_CLASSES (r);\n+ *friends;\n+ friends = &TREE_CHAIN (*friends))\n+ {\n+ *friends = copy_node (*friends);\n+ TREE_VALUE (*friends)\n+\t= tsubst (TREE_VALUE (*friends), args, complain, in_decl);\n+ }\n+\n+ if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))\n+ {\n+ maybe_retrofit_in_chrg (r);\n+ if (DECL_CONSTRUCTOR_P (r) && !grok_ctor_properties (ctx, r))\n+\treturn error_mark_node;\n+ /* If this is an instantiation of a member template, clone it.\n+\t If it isn't, that'll be handled by\n+\t clone_constructors_and_destructors. */\n+ if (PRIMARY_TEMPLATE_P (gen_tmpl))\n+\tclone_function_decl (r, /*update_methods=*/false);\n+ }\n+ else if ((complain & tf_error) != 0\n+\t && IDENTIFIER_ANY_OP_P (DECL_NAME (r))\n+\t && !grok_op_properties (r, /*complain=*/true))\n+ return error_mark_node;\n+\n+ if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))\n+ SET_DECL_FRIEND_CONTEXT (r,\n+\t\t\t tsubst (DECL_FRIEND_CONTEXT (t),\n+\t\t\t\t args, complain, in_decl));\n+\n+ /* Possibly limit visibility based on template args. */\n+ DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;\n+ if (DECL_VISIBILITY_SPECIFIED (t))\n+ {\n+ DECL_VISIBILITY_SPECIFIED (r) = 0;\n+ DECL_ATTRIBUTES (r)\n+\t= remove_attribute (\"visibility\", DECL_ATTRIBUTES (r));\n+ }\n+ determine_visibility (r);\n+ if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)\n+ && !processing_template_decl)\n+ defaulted_late_check (r);\n+\n+ apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,\n+\t\t\t\t args, complain, in_decl);\n+ return r;\n+}\n+\n+/* Subroutine of tsubst_decl for the case when T is a TEMPLATE_DECL. */\n+\n+static tree\n+tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,\n+\t\t tree lambda_fntype)\n+{\n+ /* We can get here when processing a member function template,\n+ member class template, or template template parameter. */\n+ tree decl = DECL_TEMPLATE_RESULT (t);\n+ tree in_decl = t;\n+ tree spec;\n+ tree tmpl_args;\n+ tree full_args;\n+ tree r;\n+ hashval_t hash = 0;\n+\n+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))\n+ {\n+ /* Template template parameter is treated here. */\n+ tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);\n+ if (new_type == error_mark_node)\n+\tr = error_mark_node;\n+ /* If we get a real template back, return it. This can happen in\n+\t the context of most_specialized_partial_spec. */\n+ else if (TREE_CODE (new_type) == TEMPLATE_DECL)\n+\tr = new_type;\n+ else\n+\t/* The new TEMPLATE_DECL was built in\n+\t reduce_template_parm_level. */\n+\tr = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (new_type);\n+ return r;\n+ }\n+\n+ if (!lambda_fntype)\n+ {\n+ /* We might already have an instance of this template.\n+\t The ARGS are for the surrounding class type, so the\n+\t full args contain the tsubst'd args for the context,\n+\t plus the innermost args from the template decl. */\n+ tmpl_args = DECL_CLASS_TEMPLATE_P (t)\n+\t? CLASSTYPE_TI_ARGS (TREE_TYPE (t))\n+\t: DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t));\n+ /* Because this is a template, the arguments will still be\n+\t dependent, even after substitution. If\n+\t PROCESSING_TEMPLATE_DECL is not set, the dependency\n+\t predicates will short-circuit. */\n+ ++processing_template_decl;\n+ full_args = tsubst_template_args (tmpl_args, args,\n+\t\t\t\t\tcomplain, in_decl);\n+ --processing_template_decl;\n+ if (full_args == error_mark_node)\n+\treturn error_mark_node;\n+\n+ /* If this is a default template template argument,\n+\t tsubst might not have changed anything. */\n+ if (full_args == tmpl_args)\n+\treturn t;\n+\n+ hash = hash_tmpl_and_args (t, full_args);\n+ spec = retrieve_specialization (t, full_args, hash);\n+ if (spec != NULL_TREE)\n+\treturn spec;\n+ }\n+\n+ /* Make a new template decl. It will be similar to the\n+ original, but will record the current template arguments.\n+ We also create a new function declaration, which is just\n+ like the old one, but points to this new template, rather\n+ than the old one. */\n+ r = copy_decl (t);\n+ gcc_assert (DECL_LANG_SPECIFIC (r) != 0);\n+ DECL_CHAIN (r) = NULL_TREE;\n+\n+ // Build new template info linking to the original template decl.\n+ if (!lambda_fntype)\n+ {\n+ DECL_TEMPLATE_INFO (r) = build_template_info (t, args);\n+ SET_DECL_IMPLICIT_INSTANTIATION (r);\n+ }\n+ else\n+ DECL_TEMPLATE_INFO (r) = NULL_TREE;\n+\n+ /* The template parameters for this new template are all the\n+ template parameters for the old template, except the\n+ outermost level of parameters. */\n+ DECL_TEMPLATE_PARMS (r)\n+ = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,\n+\t\t\t complain);\n+\n+ if (TREE_CODE (decl) == TYPE_DECL\n+ && !TYPE_DECL_ALIAS_P (decl))\n+ {\n+ tree new_type;\n+ ++processing_template_decl;\n+ new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);\n+ --processing_template_decl;\n+ if (new_type == error_mark_node)\n+\treturn error_mark_node;\n+\n+ TREE_TYPE (r) = new_type;\n+ /* For a partial specialization, we need to keep pointing to\n+\t the primary template. */\n+ if (!DECL_TEMPLATE_SPECIALIZATION (t))\n+\tCLASSTYPE_TI_TEMPLATE (new_type) = r;\n+ DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);\n+ DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);\n+ DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);\n+ }\n+ else\n+ {\n+ tree new_decl;\n+ ++processing_template_decl;\n+ if (TREE_CODE (decl) == FUNCTION_DECL)\n+\tnew_decl = tsubst_function_decl (decl, args, complain, lambda_fntype);\n+ else\n+\tnew_decl = tsubst (decl, args, complain, in_decl);\n+ --processing_template_decl;\n+ if (new_decl == error_mark_node)\n+\treturn error_mark_node;\n+\n+ DECL_TEMPLATE_RESULT (r) = new_decl;\n+ TREE_TYPE (r) = TREE_TYPE (new_decl);\n+ DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);\n+ if (lambda_fntype)\n+\t{\n+\t tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r));\n+\t DECL_TEMPLATE_INFO (new_decl) = build_template_info (r, args);\n+\t}\n+ else\n+\t{\n+\t DECL_TI_TEMPLATE (new_decl) = r;\n+\t DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);\n+\t}\n+ }\n+\n+ DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;\n+ DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;\n+\n+ if (PRIMARY_TEMPLATE_P (t))\n+ DECL_PRIMARY_TEMPLATE (r) = r;\n+\n+ if (TREE_CODE (decl) != TYPE_DECL && !VAR_P (decl)\n+ && !lambda_fntype)\n+ /* Record this non-type partial instantiation. */\n+ register_specialization (r, t,\n+\t\t\t DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),\n+\t\t\t false, hash);\n+\n+ return r;\n+}\n+\n /* Substitute the ARGS into the T, which is a _DECL. Return the\n result of the substitution. Issue error and warning messages under\n control of COMPLAIN. */\n@@ -12145,395 +12617,11 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)\n switch (TREE_CODE (t))\n {\n case TEMPLATE_DECL:\n- {\n-\t/* We can get here when processing a member function template,\n-\t member class template, or template template parameter. */\n-\ttree decl = DECL_TEMPLATE_RESULT (t);\n-\ttree spec;\n-\ttree tmpl_args;\n-\ttree full_args;\n-\n-\tif (DECL_TEMPLATE_TEMPLATE_PARM_P (t))\n-\t {\n-\t /* Template template parameter is treated here. */\n-\t tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);\n-\t if (new_type == error_mark_node)\n-\t r = error_mark_node;\n-\t /* If we get a real template back, return it. This can happen in\n-\t the context of most_specialized_partial_spec. */\n-\t else if (TREE_CODE (new_type) == TEMPLATE_DECL)\n-\t r = new_type;\n-\t else\n-\t /* The new TEMPLATE_DECL was built in\n-\t\t reduce_template_parm_level. */\n-\t r = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (new_type);\n-\t break;\n-\t }\n-\n-\t/* We might already have an instance of this template.\n-\t The ARGS are for the surrounding class type, so the\n-\t full args contain the tsubst'd args for the context,\n-\t plus the innermost args from the template decl. */\n-\ttmpl_args = DECL_CLASS_TEMPLATE_P (t)\n-\t ? CLASSTYPE_TI_ARGS (TREE_TYPE (t))\n-\t : DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t));\n-\t/* Because this is a template, the arguments will still be\n-\t dependent, even after substitution. If\n-\t PROCESSING_TEMPLATE_DECL is not set, the dependency\n-\t predicates will short-circuit. */\n-\t++processing_template_decl;\n-\tfull_args = tsubst_template_args (tmpl_args, args,\n-\t\t\t\t\t complain, in_decl);\n-\t--processing_template_decl;\n-\tif (full_args == error_mark_node)\n-\t RETURN (error_mark_node);\n-\n-\t/* If this is a default template template argument,\n-\t tsubst might not have changed anything. */\n-\tif (full_args == tmpl_args)\n-\t RETURN (t);\n-\n-\thash = hash_tmpl_and_args (t, full_args);\n-\tspec = retrieve_specialization (t, full_args, hash);\n-\tif (spec != NULL_TREE)\n-\t {\n-\t r = spec;\n-\t break;\n-\t }\n-\n-\t/* Make a new template decl. It will be similar to the\n-\t original, but will record the current template arguments.\n-\t We also create a new function declaration, which is just\n-\t like the old one, but points to this new template, rather\n-\t than the old one. */\n-\tr = copy_decl (t);\n-\tgcc_assert (DECL_LANG_SPECIFIC (r) != 0);\n-\tDECL_CHAIN (r) = NULL_TREE;\n-\n- // Build new template info linking to the original template decl.\n-\tDECL_TEMPLATE_INFO (r) = build_template_info (t, args);\n-\n-\tif (TREE_CODE (decl) == TYPE_DECL\n-\t && !TYPE_DECL_ALIAS_P (decl))\n-\t {\n-\t tree new_type;\n-\t ++processing_template_decl;\n-\t new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);\n-\t --processing_template_decl;\n-\t if (new_type == error_mark_node)\n-\t RETURN (error_mark_node);\n-\n-\t TREE_TYPE (r) = new_type;\n-\t /* For a partial specialization, we need to keep pointing to\n-\t the primary template. */\n-\t if (!DECL_TEMPLATE_SPECIALIZATION (t))\n-\t CLASSTYPE_TI_TEMPLATE (new_type) = r;\n-\t DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);\n-\t DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);\n-\t DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);\n-\t }\n-\telse\n-\t {\n-\t tree new_decl;\n-\t ++processing_template_decl;\n-\t new_decl = tsubst (decl, args, complain, in_decl);\n-\t --processing_template_decl;\n-\t if (new_decl == error_mark_node)\n-\t RETURN (error_mark_node);\n-\n-\t DECL_TEMPLATE_RESULT (r) = new_decl;\n-\t DECL_TI_TEMPLATE (new_decl) = r;\n-\t TREE_TYPE (r) = TREE_TYPE (new_decl);\n-\t DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);\n-\t DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);\n-\t }\n-\n-\tSET_DECL_IMPLICIT_INSTANTIATION (r);\n-\tDECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;\n-\tDECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;\n-\n-\t/* The template parameters for this new template are all the\n-\t template parameters for the old template, except the\n-\t outermost level of parameters. */\n-\tDECL_TEMPLATE_PARMS (r)\n-\t = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,\n-\t\t\t\t complain);\n-\n-\tif (PRIMARY_TEMPLATE_P (t))\n-\t DECL_PRIMARY_TEMPLATE (r) = r;\n-\n-\tif (TREE_CODE (decl) != TYPE_DECL && !VAR_P (decl))\n-\t /* Record this non-type partial instantiation. */\n-\t register_specialization (r, t,\n-\t\t\t\t DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),\n-\t\t\t\t false, hash);\n- }\n+ r = tsubst_template_decl (t, args, complain, /*lambda*/NULL_TREE);\n break;\n \n case FUNCTION_DECL:\n- {\n-\ttree gen_tmpl, argvec;\n-\n-\t/* Nobody should be tsubst'ing into non-template functions. */\n-\tgcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);\n-\n-\tif (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)\n-\t {\n-\t /* If T is not dependent, just return it. */\n-\t if (!uses_template_parms (DECL_TI_ARGS (t)))\n-\t RETURN (t);\n-\n-\t /* Calculate the most general template of which R is a\n-\t specialization, and the complete set of arguments used to\n-\t specialize R. */\n-\t gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));\n-\t argvec = tsubst_template_args (DECL_TI_ARGS\n- (DECL_TEMPLATE_RESULT\n- (DECL_TI_TEMPLATE (t))),\n-\t\t\t\t\t args, complain, in_decl);\n-\t if (argvec == error_mark_node)\n-\t RETURN (error_mark_node);\n-\n-\t /* Check to see if we already have this specialization. */\n-\t hash = hash_tmpl_and_args (gen_tmpl, argvec);\n-\t if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))\n-\t {\n-\t\tr = spec;\n-\t\tbreak;\n-\t }\n-\n-\t /* We can see more levels of arguments than parameters if\n-\t there was a specialization of a member template, like\n-\t this:\n-\n-\t\t template <class T> struct S { template <class U> void f(); }\n-\t\t template <> template <class U> void S<int>::f(U);\n-\n-\t Here, we'll be substituting into the specialization,\n-\t because that's where we can find the code we actually\n-\t want to generate, but we'll have enough arguments for\n-\t the most general template.\n-\n-\t We also deal with the peculiar case:\n-\n-\t\t template <class T> struct S {\n-\t\t template <class U> friend void f();\n-\t\t };\n-\t\t template <class U> void f() {}\n-\t\t template S<int>;\n-\t\t template void f<double>();\n-\n-\t Here, the ARGS for the instantiation of will be {int,\n-\t double}. But, we only need as many ARGS as there are\n-\t levels of template parameters in CODE_PATTERN. We are\n-\t careful not to get fooled into reducing the ARGS in\n-\t situations like:\n-\n-\t\t template <class T> struct S { template <class U> void f(U); }\n-\t\t template <class T> template <> void S<T>::f(int) {}\n-\n-\t which we can spot because the pattern will be a\n-\t specialization in this case. */\n-\t int args_depth = TMPL_ARGS_DEPTH (args);\n-\t int parms_depth =\n-\t TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t)));\n-\n-\t if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t))\n-\t args = get_innermost_template_args (args, parms_depth);\n-\t }\n-\telse\n-\t {\n-\t /* This special case arises when we have something like this:\n-\n-\t\t template <class T> struct S {\n-\t\t friend void f<int>(int, double);\n-\t\t };\n-\n-\t Here, the DECL_TI_TEMPLATE for the friend declaration\n-\t will be an IDENTIFIER_NODE. We are being called from\n-\t tsubst_friend_function, and we want only to create a\n-\t new decl (R) with appropriate types so that we can call\n-\t determine_specialization. */\n-\t gen_tmpl = NULL_TREE;\n-\t argvec = NULL_TREE;\n-\t }\n-\n-\ttree ctx = DECL_CONTEXT (t);\n-\tbool member = ctx && TYPE_P (ctx);\n-\n-\tif (member)\n-\t ctx = tsubst_aggr_type (ctx, args,\n-\t\t\t\t complain, t, /*entering_scope=*/1);\n-\n-\ttree type = tsubst (TREE_TYPE (t), args,\n-\t\t\t complain | tf_fndecl_type, in_decl);\n-\tif (type == error_mark_node)\n-\t RETURN (error_mark_node);\n-\n-\t/* If we hit excessive deduction depth, the type is bogus even if\n-\t it isn't error_mark_node, so don't build a decl. */\n-\tif (excessive_deduction_depth)\n-\t RETURN (error_mark_node);\n-\n-\t/* We do NOT check for matching decls pushed separately at this\n-\t point, as they may not represent instantiations of this\n-\t template, and in any case are considered separate under the\n-\t discrete model. */\n-\tr = copy_decl (t);\n-\tDECL_USE_TEMPLATE (r) = 0;\n-\tTREE_TYPE (r) = type;\n-\t/* Clear out the mangled name and RTL for the instantiation. */\n-\tSET_DECL_ASSEMBLER_NAME (r, NULL_TREE);\n-\tSET_DECL_RTL (r, NULL);\n-\t/* Leave DECL_INITIAL set on deleted instantiations. */\n-\tif (!DECL_DELETED_FN (r))\n-\t DECL_INITIAL (r) = NULL_TREE;\n-\tDECL_CONTEXT (r) = ctx;\n-\n-\t/* OpenMP UDRs have the only argument a reference to the declared\n-\t type. We want to diagnose if the declared type is a reference,\n-\t which is invalid, but as references to references are usually\n-\t quietly merged, diagnose it here. */\n-\tif (DECL_OMP_DECLARE_REDUCTION_P (t))\n-\t {\n-\t tree argtype\n-\t = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t))));\n-\t argtype = tsubst (argtype, args, complain, in_decl);\n-\t if (TREE_CODE (argtype) == REFERENCE_TYPE)\n-\t error_at (DECL_SOURCE_LOCATION (t),\n-\t\t\t\"reference type %qT in \"\n-\t\t\t\"%<#pragma omp declare reduction%>\", argtype);\n-\t if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)\n-\t DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),\n-\t\t\t\t\t\targtype);\n-\t }\n-\n-\tif (member && DECL_CONV_FN_P (r))\n-\t /* Type-conversion operator. Reconstruct the name, in\n-\t case it's the name of one of the template's parameters. */\n-\t DECL_NAME (r) = make_conv_op_name (TREE_TYPE (type));\n-\n-\tDECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args,\n-\t\t\t\t complain, t);\n-\tfor (tree parm = DECL_ARGUMENTS (r); parm; parm = DECL_CHAIN (parm))\n-\t DECL_CONTEXT (parm) = r;\n-\tDECL_RESULT (r) = NULL_TREE;\n-\n-\tTREE_STATIC (r) = 0;\n-\tTREE_PUBLIC (r) = TREE_PUBLIC (t);\n-\tDECL_EXTERNAL (r) = 1;\n-\t/* If this is an instantiation of a function with internal\n-\t linkage, we already know what object file linkage will be\n-\t assigned to the instantiation. */\n-\tDECL_INTERFACE_KNOWN (r) = !TREE_PUBLIC (r);\n-\tDECL_DEFER_OUTPUT (r) = 0;\n-\tDECL_CHAIN (r) = NULL_TREE;\n-\tDECL_PENDING_INLINE_INFO (r) = 0;\n-\tDECL_PENDING_INLINE_P (r) = 0;\n-\tDECL_SAVED_TREE (r) = NULL_TREE;\n-\tDECL_STRUCT_FUNCTION (r) = NULL;\n-\tTREE_USED (r) = 0;\n-\t/* We'll re-clone as appropriate in instantiate_template. */\n-\tDECL_CLONED_FUNCTION (r) = NULL_TREE;\n-\n-\t/* If we aren't complaining now, return on error before we register\n-\t the specialization so that we'll complain eventually. */\n-\tif ((complain & tf_error) == 0\n-\t && IDENTIFIER_ANY_OP_P (DECL_NAME (r))\n-\t && !grok_op_properties (r, /*complain=*/false))\n-\t RETURN (error_mark_node);\n-\n- /* When instantiating a constrained member, substitute\n- into the constraints to create a new constraint. */\n- if (tree ci = get_constraints (t))\n- if (member)\n- {\n- ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);\n- set_constraints (r, ci);\n- }\n-\n-\t/* Set up the DECL_TEMPLATE_INFO for R. There's no need to do\n-\t this in the special friend case mentioned above where\n-\t GEN_TMPL is NULL. */\n-\tif (gen_tmpl)\n-\t {\n-\t DECL_TEMPLATE_INFO (r)\n-\t = build_template_info (gen_tmpl, argvec);\n-\t SET_DECL_IMPLICIT_INSTANTIATION (r);\n-\n-\t tree new_r\n-\t = register_specialization (r, gen_tmpl, argvec, false, hash);\n-\t if (new_r != r)\n-\t /* We instantiated this while substituting into\n-\t\t the type earlier (template/friend54.C). */\n-\t RETURN (new_r);\n-\n-\t /* We're not supposed to instantiate default arguments\n-\t until they are called, for a template. But, for a\n-\t declaration like:\n-\n-\t\t template <class T> void f ()\n-\t\t { extern void g(int i = T()); }\n-\n-\t we should do the substitution when the template is\n-\t instantiated. We handle the member function case in\n-\t instantiate_class_template since the default arguments\n-\t might refer to other members of the class. */\n-\t if (!member\n-\t\t&& !PRIMARY_TEMPLATE_P (gen_tmpl)\n-\t\t&& !uses_template_parms (argvec))\n-\t tsubst_default_arguments (r, complain);\n-\t }\n-\telse\n-\t DECL_TEMPLATE_INFO (r) = NULL_TREE;\n-\n-\t/* Copy the list of befriending classes. */\n-\tfor (tree *friends = &DECL_BEFRIENDING_CLASSES (r);\n-\t *friends;\n-\t friends = &TREE_CHAIN (*friends))\n-\t {\n-\t *friends = copy_node (*friends);\n-\t TREE_VALUE (*friends)\n-\t = tsubst (TREE_VALUE (*friends), args, complain, in_decl);\n-\t }\n-\n-\tif (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))\n-\t {\n-\t maybe_retrofit_in_chrg (r);\n-\t if (DECL_CONSTRUCTOR_P (r) && !grok_ctor_properties (ctx, r))\n-\t RETURN (error_mark_node);\n-\t /* If this is an instantiation of a member template, clone it.\n-\t If it isn't, that'll be handled by\n-\t clone_constructors_and_destructors. */\n-\t if (PRIMARY_TEMPLATE_P (gen_tmpl))\n-\t clone_function_decl (r, /*update_methods=*/false);\n-\t }\n-\telse if ((complain & tf_error) != 0\n-\t\t && IDENTIFIER_ANY_OP_P (DECL_NAME (r))\n-\t\t && !grok_op_properties (r, /*complain=*/true))\n-\t RETURN (error_mark_node);\n-\n-\tif (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))\n-\t SET_DECL_FRIEND_CONTEXT (r,\n-\t\t\t\t tsubst (DECL_FRIEND_CONTEXT (t),\n-\t\t\t\t\t args, complain, in_decl));\n-\n-\t/* Possibly limit visibility based on template args. */\n-\tDECL_VISIBILITY (r) = VISIBILITY_DEFAULT;\n-\tif (DECL_VISIBILITY_SPECIFIED (t))\n-\t {\n-\t DECL_VISIBILITY_SPECIFIED (r) = 0;\n-\t DECL_ATTRIBUTES (r)\n-\t = remove_attribute (\"visibility\", DECL_ATTRIBUTES (r));\n-\t }\n-\tdetermine_visibility (r);\n-\tif (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)\n-\t && !processing_template_decl)\n-\t defaulted_late_check (r);\n-\n-\tapply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,\n-\t\t\t\t\targs, complain, in_decl);\n- }\n+ r = tsubst_function_decl (t, args, complain, /*lambda*/NULL_TREE);\n break;\n \n case PARM_DECL:\n@@ -15862,6 +15950,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,\n \t instantiate the elements directly as needed. */\n \t break;\n \t }\n+\telse if (is_capture_proxy (decl)\n+\t\t && !DECL_TEMPLATE_INSTANTIATION (current_function_decl))\n+\t {\n+\t /* We're in tsubst_lambda_expr, we've already inserted new capture\n+\t proxies, and uses will find them with lookup_name. */\n+\t break;\n+\t }\n+\telse if (DECL_IMPLICIT_TYPEDEF_P (decl)\n+\t\t && LAMBDA_TYPE_P (TREE_TYPE (decl)))\n+\t /* Don't copy the old closure; we'll create a new one in\n+\t tsubst_lambda_expr. */\n+\t break;\n \telse\n \t {\n \t init = DECL_INITIAL (decl);\n@@ -16659,6 +16759,149 @@ tsubst_non_call_postfix_expression (tree t, tree args,\n return t;\n }\n \n+/* T is a LAMBDA_EXPR. Generate a new LAMBDA_EXPR for the current\n+ instantiation context. Instantiating a pack expansion containing a lambda\n+ might result in multiple lambdas all based on the same lambda in the\n+ template. */\n+\n+tree\n+tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n+{\n+ tree oldfn = lambda_function (t);\n+ in_decl = oldfn;\n+\n+ tree r = build_lambda_expr ();\n+\n+ LAMBDA_EXPR_LOCATION (r)\n+ = LAMBDA_EXPR_LOCATION (t);\n+ LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)\n+ = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);\n+ LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);\n+\n+ if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE)\n+ LAMBDA_EXPR_EXTRA_SCOPE (r) = NULL_TREE;\n+ else\n+ record_lambda_scope (r);\n+\n+ gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE\n+\t && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);\n+\n+ for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap;\n+ cap = TREE_CHAIN (cap))\n+ {\n+ tree field = TREE_PURPOSE (cap);\n+ if (PACK_EXPANSION_P (field))\n+\tfield = PACK_EXPANSION_PATTERN (field);\n+ field = tsubst_decl (field, args, complain);\n+\n+ if (field == error_mark_node)\n+\treturn error_mark_node;\n+\n+ tree init = TREE_VALUE (cap);\n+ if (PACK_EXPANSION_P (init))\n+\tinit = tsubst_pack_expansion (init, args, complain, in_decl);\n+ else\n+\tinit = tsubst_copy_and_build (init, args, complain, in_decl,\n+\t\t\t\t /*fn*/false, /*constexpr*/false);\n+\n+ if (TREE_CODE (field) == TREE_VEC)\n+\t{\n+\t int len = TREE_VEC_LENGTH (field);\n+\t gcc_assert (TREE_CODE (init) == TREE_VEC\n+\t\t && TREE_VEC_LENGTH (init) == len);\n+\t for (int i = 0; i < len; ++i)\n+\t LAMBDA_EXPR_CAPTURE_LIST (r)\n+\t = tree_cons (TREE_VEC_ELT (field, i),\n+\t\t\t TREE_VEC_ELT (init, i),\n+\t\t\t LAMBDA_EXPR_CAPTURE_LIST (r));\n+\t}\n+ else\n+\t{\n+\t LAMBDA_EXPR_CAPTURE_LIST (r)\n+\t = tree_cons (field, init, LAMBDA_EXPR_CAPTURE_LIST (r));\n+\n+\t if (id_equal (DECL_NAME (field), \"__this\"))\n+\t LAMBDA_EXPR_THIS_CAPTURE (r) = field;\n+\t}\n+ }\n+\n+ tree type = begin_lambda_type (r);\n+\n+ /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */\n+ determine_visibility (TYPE_NAME (type));\n+\n+ register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (r));\n+\n+ tree oldtmpl = (generic_lambda_fn_p (oldfn)\n+\t\t ? DECL_TI_TEMPLATE (oldfn)\n+\t\t : NULL_TREE);\n+\n+ tree fntype = static_fn_type (oldfn);\n+ if (oldtmpl)\n+ ++processing_template_decl;\n+ fntype = tsubst (fntype, args, complain, in_decl);\n+ if (oldtmpl)\n+ --processing_template_decl;\n+\n+ if (fntype == error_mark_node)\n+ r = error_mark_node;\n+ else\n+ {\n+ /* Fix the type of 'this'. */\n+ fntype = build_memfn_type (fntype, type,\n+\t\t\t\t type_memfn_quals (fntype),\n+\t\t\t\t type_memfn_rqual (fntype));\n+ tree fn, tmpl;\n+ if (oldtmpl)\n+\t{\n+\t tmpl = tsubst_template_decl (oldtmpl, args, complain, fntype);\n+\t fn = DECL_TEMPLATE_RESULT (tmpl);\n+\t finish_member_declaration (tmpl);\n+\t}\n+ else\n+\t{\n+\t tmpl = NULL_TREE;\n+\t fn = tsubst_function_decl (oldfn, args, complain, fntype);\n+\t finish_member_declaration (fn);\n+\t}\n+\n+ /* Let finish_function set this. */\n+ DECL_DECLARED_CONSTEXPR_P (fn) = false;\n+\n+ bool nested = cfun;\n+ if (nested)\n+\tpush_function_context ();\n+\n+ tree body = start_lambda_function (fn, r);\n+\n+ local_specialization_stack s (lss_copy);\n+\n+ register_parameter_specializations (oldfn, fn);\n+\n+ tsubst_expr (DECL_SAVED_TREE (oldfn), args, complain, r,\n+\t\t /*constexpr*/false);\n+\n+ finish_lambda_function (body);\n+\n+ if (nested)\n+\tpop_function_context ();\n+\n+ /* The capture list was built up in reverse order; fix that now. */\n+ LAMBDA_EXPR_CAPTURE_LIST (r)\n+\t= nreverse (LAMBDA_EXPR_CAPTURE_LIST (r));\n+\n+ LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;\n+\n+ maybe_add_lambda_conv_op (type);\n+ }\n+\n+ finish_struct (type, /*attr*/NULL_TREE);\n+\n+ insert_pending_capture_proxies ();\n+\n+ return r;\n+}\n+\n /* Like tsubst but deals with expressions and performs semantic\n analysis. FUNCTION_P is true if T is the \"F\" in \"F (ARGS)\". */\n \n@@ -17861,7 +18104,7 @@ tsubst_copy_and_build (tree t,\n \telse if (outer_automatic_var_p (r))\n \t {\n \t r = process_outer_var_ref (r, complain);\n-\t if (is_capture_proxy (r))\n+\t if (is_capture_proxy (r) && !DECL_PACK_P (t))\n \t register_local_specialization (r, t);\n \t }\n \n@@ -17929,59 +18172,7 @@ tsubst_copy_and_build (tree t,\n \n case LAMBDA_EXPR:\n {\n-\ttree r = build_lambda_expr ();\n-\n-\ttree type = tsubst (LAMBDA_EXPR_CLOSURE (t), args, complain, NULL_TREE);\n-\tLAMBDA_EXPR_CLOSURE (r) = type;\n-\tCLASSTYPE_LAMBDA_EXPR (type) = r;\n-\n-\tLAMBDA_EXPR_LOCATION (r)\n-\t = LAMBDA_EXPR_LOCATION (t);\n-\tLAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)\n-\t = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);\n-\tLAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);\n-\tLAMBDA_EXPR_DISCRIMINATOR (r)\n-\t = (LAMBDA_EXPR_DISCRIMINATOR (t));\n-\ttree scope = LAMBDA_EXPR_EXTRA_SCOPE (t);\n-\tif (!scope)\n-\t /* No substitution needed. */;\n-\telse if (VAR_OR_FUNCTION_DECL_P (scope))\n-\t /* For a function or variable scope, we want to use tsubst so that we\n-\t don't complain about referring to an auto before deduction. */\n-\t scope = tsubst (scope, args, complain, in_decl);\n-\telse if (TREE_CODE (scope) == PARM_DECL)\n-\t {\n-\t /* Look up the parameter we want directly, as tsubst_copy\n-\t doesn't do what we need. */\n-\t tree fn = tsubst (DECL_CONTEXT (scope), args, complain, in_decl);\n-\t tree parm = FUNCTION_FIRST_USER_PARM (fn);\n-\t while (DECL_PARM_INDEX (parm) != DECL_PARM_INDEX (scope))\n-\t parm = DECL_CHAIN (parm);\n-\t scope = parm;\n-\t /* FIXME Work around the parm not having DECL_CONTEXT set. */\n-\t if (DECL_CONTEXT (scope) == NULL_TREE)\n-\t DECL_CONTEXT (scope) = fn;\n-\t }\n-\telse if (TREE_CODE (scope) == FIELD_DECL)\n-\t /* For a field, use tsubst_copy so that we look up the existing field\n-\t rather than build a new one. */\n-\t scope = RECUR (scope);\n-\telse\n-\t gcc_unreachable ();\n-\tLAMBDA_EXPR_EXTRA_SCOPE (r) = scope;\n-\n-\tgcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE\n-\t\t && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);\n-\n-\t/* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */\n-\tdetermine_visibility (TYPE_NAME (type));\n-\t/* Now that we know visibility, instantiate the type so we have a\n-\t declaration of the op() for later calls to lambda_function. */\n-\tcomplete_type (type);\n-\n-\tLAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;\n-\n-\tinsert_pending_capture_proxies ();\n+\ttree r = tsubst_lambda_expr (t, args, complain, in_decl);\n \n \tRETURN (build_lambda_object (r));\n }\n@@ -22434,10 +22625,12 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args)\n }\n else if (VAR_P (decl))\n {\n+ start_lambda_scope (decl);\n DECL_INITIAL (decl) =\n \ttsubst_expr (DECL_INITIAL (code_pattern), args,\n \t\t tf_error, DECL_TI_TEMPLATE (decl),\n \t\t /*integral_constant_expression_p=*/false);\n+ finish_lambda_scope ();\n if (VAR_HAD_UNKNOWN_BOUND (decl))\n \tTREE_TYPE (decl) = tsubst (TREE_TYPE (code_pattern), args,\n \t\t\t\t tf_error, DECL_TI_TEMPLATE (decl));\n@@ -22605,6 +22798,38 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)\n return true;\n }\n \n+/* We're starting to process the function INST, an instantiation of PATTERN;\n+ add their parameters to local_specializations. */\n+\n+static void\n+register_parameter_specializations (tree pattern, tree inst)\n+{\n+ tree tmpl_parm = DECL_ARGUMENTS (pattern);\n+ tree spec_parm = DECL_ARGUMENTS (inst);\n+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (inst))\n+ {\n+ register_local_specialization (spec_parm, tmpl_parm);\n+ spec_parm = skip_artificial_parms_for (inst, spec_parm);\n+ tmpl_parm = skip_artificial_parms_for (pattern, tmpl_parm);\n+ }\n+ for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))\n+ {\n+ if (!DECL_PACK_P (tmpl_parm))\n+\t{\n+\t register_local_specialization (spec_parm, tmpl_parm);\n+\t spec_parm = DECL_CHAIN (spec_parm);\n+\t}\n+ else\n+\t{\n+\t /* Register the (value) argument pack as a specialization of\n+\t TMPL_PARM, then move on. */\n+\t tree argpack = extract_fnparm_pack (tmpl_parm, &spec_parm);\n+\t register_local_specialization (argpack, tmpl_parm);\n+\t}\n+ }\n+ gcc_assert (!spec_parm);\n+}\n+\n /* Produce the definition of D, a _DECL generated from a template. If\n DEFER_OK is true, then we don't have to actually do the\n instantiation now; we just have to do it sometime. Normally it is\n@@ -22939,10 +23164,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)\n else if (TREE_CODE (d) == FUNCTION_DECL)\n {\n hash_map<tree, tree> *saved_local_specializations;\n- tree tmpl_parm;\n- tree spec_parm;\n tree block = NULL_TREE;\n- tree lambda_ctx = NULL_TREE;\n \n /* Save away the current list, in case we are instantiating one\n \t template from within the body of another. */\n@@ -22956,23 +23178,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)\n \t && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)\n \tblock = push_stmt_list ();\n else\n-\t{\n-\t if (push_to_top && LAMBDA_FUNCTION_P (d))\n-\t {\n-\t /* When instantiating a lambda's templated function\n-\t\t operator, we need to push the non-lambda class scope\n-\t\t of the lambda itself so that the nested function\n-\t\t stack is sufficiently correct to deal with this\n-\t\t capture. */\n-\t lambda_ctx = DECL_CONTEXT (d);\n-\t do \n-\t\tlambda_ctx = decl_type_context (TYPE_NAME (lambda_ctx));\n-\t while (lambda_ctx && LAMBDA_TYPE_P (lambda_ctx));\n-\t if (lambda_ctx)\n-\t\tpush_nested_class (lambda_ctx);\n-\t }\n-\t start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);\n-\t}\n+\tstart_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);\n \n /* Some typedefs referenced from within the template code need to be\n \t access checked at template instantiation time, i.e now. These\n@@ -22982,30 +23188,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)\n \t\t\t\t args);\n \n /* Create substitution entries for the parameters. */\n- tmpl_parm = DECL_ARGUMENTS (code_pattern);\n- spec_parm = DECL_ARGUMENTS (d);\n- if (DECL_NONSTATIC_MEMBER_FUNCTION_P (d))\n-\t{\n-\t register_local_specialization (spec_parm, tmpl_parm);\n-\t spec_parm = skip_artificial_parms_for (d, spec_parm);\n-\t tmpl_parm = skip_artificial_parms_for (code_pattern, tmpl_parm);\n-\t}\n- for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))\n-\t{\n-\t if (!DECL_PACK_P (tmpl_parm))\n-\t {\n-\t register_local_specialization (spec_parm, tmpl_parm);\n-\t spec_parm = DECL_CHAIN (spec_parm);\n-\t }\n-\t else\n-\t {\n-\t /* Register the (value) argument pack as a specialization of\n-\t\t TMPL_PARM, then move on. */\n-\t tree argpack = extract_fnparm_pack (tmpl_parm, &spec_parm);\n-\t register_local_specialization (argpack, tmpl_parm);\n-\t }\n-\t}\n- gcc_assert (!spec_parm);\n+ register_parameter_specializations (code_pattern, d);\n \n /* Substitute into the body of the function. */\n if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))\n@@ -23040,8 +23223,6 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)\n \t d = finish_function (0);\n \t expand_or_defer_fn (d);\n \t}\n- if (lambda_ctx)\n-\tpop_nested_class ();\n \n if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))\n \tcp_check_omp_declare_reduction (d);\ndiff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c\nindex fe118cd..8f28221 100644\n--- a/gcc/cp/semantics.c\n+++ b/gcc/cp/semantics.c\n@@ -3301,40 +3301,56 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)\n if (!mark_used (decl, complain))\n return error_mark_node;\n \n- bool saw_generic_lambda = false;\n if (parsing_nsdmi ())\n containing_function = NULL_TREE;\n- else\n- /* If we are in a lambda function, we can move out until we hit\n- 1. the context,\n- 2. a non-lambda function, or\n- 3. a non-default capturing lambda function. */\n- while (context != containing_function\n-\t /* containing_function can be null with invalid generic lambdas. */\n-\t && containing_function\n-\t && LAMBDA_FUNCTION_P (containing_function))\n- {\n-\ttree closure = DECL_CONTEXT (containing_function);\n-\tlambda_expr = CLASSTYPE_LAMBDA_EXPR (closure);\n \n-\tif (generic_lambda_fn_p (containing_function))\n-\t saw_generic_lambda = true;\n+ if (containing_function && DECL_TEMPLATE_INFO (context)\n+ && LAMBDA_FUNCTION_P (containing_function))\n+ {\n+ /* Check whether we've already built a proxy;\n+\t insert_pending_capture_proxies doesn't update\n+\t local_specializations. */\n+ tree d = lookup_name (DECL_NAME (decl));\n+ if (d && is_capture_proxy (d)\n+\t && DECL_CONTEXT (d) == containing_function)\n+\treturn d;\n+ }\n \n-\tif (TYPE_CLASS_SCOPE_P (closure))\n-\t /* A lambda in an NSDMI (c++/64496). */\n-\t break;\n+ /* If we are in a lambda function, we can move out until we hit\n+ 1. the context,\n+ 2. a non-lambda function, or\n+ 3. a non-default capturing lambda function. */\n+ while (context != containing_function\n+\t /* containing_function can be null with invalid generic lambdas. */\n+\t && containing_function\n+\t && LAMBDA_FUNCTION_P (containing_function))\n+ {\n+ tree closure = DECL_CONTEXT (containing_function);\n+ lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure);\n \n-\tif (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)\n-\t == CPLD_NONE)\n-\t break;\n+ if (TYPE_CLASS_SCOPE_P (closure))\n+\t/* A lambda in an NSDMI (c++/64496). */\n+\tbreak;\n \n-\tlambda_stack = tree_cons (NULL_TREE,\n-\t\t\t\t lambda_expr,\n-\t\t\t\t lambda_stack);\n+ if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)\n+\t == CPLD_NONE)\n+\tbreak;\n \n-\tcontaining_function\n-\t = decl_function_context (containing_function);\n- }\n+ lambda_stack = tree_cons (NULL_TREE,\n+\t\t\t\tlambda_expr,\n+\t\t\t\tlambda_stack);\n+\n+ containing_function\n+\t= decl_function_context (containing_function);\n+ }\n+\n+ /* In a lambda within a template, wait until instantiation\n+ time to implicitly capture. */\n+ if (context == containing_function\n+ && DECL_TEMPLATE_INFO (containing_function)\n+ && any_dependent_template_arguments_p (DECL_TI_ARGS\n+\t\t\t\t\t (containing_function)))\n+ return decl;\n \n /* Core issue 696: \"[At the July 2009 meeting] the CWG expressed\n support for an approach in which a reference to a local\n@@ -3343,26 +3359,11 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)\n the complexity of the problem\"\n \n FIXME update for final resolution of core issue 696. */\n- if (decl_maybe_constant_var_p (decl))\n+ if (decl_constant_var_p (decl))\n {\n- if (processing_template_decl && !saw_generic_lambda)\n-\t/* In a non-generic lambda within a template, wait until instantiation\n-\t time to decide whether to capture. For a generic lambda, we can't\n-\t wait until we instantiate the op() because the closure class is\n-\t already defined at that point. FIXME to get the semantics exactly\n-\t right we need to partially-instantiate the lambda body so the only\n-\t dependencies left are on the generic parameters themselves. This\n-\t probably means moving away from our current model of lambdas in\n-\t templates (instantiating the closure type) to one based on creating\n-\t the closure type when instantiating the lambda context. That is\n-\t probably also the way to handle lambdas within pack expansions. */\n-\treturn decl;\n- else if (decl_constant_var_p (decl))\n-\t{\n-\t tree t = maybe_constant_value (convert_from_reference (decl));\n-\t if (TREE_CONSTANT (t))\n-\t return t;\n-\t}\n+ tree t = maybe_constant_value (convert_from_reference (decl));\n+ if (TREE_CONSTANT (t))\n+\treturn t;\n }\n \n if (lambda_expr && VAR_P (decl)\ndiff --git a/gcc/testsuite/g++.dg/cpp1z/fold-lambda.C b/gcc/testsuite/g++.dg/cpp1z/fold-lambda.C\nnew file mode 100644\nindex 0000000..5eaed4a\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/cpp1z/fold-lambda.C\n@@ -0,0 +1,14 @@\n+// { dg-do run }\n+// { dg-options -std=c++17 }\n+\n+template <class... T>\n+auto f() {\n+ int i = 42;\n+ return ([i]{ return T(i); }() + ...);\n+}\n+\n+int main()\n+{\n+ if (f<int,double>() != 84)\n+ __builtin_abort();\n+}\ndiff --git a/gcc/testsuite/g++.dg/warn/Wshadow-6.C b/gcc/testsuite/g++.dg/warn/Wshadow-6.C\nindex 9c2e8b8..1d8d21b 100644\n--- a/gcc/testsuite/g++.dg/warn/Wshadow-6.C\n+++ b/gcc/testsuite/g++.dg/warn/Wshadow-6.C\n@@ -43,7 +43,7 @@ template <class T>\n void f4(int i) {\n [=]{\n int j = i;\t\t\t// { dg-message \"shadowed declaration\" }\n- int i;\t\t\t// { dg-warning \"shadows a lambda capture\" }\n+ int i;\t\t\t// { dg-warning \"shadows a \" }\n i = 1;\n };\n }\n", "prefixes": [] }