get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.1/patches/2223530/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2223530,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2223530/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260415140105.2344425-1-jason@redhat.com/",
    "project": {
        "id": 17,
        "url": "http://patchwork.ozlabs.org/api/1.1/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
    },
    "msgid": "<20260415140105.2344425-1-jason@redhat.com>",
    "date": "2026-04-15T13:57:48",
    "name": "[pushed] c++: coro return proxy that destroys [PR121961]",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "dd8ced85ca617682d87e157228cafc5886f01615",
    "submitter": {
        "id": 4337,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/4337/?format=api",
        "name": "Jason Merrill",
        "email": "jason@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260415140105.2344425-1-jason@redhat.com/mbox/",
    "series": [
        {
            "id": 499991,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/499991/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=499991",
            "date": "2026-04-15T13:57:48",
            "name": "[pushed] c++: coro return proxy that destroys [PR121961]",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/499991/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2223530/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2223530/checks/",
    "tags": {},
    "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=DCLX5P1w;\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=DCLX5P1w",
            "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 4fwjVz0mXdz1yHM\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 16 Apr 2026 00:01:45 +1000 (AEST)",
            "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 9E7944BA23DE\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 15 Apr 2026 14:01:43 +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 B6E844BA2E07\n for <gcc-patches@gcc.gnu.org>; Wed, 15 Apr 2026 14:01:14 +0000 (GMT)",
            "from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-522-35bBrdCCN96VAtdCuD8PgA-1; Wed,\n 15 Apr 2026 10:01:08 -0400",
            "from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17])\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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 9F97618001EE; Wed, 15 Apr 2026 14:01:07 +0000 (UTC)",
            "from jason-thinkpadp1gen4i.rmtusma.csb (unknown [10.22.66.21])\n by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id C0669195608E; Wed, 15 Apr 2026 14:01:06 +0000 (UTC)"
        ],
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 sourceware.org 9E7944BA23DE",
            "OpenDKIM Filter v2.11.0 sourceware.org B6E844BA2E07"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org B6E844BA2E07",
        "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org B6E844BA2E07",
        "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776261674; cv=none;\n b=x4EyvD2XcLEze6ylmCQEf8ZlOgHkGI0YZ86I1uyKWmo2Fko8ME2E4gQhuc7BOFQYUAbk5sNMtMe/i51WoWEJ8gbD/tLreGZcgojcD+b6DxbHqUQYEwfYZgoDkXdLwhDMffN8wr1oYq8Q/EdS7OOR2xfRtWP71XvoWaB6vYO7Fzw=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776261674; c=relaxed/simple;\n bh=/B5X1VlD2SHJ9aa4TuBkbibXeQwxPVAb94M9IC0Wy3Y=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=b6pjN66/jB/sGMSeF3vcU+Bv+XIe5VMuHXQZOP6VLBib0Ws2br7zBxMX6EIfTvHnKj8qCyhhv5dLh6qbqBE0qjpr/Lvk/3Npf01400ZymHLMd3Mev4J2Aahdk/TpFDcH1VkhsSiei0BmT9nxni8dRbZbImvlIMJ0V8QgQyoUfz8=",
        "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=1776261674;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=vE134FHxInGvKuWAG/A4MUkwTqYZ3FDttR0TAi4qLAA=;\n b=DCLX5P1w5m8qadoiRXZn9iHZDSL5P4u6S/s3MCFEBKlF/yX8F2+ef1FKC482AD4n0mNLls\n vbHFKG3e5TipvwVx9lOsW77iBRB/Rj50p95FndObqsa1oNvrdXtZRIdbU0DMTSTZy0uJRH\n 9oiZEpigkFGFlm+cghaAUl/TNDaXO9A=",
        "X-MC-Unique": "35bBrdCCN96VAtdCuD8PgA-1",
        "X-Mimecast-MFC-AGG-ID": "35bBrdCCN96VAtdCuD8PgA_1776261668",
        "From": "Jason Merrill <jason@redhat.com>",
        "To": "gcc-patches@gcc.gnu.org",
        "Cc": "Iain Sandoe <iain@sandoe.co.uk>",
        "Subject": "[pushed] c++: coro return proxy that destroys [PR121961]",
        "Date": "Wed, 15 Apr 2026 09:57:48 -0400",
        "Message-ID": "<20260415140105.2344425-1-jason@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.0 on 10.30.177.17",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "F1ykWSkZFFL74F_duPpxMN4ChCWhv9o2k3504ruJCIk_1776261668",
        "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 and 15.\n\n-- 8< --\n\nAfter the actor of simple() hits final_suspend and returns to the ramp, the\nramp returns the Wrapper variable holding the result of get_return_object,\nwhich calls operator Result.  Then we destroy the Wrapper, which calls\ndestroy() on the handle.  Then we return to the ramp, and run the rest of\nthe cleanups.\n\nBefore this patch there were two bugs causing us to clean up the frame too\nsoon, in destroy(): First, the actor destroy() handling was unconditionally\ncleaning up the frame rather than checking the refcount.  Second, the ramp\nwas decrementing the refcount too soon.\n\n\tPR c++/121961\n\ngcc/cp/ChangeLog:\n\n\t* coroutines.cc (build_actor_fn): Move the delete label before\n\tthe refcount handling.\n\t(cp_coroutine_transform::build_ramp_function): Decrement refcount\n\tafter destroying gro.\n\ngcc/testsuite/ChangeLog:\n\n\t* g++.dg/asan/coroutines1.C: New test.\n---\n gcc/cp/coroutines.cc                    | 41 +++++++-------\n gcc/testsuite/g++.dg/asan/coroutines1.C | 71 +++++++++++++++++++++++++\n 2 files changed, 94 insertions(+), 18 deletions(-)\n create mode 100644 gcc/testsuite/g++.dg/asan/coroutines1.C\n\n\nbase-commit: 83f8af8c51892a37a3c5cd749808c60980568278",
    "diff": "diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc\nindex 3de0d556a84..f9fbffa60b3 100644\n--- a/gcc/cp/coroutines.cc\n+++ b/gcc/cp/coroutines.cc\n@@ -2649,7 +2649,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,\n   /* The destroy point numbered #1 is special, in that it is reached from a\n      coroutine that is suspended after re-throwing from unhandled_exception().\n      This label just invokes the cleanup of promise, param copies and the\n-     frame itself.  */\n+     frame itself, if the ramp isn't still keeping them alive.  */\n   tree del_promise_label\n     = create_named_label_with_ctx (loc, \"coro.delete.promise\", actor);\n   finish_case_label (loc, build_int_cst (short_unsigned_type_node, 1),\n@@ -2743,6 +2743,9 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,\n   /* Add in our function body with the co_returns rewritten to final form.  */\n   add_stmt (fnbody);\n \n+  tree r = build_stmt (loc, LABEL_EXPR, del_promise_label);\n+  add_stmt (r);\n+\n   /* We are done with the frame, but if the ramp still has a hold on it\n      we should not cleanup.  So decrement the refcount and then return to\n      the ramp if it is > 0.  */\n@@ -2752,7 +2755,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,\n   tree released = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node,\n \t\t\t      coro_frame_refcount,\n \t\t\t      build_int_cst (short_unsigned_type_node, 1));\n-  tree r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released,\n+  r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released,\n \t\t\t\t tf_warning_or_error);\n   finish_expr_stmt (r);\n   tree cond = build2_loc (loc, NE_EXPR, short_unsigned_type_node,\n@@ -2765,8 +2768,6 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,\n   finish_if_stmt (ramp_cu_if);\n \n   /* Otherwise, do the tail of the function; first cleanups.  */\n-  r = build_stmt (loc, LABEL_EXPR, del_promise_label);\n-  add_stmt (r);\n \n   /* Destructors for the things we built explicitly.\n      promise... */\n@@ -5278,6 +5279,23 @@ cp_coroutine_transform::build_ramp_function ()\n       push_cleanup (p, r, /*eh_only*/false);\n     }\n \n+  /* Now that we've constructed everything in the frame, consider it\n+     used...  */\n+  r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR,\n+\t\t\t    build_int_cst (short_unsigned_type_node, 1),\n+\t\t\t    tf_warning_or_error);\n+  finish_expr_stmt (r);\n+  /* ... but when we finish we want to release that, and we want to do that\n+     before the frame cleanups run.  But after the gro cleanup, in case it\n+     calls destroy (PR121961).  */\n+  tree released\n+    = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node,\n+\t\t  coro_frame_refcount,\n+\t\t  build_int_cst (short_unsigned_type_node, 1));\n+  released = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released,\n+\t\t\t\t tf_warning_or_error);\n+  push_cleanup (NULL_TREE, released, /*eh_only*/false);\n+\n   tree get_ro\n     = coro_build_promise_expression (orig_fn_decl, p,\n \t\t\t\t     coro_get_return_object_identifier,\n@@ -5339,20 +5357,7 @@ cp_coroutine_transform::build_ramp_function ()\n \tpush_cleanup (coro_gro, coro_gro_cleanup, /*eh_only*/false);\n     }\n \n-  /* Start the coroutine body, we now have a use of the frame...  */\n-  r = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR,\n-\t\t\t    build_int_cst (short_unsigned_type_node, 1),\n-\t\t\t    tf_warning_or_error);\n-  finish_expr_stmt (r);\n-  /* ... but when we finish we want to release that, and we want to do that\n-     before any of the other cleanups run.  */\n-  tree released\n-    = build2_loc (loc, MINUS_EXPR, short_unsigned_type_node, coro_frame_refcount,\n-\t\t  build_int_cst (short_unsigned_type_node, 1));\n-  released = cp_build_modify_expr (loc, coro_frame_refcount, NOP_EXPR, released,\n-\t\t\t\t tf_warning_or_error);\n-  push_cleanup (NULL_TREE, released, /*eh_only*/false);\n-\n+  /* Start the coroutine body.  */\n   r = build_call_expr_loc (fn_start, resumer, 1, coro_fp);\n   finish_expr_stmt (r);\n \ndiff --git a/gcc/testsuite/g++.dg/asan/coroutines1.C b/gcc/testsuite/g++.dg/asan/coroutines1.C\nnew file mode 100644\nindex 00000000000..eb8909bdc83\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/asan/coroutines1.C\n@@ -0,0 +1,71 @@\n+// PR c++/121961\n+// { dg-additional-options \"-fsanitize=address\" }\n+// { dg-do run { target c++20 } }\n+\n+#include <coroutine>\n+\n+struct Result\n+{\n+  int Value;\n+};\n+\n+template<typename... Args>\n+struct std::coroutine_traits<Result, Args...>\n+{\n+  struct promise_type;\n+\n+  struct Wrapper\n+  {\n+    std::coroutine_handle<promise_type> Handle_;\n+    bool Own_ = false;\n+\n+    ~Wrapper ()\n+    {\n+      if (Own_)\n+\tHandle_.destroy ();\n+    }\n+\n+    operator Result ()\n+    {\n+      Own_ = true;\n+      return { Handle_.promise ().Value_ };\n+    }\n+  };\n+\n+  struct promise_type\n+  {\n+    int Value_ = 0;\n+\n+    std::suspend_never initial_suspend () noexcept { return {}; }\n+    std::suspend_always final_suspend () noexcept { return {}; }\n+    void unhandled_exception () {}\n+\n+    void return_value (int v) { Value_ = v; }\n+\n+    Wrapper get_return_object ()\n+    {\n+      return { std::coroutine_handle<promise_type>::from_promise (*this) };\n+    }\n+  };\n+};\n+\n+struct Awaitable\n+{\n+  int V_;\n+  bool await_ready () const noexcept { return true; }\n+  void await_suspend (std::coroutine_handle<>) const noexcept {}\n+  int await_resume () const noexcept { return V_; }\n+};\n+\n+Result simple ()\n+{\n+  auto a = co_await Awaitable { 3 };\n+  auto b = co_await Awaitable { 5 };\n+  co_return a * b;\n+}\n+\n+int main ()\n+{\n+  auto r = simple ();\n+  return r.Value == 15 ? 0 : 1;\n+}\n",
    "prefixes": [
        "pushed"
    ]
}