Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2229943/?format=api
{ "id": 2229943, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229943/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260428232721.1953782-1-dmalcolm@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": "<20260428232721.1953782-1-dmalcolm@redhat.com>", "date": "2026-04-28T23:27:21", "name": "[pushed:,r17-170] json: implement JSON Pointer parsing (RFC 6901)", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "65b0a4386ea22f18b48023b80ccd6da9f7946c99", "submitter": { "id": 24465, "url": "http://patchwork.ozlabs.org/api/1.1/people/24465/?format=api", "name": "David Malcolm", "email": "dmalcolm@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260428232721.1953782-1-dmalcolm@redhat.com/mbox/", "series": [ { "id": 501952, "url": "http://patchwork.ozlabs.org/api/1.1/series/501952/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501952", "date": "2026-04-28T23:27:21", "name": "[pushed:,r17-170] json: implement JSON Pointer parsing (RFC 6901)", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501952/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2229943/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2229943/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=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=JP6/m5EK;\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=fail reason=\"signature verification failed\" (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=JP6/m5EK", "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 4g4xSb6bthz1yHv\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 09:28:15 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 170E74BBC0B2\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 23:28:14 +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 EF3FC4BB8F6E\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:27:28 +0000 (GMT)", "from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-484-Z8va8yXNMamrgZKiUyZB-w-1; Tue,\n 28 Apr 2026 19:27:25 -0400", "from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 054B019560A7\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:27:24 +0000 (UTC)", "from t14s.localdomain.com (unknown [10.22.65.168])\n by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 5C6A3300757C; Tue, 28 Apr 2026 23:27:23 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 170E74BBC0B2", "OpenDKIM Filter v2.11.0 sourceware.org EF3FC4BB8F6E" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org EF3FC4BB8F6E", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org EF3FC4BB8F6E", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777418849; cv=none;\n b=M5Y/IOXMQNKE9OcSxbLYwQiaqS7Y09CJ3Hm2FkkwANwx6WL0P01Mao3IlEgeW6/XMJfGaQqla+CaJO5CGZKFVclPAwddz+Ab0QG3yXJPPpe8nixtdqCAxizYLFK7v7LMSDb7j29DnIgppxTKOkB+15xgF+Slstzfad9Gj7jl5nU=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777418849; c=relaxed/simple;\n bh=oK2rCftxQziKOzKtQbXucww3TAIEJ9NEZa5p/cta3Cc=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=EL3yIK2R4nhjdn51b4Up6xZ/yOqMV5FzgBrs3vn1yDCtHBuXV7yB6VJPWs4LU6txkaRs5QZoOQ9B3Jb3xSzg4pOtyODcvP6TN3DozqMuDobfLwferW5+RfTU4YcYJgDJfemXziirzkVQ0lFfFN6ZoMeGyvYvof0aeYVnEGZ5fm8=", "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=1777418848;\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=LRa+f1OlEa6n04yTKysxMGQYpzZGpAcVvnIjoXYfjKU=;\n b=JP6/m5EK1ufyhSDIexgE4wCMcaiWV9o7ePLhZGD9/xQlsyLGZfRSmLuYOq/Ja1KCIA/pR9\n ig+FYwSYEwmsR41/+SfPnA6NB2GQa0osp6URXdmr1kL1h1xVW5XmU/QlXt9Vz8y6jUy2ZD\n ZuQ/4ma5vs1wZu0kjI/xnkxrwfudz3k=", "X-MC-Unique": "Z8va8yXNMamrgZKiUyZB-w-1", "X-Mimecast-MFC-AGG-ID": "Z8va8yXNMamrgZKiUyZB-w_1777418844", "From": "David Malcolm <dmalcolm@redhat.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "David Malcolm <dmalcolm@redhat.com>", "Subject": "[pushed: r17-170] json: implement JSON Pointer parsing (RFC 6901)", "Date": "Tue, 28 Apr 2026 19:27:21 -0400", "Message-ID": "<20260428232721.1953782-1-dmalcolm@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.4", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "8ESpWbGWRtkbd-t7E7F8J6RkNs08SFsQmz4UFXsxyIs_1777418844", "X-Mimecast-Originator": "redhat.com", "Content-Type": "text/plain; charset=UTF-8", "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": "Successfully bootstrapped & regrtested on powerpc64le-unknown-linux-gnu\n(albeit without ada,cobol,d, and possibly missing some optional test dependencies)\nPushed to trunk as r17-170-g45024ece3faa77.\n\ngcc/ChangeLog:\n\t* Makefile.in (OBJS-libcommon): Add json-pointer-parsing.o.\n\t* json-pointer-parsing.cc: New file.\n\t* json-pointer-parsing.h: New file.\n\t* json.cc (json::object::set_string): Return a borrowed pointer to\n\tthe new json::value.\n\t(json::object::set_integer): Likewise.\n\t(json::array::append_string): Likewise.\n\t* json.h (json::object::set_string): Likewise.\n\t(json::object::set_integer): Likewise.\n\t(json::array::append_string): Likewise.\n\t* selftest-run-tests.cc (selftest::run_tests): Call\n\tselftest::json_pointer_parsing_cc_tests.\n\t* selftest.h (selftest::json_pointer_parsing_cc_tests): New decl.\n\ngcc/testsuite/ChangeLog:\n\t* selftests/json-pointer.json: New support file, taken directly\n\tfrom RFC 6901.\n\nSigned-off-by: David Malcolm <dmalcolm@redhat.com>\n---\n gcc/Makefile.in | 2 +-\n gcc/json-pointer-parsing.cc | 417 ++++++++++++++++++++++\n gcc/json-pointer-parsing.h | 56 +++\n gcc/json.cc | 27 +-\n gcc/json.h | 6 +-\n gcc/selftest-run-tests.cc | 1 +\n gcc/selftest.h | 1 +\n gcc/testsuite/selftests/json-pointer.json | 37 ++\n 8 files changed, 535 insertions(+), 12 deletions(-)\n create mode 100644 gcc/json-pointer-parsing.cc\n create mode 100644 gcc/json-pointer-parsing.h\n create mode 100644 gcc/testsuite/selftests/json-pointer.json", "diff": "diff --git a/gcc/Makefile.in b/gcc/Makefile.in\nindex bcbcffa4118..cbce3188794 100644\n--- a/gcc/Makefile.in\n+++ b/gcc/Makefile.in\n@@ -1905,7 +1905,7 @@ OBJS-libcommon = \\\n \tgcc-diagnostic-spec.o \\\n \tgraphviz.o pex.o \\\n \tpretty-print.o pretty-print-token-buffer.o intl.o \\\n-\tjson.o json-parsing.o json-diagnostic.o \\\n+\tjson.o json-parsing.o json-diagnostic.o json-pointer-parsing.o \\\n \tpub-sub.o \\\n \txml.o \\\n \tsbitmap.o \\\ndiff --git a/gcc/json-pointer-parsing.cc b/gcc/json-pointer-parsing.cc\nnew file mode 100644\nindex 00000000000..2a3ea8a97c4\n--- /dev/null\n+++ b/gcc/json-pointer-parsing.cc\n@@ -0,0 +1,417 @@\n+/* JSON Pointer parsing (RFC 6901).\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ Contributed by David Malcolm <dmalcolm@redhat.com>.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it under\n+the terms of the GNU General Public License as published by the Free\n+Software Foundation; either version 3, or (at your option) any later\n+version.\n+\n+GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n+for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3. If not see\n+<http://www.gnu.org/licenses/>. */\n+\n+#define INCLUDE_MAP\n+#define INCLUDE_STRING\n+#include \"config.h\"\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"json-pointer-parsing.h\"\n+#include \"pretty-print.h\"\n+#include \"pretty-print-markup-json.h\"\n+#include \"selftest.h\"\n+\n+/* Implementation of json::pointer parsing. */\n+\n+namespace {\n+\n+class json_pointer_parser\n+{\n+public:\n+ json::pointer::parser_result_t\n+ parse_utf8_string (const char *utf8_json_pointer,\n+\t\t const json::value *root_val);\n+\n+private:\n+ std::unique_ptr<json::pointer::error>\n+ make_error (const char *fmt, ...);\n+\n+ json::result<size_t, std::unique_ptr<json::pointer::error>>\n+ parse_array_index (const std::string &reftoken);\n+};\n+\n+} // anonymous namespace\n+\n+/* Parse JSON pointer. */\n+\n+json::pointer::parser_result_t\n+json_pointer_parser::parse_utf8_string (const char *utf8_json_pointer,\n+\t\t\t\t\tconst json::value *root_val)\n+{\n+ const char *ch_iter = utf8_json_pointer;\n+ const json::value *cur_val = root_val;\n+\n+ while (*ch_iter)\n+ {\n+ // Try to consume a reference-token\n+ if (*ch_iter != '/')\n+\treturn make_error (\"malformed JSON Pointer: expected %qs; got %qc\",\n+\t\t\t \"/\", *ch_iter);\n+ ch_iter++;\n+ std::string reftoken;\n+ while (char ch = *ch_iter)\n+\t{\n+\t /* End at end of string, or unescaped '/'. */\n+\t if (ch == '/' || ch == '\\0')\n+\t break;\n+\t ch_iter++;\n+\t if (ch == '~')\n+\t {\n+\t switch (*ch_iter)\n+\t\t{\n+\t\tcase '0':\n+\t\t reftoken += '~';\n+\t\t ch_iter++;\n+\t\t break;\n+\t\tcase '1':\n+\t\t reftoken += '/';\n+\t\t ch_iter++;\n+\t\t break;\n+\t\tdefault:\n+\t\t if (*ch_iter)\n+\t\t return make_error((\"malformed JSON Pointer:\"\n+\t\t\t\t \" expected %qs or %qs after %qs;\"\n+\t\t\t\t \" got %qc\"),\n+\t\t\t\t \"0\", \"1\", \"~\", *ch_iter);\n+\t\t else\n+\t\t return make_error ((\"malformed JSON Pointer:\"\n+\t\t\t\t\t\" expected %qs or %qs after %qs\"),\n+\t\t\t\t \"0\", \"1\", \"~\");\n+\t\t}\n+\t }\n+\t else\n+\t reftoken += ch;\n+\t}\n+ switch (cur_val->get_kind ())\n+\t{\n+\tdefault:\n+\t gcc_unreachable ();\n+\n+\tcase json::JSON_OBJECT:\n+\t {\n+\t const json::object *cur_obj\n+\t = static_cast<const json::object *> (cur_val);\n+\t if (const json::value *child = cur_obj->get (reftoken.c_str ()))\n+\t cur_val = child;\n+\t else\n+\t {\n+\t\tpp_markup::quoted_json_pointer obj_pointer (*cur_val);\n+\t\treturn make_error (\"unknown member %qs within object %e\",\n+\t\t\t\t reftoken.c_str (), &obj_pointer);\n+\t }\n+\t }\n+\t break;\n+\tcase json::JSON_ARRAY:\n+\t {\n+\t auto array_idx_res = parse_array_index (reftoken);\n+\t if (array_idx_res.m_err)\n+\t return std::move (array_idx_res.m_err);\n+\n+\t const json::array *cur_arr\n+\t = static_cast<const json::array *> (cur_val);\n+\t if (array_idx_res.m_val < cur_arr->size ())\n+\t cur_val = (*cur_arr)[array_idx_res.m_val];\n+\t else\n+\t {\n+\t\tpp_markup::quoted_json_pointer array_pointer (*cur_val);\n+\t\treturn make_error\n+\t\t (\"array index %li out of range for array %e\",\n+\t\t array_idx_res.m_val,\n+\t\t &array_pointer);\n+\t }\n+\t }\n+\t break;\n+\n+\tcase json::JSON_INTEGER:\n+\tcase json::JSON_FLOAT:\n+\t {\n+\t pp_markup::quoted_json_pointer cur_val_ptr (*cur_val);\n+\t return make_error\n+\t ((\"expected object or array for reference token %qs;\"\n+\t\t\" %e is a number\"),\n+\t reftoken.c_str (),\n+\t &cur_val_ptr);\n+\t }\n+\tcase json::JSON_STRING:\n+\t {\n+\t pp_markup::quoted_json_pointer cur_val_ptr (*cur_val);\n+\t return make_error\n+\t ((\"expected object or array for reference token %qs;\"\n+\t\t\" %e is a string\"),\n+\t reftoken.c_str (),\n+\t &cur_val_ptr);\n+\t }\n+\tcase json::JSON_TRUE:\n+\tcase json::JSON_FALSE:\n+\tcase json::JSON_NULL:\n+\t {\n+\t pp_markup::quoted_json_pointer cur_val_ptr (*cur_val);\n+\t return make_error\n+\t ((\"expected object or array for reference token %qs;\"\n+\t\t\" %e is a JSON literal\"),\n+\t reftoken.c_str (),\n+\t &cur_val_ptr);\n+\t }\n+\t}\n+ }\n+\n+ return cur_val;\n+}\n+\n+std::unique_ptr<json::pointer::error>\n+json_pointer_parser::make_error (const char *fmt, ...)\n+{\n+ va_list ap;\n+ va_start (ap, fmt);\n+ auto err = std::make_unique<json::pointer::error>\n+ (pretty_print_token_buffer (fmt, &ap));\n+ va_end (ap);\n+ return err;\n+}\n+\n+/* Parse array-index: '0', or decimal digits without a leading '0'. */\n+\n+json::result<size_t, std::unique_ptr<json::pointer::error>>\n+json_pointer_parser::parse_array_index (const std::string &reftoken)\n+{\n+ if (reftoken == \"0\")\n+ return 0;\n+\n+ /* Decimal digits without a leading '0'. */\n+ if (reftoken[0] < '1' || reftoken[0] > '9')\n+ return make_error (\"malformed JSON Pointer: bad array index: %qs\",\n+\t\t reftoken.c_str ());\n+\n+ size_t result = 0;\n+ for (auto digit : reftoken)\n+ {\n+ result *= 10;\n+ if (digit < '0' || digit > '9')\n+\treturn make_error (\"malformed JSON Pointer: bad array index: %qs\",\n+\t\t\t reftoken.c_str ());\n+ result += digit - '0';\n+ }\n+ return result;\n+}\n+\n+json::pointer::parser_result_t\n+json::pointer::parse_utf8_string (const char *utf8_json_pointer,\n+\t\t\t\t const json::value *root_val)\n+{\n+ json_pointer_parser p;\n+ return p.parse_utf8_string (utf8_json_pointer, root_val);\n+}\n+\n+\f\n+#if CHECKING_P\n+\n+namespace selftest {\n+\n+/* Implementation detail of ASSERT_PARSE_JSON_POINTER_EQ. */\n+\n+static void\n+assert_parse_json_pointer_eq (const location &loc,\n+\t\t\t const char *utf8_json_pointer,\n+\t\t\t const json::value *root_val,\n+\t\t\t const json::value *expected_jv)\n+{\n+ auto res = json::pointer::parse_utf8_string (utf8_json_pointer, root_val);\n+ ASSERT_EQ_AT (loc, res.m_err, nullptr);\n+ ASSERT_EQ_AT (loc, res.m_val, expected_jv);\n+}\n+\n+/* Assert that JSON_POINTER, a const char *, is a valid JSON pointer into\n+ ROOT_VAL, and equals EXPECTED_JV. */\n+#define ASSERT_PARSE_JSON_POINTER_EQ(JSON_POINTER, ROOT_VAL, EXPECTED_JV) \\\n+ assert_parse_json_pointer_eq ((SELFTEST_LOCATION), (JSON_POINTER), \\\n+\t\t\t\t(ROOT_VAL), (EXPECTED_JV))\n+\n+/* Implementation detail of ASSERT_DUMP_FROM_JSON_POINTER_STREQ. */\n+\n+static void\n+assert_dump_from_json_pointer_streq (const location &loc,\n+\t\t\t\t const json::value *root_val,\n+\t\t\t\t const char *utf8_json_pointer,\n+\t\t\t\t const char *expected_dump)\n+{\n+ auto res = json::pointer::parse_utf8_string (utf8_json_pointer, root_val);\n+ ASSERT_EQ_AT (loc, res.m_err, nullptr);\n+\n+ pretty_printer pp;\n+ res.m_val->print (&pp, false);\n+ ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected_dump);\n+}\n+\n+/* Assert that JSON_POINTER (a const char *) successfully looks up a value\n+ relative to ROOT_VAL, and that the resulting value dumps as\n+ EXPECTED_DUMP. */\n+#define ASSERT_DUMP_FROM_JSON_POINTER_STREQ(ROOT_VAL, JSON_POINTER, EXPECTED_DUMP) \\\n+ assert_dump_from_json_pointer_streq ((SELFTEST_LOCATION), (ROOT_VAL),\t\\\n+\t\t\t\t (JSON_POINTER), (EXPECTED_DUMP))\n+\n+/* Implementation detail of ASSERT_JSON_POINTER_ERR. */\n+\n+static void\n+assert_json_pointer_err (const location &loc,\n+\t\t\t const char *utf8_json_pointer,\n+\t\t\t const json::value *root_val,\n+\t\t\t const char *expected_err)\n+{\n+ auto res = json::pointer::parse_utf8_string (utf8_json_pointer, root_val);\n+ ASSERT_EQ_AT (loc, res.m_val, nullptr);\n+ ASSERT_NE_AT (loc, res.m_err, nullptr);\n+ std::string err_str = res.m_err->m_tokens.to_string ();\n+ ASSERT_STREQ_AT (loc, err_str.c_str (), expected_err);\n+}\n+\n+/* Assert that JSON_POINTER (a const char *) fails to look up a value\n+ relative to ROOT_VAL, and that the resulting error expressed as a string\n+ is EXPECTED_ERR. */\n+#define ASSERT_JSON_POINTER_ERR(JSON_POINTER, ROOT_VAL, EXPECTED_ERR) \\\n+ assert_json_pointer_err ((SELFTEST_LOCATION), (JSON_POINTER), \\\n+\t\t\t (ROOT_VAL), (EXPECTED_ERR))\n+\n+/* Selftests. */\n+\n+static void\n+test_simple ()\n+{\n+ json::object obj;\n+ auto js_bar = obj.set_string (\"foo\", \"bar\");\n+ auto baz = std::make_unique<json::array> ();\n+ json::array *js_baz = baz.get ();\n+ auto js_str0 = baz->append_string (\"x\");\n+ auto js_str1 = baz->append_string (\"y\");\n+ obj.set (\"baz\", std::move (baz));\n+\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"\", &obj, &obj);\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"/foo\", &obj, js_bar);\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"/baz\", &obj, js_baz);\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"/baz/0\", &obj, js_str0);\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"/baz/1\", &obj, js_str1);\n+}\n+\n+/* Verify that JSON Pointers are correctly escaped. */\n+\n+static void\n+test_escaping_1 ()\n+{\n+ json::object obj;\n+ auto js_a_slash_b = obj.set_integer (\"a/b\", 1);\n+ auto js_m_tilde_n = obj.set_integer (\"m~n\", 8);\n+ auto js_tilde_1 = obj.set_integer (\"~1\", 9);\n+\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"/a~1b\", &obj, js_a_slash_b);\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"/m~0n\", &obj, js_m_tilde_n);\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"/~01\", &obj, js_tilde_1);\n+}\n+\n+static void\n+test_escaping_2 ()\n+{\n+ /* The example from RFC 6901 section 5. */\n+ char *path = locate_file (\"json-pointer.json\");\n+ char *js_doc = selftest::read_file (SELFTEST_LOCATION, path);\n+ free (path);\n+ auto res = json::parse_utf8_string (js_doc, true, nullptr);\n+ ASSERT_EQ (res.m_err, nullptr);\n+ free (js_doc);\n+\n+ auto root = res.m_val.get ();\n+ ASSERT_PARSE_JSON_POINTER_EQ (\"\", root, root);\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/foo\", \"[\\\"bar\\\", \\\"baz\\\"]\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/foo/0\", \"\\\"bar\\\"\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/\", \"0\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/a~1b\", \"1\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/c%d\" , \"2\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/e^f\" , \"3\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/g|h\" , \"4\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/i\\\\j\", \"5\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/k\\\"l\", \"6\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/ \" , \"7\");\n+ ASSERT_DUMP_FROM_JSON_POINTER_STREQ (root, \"/m~0n\", \"8\");\n+}\n+\n+static void\n+test_errors ()\n+{\n+ json::object obj;\n+ json::array arr;\n+ ASSERT_JSON_POINTER_ERR (\"foo\", &obj,\n+\t\t\t \"malformed JSON Pointer: expected '/'; got 'f'\");\n+ ASSERT_JSON_POINTER_ERR (\"/~\", &obj,\n+\t\t\t \"malformed JSON Pointer: expected '0' or '1' after '~'\");\n+ ASSERT_JSON_POINTER_ERR (\"/~~\", &obj,\n+\t\t\t \"malformed JSON Pointer: expected '0' or '1' after '~';\"\n+\t\t\t \" got '~'\");\n+ ASSERT_JSON_POINTER_ERR (\"/foo\", &obj,\n+\t\t\t \"unknown member 'foo' within object ''\");\n+ ASSERT_JSON_POINTER_ERR (\"/0\", &obj,\n+\t\t\t \"unknown member '0' within object ''\");\n+ ASSERT_JSON_POINTER_ERR (\"/0\", &arr,\n+\t\t\t \"array index 0 out of range for array ''\");\n+ ASSERT_JSON_POINTER_ERR (\"/-1\", &arr,\n+\t\t\t \"malformed JSON Pointer: bad array index: '-1'\");\n+ ASSERT_JSON_POINTER_ERR (\"/8a\", &arr,\n+\t\t\t \"malformed JSON Pointer: bad array index: '8a'\");\n+\n+ {\n+ json::integer_number js_int (42);\n+ json::float_number js_float (42);\n+ json::string js_str (\"foo\");\n+ json::literal js_true (json::JSON_TRUE);\n+ ASSERT_JSON_POINTER_ERR\n+ (\"/foo\", &js_int,\n+ \"expected object or array for reference token 'foo';\"\n+ \" '' is a number\");\n+ ASSERT_JSON_POINTER_ERR\n+ (\"/foo\", &js_float,\n+ \"expected object or array for reference token 'foo';\"\n+ \" '' is a number\");\n+ ASSERT_JSON_POINTER_ERR\n+ (\"/foo\", &js_str,\n+ \"expected object or array for reference token 'foo';\"\n+ \" '' is a string\");\n+ ASSERT_JSON_POINTER_ERR\n+ (\"/foo\", &js_true,\n+ \"expected object or array for reference token 'foo';\"\n+ \" '' is a JSON literal\");\n+ }\n+\n+ /* RFC 6901 section 4 \"Evaluation\" has:\n+ \"the string '~01' correctly becomes '~1' after transformation\". */\n+ ASSERT_JSON_POINTER_ERR (\"/~01\", &obj,\n+\t\t\t \"unknown member '~1' within object ''\");\n+}\n+\n+/* Run all of the selftests within this file. */\n+\n+void\n+json_pointer_parsing_cc_tests ()\n+{\n+ test_simple ();\n+ test_escaping_1 ();\n+ test_escaping_2 ();\n+ test_errors ();\n+}\n+\n+} // namespace selftest\n+\n+#endif /* #if CHECKING_P */\ndiff --git a/gcc/json-pointer-parsing.h b/gcc/json-pointer-parsing.h\nnew file mode 100644\nindex 00000000000..142e815984b\n--- /dev/null\n+++ b/gcc/json-pointer-parsing.h\n@@ -0,0 +1,56 @@\n+/* JSON Pointer parsing (RFC 6901).\n+ Copyright (C) 2026 Free Software Foundation, Inc.\n+ Contributed by David Malcolm <dmalcolm@redhat.com>.\n+\n+This file is part of GCC.\n+\n+GCC is free software; you can redistribute it and/or modify it under\n+the terms of the GNU General Public License as published by the Free\n+Software Foundation; either version 3, or (at your option) any later\n+version.\n+\n+GCC is distributed in the hope that it will be useful, but WITHOUT ANY\n+WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n+for more details.\n+\n+You should have received a copy of the GNU General Public License\n+along with GCC; see the file COPYING3. If not see\n+<http://www.gnu.org/licenses/>. */\n+\n+#ifndef GCC_JSON_POINTER_PARSING_H\n+#define GCC_JSON_POINTER_PARSING_H\n+\n+#include \"json.h\"\n+#include \"json-parsing.h\"\n+#include \"pretty-print-token-buffer.h\"\n+\n+namespace json {\n+namespace pointer {\n+\n+class error\n+{\n+public:\n+ error (pretty_print_token_buffer tokens)\n+ : m_tokens (std::move (tokens))\n+ {\n+ }\n+\n+ pretty_print_token_buffer m_tokens;\n+};\n+\n+/* Typedef for the result of parsing JSON pointer: borrowed json::value *\n+ or of a json::pointer::error *. */\n+typedef result<const json::value*,\n+\t std::unique_ptr<error>> parser_result_t;\n+\n+/* Function for parsing JSON pointer. */\n+\n+extern parser_result_t\n+parse_utf8_string (const char *utf8_json_pointer,\n+\t\t const json::value *root_val);\n+\n+} // namespace pointer\n+} // namespace json\n+\n+#endif /* GCC_JSON_POINTER_PARSING_H */\ndiff --git a/gcc/json.cc b/gcc/json.cc\nindex 7c541d97262..bff9afffb89 100644\n--- a/gcc/json.cc\n+++ b/gcc/json.cc\n@@ -418,21 +418,27 @@ object::get (const char *key) const\n }\n \n /* Set value of KEY within this object to a JSON\n- string value based on UTF8_VALUE. */\n+ string value based on UTF8_VALUE.\n+ Return a borrowed ptr to the new json::string. */\n \n-void\n+const json::string *\n object::set_string (const char *key, const char *utf8_value)\n {\n- set (key, new json::string (utf8_value));\n+ json::string *str = new json::string (utf8_value);\n+ set (key, str);\n+ return str;\n }\n \n /* Set value of KEY within this object to a JSON\n- integer value based on V. */\n+ integer value based on V.\n+ Return a borrowed ptr to the new json::integer_number. */\n \n-void\n+const json::integer_number *\n object::set_integer (const char *key, long v)\n {\n- set (key, new json::integer_number (v));\n+ json::integer_number *js_int = new json::integer_number (v);\n+ set (key, js_int);\n+ return js_int;\n }\n \n /* Set value of KEY within this object to a JSON\n@@ -572,11 +578,16 @@ array::append (value *v)\n m_elements.safe_push (v);\n }\n \n-void\n+/* Append UTF8_VALUE to this array, returning a borrowed pointer to the\n+ new json::string. */\n+\n+const json::string *\n array::append_string (const char *utf8_value)\n {\n gcc_assert (utf8_value);\n- append (new json::string (utf8_value));\n+ auto js_str = new json::string (utf8_value);\n+ append (js_str);\n+ return js_str;\n }\n \n /* class json::float_number, a subclass of json::value, wrapping a double. */\ndiff --git a/gcc/json.h b/gcc/json.h\nindex 2ea1d13d179..3d79e2a023c 100644\n--- a/gcc/json.h\n+++ b/gcc/json.h\n@@ -222,8 +222,8 @@ class object : public value\n value *get (const char *key) const;\n const map_t &get_map () const { return m_map; }\n \n- void set_string (const char *key, const char *utf8_value);\n- void set_integer (const char *key, long v);\n+ const json::string *set_string (const char *key, const char *utf8_value);\n+ const json::integer_number *set_integer (const char *key, long v);\n void set_float (const char *key, double v);\n \n /* Set to literal true/false. */\n@@ -270,7 +270,7 @@ class array : public value\n array *dyn_cast_array () final override { return this; }\n \n void append (value *v);\n- void append_string (const char *utf8_value);\n+ const json::string *append_string (const char *utf8_value);\n \n /* Append V to this array, requiring V\n to be a specific json::value subclass.\ndiff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc\nindex 86b2340e9b9..e39a94f8688 100644\n--- a/gcc/selftest-run-tests.cc\n+++ b/gcc/selftest-run-tests.cc\n@@ -78,6 +78,7 @@ selftest::run_tests ()\n opts_cc_tests ();\n json_cc_tests ();\n json_parser_cc_tests ();\n+ json_pointer_parsing_cc_tests ();\n cgraph_cc_tests ();\n optinfo_emit_json_cc_tests ();\n ordered_hash_map_tests_cc_tests ();\ndiff --git a/gcc/selftest.h b/gcc/selftest.h\nindex e3e86ffaf0f..8891d0b7b6f 100644\n--- a/gcc/selftest.h\n+++ b/gcc/selftest.h\n@@ -239,6 +239,7 @@ extern void input_cc_tests ();\n extern void ipa_modref_tree_cc_tests ();\n extern void json_cc_tests ();\n extern void json_parser_cc_tests ();\n+extern void json_pointer_parsing_cc_tests ();\n extern void opt_suggestions_cc_tests ();\n extern void optinfo_emit_json_cc_tests ();\n extern void opts_cc_tests ();\ndiff --git a/gcc/testsuite/selftests/json-pointer.json b/gcc/testsuite/selftests/json-pointer.json\nnew file mode 100644\nindex 00000000000..e5f38d838cb\n--- /dev/null\n+++ b/gcc/testsuite/selftests/json-pointer.json\n@@ -0,0 +1,37 @@\n+/* Copyright (c) 2013 IETF Trust and the persons identified as authors of the code. All rights reserved.\n+ Redistribution and use in source and binary forms, with or without modification, are permitted provided\n+ that the following conditions are met:\n+ • Redistributions of source code must retain the above copyright notice, this list of conditions and\n+ the following disclaimer.\n+ • Redistributions in binary form must reproduce the above copyright notice, this list of conditions\n+ and the following disclaimer in the documentation and/or other materials provided with the\n+ distribution.\n+ • Neither the name of Internet Society, IETF or IETF Trust, nor the names of specific contributors,\n+ may be used to endorse or promote products derived from this software without specific prior written\n+ permission.\n+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”\n+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n+ POSSIBILITY OF SUCH DAMAGE.\n+*/\n+\n+/* The example from RFC 6901 section 5. */\n+{\n+ \"foo\": [\"bar\", \"baz\"],\n+ \"\": 0,\n+ \"a/b\": 1,\n+ \"c%d\": 2,\n+ \"e^f\": 3,\n+ \"g|h\": 4,\n+ \"i\\\\j\": 5,\n+ \"k\\\"l\": 6,\n+ \" \": 7,\n+ \"m~n\": 8\n+}\n", "prefixes": [ "pushed:", "r17-170" ] }