get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2232325,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2232325/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260504113050.155608-2-josef.melcr@suse.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": "<20260504113050.155608-2-josef.melcr@suse.com>",
    "date": "2026-05-04T11:30:51",
    "name": "[v3] Add callback_only attribute",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "a250e496811437d6bbfc40a880759593bd6c1fca",
    "submitter": {
        "id": 92126,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/92126/?format=api",
        "name": "Josef Melcr",
        "email": "josef.melcr@suse.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260504113050.155608-2-josef.melcr@suse.com/mbox/",
    "series": [
        {
            "id": 502648,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/502648/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=502648",
            "date": "2026-05-04T11:30:51",
            "name": "[v3] Add callback_only attribute",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/502648/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2232325/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2232325/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 (2048-bit key;\n unprotected) header.d=suse.com header.i=@suse.com header.a=rsa-sha256\n header.s=google header.b=MiljsYJg;\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 (2048-bit key,\n unprotected) header.d=suse.com header.i=@suse.com header.a=rsa-sha256\n header.s=google header.b=MiljsYJg",
            "sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=suse.com",
            "sourceware.org; spf=pass smtp.mailfrom=suse.com",
            "server2.sourceware.org;\n arc=none smtp.remote-ip=2a00:1450:4864:20::329"
        ],
        "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 4g8KHj28YBz1yJ9\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 04 May 2026 21:32:15 +1000 (AEST)",
            "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id DD2044BAD173\n\tfor <incoming@patchwork.ozlabs.org>; Mon,  4 May 2026 11:32:13 +0000 (GMT)",
            "from mail-wm1-x329.google.com (mail-wm1-x329.google.com\n [IPv6:2a00:1450:4864:20::329])\n by sourceware.org (Postfix) with ESMTPS id 813814BABF23\n for <gcc-patches@gcc.gnu.org>; Mon,  4 May 2026 11:31:42 +0000 (GMT)",
            "by mail-wm1-x329.google.com with SMTP id\n 5b1f17b1804b1-4896c22fcbaso28730605e9.0\n for <gcc-patches@gcc.gnu.org>; Mon, 04 May 2026 04:31:42 -0700 (PDT)",
            "from tumbleweed.suse.cz (nat2.prg.suse.com. [195.250.132.146])\n by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48a8eb69800sm259171185e9.2.2026.05.04.04.31.40\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 04 May 2026 04:31:40 -0700 (PDT)"
        ],
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 sourceware.org DD2044BAD173",
            "OpenDKIM Filter v2.11.0 sourceware.org 813814BABF23"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 813814BABF23",
        "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 813814BABF23",
        "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777894302; cv=none;\n b=PJeK7dqZxMtk2W1gkGlKdKrAXcR8ibT7aDL4sJnaf3nCceUMGR1YMfco+IQnIy8COEl0JZ0sEruQ+V6d06rX21xxzcG8hXD/DTcOFFyk4fstrnFYHRut+7IMAFTQ1qqRWegYcabKppAJ7wc9rZKcQOev8w3eXnwe+ECcJnRGPak=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777894302; c=relaxed/simple;\n bh=8NR4394GASF26Y0wvvj0pX6FspdM0BdlBdny/cwP1dg=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=JpC6zlSKUsFivAmexCAB3JijT0+Qfy8JMyloyu02eeEV8CBcAeWw/elhLhm+s2L0Sue6Irv5v90qTnaZtj0zkhbeERpQ7NnY7ZvqSrWS9UygM5fGqp2RbxvB2jdr6fl8RI+upQCOuAT4pUGfnPNVVedt6bziqZuDK+rZROUbyoI=",
        "ARC-Authentication-Results": "i=1; server2.sourceware.org",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=suse.com; s=google; t=1777894301; x=1778499101; darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:from:to:cc:subject:date:message-id:reply-to;\n bh=u1cySyRF4IMt72ggprHoNNY/QDe4sUGfA0IEDFfvrKk=;\n b=MiljsYJgrtbWlX/Lio3A274Pa0SgrO5jSEGWERzQ2lBA4nP0I1YcGY8FOkU1oIv+Fu\n zyYIGFT4+x4MZ+cbFGXyd1AvQ8BoKc88fcIETHZQPxAVAax4bT/Ft3AbKaqGQtA+Ih6f\n q5YXYOE4BnW83029I49RMKZKwVBmCfWyJ5AAD7PUg7W7iEQ7hw5E41UmoRQ0rzt9wYCr\n poFJYP6etXGFet//Icc+i4pPowfe3n4inQcLc2yOzaxywLFXCezET8BAnfcAjkVLU1uc\n FcdCjC7Chd4s7z9/sgarbvZTapbCjRlKVUCMlwSGOKhnNOQeVfZ9JnxOyiWf0BszuJdD\n BS5w==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777894301; x=1778499101;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=u1cySyRF4IMt72ggprHoNNY/QDe4sUGfA0IEDFfvrKk=;\n b=AsGXu319ah263J0Z77UyM4IUYqmY6Y0SpHYiahaidO6uAgYwsPL6uyeBlqHX1T3+X6\n kMlE+pjAj5OFELVwJsG0Fc8XyIlnqTaOXDaVmaRL+emv1/dcvdT9r30iD54+G2ISSLEO\n znSXhxG6O+yGfN+C4z2zYMY0mIAjdELvKfJMf3sOpfEIqpbBbdXFnXenu6LH6pNnCxAY\n 4+H38pP9/qCwfP4uHDJoBzatvsGJRtZ4ZonmD527ygBnewWHdE0ljbmsbZEFlGlrdIVX\n EZF+pkbJAfwPcBAyJUT5XpL8dQezSfVTWuSfrvLRoBpin96X+Mi/nddauF+mBA5V1Hb6\n KJNw==",
        "X-Gm-Message-State": "AOJu0YxPVyncp5gxtXNx6Vog+ipUUEXKmDz3e9FwltIxTwohD1Ik6Wjn\n CfPnNsfarBscuJICV6WwELVXV3WbYOHjoByFG502j/iKHfHPgNFq/4E9bSD/BXZ/4YXG2nB9pr8\n sSrRQaPU=",
        "X-Gm-Gg": "AeBDietu2ihVDFsCxURx00Cf4c/p+qfi0/zs+5kSgHLDYkoNc9KeyJaW/vfVxwZ+jl4\n eMnzVDd9EuIqjz1ZYG0IkeWLbztHiLiXdsM2KWuu0GE5aCRGHZcro5jiRJ602s8fR7f2cqS3hd1\n PC3nL7SI0xzlZVKH/NRaeqBD80Y/BMct4cL85xINHQlHVnC8hLJU9HQUg+oTRFQYpQcDD7zsHM7\n CrdSc/xjZmRL+DxzPo7d4xxoQR0M/mh/wKc95J+AhyOddEwXDFOZo7dQyxSEZqIHLD/UbCEfpO/\n G3xLzHP8WE89/Doxg6MnXjSnkZj1rrn8K+O4UCr3FygCNeKECwylixxpkKHg6EVWMyyhr03sb5O\n L4OaVjuWK0e8EqnwVrmXyMSJaEEaReRnEhabeMMsYlSQ8o50cq37VOHx5LGeazOZ+t4AAbJJRBZ\n 5G03zQqb7pTYlvxwaD3qzKJb9jMJ7EH7EuonGLrxy9IkDtEqoPry4oMyPiZZ4e",
        "X-Received": "by 2002:a05:600c:1c15:b0:48a:554d:b9a2 with SMTP id\n 5b1f17b1804b1-48a9852f593mr151334575e9.6.1777894300800;\n Mon, 04 May 2026 04:31:40 -0700 (PDT)",
        "From": "Josef Melcr <josef.melcr@suse.com>",
        "To": "gcc-patches@gcc.gnu.org",
        "Cc": "Josef Melcr <josef.melcr@suse.com>, andrew.pinski@oss.qualcomm.com,\n jakub@redhat.com",
        "Subject": "[PATCH v3] Add callback_only attribute",
        "Date": "Mon,  4 May 2026 13:30:51 +0200",
        "Message-ID": "<20260504113050.155608-2-josef.melcr@suse.com>",
        "X-Mailer": "git-send-email 2.54.0",
        "MIME-Version": "1.0",
        "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"
    },
    "content": "Hi,\nthis is a v3 of this patch (v2: https://gcc.gnu.org/pipermail/gcc-patches/2026-May/715612.html)\n\nSorry about the formatting issues, formatting is the bane of my\nexistence for some reason.\n\nI did not retest the patch, as I only made formatting changes.\n\nChanges in v3:\n - Fixed formatting\n\nChanges in v2:\n - Documentation tweaks suggested by Andrew\n\nThis patch allows the callback attribute to be used outside of GCC under\nthe name 'gnu::callback_only'.  It also fixes some missing bounds checks\nin the attribute handler.  The attribute is not recognized outside of\nthe gnu namespace, I did this so that there is no accidental mixup with\nthe LLVM callback attribute, which has different syntax.  I am not great\nat user-facing documentation, I hope the docs are clear about the\nattribute's usage.  Suggestions are of course welcome.\n\nOK for master?\n\nBest regards,\nJosef\n\ngcc/ChangeLog:\n\n\t* attr-callback.cc (callback_edge_callee_has_attr): Specify gnu\n\tnamespace in attribute lookup.\n\t(callback_fetch_attr_by_edge): Likewise.\n\t(handle_callback_attribute): Fix bugs in bounds checks, add gnu\n\tnamespace to attribute lookup.\n\t* attr-callback.h (CALLBACK_ATTR_IDENT): Change identifier to\n\t'callback_only'.\n\t* builtin-attrs.def (ATTR_CALLBACK): Likewise.\n\t* cgraph.cc (cgraph_edge::redirect_call_stmt_to_callee): Specify\n\tgnu namespace in attribute lookup.\n\t(cgraph_node::verify_node): Likewise.\n\t* doc/extend.texi: Add gnu::callback_only attribute\n\tdocumentation.\n\t* ipa-cp.cc (purge_useless_callback_edges): Specify gnu\n\tnamespace in attribute lookup.\n\t* ipa-prop.cc (ipa_compute_jump_functions_for_edge): Likewise.\n\t* tree-core.h: Change ECF_CB_* comment from 'callback' to\n\t'callback_only'.\n\ngcc/c-family/ChangeLog:\n\n\t* c-attribs.cc: Define the 'callback_only' attribute in gnu\n\tnamespace only.\n\t* c-common.h: Add extern decl for the callback attribute table.\n\ngcc/c/ChangeLog:\n\n\t* c-objc-common.h: Add the callback attribute table to allow it\n\tto be registered.\n\ngcc/cp/ChangeLog:\n\n\t* cp-objcp-common.h: Likewise.\n\ngcc/testsuite/ChangeLog:\n\n\t* gcc.dg/attr-callback.c: New test.\n\t* gcc.dg/ipa/ipcp-cb2.c: New test.\n\nSigned-off-by: Josef Melcr <josef.melcr@suse.com>\n---\n gcc/attr-callback.cc                 |  20 ++---\n gcc/attr-callback.h                  |   2 +-\n gcc/builtin-attrs.def                |   2 +-\n gcc/c-family/c-attribs.cc            |  13 +++-\n gcc/c-family/c-common.h              |   1 +\n gcc/c/c-objc-common.h                |   3 +-\n gcc/cgraph.cc                        |  12 +--\n gcc/cp/cp-objcp-common.h             |   1 +\n gcc/doc/extend.texi                  |  39 ++++++++++\n gcc/ipa-cp.cc                        |   2 +-\n gcc/ipa-prop.cc                      |   4 +-\n gcc/testsuite/gcc.dg/attr-callback.c | 107 +++++++++++++++++++++++++++\n gcc/testsuite/gcc.dg/ipa/ipcp-cb2.c  |  60 +++++++++++++++\n gcc/tree-core.h                      |   2 +-\n 14 files changed, 245 insertions(+), 23 deletions(-)\n create mode 100755 gcc/testsuite/gcc.dg/attr-callback.c\n create mode 100644 gcc/testsuite/gcc.dg/ipa/ipcp-cb2.c",
    "diff": "diff --git a/gcc/attr-callback.cc b/gcc/attr-callback.cc\nindex c654d74164d..041e2463592 100644\n--- a/gcc/attr-callback.cc\n+++ b/gcc/attr-callback.cc\n@@ -87,7 +87,7 @@ callback_special_case_attr (tree decl)\n bool\n callback_edge_callee_has_attr (cgraph_edge *e)\n {\n-  return lookup_attribute (CALLBACK_ATTR_IDENT,\n+  return lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n \t\t\t   DECL_ATTRIBUTES (e->callee->decl))\n \t || callback_is_special_cased (e->callee->decl, e->call_stmt);\n }\n@@ -113,12 +113,12 @@ callback_fetch_attr_by_edge (cgraph_edge *e, cgraph_edge *carrying)\n   if (callback_is_special_cased (carrying->callee->decl, e->call_stmt))\n     return callback_special_case_attr (carrying->callee->decl);\n \n-  tree cb_attr = lookup_attribute (CALLBACK_ATTR_IDENT,\n+  tree cb_attr = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n \t\t\t\t   DECL_ATTRIBUTES (carrying->callee->decl));\n   gcc_checking_assert (cb_attr);\n   tree res = NULL_TREE;\n-  for (; cb_attr;\n-       cb_attr = lookup_attribute (CALLBACK_ATTR_IDENT, TREE_CHAIN (cb_attr)))\n+  for (; cb_attr; cb_attr = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n+\t\t\t\t\t      TREE_CHAIN (cb_attr)))\n     {\n       unsigned id = callback_get_fn_index (cb_attr);\n       if (id == e->callback_id)\n@@ -229,10 +229,11 @@ handle_callback_attribute (tree *node, tree name, tree args,\n       return NULL_TREE;\n     }\n   --callback_fn_idx;\n-  if (callback_fn_idx >= decl_nargs)\n+  if (callback_fn_idx < 0 || callback_fn_idx >= decl_nargs)\n     {\n       error_at (DECL_SOURCE_LOCATION (decl),\n-\t\t\"callback function position out of range\");\n+\t\t\"callback function index %d is out of range\",\n+\t\tcallback_fn_idx + 1);\n       *no_add_attrs = true;\n       return NULL_TREE;\n     }\n@@ -305,7 +306,7 @@ handle_callback_attribute (tree *node, tree name, tree args,\n       arg_idx -= 1;\n       /* Report an error if the position is out of bounds,\n \t but we can still check the rest of the arguments.  */\n-      if (arg_idx >= decl_nargs)\n+      if (arg_idx < 0 || arg_idx >= decl_nargs)\n \t{\n \t  error_at (DECL_SOURCE_LOCATION (decl),\n \t\t    \"callback argument index %d is out of range\", arg_idx + 1);\n@@ -331,8 +332,9 @@ handle_callback_attribute (tree *node, tree name, tree args,\n \n   /* Check that the decl does not already have a callback attribute describing\n      the same argument.  */\n-  it = lookup_attribute (CALLBACK_ATTR_IDENT, DECL_ATTRIBUTES (decl));\n-  for (; it; it = lookup_attribute (CALLBACK_ATTR_IDENT, TREE_CHAIN (it)))\n+  it = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT, DECL_ATTRIBUTES (decl));\n+  for (; it;\n+       it = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT, TREE_CHAIN (it)))\n     if (callback_get_fn_index (it) == callback_fn_idx)\n       {\n \terror_at (DECL_SOURCE_LOCATION (decl),\ndiff --git a/gcc/attr-callback.h b/gcc/attr-callback.h\nindex b2c1c3c09c5..e51c4c6c571 100644\n--- a/gcc/attr-callback.h\n+++ b/gcc/attr-callback.h\n@@ -28,7 +28,7 @@ enum callback_position\n   CB_UNKNOWN_POS = 0\n };\n \n-#define CALLBACK_ATTR_IDENT \" callback\"\n+#define CALLBACK_ATTR_IDENT \"callback_only\"\n \n /* Returns a callback attribute with callback index FN_IDX, and ARG_COUNT\n    arguments specified by VA_ARGS.  */\ndiff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def\nindex be80184b1a1..a395f454be1 100644\n--- a/gcc/builtin-attrs.def\n+++ b/gcc/builtin-attrs.def\n@@ -130,7 +130,7 @@ DEF_ATTR_IDENT (ATTR_TM_TMPURE, \"transaction_pure\")\n DEF_ATTR_IDENT (ATTR_RETURNS_TWICE, \"returns_twice\")\n DEF_ATTR_IDENT (ATTR_RETURNS_NONNULL, \"returns_nonnull\")\n DEF_ATTR_IDENT (ATTR_WARN_UNUSED_RESULT, \"warn_unused_result\")\n-DEF_ATTR_IDENT (ATTR_CALLBACK, \" callback\")\n+DEF_ATTR_IDENT (ATTR_CALLBACK, \"callback_only\")\n \n DEF_ATTR_TREE_LIST (ATTR_NOVOPS_LIST, ATTR_NOVOPS, ATTR_NULL, ATTR_NULL)\n \ndiff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc\nindex d437c55285e..598acc70d9f 100644\n--- a/gcc/c-family/c-attribs.cc\n+++ b/gcc/c-family/c-attribs.cc\n@@ -485,8 +485,6 @@ const struct attribute_spec c_common_gnu_attributes[] =\n \t\t\t      handle_tm_attribute, NULL },\n   { \"transaction_may_cancel_outer\", 0, 0, false, true, false, false,\n \t\t\t      handle_tm_attribute, NULL },\n-  { CALLBACK_ATTR_IDENT,      1, -1, true, false, false, false,\n-\t\t\t      handle_callback_attribute, NULL },\n   /* ??? These two attributes didn't make the transition from the\n      Intel language document to the multi-vendor language document.  */\n   { \"transaction_pure\",       0, 0, false, true,  false, false,\n@@ -707,6 +705,17 @@ const struct scoped_attribute_specs c_common_format_attribute_table =\n   \"gnu\", { c_common_format_attributes }\n };\n \n+/* Attribute table for the callback attribute to be used by the C frontends.\n+   We don't want to expose the attribute outside of the GNU namespace, so it\n+   has to be separated out.  */\n+const struct attribute_spec c_common_callback_attribute[] = {\n+  { CALLBACK_ATTR_IDENT, 1, -1, true, false, false, false,\n+   handle_callback_attribute, NULL },\n+};\n+\n+const struct scoped_attribute_specs c_common_callback_attribute_table\n+  = { \"gnu\", { c_common_callback_attribute } };\n+\n /* Returns TRUE iff the attribute indicated by ATTR_ID takes a plain\n    identifier as an argument, so the front end shouldn't look it up.  */\n \ndiff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h\nindex a4cd6786109..bcd23f098d0 100644\n--- a/gcc/c-family/c-common.h\n+++ b/gcc/c-family/c-common.h\n@@ -832,6 +832,7 @@ extern struct visibility_flags visibility_options;\n extern const struct scoped_attribute_specs c_common_gnu_attribute_table;\n extern const struct scoped_attribute_specs c_common_clang_attribute_table;\n extern const struct scoped_attribute_specs c_common_format_attribute_table;\n+extern const struct scoped_attribute_specs c_common_callback_attribute_table;\n \n /* Pointer to function to lazily generate the VAR_DECL for __FUNCTION__ etc.\n    ID is the identifier to use, NAME is the string.\ndiff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h\nindex e103646b67e..11f08a2f0ca 100644\n--- a/gcc/c/c-objc-common.h\n+++ b/gcc/c/c-objc-common.h\n@@ -82,7 +82,8 @@ static const scoped_attribute_specs *const c_objc_attribute_table[] =\n   &std_attribute_table,\n   &c_common_gnu_attribute_table,\n   &c_common_clang_attribute_table,\n-  &c_common_format_attribute_table\n+  &c_common_format_attribute_table,\n+  &c_common_callback_attribute_table\n };\n \n #undef LANG_HOOKS_ATTRIBUTE_TABLE\ndiff --git a/gcc/cgraph.cc b/gcc/cgraph.cc\nindex 353e8b498aa..85a717bf865 100644\n--- a/gcc/cgraph.cc\n+++ b/gcc/cgraph.cc\n@@ -1843,7 +1843,7 @@ cgraph_edge::redirect_call_stmt_to_callee (cgraph_edge *e,\n     {\n       cgraph_edge *carrying = e->get_callback_carrying_edge ();\n       if (!callback_is_special_cased (carrying->callee->decl, e->call_stmt)\n-\t  && !lookup_attribute (CALLBACK_ATTR_IDENT,\n+\t  && !lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n \t\t\t\tDECL_ATTRIBUTES (carrying->callee->decl)))\n \t/* Callback attribute is removed if the dispatching function changes\n \t   signature, as the indices wouldn't be correct anymore.  These edges\n@@ -4419,11 +4419,13 @@ cgraph_node::verify_node (void)\n \t    {\n \t      int ncallbacks = 0;\n \t      int nfound_edges = 0;\n-\t      for (tree cb = lookup_attribute (CALLBACK_ATTR_IDENT, DECL_ATTRIBUTES (\n-\t\t\t\t\t\t\t     e->callee->decl));\n-\t\t   cb; cb = lookup_attribute (CALLBACK_ATTR_IDENT, TREE_CHAIN (cb)),\n-\t\t\tncallbacks++)\n+\t      for (tree cb\n+\t\t   = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n+\t\t\t\t       DECL_ATTRIBUTES (e->callee->decl));\n+\t\t   cb; cb = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n+\t\t\t\t\t      TREE_CHAIN (cb)), ncallbacks++)\n \t\t;\n+\n \t      for (cgraph_edge *cbe = callees; cbe; cbe = cbe->next_callee)\n \t\t{\n \t\t  if (cbe->callback && cbe->call_stmt == e->call_stmt\ndiff --git a/gcc/cp/cp-objcp-common.h b/gcc/cp/cp-objcp-common.h\nindex ed29e65e4f3..4a4c6de1aea 100644\n--- a/gcc/cp/cp-objcp-common.h\n+++ b/gcc/cp/cp-objcp-common.h\n@@ -131,6 +131,7 @@ static const scoped_attribute_specs *const cp_objcp_attribute_table[] =\n   &c_common_gnu_attribute_table,\n   &c_common_clang_attribute_table,\n   &c_common_format_attribute_table,\n+  &c_common_callback_attribute_table,\n   &internal_attribute_table\n };\n \ndiff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi\nindex 8dd0b3137bc..b6505e3914a 100644\n--- a/gcc/doc/extend.texi\n+++ b/gcc/doc/extend.texi\n@@ -2357,6 +2357,45 @@ Note that the BTF format currently only has a representation for type\n tags associated with pointer types.  Type tags on non-pointer types\n may be silently skipped when generating BTF.\n \n+@atindex @code{callback_only}\n+@cindex functions with callbacks\n+@item callback_only\n+The @code{callback_only} attribute specifies that the annotated function may\n+call the specified callback function. The first parameter identifies the index\n+of the callback function, the rest of the arguments specify the indices of the\n+arguments of the indirect call. All indices start from 1. If the function takes\n+the implicit @code{this} pointer, it is referred to by the index 1, with the\n+rest of the arguments starting at index 2. The index 0 marks an argument not\n+present in the arguments of the annotated function, an argument which is\n+modified before calling the callback function. The annotated function must pass\n+the specified arguments in the specified order to the callback function, which\n+must be callable with the number, order and type of the arguments. The\n+specified pointer to the callback may not escape the translation unit of the\n+annotated function and it may not be captured. The annotated function is\n+required to pass the arguments through, it may not change or dereference them.\n+The arguments also may not escape. The attribute may be used multiple times per\n+function, though only one @code{callback_only} attribute may be used per\n+function parameter.\n+\n+The attribute exposes the potentially hidden callsite in the annotated\n+function, enabling interprocedural optimizations which may not be possible\n+without the attribute. It is most useful for annotating functions from\n+dynamically linked libraries, as their bodies are not available during\n+compilation.\n+\n+This attribute is similar to the clang @code{callback} attribute but it is not\n+compatible with it. The clang implementation allows identifiers as arguments,\n+marks an unknown argument with -1 and the @code{this} pointer with the index 0.\n+\n+An example usage:\n+\n+@smallexample\n+[[gnu::callback_only(1, 3, 2)]]\n+void foo(void (*bar)(int*, double*), double* y, int* x);\n+@end smallexample\n+\n+means that there is a call @code{bar (x, y)} inside @code{foo}.\n+\n @atindex @code{cleanup}\n @cindex cleanup functions\n @item cleanup (@var{cleanup_function})\ndiff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc\nindex 337fca71013..763ec9db8ae 100644\n--- a/gcc/ipa-cp.cc\n+++ b/gcc/ipa-cp.cc\n@@ -6505,7 +6505,7 @@ purge_useless_callback_edges ()\n \t      if (dump_file)\n \t\tfprintf (dump_file, \"\\tExamining callbacks of edge %s -> %s:\\n\",\n \t\t\t e->caller->dump_name (), e->callee->dump_name ());\n-\t      if (!lookup_attribute (CALLBACK_ATTR_IDENT,\n+\t      if (!lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n \t\t\t\t     DECL_ATTRIBUTES (e->callee->decl))\n \t\t  && !callback_is_special_cased (e->callee->decl, e->call_stmt))\n \t\t{\ndiff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc\nindex cb89934ee38..f34ca56dd4f 100644\n--- a/gcc/ipa-prop.cc\n+++ b/gcc/ipa-prop.cc\n@@ -2608,11 +2608,11 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,\n \t\t  /* Argument is a pointer to a function. Look for a callback\n \t\t     attribute describing this argument.  */\n \t\t  tree callback_attr\n-\t\t    = lookup_attribute (CALLBACK_ATTR_IDENT,\n+\t\t    = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n \t\t\t\t\tDECL_ATTRIBUTES (cs->callee->decl));\n \t\t  for (; callback_attr;\n \t\t       callback_attr\n-\t\t       = lookup_attribute (CALLBACK_ATTR_IDENT,\n+\t\t       = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT,\n \t\t\t\t\t   TREE_CHAIN (callback_attr)))\n \t\t    if (callback_get_fn_index (callback_attr) == n)\n \t\t      break;\ndiff --git a/gcc/testsuite/gcc.dg/attr-callback.c b/gcc/testsuite/gcc.dg/attr-callback.c\nnew file mode 100755\nindex 00000000000..a45ad8464cd\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/attr-callback.c\n@@ -0,0 +1,107 @@\n+/* Test callback attribute error checking. */\n+\n+/* { dg-do compile } */\n+/* { dg-options \"-std=gnu17 -Wattributes\" } */\n+\n+[[gnu::callback_only(1, 2)]]\n+void\n+correct_1(void (*)(int*), int*);\n+\n+[[gnu::callback_only(1, 2, 3)]]\n+void\n+correct_2(void (*)(int*, double*), int*, double*);\n+\n+[[gnu::callback_only(1, 2, 3), gnu::callback_only(4, 5)]]\n+void\n+correct_3(void (*)(int*, double*), int*, double*, int (*)(void*), void*);\n+\n+[[gnu::callback_only(1, 0)]]\n+void\n+unknown_1(void (*)(int*));\n+\n+[[gnu::callback_only(1, 2, 0)]]\n+void\n+unknown_2(void (*)(int*, double*), int*, double*, char*);\n+\n+[[gnu::callback_only(1, 0, 3, 3)]]\n+void\n+too_many(void (*)(int*, double*), int*, double*); /* { dg-error \"argument number mismatch, 2 expected, got 3\" }*/\n+\n+[[gnu::callback_only(1, 2)]]\n+void\n+too_few_1(void (*)(int*, double*), int*, double*); /* { dg-error \"argument number mismatch, 2 expected, got 1\" }*/\n+\n+[[gnu::callback_only(1)]]\n+void\n+too_few_2(void (*)(int*, double*), int*, double*); /* { dg-error \"argument number mismatch, 2 expected, got 0\" }*/\n+\n+[[gnu::callback_only(3, 1)]]\n+void\n+promotion(char*, float, int (*)(int*));\n+\n+[[gnu::callback_only(2, 3)]]\n+void\n+downcast(char*, void* (*)(float*), double*);\n+\n+[[gnu::callback_only(1, 2, 5)]]\n+void\n+out_of_range_1(char (*)(float*, double*), float*, double*, int*); /* { dg-error \"callback argument index 5 is out of range\" } */\n+\n+[[gnu::callback_only(1, -2, 3)]]\n+void\n+out_of_range_2(char (*)(float*, double*), float*, double*, int*); /* { dg-error \"callback argument index -2 is out of range\" } */\n+\n+[[gnu::callback_only(-1, 2, 3)]]\n+void\n+out_of_range_3(char (*)(float*, double*), float*, double*, int*); /* { dg-error \"callback function index -1 is out of range\" } */\n+\n+[[gnu::callback_only(67, 2, 3)]]\n+void\n+out_of_range_4(char (*)(float*, double*), float*, double*, int*); /* { dg-error \"callback function index 67 is out of range\" } */\n+\n+[[gnu::callback_only(0, 2, 3)]]\n+void\n+unknown_fn(char (*)(float*, double*), float*, double*, int*); /* { dg-error \"callback function position cannot be marked as unknown\" } */\n+\n+[[gnu::callback_only(1, 2)]]\n+void\n+not_a_fn(int, int); /* { dg-error \"argument no. 1 is not an address of a function\" } */\n+\n+struct S\n+{\n+  int x;\n+};\n+\n+[[gnu::callback_only(1, 2)]]\n+void\n+incompatible_types_1(void (*)(struct S*), struct S); /* { dg-error \"argument type at index 2 is not compatible with callback argument type at index 1\" } */\n+\n+[[gnu::callback_only(1, 3, 2)]]\n+void\n+incompatible_types_2(void (*)(struct S*, int*), int*, double); /* { dg-error \"argument type at index 3 is not compatible with callback argument type at index 1\" } */\n+\n+[[gnu::callback_only(1, \"2\")]]\n+void\n+wrong_arg_type_1(void (*)(void*), void*); /* { dg-error \"argument no. 1 is not an integer constant\" } */\n+\n+[[gnu::callback_only(\"not a number\", 2, 2)]]\n+void\n+wrong_arg_type_2(void (*)(void*, void*), void*); /* { dg-error \"argument specifying callback function position is not an integer constant\" } */\n+\n+[[gnu::callback_only(1, 2), gnu::callback_only(1, 3)]]\n+void\n+multiple_single_fn(void (*)(int*), int*, int*); /* { dg-error \"function declaration has multiple callback attributes describing argument no. 1\" } */\n+\n+/* Check that the attribute won't resolve outside of our namespace.  */\n+\n+[[callback_only(1, 2)]] /* { dg-warning \"ignored\" } */\n+void\n+ignore_1(void (*)(int*), int*);\n+\n+[[callback(1, 2)]] /* { dg-warning \"ignored\" } */\n+void\n+ignore_2(void (*)(int*), int*);\n+\n+[[gnu::callback(1, 2)]]\n+void\n+ignore_3(void (*)(int*), int*); /* { dg-warning \"ignored\" } */\ndiff --git a/gcc/testsuite/gcc.dg/ipa/ipcp-cb2.c b/gcc/testsuite/gcc.dg/ipa/ipcp-cb2.c\nnew file mode 100644\nindex 00000000000..201d41d48f3\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/ipa/ipcp-cb2.c\n@@ -0,0 +1,60 @@\n+/* Test that we can handle multiple callback attributes and use them to\n+   propagate into callbacks. 'cb1' body borrowed from a ipa-cp test to get the\n+   pass to work. */\n+\n+/* { dg-do compile } */\n+/* { dg-options \"-O3 -fdump-ipa-cp\" } */\n+\n+struct S\n+{\n+  int a, b, c;\n+};\n+\n+extern void *blah (int, void *);\n+\n+[[gnu::callback_only (1, 2), gnu::callback_only (3, 4, 5)]] extern void\n+call (void (*fn1) (struct S *), struct S *a,\n+      void (*fn2) (struct S *, struct S *), struct S *b, struct S *c);\n+\n+void\n+cb1 (struct S *p)\n+{\n+  int i, c = p->c;\n+  int b = p->b;\n+  void *v = (void *) p;\n+\n+  for (i = 0; i < c; i++)\n+    v = blah (b + i, v);\n+}\n+\n+void\n+cb2 (struct S *a, struct S *b)\n+{\n+  cb1 (a);\n+  cb1 (b);\n+}\n+\n+void\n+test (int a, int b, int c)\n+{\n+  struct S s;\n+  s.a = a;\n+  s.b = b;\n+  s.c = c;\n+  struct S ss;\n+  ss.a = s.c;\n+  ss.b = s.b;\n+  ss.c = s.a;\n+  call (cb1, &s, cb2, &s, &ss);\n+}\n+\n+int\n+main ()\n+{\n+  test (1, 64, 32);\n+  return 0;\n+}\n+\n+/* { dg-final { scan-ipa-dump \"Creating a specialized node of cb1\" \"cp\" } } */\n+/* { dg-final { scan-ipa-dump \"Creating a specialized node of cb2\" \"cp\" } } */\n+/* { dg-final { scan-ipa-dump-times \"Aggregate replacements: \" 2 \"cp\" } } */\ndiff --git a/gcc/tree-core.h b/gcc/tree-core.h\nindex 07e9318f5e8..0169c0d4c67 100644\n--- a/gcc/tree-core.h\n+++ b/gcc/tree-core.h\n@@ -102,7 +102,7 @@ struct die_struct;\n    meant to be used for the construction of builtin functions.  They were only\n    added because Fortran uses them for attributes of builtins.  */\n \n-/* callback(1, 2) */\n+/* callback_only(1, 2) */\n #define ECF_CB_1_2\t\t  (1 << 17)\n \n /* Call argument flags.  */\n",
    "prefixes": [
        "v3"
    ]
}