Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2232291/?format=api
{ "id": 2232291, "url": "http://patchwork.ozlabs.org/api/patches/2232291/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260504084022.29508-2-josef.melcr@suse.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260504084022.29508-2-josef.melcr@suse.com>", "list_archive_url": null, "date": "2026-05-04T08:40:23", "name": "[v2] Add callback_only attribute", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "6e2b0627a130e0f72e0a381614e60b09664ea284", "submitter": { "id": 92126, "url": "http://patchwork.ozlabs.org/api/people/92126/?format=api", "name": "Josef Melcr", "email": "josef.melcr@suse.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260504084022.29508-2-josef.melcr@suse.com/mbox/", "series": [ { "id": 502626, "url": "http://patchwork.ozlabs.org/api/series/502626/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=502626", "date": "2026-05-04T08:40:23", "name": "[v2] Add callback_only attribute", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/502626/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2232291/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2232291/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 (2048-bit key;\n unprotected) header.d=suse.com header.i=@suse.com header.a=rsa-sha256\n header.s=google header.b=Yefm4EgX;\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=Yefm4EgX", "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::32c" ], "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 4g8FVM3CgLz1y04\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 04 May 2026 18:41:14 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id ECF484B99F58\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 4 May 2026 08:41:10 +0000 (GMT)", "from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com\n [IPv6:2a00:1450:4864:20::32c])\n by sourceware.org (Postfix) with ESMTPS id 8A5264BABF0B\n for <gcc-patches@gcc.gnu.org>; Mon, 4 May 2026 08:40:38 +0000 (GMT)", "by mail-wm1-x32c.google.com with SMTP id\n 5b1f17b1804b1-48d102471a4so3635055e9.2\n for <gcc-patches@gcc.gnu.org>; Mon, 04 May 2026 01:40:38 -0700 (PDT)", "from tumbleweed.suse.cz (nat2.prg.suse.com. [195.250.132.146])\n by smtp.gmail.com with ESMTPSA id\n ffacd0b85a97d-44a981dee90sm23765235f8f.22.2026.05.04.01.40.35\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 04 May 2026 01:40:35 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org ECF484B99F58", "OpenDKIM Filter v2.11.0 sourceware.org 8A5264BABF0B" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 8A5264BABF0B", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 8A5264BABF0B", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777884038; cv=none;\n b=lqNLm9F29FmlvJaWCt4rALqvzLFMbutQUFkmiiTSW7PKcjhq7BpFOOyWkwoCoRyheyWYkQUf50p6WerpzGjOI3nYXwxSB+VcGxI1Q93N1BQGZ56AftYuP8ciRgB0TPF6lmLsaxLzXEeF/q/C1TWhDDMffxbFU3YywonOcjR0epM=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777884038; c=relaxed/simple;\n bh=f9+Eewek+ygWDePvUXaGrm8Y0cHSIP3OjVXiamkmksQ=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=i/aT8++JZwhB6kk1e55V/RM3vgP+1kO6Re+DWClBQtdr3e4iZL/T0WXA/EJ+UkSDkTmz3X5U/GbLkX+FNaxL8db7vOTskJcvM4jYixKkYKTLFD2CZDHqbtBYy9dQ4/Lfdw3Lm9X4aUN4SAF0+KIyF52CFSMvi0GeuFqLqfvcVbM=", "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=1777884036; x=1778488836; 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=nwtZfVowJ4oLqZwXZsvnG02YCAUKJncZc2HIkJCtTB8=;\n b=Yefm4EgXxvDzfkqHCCPLwV324BUZC/q/Akg11njmf06EeWDfll1/d0zdL+jdWmLW34\n TI613kSzXOe2ZJFHzInspHoa9Av7b0/n9vQExVssAWYZ4DN9jMpiHsP8YeLxWCmKAYzH\n UBeGZ0TYP1aercaRe6DkzAqGsNbIa3G2n9aEcGP5IZG7zPhJECQsBfNodrklrzK6bPF/\n Ziw6FIFqFxPpqk4KNWYETS0P3zJeAInfUc09cI+FWazoFr2HQc7y0a93hFOOTCnhACro\n jA2kputk8xVeINAUoiEqZadPRE00MeZZvlyRHpP7hLll5xSXv+M+1KIj/l+GvNGXtPAh\n muZQ==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777884036; x=1778488836;\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=nwtZfVowJ4oLqZwXZsvnG02YCAUKJncZc2HIkJCtTB8=;\n b=brBtcIhpNToRwCML8wyLU3wQxabo5Z7jrCpHx3b2d+NnYZpmOUTiQzOliSHh23c87M\n D2zQOSetwrOZcXiv7Urw8MuJtNbgGCdt6gzF9BZCvWAe9SwdEc+Zaa75eMRdS9t8ow5n\n jpv3qR0Od8pHEouywLKFXHxWfC3COWO8sNAuvg0SNJTpP/hn6+j2gZQP3iMrsG6gXp4t\n TdkeRLzMryOezxr9gVbhjAdSc4VNHCrTrdwuXO/r1ZVqbKfY8r7icPV+JZoZRPKWvjaU\n oVrFU6TBase5feg+b5pWQee/2FlTXjBV+Oy+DOy85dPKM4VvkI/6/kTPDp/mp5OQy+D9\n xVlQ==", "X-Gm-Message-State": "AOJu0Yw5+/yCCMT459AeaN6ECbP0dKQ9OCK9Y+8WMTUts5WJxsyf7TsG\n VUSQPlzouM8Y15dWdHVFfW1CSxs96o7sz1hdEq2cSxlQP1DVFCJQww6SjMjiaAprhB7zxyGg9DT\n zw1yKldo=", "X-Gm-Gg": "AeBDietZeRp6N4TCxCU0HseVP9LixLXnPSAaUi7I/51pJzCH8rmjorFuG4V7ZwX9ci8\n jcRxWOtvnE2FcD0Iuc/W3MfAFHNbbV6ek84RzYZrXnb092LTipEAha1faZp2p2GqduRtsK5R5se\n Z65L2YGq+olfyUvKyhgkAdxxzpssEAb70nmNyNx/Ia1NkXnbLDJU2ZS3ILtNZsVx241gm97bSxQ\n aVE7RG+lIKdcC/0RjaAKnnQY0SMmxabjlhdQaRsadNUFlcTkcm63r16GkO2SL9UGQQlSX4QC9oD\n kmbenHvySzQavFEgYkqcaCUkn0VHkvnZ/KobeqNO18v6wuGOrXlp+s4Y1mDG3h8AcuqXpaM01JB\n 3lVCWs+EFFsBL3A8GetZ9/gdKJEbxu5HwdcaPwGCHs7h/Qex0z114dF/nK/vJ5jFq2t/xnRCcCh\n 0ux6rTTCGLw9gm3vxIZDG8FIydCYjX+6rSg0PRNEQqy+HlQE8jmfQ0y1ksyPn/FupKY0gWn+Y=", "X-Received": "by 2002:a05:600c:5308:b0:48a:5565:ec3d with SMTP id\n 5b1f17b1804b1-48d03b401f5mr79681525e9.22.1777884035983;\n Mon, 04 May 2026 01:40:35 -0700 (PDT)", "From": "Josef Melcr <josef.melcr@suse.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "Josef Melcr <josef.melcr@suse.com>,\n\tandrew.pinski@oss.qualcomm.com", "Subject": "[PATCH v2] Add callback_only attribute", "Date": "Mon, 4 May 2026 10:40:23 +0200", "Message-ID": "<20260504084022.29508-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 v2 of this patch (v1: https://gcc.gnu.org/pipermail/gcc-patches/2025-October/698696.html)\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\nBootstrapped and retested on trunk on x86_64-linux without issues.\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 | 16 ++--\n gcc/attr-callback.h | 2 +-\n gcc/builtin-attrs.def | 2 +-\n gcc/c-family/c-attribs.cc | 16 +++-\n gcc/c-family/c-common.h | 1 +\n gcc/c/c-objc-common.h | 3 +-\n gcc/cgraph.cc | 6 +-\n gcc/cp/cp-objcp-common.h | 1 +\n gcc/doc/extend.texi | 36 +++++++++\n gcc/ipa-cp.cc | 2 +-\n gcc/ipa-prop.cc | 4 +-\n gcc/testsuite/gcc.dg/attr-callback.c | 106 +++++++++++++++++++++++++++\n gcc/testsuite/gcc.dg/ipa/ipcp-cb2.c | 51 +++++++++++++\n gcc/tree-core.h | 2 +-\n 14 files changed, 228 insertions(+), 20 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..b3fa9f66f44 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+ cb_attr = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT, TREE_CHAIN (cb_attr)))\n {\n unsigned id = callback_get_fn_index (cb_attr);\n if (id == e->callback_id)\n@@ -229,10 +229,10 @@ 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\", callback_fn_idx + 1);\n *no_add_attrs = true;\n return NULL_TREE;\n }\n@@ -305,7 +305,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 +331,8 @@ 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; 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..2d04b4c1ad2 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,20 @@ 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. We\n+ don't want to expose the attribute outside of the GNU namespace, so it has to\n+ be separated out. */\n+const struct attribute_spec c_common_callback_attribute[] =\n+{\n+ { CALLBACK_ATTR_IDENT, 1, -1, true, false, false, false,\n+\t\t\t handle_callback_attribute, NULL },\n+};\n+\n+const struct scoped_attribute_specs c_common_callback_attribute_table =\n+{\n+ \"gnu\", { c_common_callback_attribute }\n+};\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..c1724197c3d 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,9 +4419,9 @@ 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 for (tree cb = lookup_attribute (\"gnu\", 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 cb; cb = lookup_attribute (\"gnu\", CALLBACK_ATTR_IDENT, TREE_CHAIN (cb)),\n \t\t\tncallbacks++)\n \t\t;\n \t for (cgraph_edge *cbe = callees; cbe; cbe = cbe->next_callee)\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..8cc3bf6532e 100644\n--- a/gcc/doc/extend.texi\n+++ b/gcc/doc/extend.texi\n@@ -2357,6 +2357,42 @@ 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+@cindex @code{callback_only} function attribute\n+@item callback_only\n+The @code{callback_only} attribute specifies that the annotated\n+function may call the specified callback function. The first parameter\n+identifies the index of the callback function, the rest of the arguments specify the\n+indices of the arguments of the indirect call. All indices start from 1. If the function\n+takes the implicit @code{this} pointer, it is referred to by the index 1, with\n+the 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 the\n+specified arguments in the specified order to the callback function, which must be\n+callable with the number, order and type of the arguments. The specified pointer\n+to the callback may not escape the translation unit of the annotated function and it\n+may not be captured. The annotated function is required to pass the arguments\n+through, it may not change or dereference them. The arguments also may not escape.\n+The attribute may be used multiple times per function, though only one @code{callback_only}\n+attribute may be used per function parameter.\n+\n+The attribute exposes the potentially hidden callsite in the annotated function,\n+enabling interprocedural optimizations which may not be possible without the\n+attribute. It is most useful for annotating functions from dynamically linked libraries,\n+as their bodies are not available during compilation.\n+\n+This attribute is similar to the clang @code{callback} attribute but it is not compatible\n+with it. The clang implementation allows identifiers as arguments, marks an unknown\n+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..4ebd8eefff2\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/attr-callback.c\n@@ -0,0 +1,106 @@\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+ 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..f7ff9868b55\n--- /dev/null\n+++ b/gcc/testsuite/gcc.dg/ipa/ipcp-cb2.c\n@@ -0,0 +1,51 @@\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+ 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, void (*fn2)(struct S *, struct S *),\n+ struct S *b, struct S *c);\n+\n+void cb1(struct S *p) {\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 cb2(struct S *a, struct S *b) {\n+ cb1(a);\n+ cb1(b);\n+}\n+\n+void test(int a, int b, int c) {\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 main() {\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": [ "v2" ] }