get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "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"
    ]
}