get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 2196540,
    "url": "http://patchwork.ozlabs.org/api/patches/2196540/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260214155201.1049644-5-dmalcolm@redhat.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": "<20260214155201.1049644-5-dmalcolm@redhat.com>",
    "list_archive_url": null,
    "date": "2026-02-14T15:52:00",
    "name": "[4/5] Add json-diagnostic.{cc,h}",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "4ffc111b3017804322f5df1b4fefcc14da3c45ea",
    "submitter": {
        "id": 24465,
        "url": "http://patchwork.ozlabs.org/api/people/24465/?format=api",
        "name": "David Malcolm",
        "email": "dmalcolm@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260214155201.1049644-5-dmalcolm@redhat.com/mbox/",
    "series": [
        {
            "id": 492183,
            "url": "http://patchwork.ozlabs.org/api/series/492183/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=492183",
            "date": "2026-02-14T15:51:56",
            "name": "Improve diagnostics for bad JSON inputs [PR124094]",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/492183/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2196540/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2196540/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 (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=A7HAjH5S;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)",
            "sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=A7HAjH5S",
            "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 4fCtw86bkwz1xpl\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 15 Feb 2026 02:57:28 +1100 (AEDT)",
            "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id EB1D94B9DB7F\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 14 Feb 2026 15:57:26 +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 427004BAD169\n for <gcc-patches@gcc.gnu.org>; Sat, 14 Feb 2026 15:52:30 +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-52-5pG0BbG5OZGwd7tVIWI23g-1; Sat,\n 14 Feb 2026 10:52:24 -0500",
            "from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id B3FB91956053; Sat, 14 Feb 2026 15:52:22 +0000 (UTC)",
            "from t14s.localdomain.com (unknown [10.22.88.22])\n by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id D789C1955D85; Sat, 14 Feb 2026 15:52:19 +0000 (UTC)"
        ],
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 sourceware.org EB1D94B9DB7F",
            "OpenDKIM Filter v2.11.0 sourceware.org 427004BAD169"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 427004BAD169",
        "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 427004BAD169",
        "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1771084355; cv=none;\n b=xSx8GRfjpbB0ATE/7MIwc7R2UcrpTyvb1Y4uETG6+QC5drFS/mLvswVIvZ2/hWUP7QHA2pmhzmVIM+dH8KrVPwFUDOBgJl32/zuXIXXMNQcy7T1V+C+Hk3lMtpGbfsntKroNtBcfG5G1PgycopBL6/WJW55We4lDN9Vnbe5rSdI=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1771084355; c=relaxed/simple;\n bh=dYHotCI7Yz7tIGBjGb/CBLBQdRopOPWkuOXy/QyWLh8=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=s398A86HUFNYqUeYsgnrf9CK3xzt/GLWv/qn773xToPXLtfVBfeoKiwV76tV00gNcPve/b0qxYE/LdvHuI3wSuKTPCRU1Mb8LBoMw8YWk9mCW4OexRDqCqivPPXNYQRtoMc50wjIy6HpyIO0GdcWDl2Am4ql62MUA0j9MmCGdtI=",
        "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=1771084349;\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 in-reply-to:in-reply-to:references:references;\n bh=7zuC5/q4sEyUZwNLDjerarWXYaYE3wxohYnVDG/2X34=;\n b=A7HAjH5SU525BV1v3UVt/othXqUT+DOSIzx2YcaQog0yxQfTiujuj6QAzp5vu8Swu4Y4ep\n nsczQH3QtQnagvbsMBDlPHyoVQkS9UVg4M34dmpHEjUF/0s5wMctr3NOC3EfvteFnffVFB\n YIvZQc5QqKmcc901RQcC/wQr8ifsPA4=",
        "X-MC-Unique": "5pG0BbG5OZGwd7tVIWI23g-1",
        "X-Mimecast-MFC-AGG-ID": "5pG0BbG5OZGwd7tVIWI23g_1771084343",
        "From": "David Malcolm <dmalcolm@redhat.com>",
        "To": "gcc-patches@gcc.gnu.org, Yangyu Chen <cyy@cyyself.name>,\n Soumya AR <soumyaa@nvidia.com>, jakub@redhat.com,\n Richard Biener <richard.guenther@gmail.com>",
        "Cc": "Alfie Richards <alfie.richards@arm.com>,\n Sandra Loosemore <sloosemore@baylibre.com>,\n Martin Liska <martin.liska@hey.com>,\n Evgeny Stupachenko <evstupac@gmail.com>,\n Alice Carlotti <alice.carlotti@arm.com>,\n Jeff Law <jeffrey.law@oss.qualcomm.com>,\n Jerry DeLisle <jvdelisle@gcc.gnu.org>, Harald Anlauf <anlauf@gmx.de>,\n Paul Thomas <pault@gcc.gnu.org>,\n Richard Sandiford <rdsandiford@googlemail.com>,\n Joseph Myers <josmyers@redhat.com>, Jason Merrill <jason@redhat.com>,\n David Malcolm <dmalcolm@redhat.com>",
        "Subject": "[PATCH 4/5] Add json-diagnostic.{cc,h}",
        "Date": "Sat, 14 Feb 2026 10:52:00 -0500",
        "Message-ID": "<20260214155201.1049644-5-dmalcolm@redhat.com>",
        "In-Reply-To": "<20260214155201.1049644-1-dmalcolm@redhat.com>",
        "References": "<tencent_048DF6A8630E2E590C79C840A31F1FA86006@qq.com>\n <20260214155201.1049644-1-dmalcolm@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.0 on 10.30.177.17",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "9L_EByHSz01U7w6vy6ZdtPQHDudKgn71QvBCpPqmFwU_1771084343",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true",
        "X-BeenThere": "gcc-patches@gcc.gnu.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>",
        "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>",
        "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>",
        "List-Post": "<mailto:gcc-patches@gcc.gnu.org>",
        "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>",
        "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>",
        "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"
    },
    "content": "This patch adds support for emitting diagnostics about JSON input files\nto global_dc, showing both the file/line/columns and the JSON Pointer\nfor the problematic json::value.  Test coverage is added by the followup\non aarch64.\n\ngcc/ChangeLog:\n\t* Makefile.in (OBJS-libcommon): Add json-diagnostic.o.\n\t* diagnostics/client-data-hooks.h\n\t(class client_data_hooks_decorator): New.\n\t* diagnostics/context.cc (context::set_client_data_hooks): Return\n\tthe old hooks.\n\t* diagnostics/context.h (context::set_client_data_hooks): Update\n\tdecl likewise.\n\t* json-diagnostic.cc: New file.\n\t* json-diagnostic.h: New file.\n\nSigned-off-by: David Malcolm <dmalcolm@redhat.com>\n---\n gcc/Makefile.in                     |   2 +-\n gcc/diagnostics/client-data-hooks.h |  53 ++++\n gcc/diagnostics/context.cc          |   5 +-\n gcc/diagnostics/context.h           |   4 +-\n gcc/json-diagnostic.cc              | 374 ++++++++++++++++++++++++++++\n gcc/json-diagnostic.h               |  74 ++++++\n 6 files changed, 508 insertions(+), 4 deletions(-)\n create mode 100644 gcc/json-diagnostic.cc\n create mode 100644 gcc/json-diagnostic.h",
    "diff": "diff --git a/gcc/Makefile.in b/gcc/Makefile.in\nindex 54865765b6ef6..d4170dd7a3262 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 intl.o \\\n-\tjson.o json-parsing.o \\\n+\tjson.o json-parsing.o json-diagnostic.o \\\n \tpub-sub.o \\\n \txml.o \\\n \tsbitmap.o \\\ndiff --git a/gcc/diagnostics/client-data-hooks.h b/gcc/diagnostics/client-data-hooks.h\nindex 6fa31d0d65e00..bd760dcb70bba 100644\n--- a/gcc/diagnostics/client-data-hooks.h\n+++ b/gcc/diagnostics/client-data-hooks.h\n@@ -63,6 +63,59 @@ class client_data_hooks\n   add_sarif_invocation_properties (sarif_object &invocation_obj) const = 0;\n };\n \n+/* Implementation of client_data_hooks that delegates vfuncs to an\n+   optional inner object.  */\n+\n+class client_data_hooks_decorator : public client_data_hooks\n+{\n+ public:\n+  client_data_hooks_decorator (const client_data_hooks *inner)\n+  : m_inner (inner)\n+  {\n+  }\n+\n+  const client_version_info *get_any_version_info () const override\n+  {\n+    if (m_inner)\n+      return m_inner->get_any_version_info ();\n+    return nullptr;\n+  }\n+\n+  const logical_locations::manager *\n+  get_logical_location_manager () const override\n+  {\n+    if (m_inner)\n+      return m_inner->get_logical_location_manager ();\n+    return nullptr;\n+  }\n+\n+  logical_locations::key\n+  get_current_logical_location () const override\n+  {\n+    if (m_inner)\n+      return m_inner->get_current_logical_location ();\n+    return logical_locations::key ();\n+  }\n+\n+  const char *\n+  maybe_get_sarif_source_language (const char *filename) const override\n+  {\n+    if (m_inner)\n+      return m_inner->maybe_get_sarif_source_language (filename);\n+    return nullptr;\n+  }\n+\n+  void\n+  add_sarif_invocation_properties (sarif_object &invocation_obj) const override\n+  {\n+    if (m_inner)\n+      m_inner->add_sarif_invocation_properties (invocation_obj);\n+  }\n+\n+private:\n+  const client_data_hooks *m_inner;\n+};\n+\n class client_plugin_info;\n \n /* Abstract base class for a diagnostics::context to get at\ndiff --git a/gcc/diagnostics/context.cc b/gcc/diagnostics/context.cc\nindex 03d570665843d..98af6ecb1b665 100644\n--- a/gcc/diagnostics/context.cc\n+++ b/gcc/diagnostics/context.cc\n@@ -529,12 +529,13 @@ context::set_main_input_filename (const char *filename)\n     sink_->set_main_input_filename (filename);\n }\n \n-void\n+std::unique_ptr<client_data_hooks>\n context::set_client_data_hooks (std::unique_ptr<client_data_hooks> hooks)\n {\n-  delete m_client_data_hooks;\n+  std::unique_ptr<client_data_hooks> old_hooks (m_client_data_hooks);\n   /* Ideally the field would be a std::unique_ptr here.  */\n   m_client_data_hooks = hooks.release ();\n+  return old_hooks;\n }\n \n void\ndiff --git a/gcc/diagnostics/context.h b/gcc/diagnostics/context.h\nindex 742319fbd204f..514ff1e68f9b8 100644\n--- a/gcc/diagnostics/context.h\n+++ b/gcc/diagnostics/context.h\n@@ -388,7 +388,9 @@ public:\n   /* Various setters for use by option-handling logic.  */\n   void set_sink (std::unique_ptr<sink> sink_);\n   void set_text_art_charset (enum diagnostic_text_art_charset charset);\n-  void set_client_data_hooks (std::unique_ptr<client_data_hooks> hooks);\n+\n+  std::unique_ptr<client_data_hooks>\n+  set_client_data_hooks (std::unique_ptr<client_data_hooks> hooks);\n \n   void push_owned_urlifier (std::unique_ptr<urlifier>);\n   void push_borrowed_urlifier (const urlifier &);\ndiff --git a/gcc/json-diagnostic.cc b/gcc/json-diagnostic.cc\nnew file mode 100644\nindex 0000000000000..bf61cd0007ecf\n--- /dev/null\n+++ b/gcc/json-diagnostic.cc\n@@ -0,0 +1,374 @@\n+/* Diagnostics relating to JSON values.\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+#define INCLUDE_VECTOR\n+#include \"config.h\"\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"intl.h\"\n+#include \"diagnostic.h\"\n+#include \"json-diagnostic.h\"\n+#include \"diagnostics/dumping.h\"\n+#include \"diagnostics/logging.h\"\n+#include \"diagnostics/logical-locations.h\"\n+#include \"diagnostics/client-data-hooks.h\"\n+#include \"diagnostics/text-sink.h\"\n+#include \"diagnostics/physical-location-maker.h\"\n+#include \"pretty-print-markup.h\"\n+\n+static bool\n+emit_json_diagnostic (gcc_json_context &ctxt,\n+\t\t      enum diagnostics::kind kind,\n+\t\t      const json::value &js_val,\n+\t\t      diagnostics::option_id option_id,\n+\t\t      const char *gmsgid, va_list *ap)\n+  ATTRIBUTE_GCC_DIAG(5,0);\n+\n+using log_function_params = diagnostics::logging::log_function_params;\n+using auto_inc_log_depth = diagnostics::logging::auto_inc_depth;\n+\n+class json_logical_location_manager\n+  : public diagnostics::logical_locations::manager\n+{\n+public:\n+  using key = diagnostics::logical_locations::key;\n+  using kind = diagnostics::logical_locations::kind;\n+\n+  void\n+  dump (FILE *outfile, int indent) const final override\n+  {\n+    diagnostics::dumping::emit_heading (outfile, indent,\n+\t\t\t\t\t\"json_logical_location_manager\");\n+  }\n+\n+  label_text\n+  get_short_name (key k) const final override\n+  {\n+    auto *js_val = js_from_key (k);\n+    const json::pointer::token &pointer_token = js_val->get_pointer_token ();\n+    pretty_printer pp;\n+    pointer_token.print (&pp);\n+    return label_text::take (xstrdup (pp_formatted_text (&pp)));\n+  }\n+\n+  label_text\n+  get_name_with_scope (key k) const final override\n+  {\n+    auto *js_val = js_from_key (k);\n+    pretty_printer pp;\n+    js_val->print_pointer (&pp);\n+    return label_text::take (xstrdup (pp_formatted_text (&pp)));\n+  }\n+\n+  label_text\n+  get_internal_name (key) const final override\n+  {\n+    return label_text ();\n+  }\n+\n+  kind\n+  get_kind (key k) const final override\n+  {\n+    auto *js_val = js_from_key (k);\n+\n+    switch (js_val->get_kind ())\n+      {\n+      default:\n+\tgcc_unreachable ();\n+\n+      case json::JSON_OBJECT:\n+\treturn kind::object;\n+\n+      case json::JSON_ARRAY:\n+\treturn kind::array;\n+\n+      case json::JSON_INTEGER:\n+      case json::JSON_FLOAT:\n+      case json::JSON_STRING:\n+      case json::JSON_TRUE:\n+      case json::JSON_FALSE:\n+      case json::JSON_NULL:\n+\treturn kind::property;\n+      }\n+  }\n+\n+  label_text\n+  get_name_for_path_output (key k) const final override\n+  {\n+    return get_name_with_scope (k);\n+  }\n+\n+  key\n+  get_parent (key k) const final override\n+  {\n+    auto *js_val = js_from_key (k);\n+    auto &pointer_token = js_val->get_pointer_token ();\n+    return key_from_js (pointer_token.m_parent);\n+  }\n+\n+  static const json::value *\n+  js_from_key (key k)\n+  {\n+    return k.cast_to<const json::value *> ();\n+  }\n+\n+  static key\n+  key_from_js (const json::value *js_val)\n+  {\n+    return key::from_ptr (js_val);\n+  }\n+\n+private:\n+  static void\n+    print_json_pointer_token (pretty_printer *);\n+};\n+\n+/* Implementation of diagnostics::client_data_hooks\n+   for reporting a diagnostic at a particular json::value\n+   in a JSON input file.\n+\n+   It wraps another hooks instance, but uses a\n+   json_logical_location_manager, has a specific\n+   json::value for the current logical location,\n+   and treats the SARIF source lang as \"json\".  */\n+\n+class json_client_data_hooks : public diagnostics::client_data_hooks_decorator\n+{\n+public:\n+  json_client_data_hooks (const json::value &js_val,\n+\t\t\t  const client_data_hooks *inner)\n+  : diagnostics::client_data_hooks_decorator (inner),\n+    m_js_val (js_val)\n+  {}\n+\n+  const diagnostics::logical_locations::manager *\n+  get_logical_location_manager () const override\n+  {\n+    return &m_logical_loc_mgr;\n+  }\n+\n+  diagnostics::logical_locations::key\n+  get_current_logical_location () const override\n+  {\n+    /* Use the json value's pointer as the key.  */\n+    return json_logical_location_manager::key_from_js (&m_js_val);\n+  }\n+\n+  const char *\n+  maybe_get_sarif_source_language (const char *) const override\n+  {\n+    return \"json\";\n+  }\n+\n+private:\n+  json_logical_location_manager m_logical_loc_mgr;\n+  const json::value &m_js_val;\n+};\n+\n+namespace pp_markup {\n+\n+/* Print the JSON Pointer of a given json::value in quotes.  */\n+\n+class quoted_json_pointer : public pp_element\n+{\n+public:\n+  quoted_json_pointer (const json::value &js_val)\n+  : m_js_val (js_val)\n+  {\n+  }\n+\n+  void\n+  add_to_phase_2 (context &ctxt) final override\n+  {\n+    ctxt.begin_quote ();\n+    m_js_val.print_pointer (&ctxt.m_pp);\n+    ctxt.end_quote ();\n+  }\n+\n+private:\n+  const json::value &m_js_val;\n+};\n+\n+} // namespace pp_markup\n+\n+/* text_sink starter for diagnostics relating to JSON.  */\n+\n+static void\n+json_text_starter (diagnostics::text_sink &sink,\n+\t\t   const diagnostics::diagnostic_info *diagnostic)\n+{\n+  pretty_printer *pp = sink.get_printer ();\n+\n+  /* If this isn't the root value, report its json pointer.  */\n+  diagnostics::logical_locations::key k;\n+  if (auto data_hooks = sink.get_context ().get_client_data_hooks ())\n+    k = data_hooks->get_current_logical_location ();\n+  const json::value *js_val = json_logical_location_manager::js_from_key (k);\n+  if (js_val && js_val->get_pointer_token ().m_parent)\n+    {\n+      const char *file = LOCATION_FILE (diagnostic_location (diagnostic));\n+      char *new_prefix = file ?  sink.file_name_as_prefix (file) : nullptr;\n+      pp_set_prefix (pp, new_prefix);\n+\n+      pp_markup::quoted_json_pointer e (*js_val);\n+      switch (js_val->get_kind ())\n+\t{\n+\tdefault:\n+\t  pp_printf (pp, _(\"In JSON value %e\"), &e);\n+\t  break;\n+\tcase json::JSON_OBJECT:\n+\t  pp_printf (pp, _(\"In JSON object %e\"), &e);\n+\t  break;\n+\tcase json::JSON_ARRAY:\n+\t  pp_printf (pp, _(\"In JSON array %e\"), &e);\n+\t  break;\n+\t}\n+      pp_newline (pp);\n+    }\n+\n+  pp_set_prefix (pp, sink.build_prefix (*diagnostic));\n+}\n+\n+\n+/* class gcc_json_context : public json::simple_location_map.  */\n+\n+location_t\n+gcc_json_context::make_location_for_point (const json::location_map::point &p)\n+{\n+  diagnostics::physical_location_maker m (line_table);\n+  return m.new_location_from_file_line_column (m_filename,\n+\t\t\t\t\t       p.m_line,\n+\t\t\t\t\t       p.m_column + 1);\n+}\n+\n+location_t\n+gcc_json_context::make_location_for_range (const json::location_map::range &r)\n+{\n+  location_t start_loc = make_location_for_point (r.m_start);\n+  location_t end_loc = make_location_for_point (r.m_end);\n+  return make_location (start_loc, start_loc, end_loc);\n+}\n+\n+/* Emit a diagnostic on global_dc of the relevant KIND relating to JS_VAL,\n+   using CTXT to get at file/line/column info.\n+\n+   Temporarily override global_dc's logical location to refer to JS_VAL\n+   and the text_sink starter and finalizer to be suitable for handling\n+   reporting within a JSON file.  */\n+\n+static bool\n+emit_json_diagnostic (gcc_json_context &ctxt,\n+\t\t      enum diagnostics::kind kind,\n+\t\t      const json::value &js_val,\n+\t\t      diagnostics::option_id option_id,\n+\t\t      const char *gmsgid, va_list *ap)\n+{\n+  auto logger = global_dc->get_logger ();\n+  log_function_params (logger, __func__)\n+    .log_param_option_id (\"option_id\", option_id)\n+    .log_param_string (\"gmsgid\", gmsgid);\n+  auto_inc_log_depth depth_sentinel (logger);\n+\n+  auto_diagnostic_group d;\n+\n+  // Get physical location for JS_VAL.\n+  location_t phys_loc\n+    = ctxt.make_location_for_range (ctxt.get_range_for_value (js_val));\n+  rich_location richloc (line_table, phys_loc);\n+\n+  // Set logical location by overriding client data hooks\n+  auto tmp_client_data_hooks\n+    = std::make_unique<json_client_data_hooks>\n+\t(js_val, global_dc->get_client_data_hooks ());\n+  auto old_client_data_hooks\n+    = global_dc->set_client_data_hooks (std::move (tmp_client_data_hooks));\n+\n+  // Override text hooks\n+  auto old_text_starter = text_starter (global_dc);\n+  auto old_text_finalizer = text_finalizer (global_dc);\n+  text_starter (global_dc) = json_text_starter;\n+  text_finalizer (global_dc) = diagnostics::default_text_finalizer;\n+\n+  bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_id,\n+\t\t\t\t\t gmsgid, ap, kind);\n+\n+  // Restore old text and client data hooks:\n+  text_starter (global_dc) = old_text_starter;\n+  text_finalizer (global_dc) = old_text_finalizer;\n+  global_dc->set_client_data_hooks (std::move (old_client_data_hooks));\n+\n+  if (logger)\n+    logger->log_bool_return (\"emit_diagnostic\", ret);\n+\n+  return ret;\n+}\n+\n+\n+/* Emit an error on gcc's global_dc relating to JS_VAL.  */\n+\n+void\n+json_error (gcc_json_context &ctxt,\n+\t    const json::value &js_val,\n+\t    const char *gmsgid, ...)\n+{\n+  va_list ap;\n+  va_start (ap, gmsgid);\n+  emit_json_diagnostic (ctxt,\n+\t\t\tdiagnostics::kind::error,\n+\t\t\tjs_val, -1,\n+\t\t\tgmsgid, &ap);\n+  va_end (ap);\n+}\n+\n+/* Emit a warning on gcc's global_dc relating to JS_VAL.  */\n+\n+bool\n+json_warning (gcc_json_context &ctxt,\n+\t      const json::value &js_val,\n+\t      diagnostics::option_id option_id,\n+\t      const char *gmsgid, ...)\n+{\n+  va_list ap;\n+  va_start (ap, gmsgid);\n+  bool ret = emit_json_diagnostic (ctxt,\n+\t\t\t\t   diagnostics::kind::warning,\n+\t\t\t\t   js_val, option_id,\n+\t\t\t\t   gmsgid, &ap);\n+  va_end (ap);\n+  return ret;\n+}\n+\n+/* Emit a note on gcc's global_dc relating to JS_VAL.  */\n+\n+void\n+json_note (gcc_json_context &ctxt,\n+\t   const json::value &js_val,\n+\t   const char *gmsgid, ...)\n+{\n+  va_list ap;\n+  va_start (ap, gmsgid);\n+  emit_json_diagnostic (ctxt,\n+\t\t\tdiagnostics::kind::note,\n+\t\t\tjs_val, -1,\n+\t\t\tgmsgid, &ap);\n+  va_end (ap);\n+}\ndiff --git a/gcc/json-diagnostic.h b/gcc/json-diagnostic.h\nnew file mode 100644\nindex 0000000000000..1773ee0a0fd50\n--- /dev/null\n+++ b/gcc/json-diagnostic.h\n@@ -0,0 +1,74 @@\n+/* Diagnostics relating to JSON values.\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_DIAGNOSTIC_H\n+#define GCC_JSON_DIAGNOSTIC_H\n+\n+#include \"json-parsing.h\"\n+\n+/* Implementation of json::location_map for use with\n+   GCC diagnostics.\n+   Stores location information for json::value * from parsing, and\n+   can generate location_t values for the.  */\n+\n+class gcc_json_context : public json::simple_location_map\n+{\n+public:\n+  gcc_json_context (const char *filename)\n+  : m_filename (filename)\n+  {\n+  }\n+\n+  location_t\n+  make_location_for_point (const json::location_map::point &);\n+\n+  location_t\n+  make_location_for_range (const json::location_map::range &);\n+\n+private:\n+  const char *m_filename;\n+};\n+\n+/* Emit an error on gcc's global_dc relating to JS_VAL.  */\n+\n+extern void\n+json_error (gcc_json_context &ctxt,\n+\t    const json::value &js_val,\n+\t    const char *gmsgid, ...)\n+  ATTRIBUTE_GCC_DIAG(3,4);\n+\n+/* Emit a warning on gcc's global_dc relating to JS_VAL.  */\n+\n+extern bool\n+json_warning (gcc_json_context &ctxt,\n+\t      const json::value &js_val,\n+\t      diagnostics::option_id option_id,\n+\t      const char *gmsgid, ...)\n+  ATTRIBUTE_GCC_DIAG(4,5);\n+\n+/* Emit a note on gcc's global_dc relating to JS_VAL.  */\n+\n+extern void\n+json_note (gcc_json_context &ctxt,\n+\t   const json::value &js_val,\n+\t   const char *gmsgid, ...)\n+  ATTRIBUTE_GCC_DIAG(3,4);\n+\n+#endif  /* GCC_JSON_DIAGNOSTIC_H  */\n",
    "prefixes": [
        "4/5"
    ]
}