Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2222587/?format=api
{ "id": 2222587, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2222587/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260413060430.722013-1-jason@redhat.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.2/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": "<20260413060430.722013-1-jason@redhat.com>", "list_archive_url": null, "date": "2026-04-13T06:03:59", "name": "[pushed] c++: lambda capture scope and requires [PR122884]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "16af272db5611db06231f280e595a820e9677f78", "submitter": { "id": 4337, "url": "http://patchwork.ozlabs.org/api/1.2/people/4337/?format=api", "name": "Jason Merrill", "email": "jason@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260413060430.722013-1-jason@redhat.com/mbox/", "series": [ { "id": 499647, "url": "http://patchwork.ozlabs.org/api/1.2/series/499647/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=499647", "date": "2026-04-13T06:03:59", "name": "[pushed] c++: lambda capture scope and requires [PR122884]", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/499647/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2222587/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2222587/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=ExHNcSeO;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=ExHNcSeO", "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com", "sourceware.org; spf=pass smtp.mailfrom=redhat.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.133.124" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fvH2N6lq4z1xtJ\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 13 Apr 2026 16:05:11 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id B498C4BA23D4\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 13 Apr 2026 06:05:07 +0000 (GMT)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id CBF834BA2E10\n for <gcc-patches@gcc.gnu.org>; Mon, 13 Apr 2026 06:04:37 +0000 (GMT)", "from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-220-Jibczs6LMfakZjagv7Drzw-1; Mon,\n 13 Apr 2026 02:04:33 -0400", "from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 7D5E2195608E\n for <gcc-patches@gcc.gnu.org>; Mon, 13 Apr 2026 06:04:32 +0000 (UTC)", "from jason-thinkpadp1gen4i.rmtusma.csb (unknown [10.22.80.15])\n by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 20F5E1800451\n for <gcc-patches@gcc.gnu.org>; Mon, 13 Apr 2026 06:04:31 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org B498C4BA23D4", "OpenDKIM Filter v2.11.0 sourceware.org CBF834BA2E10" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org CBF834BA2E10", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org CBF834BA2E10", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776060277; cv=none;\n b=TvQwbxf7ZD4d5Ya1UKEUjo9oEmOkl3Pdp8KgrgfWs7MbMxYzpyDGS2WaXYbqySlyL3foXRS0IbnMHa5dLpUR0OqTu4E1ekxfxt6qd6WqF9lLJmITbXWv/cxRjfleuK7QpSPDptGpBI/7v0jnDdYYqSF4Ry4bMOYvH2C3bXJeiqA=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776060277; c=relaxed/simple;\n bh=BmfSD3GbkxMhZM/Z2Pkcy7ny646k1x3ll8H0Hc+SEps=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=mjecux/mgrwjEkSYNFenG9827MLhWQ4KqGCjHJEJ1xE/iSI+VOVRqpVPdbYHa0wFe0M2Gy/1MVPTJUpsxya+2ulmo4a4u8/AnD1T8JWcaWbF1yF9LytrOGoH8WGX2Npv2wxn6uuf3al9yriGU2dW9ZYLdr/HtIjULyAwQKPAoGA=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1776060277;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=YdaBl3lzaOVyjfYdor0YoCMPF0gVV+WNFAGwE4/js/U=;\n b=ExHNcSeOwmoM32PJ1PSKrgJRuIx1fFhmShNiJgoDkb72/E8C6vnzDvrm9QxDbTJarXBASj\n zkuypASAXV5XSDR4VXHSquiwCSNkECdTtk0pVPzzmBsVxb6nKhwEVmPJZimnHsxXOmKHzx\n i7Wb+hgZHbTgaXdy7M3na5AEP+KApv4=", "X-MC-Unique": "Jibczs6LMfakZjagv7Drzw-1", "X-Mimecast-MFC-AGG-ID": "Jibczs6LMfakZjagv7Drzw_1776060272", "From": "Jason Merrill <jason@redhat.com>", "To": "gcc-patches@gcc.gnu.org", "Subject": "[pushed] c++: lambda capture scope and requires [PR122884]", "Date": "Mon, 13 Apr 2026 02:03:59 -0400", "Message-ID": "<20260413060430.722013-1-jason@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.93", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "e1KStN4ScGhNKu4C3xdQCOkvMmLM3UyOXsTMDYLSzgQ_1776060272", "X-Mimecast-Originator": "redhat.com", "Content-Transfer-Encoding": "8bit", "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "Tested x86_64-pc-linux-gnu, applying to trunk.\n\n-- 8< --\n\nI spent quite a while working on improving our representation of early\ncapture proxies, which was enough to make the noexcept work, but eventually\nrealized that for constraints, since they are substituted before we start to\nbuild the actual function declaration, we need to handle reconstructing\ncapture proxies during substitution like we already do for parameters. So\nthis patch only does that; the early proxy representation changes can wait\nfor stage 1.\n\n\tPR c++/122884\n\ngcc/cp/ChangeLog:\n\n\t* pt.cc (reconstruct_lambda_capture_pack): New.\n\t(tsubst_pack_expansion): Use it.\n\t(tsubst_decl): Handle capture proxy.\n\t(tsubst): Handle lambda closure.\n\t(tsubst_expr): Handle closure field.\n\t(tsubst_lambda_expr): Copy closure location.\n\t* constraint.cc (satisfy_declaration_constraints): Set up\n\tlocal_specializations for a lambda.\n\ngcc/testsuite/ChangeLog:\n\n\t* g++.dg/cpp23/lambda-scope10.C: New test.\n\t* g++.dg/cpp23/lambda-scope10a.C: New test.\n---\n gcc/cp/constraint.cc | 7 +-\n gcc/cp/pt.cc | 174 ++++++++++++++++---\n gcc/testsuite/g++.dg/cpp23/lambda-scope10.C | 19 ++\n gcc/testsuite/g++.dg/cpp23/lambda-scope10a.C | 19 ++\n 4 files changed, 191 insertions(+), 28 deletions(-)\n create mode 100644 gcc/testsuite/g++.dg/cpp23/lambda-scope10.C\n create mode 100644 gcc/testsuite/g++.dg/cpp23/lambda-scope10a.C\n\n\nbase-commit: c84e0635059164c99176774e610425a5c8b9915b", "diff": "diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc\nindex 6fe75b6b8f0..c4118788d4c 100644\n--- a/gcc/cp/constraint.cc\n+++ b/gcc/cp/constraint.cc\n@@ -2826,7 +2826,12 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info)\n tree pattern = DECL_TEMPLATE_RESULT (t);\n push_to_top_level ();\n push_access_scope (pattern);\n- result = satisfy_normalized_constraints (norm, args, info);\n+ {\n+\t/* For reconstruct_lambda_capture_pack. */\n+\tlocal_specialization_stack lss (LAMBDA_FUNCTION_P (t)\n+\t\t\t\t\t? lss_blank : lss_nop);\n+\tresult = satisfy_normalized_constraints (norm, args, info);\n+ }\n pop_access_scope (pattern);\n pop_from_top_level ();\n pop_tinst_level ();\ndiff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc\nindex 38e784517a5..f778c7c270d 100644\n--- a/gcc/cp/pt.cc\n+++ b/gcc/cp/pt.cc\n@@ -14044,6 +14044,89 @@ add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl)\n return args;\n }\n \n+/* We've seen a lambda capture proxy pack PAT in a context outside the body,\n+ such as in a trailing requires-clause. Here we cannot use\n+ lookup_init_capture_pack, both because checking satisfaction comes after\n+ tsubst_lambda_expr (so the field pack isn't in local_specializations) and\n+ before start_lambda_function (so the proxies aren't there to lookup_name).\n+\n+ However, because satisfy_declaration_constraints pushed into the context of\n+ the substituted closure type, we can find it in current_class_type,\n+ enumerate the expanded field pack, and then use that to expand the capture\n+ proxy pack.\n+\n+ This seems like cheating, but there's really no alternative since lambdas\n+ are not instantiated; we have to use the same closure type. To address this\n+ in the language, probably lambda constraints should be substituted\n+ immediately like lambda noexcept. */\n+\n+tree\n+reconstruct_lambda_capture_pack (tree pat, tree args, tsubst_flags_t complain,\n+\t\t\t\t tree in_decl)\n+{\n+ gcc_assert (cp_unevaluated_operand && !at_function_scope_p ());\n+ tree newc = current_class_type;\n+\n+ /* Look up the pattern FIELD_DECL. */\n+ tree oldfield = TREE_OPERAND (DECL_VALUE_EXPR (pat), 1);\n+ gcc_assert (DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (oldfield)))\n+\t == DECL_SOURCE_LOCATION (TYPE_NAME (newc)));\n+\n+ if (!retrieve_local_specialization (oldfield))\n+ {\n+ /* Look through TYPE_FIELDS to find captures with matching\n+\t capture#1 names. */\n+ tree pn = DECL_NAME (oldfield);\n+ const char *ps = IDENTIFIER_POINTER (pn);\n+ int pl = IDENTIFIER_LENGTH (pn);\n+ tree firstcap = NULL_TREE;\n+ int ncap = 0;\n+ for (tree f = next_subobject_field (TYPE_FIELDS (newc));\n+\t f; f = DECL_CHAIN (f))\n+\t{\n+\t const char *s = IDENTIFIER_POINTER (DECL_NAME (f));\n+\t if (strncmp (ps, s, pl) == 0 && s[pl] == '#')\n+\t {\n+\t if (!firstcap)\n+\t\tfirstcap = f;\n+\t ++ncap;\n+\t }\n+\t else if (firstcap)\n+\t break;\n+\t}\n+ tree fpack = make_tree_vec (ncap);\n+ for (int i = 0; i < ncap; ++i)\n+\t{\n+\t TREE_VEC_ELT (fpack, i) = firstcap;\n+\t firstcap = DECL_CHAIN (firstcap);\n+\t}\n+ tree spec = make_node (NONTYPE_ARGUMENT_PACK);\n+ ARGUMENT_PACK_ARGS (spec) = fpack;\n+ /* satisfy_declaration_constraints set up local_specializations. */\n+ register_local_specialization (spec, oldfield);\n+ }\n+\n+ /* Now that the field pack is in local_specializations, we can substitute\n+ into the DECL_VALUE_EXPR of the proxy. */\n+ tree ve = DECL_VALUE_EXPR (pat);\n+ ve = make_pack_expansion (ve);\n+ ve = tsubst_pack_expansion (ve, args, complain, in_decl);\n+ const int len = TREE_VEC_LENGTH (ve);\n+ tree ppack = make_tree_vec (len);\n+ for (int i = 0; i < len; ++i)\n+ {\n+ tree p = copy_decl (pat);\n+ tree vei = TREE_VEC_ELT (ve, i);\n+ SET_DECL_VALUE_EXPR (p, vei);\n+ TREE_TYPE (p) = lambda_proxy_type (vei);\n+ TREE_VEC_ELT (ppack, i) = p;\n+ }\n+ tree spec = make_node (NONTYPE_ARGUMENT_PACK);\n+ ARGUMENT_PACK_ARGS (spec) = ppack;\n+ register_local_specialization (spec, pat);\n+ return spec;\n+}\n+\n /* Substitute ARGS into T, which is a pack expansion\n (i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a\n TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node\n@@ -14139,6 +14222,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,\n else if (is_capture_proxy (parm_pack))\n \t{\n \t arg_pack = retrieve_local_specialization (parm_pack);\n+\t if (!arg_pack)\n+\t arg_pack = reconstruct_lambda_capture_pack (parm_pack, args,\n+\t\t\t\t\t\t\tcomplain, in_decl);\n \t if (DECL_DECOMPOSITION_P (arg_pack))\n \t {\n \t orig_arg = arg_pack;\n@@ -14147,6 +14233,9 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain,\n \t if (DECL_PACK_P (arg_pack))\n \t arg_pack = NULL_TREE;\n \t}\n+ else if (TREE_CODE (parm_pack) == FIELD_DECL)\n+\t/* For reconstruct_lambda_capture_pack. */\n+\targ_pack = retrieve_local_specialization (parm_pack);\n else if (DECL_DECOMPOSITION_P (parm_pack))\n \t{\n \t orig_arg = retrieve_local_specialization (parm_pack);\n@@ -16156,6 +16245,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,\n \t tcomplain |= tf_tst_ok;\n \t if (DECL_DECOMPOSITION_P (t) && DECL_PACK_P (t))\n \t type = NULL_TREE;\n+\t else if (is_capture_proxy (t) && WILDCARD_TYPE_P (type))\n+\t /* We'll set type from DECL_VALUE_EXPR. */\n+\t type = NULL_TREE;\n \t else\n \t type = tsubst (type, args, tcomplain, in_decl);\n \t /* Substituting the type might have recursively instantiated this\n@@ -16185,6 +16277,36 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,\n \t\tSET_TYPE_STRUCTURAL_EQUALITY (type);\n \t\tPACK_EXPANSION_PARAMETER_PACKS (type) = r;\n \t }\n+\t if (DECL_HAS_VALUE_EXPR_P (t))\n+\t {\n+\t\ttree ve = DECL_VALUE_EXPR (t);\n+\t\t/* If the DECL_VALUE_EXPR is converted to the declared type,\n+\t\t preserve the identity so that gimplify_type_sizes works. */\n+\t\tbool nop = (type && TREE_CODE (ve) == NOP_EXPR);\n+\t\tif (nop)\n+\t\t ve = TREE_OPERAND (ve, 0);\n+\t\tve = tsubst_expr (ve, args, complain, in_decl);\n+\t\tgcc_assert (ve != error_mark_node);\n+\t\tif (REFERENCE_REF_P (ve))\n+\t\t {\n+\t\t gcc_assert (!type || TYPE_REF_P (type));\n+\t\t ve = TREE_OPERAND (ve, 0);\n+\t\t }\n+\t\tif (nop)\n+\t\t ve = build_nop (type, ve);\n+\t\telse if (!type && is_capture_proxy (t))\n+\t\t type = lambda_proxy_type (ve);\n+\t\telse if (DECL_LANG_SPECIFIC (t)\n+\t\t\t && DECL_OMP_PRIVATIZED_MEMBER (t)\n+\t\t\t && TREE_CODE (ve) == COMPONENT_REF\n+\t\t\t && TREE_CODE (TREE_OPERAND (ve, 1)) == FIELD_DECL\n+\t\t\t && DECL_BIT_FIELD_TYPE (TREE_OPERAND (ve, 1)) == type)\n+\t\t type = TREE_TYPE (ve);\n+\t\telse\n+\t\t gcc_checking_assert (TYPE_MAIN_VARIANT (TREE_TYPE (ve))\n+\t\t\t\t == TYPE_MAIN_VARIANT (type));\n+\t\tSET_DECL_VALUE_EXPR (r, ve);\n+\t }\n \t if (TREE_CODE (type) == FUNCTION_TYPE)\n \t {\n \t\t/* It may seem that this case cannot occur, since:\n@@ -16212,33 +16334,6 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain,\n \t DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r) = 0;\n \t type = check_var_type (DECL_NAME (r), type,\n \t\t\t\t DECL_SOURCE_LOCATION (r));\n-\t if (DECL_HAS_VALUE_EXPR_P (t))\n-\t {\n-\t\ttree ve = DECL_VALUE_EXPR (t);\n-\t\t/* If the DECL_VALUE_EXPR is converted to the declared type,\n-\t\t preserve the identity so that gimplify_type_sizes works. */\n-\t\tbool nop = (TREE_CODE (ve) == NOP_EXPR);\n-\t\tif (nop)\n-\t\t ve = TREE_OPERAND (ve, 0);\n-\t\tve = tsubst_expr (ve, args, complain, in_decl);\n-\t\tif (REFERENCE_REF_P (ve))\n-\t\t {\n-\t\t gcc_assert (TYPE_REF_P (type));\n-\t\t ve = TREE_OPERAND (ve, 0);\n-\t\t }\n-\t\tif (nop)\n-\t\t ve = build_nop (type, ve);\n-\t\telse if (DECL_LANG_SPECIFIC (t)\n-\t\t\t && DECL_OMP_PRIVATIZED_MEMBER (t)\n-\t\t\t && TREE_CODE (ve) == COMPONENT_REF\n-\t\t\t && TREE_CODE (TREE_OPERAND (ve, 1)) == FIELD_DECL\n-\t\t\t && DECL_BIT_FIELD_TYPE (TREE_OPERAND (ve, 1)) == type)\n-\t\t type = TREE_TYPE (ve);\n-\t\telse\n-\t\t gcc_checking_assert (TYPE_MAIN_VARIANT (TREE_TYPE (ve))\n-\t\t\t\t == TYPE_MAIN_VARIANT (type));\n-\t\tSET_DECL_VALUE_EXPR (r, ve);\n-\t }\n \t }\n \telse if (DECL_SELF_REFERENCE_P (t))\n \t SET_DECL_SELF_REFERENCE_P (r);\n@@ -17030,6 +17125,19 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n case ENUMERAL_TYPE:\n if (TYPE_TEMPLATE_INFO (t) && uses_template_parms (t))\n \t{\n+\t if (LAMBDA_TYPE_P (t))\n+\t {\n+\t /* In reconstruct_lambda_capture_pack we need to be able to\n+\t\t rebuild the lambda closure parm, which means looking up the\n+\t\t closure type. See the comment for that function about using\n+\t\t current_class_type. */\n+\t tree c = current_class_type;\n+\t if (LAMBDA_TYPE_P (c)\n+\t\t && (DECL_SOURCE_LOCATION (TYPE_NAME (t))\n+\t\t == DECL_SOURCE_LOCATION (TYPE_NAME (c))))\n+\t\treturn c;\n+\t gcc_unreachable ();\n+\t }\n \t /* Figure out what arguments are appropriate for the\n \t type we are trying to find. For example, given:\n \n@@ -20991,6 +21099,8 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n /* If we're pushed into another scope (PR105652), fix it. */\n TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_NAME (type))\n = TYPE_CONTEXT (TREE_TYPE (t));\n+ DECL_SOURCE_LOCATION (TYPE_NAME (type))\n+ = DECL_SOURCE_LOCATION (TYPE_NAME (TREE_TYPE (t)));\n record_lambda_scope_discriminator (r);\n \n /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */\n@@ -22502,6 +22612,16 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)\n \t member = tsubst_baselink (member,\n \t\t\t\t non_reference (TREE_TYPE (object)),\n \t\t\t\t args, complain, in_decl);\n+\t/* In reconstruct_lambda_capture_pack, handle replacing the FIELD_DECL\n+\t pack with an element. */\n+\telse if (object_type && LAMBDA_TYPE_P (object_type)\n+\t\t && TREE_CODE (member) == FIELD_DECL\n+\t\t && (r = retrieve_local_specialization (member)))\n+\t {\n+\t if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)\n+\t r = argument_pack_select_arg (r);\n+\t member = r;\n+\t }\n \telse\n \t member = tsubst_name (member, args, complain, in_decl);\n \tif (member == error_mark_node)\ndiff --git a/gcc/testsuite/g++.dg/cpp23/lambda-scope10.C b/gcc/testsuite/g++.dg/cpp23/lambda-scope10.C\nnew file mode 100644\nindex 00000000000..a19dc290434\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/cpp23/lambda-scope10.C\n@@ -0,0 +1,19 @@\n+// PR c++/122884\n+// { dg-do compile { target c++23 } }\n+\n+struct demux_t {\n+ template <class Fn, class... Slots>\n+ static constexpr auto operator()(Fn&& fn, Slots&&... slots) {\n+ return [fn{fn}, ... slots{slots}]<class Self, class... Args>(\n+ this Self&&,\n+ Args&&... args)\n+ noexcept(noexcept(fn(slots(args...)...))) // comment this\n+ -> decltype(auto)\n+ requires requires { fn(slots(args...)...); } // and this, no longer crash\n+ { return fn(slots(args...)...); };\n+ }\n+} static constexpr demux{};\n+\n+static_assert(demux([](auto x, auto y) { return x + y; },\n+ [](auto...) { return 1; },\n+ [](auto...) { return 2; })(1, 2) == 3);\ndiff --git a/gcc/testsuite/g++.dg/cpp23/lambda-scope10a.C b/gcc/testsuite/g++.dg/cpp23/lambda-scope10a.C\nnew file mode 100644\nindex 00000000000..ade9a1eaf39\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/cpp23/lambda-scope10a.C\n@@ -0,0 +1,19 @@\n+// PR c++/122884\n+// { dg-do compile { target c++23 } }\n+\n+struct demux_t {\n+ template <class Fn, class... Slots>\n+ static constexpr auto operator()(Fn&& fn, Slots&&... slots) {\n+ return [fn{fn}, ... slots{slots}]<class Self, class... Args>(\n+ this Self&&,\n+ Args&&... args)\n+ noexcept(noexcept(fn(slots(args...)...))) // comment this\n+ -> decltype(auto)\n+\t requires (!noexcept (fn(slots(args...)...))) // and this, no longer crash\n+ { return fn(slots(args...)...); };\n+ }\n+} static constexpr demux{};\n+\n+static_assert(demux([](auto x, auto y) { return x + y; },\n+ [](auto...) { return 1; },\n+ [](auto...) { return 2; })(1, 2) == 3);\n", "prefixes": [ "pushed" ] }