[{"id":3674804,"web_url":"http://patchwork.ozlabs.org/comment/3674804/","msgid":"<573f3fe5-e7f5-42a9-aae5-2451916c7b0c@redhat.com>","list_archive_url":null,"date":"2026-04-08T14:27:06","subject":"Re: [PATCH v2] c++, contracts: No implicit capture in lambda contract\n assertions [PR124648].","submitter":{"id":4337,"url":"http://patchwork.ozlabs.org/api/people/4337/","name":"Jason Merrill","email":"jason@redhat.com"},"content":"On 4/8/26 5:47 AM, Iain Sandoe wrote:\n> \n>>> +#define DECL_CONTRACT_CAPTURE_P(NODE) \\\n>>> +  DECL_LANG_FLAG_8 (FIELD_DECL_CHECK (NODE))\n> \n>> All the #defines above have a comment so this one should have one too.\n>> Please also update the \"Usage of DECL_LANG_FLAG_?\" comment above.\n> \n> Oops... done,\n> \n>>> +      {\n>>> + tree le = LAMBDA_EXPR_CAPTURE_LIST (current_lambda_expr ());\n> \n>> Was this really meant to be current_lambda_expr() instead of lambda_expr?\n> \n> No, changed.\n> \n>>> + for (; le; le = TREE_CHAIN (le))\n> \n>> Why not put the LAMBDA_EXPR_CAPTURE_LIST in the for and then lose the\n>> { } in the if (flag_contracts)?\n> \n> I did not / do not particularly want to make every lambda walk the capture\n> list, but although we have a way to determine that there are pre/post\n> conditions on a function we do not have an easy way to determine that there\n> are any contract_asserts.  So for now the best I could think of doing was\n> to avoid the walk unless contracts are enabled.\n> Happy to go with any other flow that is preferred, of course,\n> \n> re-tested on x86_64-darwin / powerpc64le-linux, OK for trunk/when?\n> Iain\n> \n> --- 8< ---\n> \n> We were currently accepting invalid code by allowing contract assertions\n> to trigger implicit lambda captures contrary to:\n> [expr.prim.lambda.closure] / p10.\n> \n> The solution here is to mark captures that occur within contract\n> assertion scopes and then clear that mark if we then see a normal\n> capture for the same entity - we must defer the error handling since\n> the following is valid:\n> \n>    auto f5 = [=] {\n>      contract_assert (i > 0); // OK, i is referenced elsewhere.\n>      return i;\n>    };\n> \n> \tPR c++/124648\n> \n> gcc/cp/ChangeLog:\n> \n> \t* cp-tree.h (DECL_CONTRACT_CAPTURE_P): New.\n> \t* parser.cc (cp_parser_lambda_body): Scan the captures for\n> \tones were only added in contract assertion scopes.  Issue\n> \terrors for those found.\n> \t* semantics.cc (process_outer_var_ref): Mark implicit\n> \tcaptures that occur in contract assertion scopes.  Clear\n> \tthe mark if the entity is subsequently captured 'normally'.\n> \n> gcc/testsuite/ChangeLog:\n> \n> \t* g++.dg/contracts/cpp26/expr.prim.lambda.closure.p10.C: New test.\n> \n> Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>\n> ---\n>   gcc/cp/cp-tree.h                              |  8 +++\n>   gcc/cp/parser.cc                              | 21 ++++++++\n>   gcc/cp/semantics.cc                           | 27 ++++++++--\n>   .../cpp26/expr.prim.lambda.closure.p10.C      | 53 +++++++++++++++++++\n>   4 files changed, 106 insertions(+), 3 deletions(-)\n>   create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/expr.prim.lambda.closure.p10.C\n> \n> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h\n> index c0822da8283..352988294c3 100644\n> --- a/gcc/cp/cp-tree.h\n> +++ b/gcc/cp/cp-tree.h\n> @@ -593,6 +593,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];\n>         DECL_DECLARED_CONSTINIT_P (in VAR_DECL)\n>         TYPE_DECL_FOR_LINKAGE_PURPOSES_P (in TYPE_DECL)\n>      8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL)\n> +      DECL_CONTRACT_CAPTURE_P (in FIELD_DECL)\n>   \n>      Usage of language-independent fields in a language-dependent manner:\n>   \n> @@ -5367,6 +5368,13 @@ get_vec_init_expr (tree t)\n>   #define DECL_NORMAL_CAPTURE_P(NODE) \\\n>     DECL_LANG_FLAG_7 (FIELD_DECL_CHECK (NODE))\n>   \n> +/* True when a field decl relates to a lambda capture that has currently been\n> +   made to satisfy a use within a contract check.  Reset to false when the\n> +   capture is required outside a contract check.  Used to diagnose cases where\n> +   a capture is only made within contract checks.  */\n> +#define DECL_CONTRACT_CAPTURE_P(NODE) \\\n> +  DECL_LANG_FLAG_8 (FIELD_DECL_CHECK (NODE))\n> +\n>   /* Nonzero if TYPE is an anonymous union or struct type.  We have to use a\n>      flag for this because \"A union for which objects or pointers are\n>      declared is not an anonymous union\" [class.union].  */\n> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc\n> index 518858fc776..8b26a1de72d 100644\n> --- a/gcc/cp/parser.cc\n> +++ b/gcc/cp/parser.cc\n> @@ -13745,6 +13745,27 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)\n>          finish_function (which will try to emit the contracts).  */\n>       cp_parser_late_contracts (parser, fco);\n>   \n> +    /* Check that we have not caused captures that only relate to contracts.\n> +       [expr.prim.lambda.closure] / P10.  */\n> +    if (flag_contracts)\n> +      {\n> +\tgcc_checking_assert (current_lambda_expr () == lambda_expr);\n> +\tfor (tree le = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); le;\n> +\t     le = TREE_CHAIN (le))\n> +\t  {\n> +\t    tree cap_fld = TREE_PURPOSE (le);\n\nYou probably need to look through EXPR_PACK_EXPANSION here for a capture \npack.\n\n> +\t    if (TREE_CODE (cap_fld) == FIELD_DECL\n> +\t\t&& DECL_CONTRACT_CAPTURE_P (cap_fld))\n> +\t      {\n> +\t\tauto_diagnostic_group d;\n> +\t\ttree expr = TREE_VALUE (le);\n> +\t\tlocation_t loc = DECL_SOURCE_LOCATION (cap_fld);\n> +\t\terror_at (loc, \"%qE is not implicitly captured by a contract\"\n> +\t\t\t  \" assertion\", expr);\n> +\t\tinform (DECL_SOURCE_LOCATION (expr), \"%q#E declared here\", expr);\n> +\t      }\n> +\t  }\n> +      }\n>       finish_lambda_function (body);\n>     }\n>   \n> diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc\n> index abd1156a2dc..f836ab47ab5 100644\n> --- a/gcc/cp/semantics.cc\n> +++ b/gcc/cp/semantics.cc\n> @@ -4619,6 +4619,17 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)\n>   \n>         if (d && d != decl && is_capture_proxy (d))\n>   \t{\n> +\t  if (flag_contracts && !processing_contract_condition)\n> +\t    {\n> +\t      /* We might have created a capture for a contract_assert ref. to\n> +\t\t some var, if that is now captured 'normally' then this is OK.\n> +\t\t Otherwise we leave the capture marked as incorrect.  */\n> +\t      gcc_checking_assert (DECL_HAS_VALUE_EXPR_P (d));\n> +\t      tree proxy = DECL_VALUE_EXPR (d);\n> +\t      gcc_checking_assert (TREE_CODE (proxy) == COMPONENT_REF\n> +\t\t\t\t&& TREE_CODE (TREE_OPERAND (proxy, 1)) == FIELD_DECL);\n> +              DECL_CONTRACT_CAPTURE_P (TREE_OPERAND (proxy, 1)) = false;\n\nLet's factor out this pattern that only differs in the value we're setting.\n\n> +\t    }\n>   \t  if (DECL_CONTEXT (d) == containing_function)\n>   \t    /* We already have an inner proxy.  */\n>   \t    return d;\n> @@ -4667,10 +4678,20 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)\n>         return error_mark_node;\n>       }\n>     /* Do lambda capture when processing the id-expression, not when\n> -     odr-using a variable.  */\n> +     odr-using a variable, but uses in a contract must not cause a capture.  */\n>     if (!odr_use && context == containing_function)\n> -    decl = add_default_capture (lambda_stack,\n> -\t\t\t\t/*id=*/DECL_NAME (decl), initializer);\n> +    {\n> +      decl = add_default_capture (lambda_stack,\n> +\t\t\t\t  /*id=*/DECL_NAME (decl), initializer);\n> +      if (flag_contracts && processing_contract_condition)\n> +\t{\n> +\t  gcc_checking_assert (DECL_HAS_VALUE_EXPR_P (decl));\n> +\t  tree proxy = DECL_VALUE_EXPR (decl);\n> +\t  gcc_checking_assert (TREE_CODE (proxy) == COMPONENT_REF\n> +\t\t\t\t&& TREE_CODE (TREE_OPERAND (proxy, 1)) == FIELD_DECL);\n> +          DECL_CONTRACT_CAPTURE_P (TREE_OPERAND (proxy, 1)) = true;\n> +        }\n> +    }\n>     /* Only an odr-use of an outer automatic variable causes an\n>        error, and a constant variable can decay to a prvalue\n>        constant without odr-use.  So don't complain yet.  */\n> diff --git a/gcc/testsuite/g++.dg/contracts/cpp26/expr.prim.lambda.closure.p10.C b/gcc/testsuite/g++.dg/contracts/cpp26/expr.prim.lambda.closure.p10.C\n> new file mode 100644\n> index 00000000000..5a165c48166\n> --- /dev/null\n> +++ b/gcc/testsuite/g++.dg/contracts/cpp26/expr.prim.lambda.closure.p10.C\n> @@ -0,0 +1,53 @@\n> +// N5008 :\n> +// [expr.prim.lambda.closure]/p10\n> +// If all potential references to a local entity implicitly captured by a\n> +// lambda-expression L occur within the function contract assertions of the\n> +// call operator or operator template of L or within assertion-statements\n> +// within the body of L, the program is ill-formed.\n> +// [Note 4: Adding a contract assertion to an existing C++ program cannot\n> +//  cause additional captures. — end note]\n> +// { dg-do compile { target c++26 } }\n> +// { dg-additional-options \"-fcontracts -fsyntax-only\" }\n> +\n> +auto gl0 = [] (int x)\n> +  pre (x > 10) { return x; }; // OK\n> +\n> +static int i = 0;\n> +\n> +void\n> +foo ()\n> +{\n> +  auto f1 = [=]\n> +    pre (i > 0) {};  // OK, no local entities are captured.\n> +\n> +  int i = 1;\n> +\n> +  auto f2 = [=]\n> +    pre (i > 0) {};  // { dg-error {'i' is not implicitly captured by a contract assertion} }\n> +\n> +  auto f3 = [i]\n> +    pre (i > 0) {};  // OK, i is captured explicitly.\n> +\n> +  auto f4 = [=] {\n> +    contract_assert (i > 0); // { dg-error {'i' is not implicitly captured by a contract assertion} }\n> +  };\n> +\n> +  auto f5 = [=] {\n> +    contract_assert (i > 0); // OK, i is referenced elsewhere.\n> +    return i;\n> +  };\n> +\n> +  auto f6 = [=] pre (                // #1\n> +    []{\n> +      bool x = true;\n> +      return [=]{ return x; }();    // OK, #1 captures nothing.\n> +    }()) {};\n> +\n> +// TODO: lambda captures in function contract specifiers are not yet\n> +// fully functional.\n> +#if 0\n> +  bool y = true;\n> +  auto f7 = [=]\n> +    pre([=]{ return y; }()); // error: outer capture of y is invalid.\n> +#endif\n> +}","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=Y0hk6KAM;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::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=Y0hk6KAM","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\n [IPv6:2620:52:6:3111::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 4frQQF4wpKz1xv0\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 09 Apr 2026 00:27:48 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 33E624BA2E14\n\tfor <incoming@patchwork.ozlabs.org>; Wed,  8 Apr 2026 14:27:46 +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 433AF4BA5436\n for <gcc-patches@gcc.gnu.org>; Wed,  8 Apr 2026 14:27:12 +0000 (GMT)","from mail-qk1-f198.google.com (mail-qk1-f198.google.com\n [209.85.222.198]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-216-PRRroT6cMaaVKZmd6ZIJOg-1; Wed, 08 Apr 2026 10:27:10 -0400","by mail-qk1-f198.google.com with SMTP id\n af79cd13be357-8d3ea68b9cdso1251643685a.3\n for <gcc-patches@gcc.gnu.org>; Wed, 08 Apr 2026 07:27:10 -0700 (PDT)","from [192.168.50.130]\n (130-44-146-247.s12789.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com.\n [130.44.146.247]) by smtp.gmail.com with ESMTPSA id\n af79cd13be357-8db0d85a237sm175876185a.5.2026.04.08.07.27.07\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Wed, 08 Apr 2026 07:27:08 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 33E624BA2E14","OpenDKIM Filter v2.11.0 sourceware.org 433AF4BA5436"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 433AF4BA5436","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 433AF4BA5436","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775658432; cv=none;\n b=wn0wDUnPUkYmV8iv1VUV/mTH3hicUxSEJ5jSfW8WrBMV4v+0w3VatbuZYbJ3jdQ/UTRFmjDb9LaDG+B7rQTzTknIwi1TbD7toY4icniV5hvwXUWEUpzf1u4XrFwQ0dw4ytQ9q/inRSUJ49FJy2FwgYLC+CkgC71ai4jZIzi25Dk=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1775658432; c=relaxed/simple;\n bh=sPAypLOVetU04AIMde0It+3NJEz6OTg0vx8UM/lWNlU=;\n h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From;\n b=R1VGBLms5xikD/lpdOkQ9prTjD8TfcKxoGf+R8l+L2dflpQ2hUeFLud63nZ7NMKpZOKT6Nwz7DxOpGcnjw4jsNrrfXqKGMugoVOELjOEpEl8Pald3s7xhnjkGey1m3BwSf6Vyl9d6nHexzQ4SI8EU2tC7EV9Z4Yo1PDetdI6yN4=","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=1775658431;\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 in-reply-to:in-reply-to:references:references;\n bh=1LTmMFwfxofMnDZlqF7Q+fc9Qknqt8ZPYFDT4t0ilNg=;\n b=Y0hk6KAM2Nozlt1db7kVHCl/Y8eKuaFSpcaWSQTeS/pd4mAB8afLoEmJ7yurzKXKorvFe5\n GjfUxwRdrCEaSOfFz02Yl/NTJtZUHFt8ZXmU9gNPqp2kJA5U0A5JsnNzifBNZ+pDgipqPt\n 2JiCyu829z5ysVX8CtiC37zKKpxs+cc=","X-MC-Unique":"PRRroT6cMaaVKZmd6ZIJOg-1","X-Mimecast-MFC-AGG-ID":"PRRroT6cMaaVKZmd6ZIJOg_1775658430","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775658429; x=1776263229;\n h=content-transfer-encoding:in-reply-to:from:content-language\n :references:to:subject:user-agent:mime-version:date:message-id\n :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id\n :reply-to;\n bh=1LTmMFwfxofMnDZlqF7Q+fc9Qknqt8ZPYFDT4t0ilNg=;\n b=YeofdAznvsoKdpujMLljU7x5aAWfWFBvyHLZlZ/6sb12c08ffjGfftEP8M5cd16hbb\n A8jhowi8R6uKdGlCK/bLGeYHA22RLrhZ+EgtiYLcTUybLwt0DMJPkr0vn7pZGMggqalv\n VKAKH2WXuPi4DRfDunsn1yg2SkhlUZaC3j1LYgKN7E2exHO+4V6+lqrUGI/pldNfm229\n sr/NojB7pzVrcllJ4TIui65O1ENfhqFXSsEZqwUj+6GW4oaZFRqNAdrvoZjA5egSinLl\n C3ETJGyEFG4Yn6sEHeMdn/r1l2fo59w9aAoXQMXqufqFCMbJKzjDaCB/R+c5eMEeAAR5\n Y22g==","X-Forwarded-Encrypted":"i=1;\n AJvYcCX2NeTQcpiiehiJSkTSN5iiIzaOB2SHBsyRO6bFNbY96uekihuqHGc+lPgER/IlLN8fm/pyefq66ahrkg==@gcc.gnu.org","X-Gm-Message-State":"AOJu0YzR0n5Y+7o0KGga2RJgC0w4wvybhw/baiV7oHc5DdKRJQ2473/2\n JxrJczx1wCLqu+OBd+aeRM3PFYjpR4b3WuYm0fgaDpBVycM9ixDJADDMBnvIJRplc5bqZQmyR2W\n sgSUSnRDrZFo4iYPu9MrQAzHDndLMCUdr01v5DkNccVxEahIugW9CTWbf9mKBQ+6kMfc=","X-Gm-Gg":"AeBDietqnTVtc6C1VC/cX801+nfzeHaO/wCyHfW+vY83+hu156QARqpTIjf81B2VjnS\n TLR05ZMqjLk5oIdVGKAC1PpF02xC9AuMhrmMBNRZJBy2j09VDuh9PpoPbS+lYmRlcMx4+2nslBg\n +XxWmPSRTXB04Puo2DwULrhaNPbCoGdTAbED3SEPfBvWLt6Iqb7R1PHaQpx0v9ywK8Igx9Fr+ok\n rmRhFCmiaKxTm5ZGMW+MFJDR33iLgLUe8jkkABwzU+Le4O5uMX7bEt9x9duuXsLBNgabcXXzcqr\n KXL1GtWXCYERHQ30w1f2vw+DBxoiQN4DU65hAFrOlckAuodSDJaS12Xro73X0GucJguYm8n97gV\n /DPwZ94E8bgT/Y8WY4zhzQ2VtkIbx/08ShG1qWPsjxCzIQmPJKzfQ2Sm0vDGRhphfX4p6QPmLiM\n AlLkyh5q+9gyn2WXIfT+xtMk6K8ry3rtc=","X-Received":["by 2002:a05:620a:170e:b0:8ca:4288:b168 with SMTP id\n af79cd13be357-8d41dd41782mr2917126385a.42.1775658429313;\n Wed, 08 Apr 2026 07:27:09 -0700 (PDT)","by 2002:a05:620a:170e:b0:8ca:4288:b168 with SMTP id\n af79cd13be357-8d41dd41782mr2917121785a.42.1775658428711;\n Wed, 08 Apr 2026 07:27:08 -0700 (PDT)"],"Message-ID":"<573f3fe5-e7f5-42a9-aae5-2451916c7b0c@redhat.com>","Date":"Wed, 8 Apr 2026 10:27:06 -0400","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2] c++, contracts: No implicit capture in lambda contract\n assertions [PR124648].","To":"iain@sandoe.co.uk, polacek@redhat.com, gcc-patches@gcc.gnu.org","References":"<acV586ggm1HnlZAL@redhat.com>\n <20260408094730.49390-1-iain@sandoe.co.uk>","From":"Jason Merrill <jason@redhat.com>","In-Reply-To":"<20260408094730.49390-1-iain@sandoe.co.uk>","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"Y17FvoWHpYyNxtIKvzb-ir7QOJciFyY-ULtZQ7UDnIg_1775658430","X-Mimecast-Originator":"redhat.com","Content-Language":"en-US","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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"}},{"id":3677825,"web_url":"http://patchwork.ozlabs.org/comment/3677825/","msgid":"<6b5ca19b-3c7a-4ea7-9acb-59231fe7203a@redhat.com>","list_archive_url":null,"date":"2026-04-15T21:27:17","subject":"Re: [PATCH v2] c++, contracts: No implicit capture in lambda contract\n assertions [PR124648].","submitter":{"id":4337,"url":"http://patchwork.ozlabs.org/api/people/4337/","name":"Jason Merrill","email":"jason@redhat.com"},"content":"On 4/8/26 10:27 AM, Jason Merrill wrote:\n> On 4/8/26 5:47 AM, Iain Sandoe wrote:\n>>\n>>>> +#define DECL_CONTRACT_CAPTURE_P(NODE) \\\n>>>> +  DECL_LANG_FLAG_8 (FIELD_DECL_CHECK (NODE))\n>>\n>>> All the #defines above have a comment so this one should have one too.\n>>> Please also update the \"Usage of DECL_LANG_FLAG_?\" comment above.\n>>\n>> Oops... done,\n>>\n>>>> +      {\n>>>> + tree le = LAMBDA_EXPR_CAPTURE_LIST (current_lambda_expr ());\n>>\n>>> Was this really meant to be current_lambda_expr() instead of \n>>> lambda_expr?\n>>\n>> No, changed.\n>>\n>>>> + for (; le; le = TREE_CHAIN (le))\n>>\n>>> Why not put the LAMBDA_EXPR_CAPTURE_LIST in the for and then lose the\n>>> { } in the if (flag_contracts)?\n>>\n>> I did not / do not particularly want to make every lambda walk the \n>> capture\n>> list, but although we have a way to determine that there are pre/post\n>> conditions on a function we do not have an easy way to determine that \n>> there\n>> are any contract_asserts.  So for now the best I could think of doing was\n>> to avoid the walk unless contracts are enabled.\n>> Happy to go with any other flow that is preferred, of course,\n>>\n>> re-tested on x86_64-darwin / powerpc64le-linux, OK for trunk/when?\n>> Iain\n>>\n>> --- 8< ---\n>>\n>> We were currently accepting invalid code by allowing contract assertions\n>> to trigger implicit lambda captures contrary to:\n>> [expr.prim.lambda.closure] / p10.\n>>\n>> The solution here is to mark captures that occur within contract\n>> assertion scopes and then clear that mark if we then see a normal\n>> capture for the same entity - we must defer the error handling since\n>> the following is valid:\n>>\n>>    auto f5 = [=] {\n>>      contract_assert (i > 0); // OK, i is referenced elsewhere.\n>>      return i;\n>>    };\n>>\n>>     PR c++/124648\n>>\n>> gcc/cp/ChangeLog:\n>>\n>>     * cp-tree.h (DECL_CONTRACT_CAPTURE_P): New.\n>>     * parser.cc (cp_parser_lambda_body): Scan the captures for\n>>     ones were only added in contract assertion scopes.  Issue\n>>     errors for those found.\n>>     * semantics.cc (process_outer_var_ref): Mark implicit\n>>     captures that occur in contract assertion scopes.  Clear\n>>     the mark if the entity is subsequently captured 'normally'.\n>>\n>> gcc/testsuite/ChangeLog:\n>>\n>>     * g++.dg/contracts/cpp26/expr.prim.lambda.closure.p10.C: New test.\n>>\n>> Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>\n>> ---\n>>   gcc/cp/cp-tree.h                              |  8 +++\n>>   gcc/cp/parser.cc                              | 21 ++++++++\n>>   gcc/cp/semantics.cc                           | 27 ++++++++--\n>>   .../cpp26/expr.prim.lambda.closure.p10.C      | 53 +++++++++++++++++++\n>>   4 files changed, 106 insertions(+), 3 deletions(-)\n>>   create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/ \n>> expr.prim.lambda.closure.p10.C\n>>\n>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h\n>> index c0822da8283..352988294c3 100644\n>> --- a/gcc/cp/cp-tree.h\n>> +++ b/gcc/cp/cp-tree.h\n>> @@ -593,6 +593,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];\n>>         DECL_DECLARED_CONSTINIT_P (in VAR_DECL)\n>>         TYPE_DECL_FOR_LINKAGE_PURPOSES_P (in TYPE_DECL)\n>>      8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL)\n>> +      DECL_CONTRACT_CAPTURE_P (in FIELD_DECL)\n>>      Usage of language-independent fields in a language-dependent manner:\n>> @@ -5367,6 +5368,13 @@ get_vec_init_expr (tree t)\n>>   #define DECL_NORMAL_CAPTURE_P(NODE) \\\n>>     DECL_LANG_FLAG_7 (FIELD_DECL_CHECK (NODE))\n>> +/* True when a field decl relates to a lambda capture that has \n>> currently been\n>> +   made to satisfy a use within a contract check.  Reset to false \n>> when the\n>> +   capture is required outside a contract check.  Used to diagnose \n>> cases where\n>> +   a capture is only made within contract checks.  */\n>> +#define DECL_CONTRACT_CAPTURE_P(NODE) \\\n>> +  DECL_LANG_FLAG_8 (FIELD_DECL_CHECK (NODE))\n>> +\n>>   /* Nonzero if TYPE is an anonymous union or struct type.  We have to \n>> use a\n>>      flag for this because \"A union for which objects or pointers are\n>>      declared is not an anonymous union\" [class.union].  */\n>> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc\n>> index 518858fc776..8b26a1de72d 100644\n>> --- a/gcc/cp/parser.cc\n>> +++ b/gcc/cp/parser.cc\n>> @@ -13745,6 +13745,27 @@ cp_parser_lambda_body (cp_parser* parser, \n>> tree lambda_expr)\n>>          finish_function (which will try to emit the contracts).  */\n>>       cp_parser_late_contracts (parser, fco);\n>> +    /* Check that we have not caused captures that only relate to \n>> contracts.\n>> +       [expr.prim.lambda.closure] / P10.  */\n>> +    if (flag_contracts)\n>> +      {\n>> +    gcc_checking_assert (current_lambda_expr () == lambda_expr);\n>> +    for (tree le = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); le;\n>> +         le = TREE_CHAIN (le))\n>> +      {\n>> +        tree cap_fld = TREE_PURPOSE (le);\n> \n> You probably need to look through EXPR_PACK_EXPANSION here for a capture \n> pack.\n\nActually it's fine that we don't check this in a dependent lambda, but\nI tried adding such a testcase, and it fails early; it seems that lambda \ncontracts aren't instantiated by tsubst_lambda_expr, so we try to \nevaluate the unsubstituted expression.\n\ntemplate <class T, class...Ts>\nvoid\nbar (T t, Ts... ts)\n{\n   auto f1 = [=]\n     pre ((ts + ...) == 0) {};\n}\n\ntemplate void bar<int,short,char>(int, short, char);\n\nIn the meantime I'll test and push this with the refactoring I mentioned.\n\nJason","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=WNsKV/zE;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::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=WNsKV/zE","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.129.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::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 4fwvPk3j8Cz1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 07:27:53 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 41B3D4BA2E23\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 15 Apr 2026 21:27:51 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id 1A4D94BA2E07\n for <gcc-patches@gcc.gnu.org>; Wed, 15 Apr 2026 21:27:22 +0000 (GMT)","from mail-vs1-f71.google.com (mail-vs1-f71.google.com\n [209.85.217.71]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-205--Si0adjtMSie3EH_Tvk-lA-1; Wed, 15 Apr 2026 17:27:20 -0400","by mail-vs1-f71.google.com with SMTP id\n ada2fe7eead31-6130270a5f1so1764032137.1\n for <gcc-patches@gcc.gnu.org>; Wed, 15 Apr 2026 14:27:20 -0700 (PDT)","from [192.168.50.130]\n (130-44-146-247.s12789.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com.\n [130.44.146.247]) by smtp.gmail.com with ESMTPSA id\n 6a1803df08f44-8ae6cb9eb02sm26090636d6.25.2026.04.15.14.27.17\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Wed, 15 Apr 2026 14:27:18 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 41B3D4BA2E23","OpenDKIM Filter v2.11.0 sourceware.org 1A4D94BA2E07"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 1A4D94BA2E07","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 1A4D94BA2E07","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776288442; cv=none;\n b=YET1FMGxeDTQ9EpLA5wGgrhUaE5093R9v07+B2DrXV5+066I31LGZU0gfel7IsvR2gCTjRsLetAEjRvtLLzP+iylyzXMUOPplIwYEY91S2NNKk6ht9Ieg8nVyyn1VEb+qMy+qHrc97cSoW2LgrVhQwomjkQIvF+uMpcUD5kszsc=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776288442; c=relaxed/simple;\n bh=Q3Rr+ooZXaS+vNxndnL28x8NRhDBF/UFZOQULJuJk3I=;\n h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:From:To;\n b=ZxLgmvIhigJq/fmEwvYlWELdUiN95bMF9hWRjKzsxel8d/Fq3QpvT+5qPbJHYfu+sKnYK2+n9o3AlCRVQxrRisbu+gGogvE/n7YAJ+YISfzkd8l1eMbGjhwA1u2V1b+K8RXsBrn0Sqjcsb3X+FW4j1UlrvoEHhcT9+scSIUvWTE=","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=1776288441;\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 in-reply-to:in-reply-to:references:references;\n bh=JVrl3JzSa9YsJDpOqxnVdYg8cZbZRqU5VXLQq6vWUqw=;\n b=WNsKV/zEs8mo3oSELSfs5kV9tA1rDf/jRpTcv7E8kT6S5U1SZ+2iRbK1rupA/5iR/Pr4Z3\n vhm969IYUKpKXjZ/FPJwKSyr1Ual478lmUgbMyp9fdWO7jQnHAJXi4KQWfjbTiET7XQUEP\n Pw8dblltihVelbtvCKiwgHkxcThlCHM=","X-MC-Unique":"-Si0adjtMSie3EH_Tvk-lA-1","X-Mimecast-MFC-AGG-ID":"-Si0adjtMSie3EH_Tvk-lA_1776288440","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776288440; x=1776893240;\n h=content-transfer-encoding:in-reply-to:content-language:references\n :to:from:subject:user-agent:mime-version:date:message-id:x-gm-gg\n :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;\n bh=JVrl3JzSa9YsJDpOqxnVdYg8cZbZRqU5VXLQq6vWUqw=;\n b=NKIkQbJ8SdeuC4RVDatIB4JySsWfGG0hEM7CVK62Tja9RkNTJ4/IKW+Oqd2ijtD2R/\n 9P7CD1t5QILljQWcUgT7qRilvr8tOXZBYkT9w+M1bLxU/UhFWuyEj9QSZgl6lsRQhzsI\n BVrmIZQrhTkwjRwDDUu/hNBFBqWwkeIO4+3b7HsX37dbA423fAij9zzQpuPOn8S0gF9v\n vfKAKlACsYUcZJ3EG3SVKrCkBkRbIsXAvtVvz46ntbmf0YOM4c9/QEs/zfmERVbjPKzQ\n hlRqAafc+Hd4tZGR0eK8uxJ8jBR7HIKNHonPdVoT1HJSZZWqUDMC0dsmWvN9pBo8dfqq\n 0rJw==","X-Forwarded-Encrypted":"i=1;\n AFNElJ8uGJcQHnxoiboI9hNm0vIRIfa5CWVutKWH3yhXT3a+JtJQlW5mFlxJd2CP3JX9NGUceV+wwRzeF9LfuA==@gcc.gnu.org","X-Gm-Message-State":"AOJu0YzSn/QaLqMYXLjlcZ0y9RIGcuJ2moAN9vpyRXbwZK3+TbLstPdT\n SYpjr2kOxh5Fw0gFhM+ljdXRdwD1dpxX3H1AwLOX0VGYI6dfKWoUaval6VJPycX/C/U9IfSEI07\n JTjzbhkK8Ybtx8rs+PPI6zmrq/4oJd74GnA7aXTSoXpihtB/5r6lzpbqUOtE=","X-Gm-Gg":"AeBDieuDvVWqhbzKfV+RjojhUfMMhsh1MFwmqGPBRrU4MmjHhD9KaJxWtXzTGOOslIO\n gpir+4mxW41Oj7RfgGLBm1EoX0XFgQT8iRGgitn9ugtoW1tzsNg/YJ0ZJS+mlZsrAmXeRrfR2lT\n Fj0tFZ7VK/S+DCK674wUCeGhrg6Hphq3B+ER5bQuMG454TUdZmLGk72MphjMUoXPb0SPDzT5lga\n h5pEysrDCC7JIvR6EU8qCEfSVyhj+AQzQWp89shJm4epQ3TGu1yZ35MHqOpyeeHIdRRDyXwB57G\n vPKpIAauTHVHa88Vrpk8LVkCrsZ4Q3B/DAGYCAD8HkJwRxcIllqNsx3IUn9CwOKbVWinhUlJnn7\n PP6iojZfrteo85kl9M8ZmfSNaoZn4ekCQH8mJkREx7ktfflj0FJAOOi0LJoaUoU6pcC5Ab28EAk\n nTqyGCHSkNcvusEGn7Aefc2yGzlOZolkvCzkO8uK1lAg==","X-Received":["by 2002:a05:6102:5106:b0:602:ba51:5235 with SMTP id\n ada2fe7eead31-60a0136cf48mr11709673137.29.1776288439441;\n Wed, 15 Apr 2026 14:27:19 -0700 (PDT)","by 2002:a05:6102:5106:b0:602:ba51:5235 with SMTP id\n ada2fe7eead31-60a0136cf48mr11709630137.29.1776288438912;\n Wed, 15 Apr 2026 14:27:18 -0700 (PDT)"],"Message-ID":"<6b5ca19b-3c7a-4ea7-9acb-59231fe7203a@redhat.com>","Date":"Wed, 15 Apr 2026 17:27:17 -0400","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2] c++, contracts: No implicit capture in lambda contract\n assertions [PR124648].","From":"Jason Merrill <jason@redhat.com>","To":"iain@sandoe.co.uk, polacek@redhat.com, gcc-patches@gcc.gnu.org","References":"<acV586ggm1HnlZAL@redhat.com>\n <20260408094730.49390-1-iain@sandoe.co.uk>\n <573f3fe5-e7f5-42a9-aae5-2451916c7b0c@redhat.com>","In-Reply-To":"<573f3fe5-e7f5-42a9-aae5-2451916c7b0c@redhat.com>","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"cDNnmWep0CnLWmwcpeqZ4MO6GUyZKR9Di0n16UTqNdg_1776288440","X-Mimecast-Originator":"redhat.com","Content-Language":"en-US","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","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"}},{"id":3677882,"web_url":"http://patchwork.ozlabs.org/comment/3677882/","msgid":"<95251e08-07f1-43c0-bc38-17ff0954277a@redhat.com>","list_archive_url":null,"date":"2026-04-16T00:29:52","subject":"Re: [PATCH v2] c++, contracts: No implicit capture in lambda contract\n assertions [PR124648].","submitter":{"id":4337,"url":"http://patchwork.ozlabs.org/api/people/4337/","name":"Jason Merrill","email":"jason@redhat.com"},"content":"On 4/15/26 5:27 PM, Jason Merrill wrote:\n> On 4/8/26 10:27 AM, Jason Merrill wrote:\n>> On 4/8/26 5:47 AM, Iain Sandoe wrote:\n>>>\n>>>>> +#define DECL_CONTRACT_CAPTURE_P(NODE) \\\n>>>>> +  DECL_LANG_FLAG_8 (FIELD_DECL_CHECK (NODE))\n>>>\n>>>> All the #defines above have a comment so this one should have one too.\n>>>> Please also update the \"Usage of DECL_LANG_FLAG_?\" comment above.\n>>>\n>>> Oops... done,\n>>>\n>>>>> +      {\n>>>>> + tree le = LAMBDA_EXPR_CAPTURE_LIST (current_lambda_expr ());\n>>>\n>>>> Was this really meant to be current_lambda_expr() instead of \n>>>> lambda_expr?\n>>>\n>>> No, changed.\n>>>\n>>>>> + for (; le; le = TREE_CHAIN (le))\n>>>\n>>>> Why not put the LAMBDA_EXPR_CAPTURE_LIST in the for and then lose the\n>>>> { } in the if (flag_contracts)?\n>>>\n>>> I did not / do not particularly want to make every lambda walk the \n>>> capture\n>>> list, but although we have a way to determine that there are pre/post\n>>> conditions on a function we do not have an easy way to determine that \n>>> there\n>>> are any contract_asserts.  So for now the best I could think of doing \n>>> was\n>>> to avoid the walk unless contracts are enabled.\n>>> Happy to go with any other flow that is preferred, of course,\n>>>\n>>> re-tested on x86_64-darwin / powerpc64le-linux, OK for trunk/when?\n>>> Iain\n>>>\n>>> --- 8< ---\n>>>\n>>> We were currently accepting invalid code by allowing contract assertions\n>>> to trigger implicit lambda captures contrary to:\n>>> [expr.prim.lambda.closure] / p10.\n>>>\n>>> The solution here is to mark captures that occur within contract\n>>> assertion scopes and then clear that mark if we then see a normal\n>>> capture for the same entity - we must defer the error handling since\n>>> the following is valid:\n>>>\n>>>    auto f5 = [=] {\n>>>      contract_assert (i > 0); // OK, i is referenced elsewhere.\n>>>      return i;\n>>>    };\n>>>\n>>>     PR c++/124648\n>>>\n>>> gcc/cp/ChangeLog:\n>>>\n>>>     * cp-tree.h (DECL_CONTRACT_CAPTURE_P): New.\n>>>     * parser.cc (cp_parser_lambda_body): Scan the captures for\n>>>     ones were only added in contract assertion scopes.  Issue\n>>>     errors for those found.\n>>>     * semantics.cc (process_outer_var_ref): Mark implicit\n>>>     captures that occur in contract assertion scopes.  Clear\n>>>     the mark if the entity is subsequently captured 'normally'.\n>>>\n>>> gcc/testsuite/ChangeLog:\n>>>\n>>>     * g++.dg/contracts/cpp26/expr.prim.lambda.closure.p10.C: New test.\n>>>\n>>> Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>\n>>> ---\n>>>   gcc/cp/cp-tree.h                              |  8 +++\n>>>   gcc/cp/parser.cc                              | 21 ++++++++\n>>>   gcc/cp/semantics.cc                           | 27 ++++++++--\n>>>   .../cpp26/expr.prim.lambda.closure.p10.C      | 53 +++++++++++++++++++\n>>>   4 files changed, 106 insertions(+), 3 deletions(-)\n>>>   create mode 100644 gcc/testsuite/g++.dg/contracts/cpp26/ \n>>> expr.prim.lambda.closure.p10.C\n>>>\n>>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h\n>>> index c0822da8283..352988294c3 100644\n>>> --- a/gcc/cp/cp-tree.h\n>>> +++ b/gcc/cp/cp-tree.h\n>>> @@ -593,6 +593,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];\n>>>         DECL_DECLARED_CONSTINIT_P (in VAR_DECL)\n>>>         TYPE_DECL_FOR_LINKAGE_PURPOSES_P (in TYPE_DECL)\n>>>      8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL)\n>>> +      DECL_CONTRACT_CAPTURE_P (in FIELD_DECL)\n>>>      Usage of language-independent fields in a language-dependent \n>>> manner:\n>>> @@ -5367,6 +5368,13 @@ get_vec_init_expr (tree t)\n>>>   #define DECL_NORMAL_CAPTURE_P(NODE) \\\n>>>     DECL_LANG_FLAG_7 (FIELD_DECL_CHECK (NODE))\n>>> +/* True when a field decl relates to a lambda capture that has \n>>> currently been\n>>> +   made to satisfy a use within a contract check.  Reset to false \n>>> when the\n>>> +   capture is required outside a contract check.  Used to diagnose \n>>> cases where\n>>> +   a capture is only made within contract checks.  */\n>>> +#define DECL_CONTRACT_CAPTURE_P(NODE) \\\n>>> +  DECL_LANG_FLAG_8 (FIELD_DECL_CHECK (NODE))\n>>> +\n>>>   /* Nonzero if TYPE is an anonymous union or struct type.  We have \n>>> to use a\n>>>      flag for this because \"A union for which objects or pointers are\n>>>      declared is not an anonymous union\" [class.union].  */\n>>> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc\n>>> index 518858fc776..8b26a1de72d 100644\n>>> --- a/gcc/cp/parser.cc\n>>> +++ b/gcc/cp/parser.cc\n>>> @@ -13745,6 +13745,27 @@ cp_parser_lambda_body (cp_parser* parser, \n>>> tree lambda_expr)\n>>>          finish_function (which will try to emit the contracts).  */\n>>>       cp_parser_late_contracts (parser, fco);\n>>> +    /* Check that we have not caused captures that only relate to \n>>> contracts.\n>>> +       [expr.prim.lambda.closure] / P10.  */\n>>> +    if (flag_contracts)\n>>> +      {\n>>> +    gcc_checking_assert (current_lambda_expr () == lambda_expr);\n>>> +    for (tree le = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); le;\n>>> +         le = TREE_CHAIN (le))\n>>> +      {\n>>> +        tree cap_fld = TREE_PURPOSE (le);\n>>\n>> You probably need to look through EXPR_PACK_EXPANSION here for a \n>> capture pack.\n> \n> Actually it's fine that we don't check this in a dependent lambda, but\n> I tried adding such a testcase, and it fails early; it seems that lambda \n> contracts aren't instantiated by tsubst_lambda_expr, so we try to \n> evaluate the unsubstituted expression.\n> \n> template <class T, class...Ts>\n> void\n> bar (T t, Ts... ts)\n> {\n>    auto f1 = [=]\n>      pre ((ts + ...) == 0) {};\n> }\n> \n> template void bar<int,short,char>(int, short, char);\n> \n> In the meantime I'll test and push this with the refactoring I mentioned.\n\nThus:","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=Pj7RKbhe;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::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=Pj7RKbhe","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.129.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::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 4fwzST1GkXz1yG9\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 10:30:31 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id C921F4BA2E3C\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 00:30:29 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id C2FD94BA2E3C\n for <gcc-patches@gcc.gnu.org>; Thu, 16 Apr 2026 00:29:58 +0000 (GMT)","from mail-qv1-f70.google.com (mail-qv1-f70.google.com\n [209.85.219.70]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-373-9_PhS52EM7iwuADP1xg4oQ-1; Wed, 15 Apr 2026 20:29:56 -0400","by mail-qv1-f70.google.com with SMTP id\n 6a1803df08f44-8ae752c5273so23631626d6.2\n for <gcc-patches@gcc.gnu.org>; Wed, 15 Apr 2026 17:29:56 -0700 (PDT)","from [192.168.50.130]\n (130-44-146-247.s12789.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com.\n [130.44.146.247]) by smtp.gmail.com with ESMTPSA id\n 6a1803df08f44-8ae6ceb891csm23703396d6.48.2026.04.15.17.29.53\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Wed, 15 Apr 2026 17:29:53 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org C921F4BA2E3C","OpenDKIM Filter v2.11.0 sourceware.org C2FD94BA2E3C"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org C2FD94BA2E3C","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org C2FD94BA2E3C","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776299398; cv=none;\n b=rHOtxNkDrMIycshC5glUedb3YwqWPV2zE7D+EuTlZkIyXnTAt+CatO9xa0loeQTILGbL4Mel7GPb2pm7IiokQQSNQTXOYB1YgiZJf7kNrRnkkKYjfrnag0y9nVmIb6E5w1vzAOimgxUXV9dJbL2VFTFaUkfJTSv3M9hh8WHVVb8=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776299398; c=relaxed/simple;\n bh=T51wHn3ReoiXTGd57wB7AUDkINYPbo0OKbFmQ4u5a/M=;\n h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:From:To;\n b=DMBhZQuwDg90kQ/UDv7i+XG5IxnrphRT8uFp0xTu/KgbcDgJ/BjfRc5KUjEaFcxEQ0UMNKE5SQtfXxu5U6/sv0ZO1hHek0lFXtuk53g6HPBK5kHrbLWNjk6XgvFf6YfWr1zXERqr+DAQCK+sAleLhKUhx0Cq/73yA3cmKnqETzg=","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=1776299398;\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 in-reply-to:in-reply-to:references:references;\n bh=/vwzyBTBQClwPQmV6B7pNJWQ/BVRUB3JAhF3LY2czGI=;\n b=Pj7RKbheSjwUM5l3qCXmB5ly+FLI08zBWAQsuHpMI+cCeeWD+1QLGnerNh+qRpIkftBlX8\n k5fsTcs7Qmcpf+2jIJEIfVqHcP1b0HKCrZ1HUUGn4uFCFuGYcz02x/aNPk7qZfnGtTAide\n bwYLyNk8Q8uEyeZAGWImAel3QE+vkOc=","X-MC-Unique":"9_PhS52EM7iwuADP1xg4oQ-1","X-Mimecast-MFC-AGG-ID":"9_PhS52EM7iwuADP1xg4oQ_1776299395","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776299395; x=1776904195;\n h=in-reply-to:content-language:references:to:from:subject:user-agent\n :mime-version:date:message-id:x-gm-gg:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=uQ9F4VS4NCYlkwwo7LX1c+jC0pgIUepH+xvL0O2X5B4=;\n b=Wlo46LHc2dHJ8CVmSBz1kiI0DewFAyZeDFUP23T1qmT0sITA7BE/y/xvtL32pZpygq\n +5x+kauF7DrzdFcfnJilX9qRvuZcmnt6NWX1xiEdN6MHKvH5C2SHKZLmYNsgK8nae5WK\n BDLU2Up2bKHus8N9uu5yt4M9OiXKyyKKMDdz8suXRXWJVDBzG4yVpfgNbimAyWwU82M0\n uwI1jvmmUrDFqktLBvDy3vTODeivjrcN94Gh7llLzhlvh6OOVPcJULf/RbAhRskPNOhi\n HXOxQHbAwotVjEYESaKhvyPGCfMyTXhg4iSJXjeA+m8TXcF9xgMcOe5r14jTpIhBQymf\n jsjA==","X-Forwarded-Encrypted":"i=1;\n AFNElJ+x3xZAqLkxk9Oy8wRIsqh0aoOjAGG3F8jv70k8O3/YF5cpu3k59t7K1GVPIptfWbCm/I+u0v9vMYmh7A==@gcc.gnu.org","X-Gm-Message-State":"AOJu0YwI+jyasW+IdNaac0jZZDzBk2MehakxsOBFfSbRM8vc0vRkXFuW\n Gzne0l0BHodbxY9DrFSD+wvPSQI9zkEquXPTK53CG1FAOuj4pFGD46lMcg3wnsDcaG+MjlmzdzM\n a/LhTh8E0KP25PrFdAPkMfi5cvd88a5NFQB/BmXMnUlfsS3rbKGulGFRleJc=","X-Gm-Gg":"AeBDieuK/l86GozCZx4/D0vxf/naBLiXuOP4X7eM6YDEljgzL8aGKnVm31gGO+/EgIZ\n rNBLu9NARwsNop8xwvrikfomwCr5DmzqSNLxFRUnZi847o97nzZbYQ4G8Z6M1SXkWAXfqV9HrW7\n WbLu5NhUF7k0HdL6TMOUzWxcouE47WCoQIb+t+k8xYcBI3c5x8FZ1Rvx96nXsDFCtEzvAbDhN5i\n jrryOykxPEBP3kyo6H0+BnL7Uc6lkzBPqzhYD0vy5mVlLtGpwQQQej5IuYHsuWYmF5yyN9dOIrk\n eoQ1gHV4mGK0ACdkSMfS4a0gTeC2nBl8Rnd8FWW5c/VWjKmfQ9Lf1TCnt3OvzUa3xOj0+/32uVa\n nhGdCuhb0FCa5lDQJAH5EvyepYEeV4X754J44WXmcatKwO4UipTGFvf2zqEipsfMtlD/nQYSnyQ\n vWTh7ASd/SXSEluVFkluNu1AKA0z4QSsDhvcPKyNLDsA==","X-Received":["by 2002:a05:620a:6914:b0:8cd:87aa:e3e1 with SMTP id\n af79cd13be357-8ddce3c9130mr3332355285a.29.1776299395423;\n Wed, 15 Apr 2026 17:29:55 -0700 (PDT)","by 2002:a05:620a:6914:b0:8cd:87aa:e3e1 with SMTP id\n af79cd13be357-8ddce3c9130mr3332351885a.29.1776299394932;\n Wed, 15 Apr 2026 17:29:54 -0700 (PDT)"],"Message-ID":"<95251e08-07f1-43c0-bc38-17ff0954277a@redhat.com>","Date":"Wed, 15 Apr 2026 20:29:52 -0400","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v2] c++, contracts: No implicit capture in lambda contract\n assertions [PR124648].","From":"Jason Merrill <jason@redhat.com>","To":"iain@sandoe.co.uk, polacek@redhat.com, gcc-patches@gcc.gnu.org","References":"<acV586ggm1HnlZAL@redhat.com>\n <20260408094730.49390-1-iain@sandoe.co.uk>\n <573f3fe5-e7f5-42a9-aae5-2451916c7b0c@redhat.com>\n <6b5ca19b-3c7a-4ea7-9acb-59231fe7203a@redhat.com>","In-Reply-To":"<6b5ca19b-3c7a-4ea7-9acb-59231fe7203a@redhat.com>","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"u5NLtOjM5JpWUUMNOgRzb0p-R6ibITG-j_cxmaSFZvc_1776299395","X-Mimecast-Originator":"redhat.com","Content-Type":"multipart/mixed; boundary=\"------------2n0zYVAjYDwHTG0e20U9Xb7D\"","Content-Language":"en-US","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"}}]