Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2229942/?format=api
{ "id": 2229942, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229942/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260428232709.1953743-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": "<20260428232709.1953743-1-dmalcolm@redhat.com>", "date": "2026-04-28T23:27:09", "name": "[pushed:,r17-169] Introduce pretty-print-token-buffer.{cc,h}", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "9b9a41b10d49702d352ca514ad60abfcffd95bde", "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/20260428232709.1953743-1-dmalcolm@redhat.com/mbox/", "series": [ { "id": 501951, "url": "http://patchwork.ozlabs.org/api/1.1/series/501951/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501951", "date": "2026-04-28T23:27:09", "name": "[pushed:,r17-169] Introduce pretty-print-token-buffer.{cc,h}", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501951/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2229942/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2229942/checks/", "tags": {}, "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=WdXX6MvK;\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=WdXX6MvK", "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.129.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 4g4xSN2wrmz1yHv\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 09:28:04 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 4F7504BBC0D1\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 23:28:02 +0000 (GMT)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by sourceware.org (Postfix) with ESMTP id 687934BBC0D6\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:27:20 +0000 (GMT)", "from mx-prod-mc-05.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-43-mruw_Jw9NmqAgLxi7f3ekQ-1; Tue,\n 28 Apr 2026 19:27:18 -0400", "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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 6547E1956095\n for <gcc-patches@gcc.gnu.org>; Tue, 28 Apr 2026 23:27:17 +0000 (UTC)", "from t14s.localdomain.com (unknown [10.22.65.168])\n by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id BAF1D195608E; Tue, 28 Apr 2026 23:27:16 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 4F7504BBC0D1", "OpenDKIM Filter v2.11.0 sourceware.org 687934BBC0D6" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 687934BBC0D6", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 687934BBC0D6", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777418840; cv=none;\n b=R94a/HsGAF11JiavAwLfHugseYV7s/Gz0hmm1nB0GQtu6qv+fZAs6GKSmwaYlHSL8/uiiu+eiWV5f06iJUqxhdu+AiR03rMtmUHQMGaeXGO9DUpTySyNpz5C6CZKYmp4Gq03byqHfqzNcXxSksZb6qod5p99bOeQ2emmDwNDsO8=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777418840; c=relaxed/simple;\n bh=OZ6fmSh1HiU4wgGskN7G1RKxfjkOJTU9uJsPFOmdSmA=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=uR5EoryzU5XCeFUI8nIztPUpRVdxStN3p8GMwNv1nbCVFCmI3oE2Zd6om3tbPQJJBy866XbBL3enNIqnPZe/ZvsuMWa2IxNXy+Z8xrnPGLkl67DRGufNTdpR7IHVNfPkYSmKOIEv43XprgYl4digmyam9Vpdu0KoJlppZaz2t78=", "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=1777418840;\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=QVbkrhJGE/kmFaUcCa3LJjdgGXsbTLyWnVSPjq3szEo=;\n b=WdXX6MvKiqYOVTiXlz8fz6+W1NEfYMDzUWpfnrpdWnvLdljwpjTLQED5Jg4gkVAr4Y0Fmw\n 6qq7XXuPiQzZ5HCry/l3V8dIAVQ+Kf7FoyZG70ERSrcdbw7DunRxWhY9JNRGO5FG2Fr37D\n vY1SoTaRv6tfLOsDCpuHZA9QdwHplyo=", "X-MC-Unique": "mruw_Jw9NmqAgLxi7f3ekQ-1", "X-Mimecast-MFC-AGG-ID": "mruw_Jw9NmqAgLxi7f3ekQ_1777418837", "From": "David Malcolm <dmalcolm@redhat.com>", "To": "gcc-patches@gcc.gnu.org", "Cc": "David Malcolm <dmalcolm@redhat.com>", "Subject": "[pushed: r17-169] Introduce pretty-print-token-buffer.{cc,h}", "Date": "Tue, 28 Apr 2026 19:27:09 -0400", "Message-ID": "<20260428232709.1953743-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": "sCxxELGCNz5FKXXxCWSEQp3C_14bplyQDFWhK-LdTfg_1777418837", "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": "Move the implementation of diagnostic_message_buffer from libdiagnostics\nto a new pretty-print-token-buffer.{cc,h}, for capturing the tokens from\na pretty-print.\n\nImplement a new class pp_token_buffer_element for replaying the tokens\nin a pretty_print_token_buffer into another pretty-print, using \"%e\".\n\nAdd selftests.\n\nSuccessfully 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-169-g9c529989e0fd9c.\n\ngcc/ChangeLog:\n\t* Makefile.in (OBJS-libcommon): Add pretty-print-token-buffer.o.\n\t* libgdiagnostics.cc: Drop include of \"auto-obstack.h\".\n\tInclude \"pretty-print-token-buffer.h\".\n\t(class copying_token_printer): Move to\n\tpretty-print-token-buffer.cc.\n\t(struct diagnostic_message_buffer): Reimplement as a subclass of\n\tpretty_print_token_buffer.\n\t(diagnostic_message_buffer::to_string): Rename to\n\tpretty_print_token_buffer::to_string and move to\n\tpretty-print-token-buffer.cc.\n\t* pretty-print-token-buffer.cc: New file, based on material from\n\tlibgdiagnostics.cc.\n\t* pretty-print-token-buffer.h: New file, based on material from\n\tlibgdiagnostics.h.\n\t* selftest-run-tests.cc (selftest::run_tests): Call\n\tselftest::pretty_print_token_buffer_cc_tests.\n\t* selftest.h (selftest::pretty_print_token_buffer_cc_tests): New\n\tdecl.\n\nSigned-off-by: David Malcolm <dmalcolm@redhat.com>\n---\n gcc/Makefile.in | 2 +-\n gcc/libgdiagnostics.cc | 177 +--------------\n gcc/pretty-print-token-buffer.cc | 362 +++++++++++++++++++++++++++++++\n gcc/pretty-print-token-buffer.h | 70 ++++++\n gcc/selftest-run-tests.cc | 1 +\n gcc/selftest.h | 1 +\n 6 files changed, 440 insertions(+), 173 deletions(-)\n create mode 100644 gcc/pretty-print-token-buffer.cc\n create mode 100644 gcc/pretty-print-token-buffer.h", "diff": "diff --git a/gcc/Makefile.in b/gcc/Makefile.in\nindex 8ecef4ccdc7..bcbcffa4118 100644\n--- a/gcc/Makefile.in\n+++ b/gcc/Makefile.in\n@@ -1904,7 +1904,7 @@ OBJS-libcommon = \\\n \tdiagnostics/diagnostics-selftests.o \\\n \tgcc-diagnostic-spec.o \\\n \tgraphviz.o pex.o \\\n-\tpretty-print.o intl.o \\\n+\tpretty-print.o pretty-print-token-buffer.o intl.o \\\n \tjson.o json-parsing.o json-diagnostic.o \\\n \tpub-sub.o \\\n \txml.o \\\ndiff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc\nindex dd5109229b3..1cf451273d0 100644\n--- a/gcc/libgdiagnostics.cc\n+++ b/gcc/libgdiagnostics.cc\n@@ -44,7 +44,7 @@ along with GCC; see the file COPYING3. If not see\n #include \"libgdiagnostics-private.h\"\n #include \"pretty-print-format-impl.h\"\n #include \"pretty-print-markup.h\"\n-#include \"auto-obstack.h\"\n+#include \"pretty-print-token-buffer.h\"\n \n class owned_nullable_string\n {\n@@ -252,97 +252,6 @@ private:\n diagnostics::source_printing_options m_source_printing;\n };\n \n-/* A token_printer that makes a deep copy of the pp_token_list\n- into another obstack. */\n-\n-class copying_token_printer : public token_printer\n-{\n-public:\n- copying_token_printer (obstack &dst_obstack,\n-\t\t\t pp_token_list &dst_token_list)\n- : m_dst_obstack (dst_obstack),\n- m_dst_token_list (dst_token_list)\n- {\n- }\n-\n- void\n- print_tokens (pretty_printer *,\n-\t\tconst pp_token_list &tokens) final override\n- {\n- for (auto iter = tokens.m_first; iter; iter = iter->m_next)\n- switch (iter->m_kind)\n-\t{\n-\tdefault:\n-\t gcc_unreachable ();\n-\n-\tcase pp_token::kind::text:\n-\t {\n-\t const pp_token_text *sub = as_a <const pp_token_text *> (iter);\n-\t /* Copy the text, with null terminator. */\n-\t obstack_grow (&m_dst_obstack, sub->m_value.get (),\n-\t\t\t strlen (sub->m_value.get ()) + 1);\n-\t m_dst_token_list.push_back_text\n-\t (label_text::borrow (XOBFINISH (&m_dst_obstack,\n-\t\t\t\t\t const char *)));\n-\t }\n-\t break;\n-\n-\tcase pp_token::kind::begin_color:\n-\t {\n-\t pp_token_begin_color *sub = as_a <pp_token_begin_color *> (iter);\n-\t /* Copy the color, with null terminator. */\n-\t obstack_grow (&m_dst_obstack, sub->m_value.get (),\n-\t\t\t strlen (sub->m_value.get ()) + 1);\n-\t m_dst_token_list.push_back<pp_token_begin_color>\n-\t (label_text::borrow (XOBFINISH (&m_dst_obstack,\n-\t\t\t\t\t const char *)));\n-\t }\n-\t break;\n-\tcase pp_token::kind::end_color:\n-\t m_dst_token_list.push_back<pp_token_end_color> ();\n-\t break;\n-\n-\tcase pp_token::kind::begin_quote:\n-\t m_dst_token_list.push_back<pp_token_begin_quote> ();\n-\t break;\n-\tcase pp_token::kind::end_quote:\n-\t m_dst_token_list.push_back<pp_token_end_quote> ();\n-\t break;\n-\n-\tcase pp_token::kind::begin_url:\n-\t {\n-\t pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter);\n-\t /* Copy the URL, with null terminator. */\n-\t obstack_grow (&m_dst_obstack, sub->m_value.get (),\n-\t\t\t strlen (sub->m_value.get ()) + 1);\n-\t m_dst_token_list.push_back<pp_token_begin_url>\n-\t (label_text::borrow (XOBFINISH (&m_dst_obstack,\n-\t\t\t\t\t const char *)));\n-\t }\n-\t break;\n-\tcase pp_token::kind::end_url:\n-\t m_dst_token_list.push_back<pp_token_end_url> ();\n-\t break;\n-\n-\tcase pp_token::kind::event_id:\n-\t {\n-\t pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);\n-\t m_dst_token_list.push_back<pp_token_event_id> (sub->m_event_id);\n-\t }\n-\t break;\n-\n-\tcase pp_token::kind::custom_data:\n-\t /* These should have been eliminated by replace_custom_tokens. */\n-\t gcc_unreachable ();\n-\t break;\n-\t}\n- }\n-\n-private:\n- obstack &m_dst_obstack;\n- pp_token_list &m_dst_token_list;\n-};\n-\n class sarif_sink : public sink\n {\n public:\n@@ -352,31 +261,13 @@ public:\n \t const diagnostics::sarif_generation_options &sarif_gen_opts);\n };\n \n-struct diagnostic_message_buffer\n+struct diagnostic_message_buffer : public pretty_print_token_buffer\n {\n- diagnostic_message_buffer ()\n- : m_tokens (m_obstack)\n- {\n- }\n-\n- diagnostic_message_buffer (const char *gmsgid,\n-\t\t\t va_list *args)\n- : m_tokens (m_obstack)\n+ diagnostic_message_buffer () {}\n+ diagnostic_message_buffer (const char *gmsgid, va_list *args)\n+ : pretty_print_token_buffer (gmsgid, args)\n {\n- text_info text (gmsgid, args, errno);\n- pretty_printer pp;\n- pp.set_output_stream (nullptr);\n- copying_token_printer tok_printer (m_obstack, m_tokens);\n- pp.set_token_printer (&tok_printer);\n- pp_format (&pp, &text);\n- pp_output_formatted_text (&pp, nullptr);\n }\n-\n-\n- std::string to_string () const;\n-\n- auto_obstack m_obstack;\n- pp_token_list m_tokens;\n };\n \n /* A pp_element subclass that replays the saved tokens in a\n@@ -1566,64 +1457,6 @@ sarif_sink (diagnostic_manager &mgr,\n mgr.get_dc ().add_sink (std::move (inner_sink));\n }\n \n-// struct diagnostic_message_buffer\n-\n-std::string\n-diagnostic_message_buffer::to_string () const\n-{\n- std::string result;\n-\n- /* Convert to text, dropping colorization, URLs, etc. */\n- for (auto iter = m_tokens.m_first; iter; iter = iter->m_next)\n- switch (iter->m_kind)\n- {\n- default:\n-\tgcc_unreachable ();\n-\n- case pp_token::kind::text:\n-\t{\n-\t pp_token_text *sub = as_a <pp_token_text *> (iter);\n-\t result += sub->m_value.get ();\n-\t}\n-\tbreak;\n-\n- case pp_token::kind::begin_color:\n- case pp_token::kind::end_color:\n-\t// Skip\n-\tbreak;\n-\n- case pp_token::kind::begin_quote:\n-\tresult += open_quote;\n-\tbreak;\n-\n- case pp_token::kind::end_quote:\n-\tresult += close_quote;\n-\tbreak;\n-\n- case pp_token::kind::begin_url:\n- case pp_token::kind::end_url:\n-\t// Skip\n-\tbreak;\n-\n- case pp_token::kind::event_id:\n-\t{\n-\t pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);\n-\t gcc_assert (sub->m_event_id.known_p ());\n-\t result += '(';\n-\t result += std::to_string (sub->m_event_id.one_based ());\n-\t result += ')';\n-\t}\n-\tbreak;\n-\n- case pp_token::kind::custom_data:\n-\t/* We don't have a way of handling custom_data tokens here. */\n-\tgcc_unreachable ();\n-\tbreak;\n- }\n-\n- return result;\n-}\n-\n /* struct diagnostic_manager. */\n \n void\ndiff --git a/gcc/pretty-print-token-buffer.cc b/gcc/pretty-print-token-buffer.cc\nnew file mode 100644\nindex 00000000000..61c4a7608b3\n--- /dev/null\n+++ b/gcc/pretty-print-token-buffer.cc\n@@ -0,0 +1,362 @@\n+/* Capturing the results of pretty_print for later playback.\n+ Copyright (C) 2023-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+#include \"config.h\"\n+#define INCLUDE_STRING\n+#include \"system.h\"\n+#include \"coretypes.h\"\n+#include \"intl.h\"\n+#include \"pretty-print.h\"\n+#include \"pretty-print-token-buffer.h\"\n+#include \"selftest.h\"\n+\n+/* A token_printer that makes a deep copy of the pp_token_list\n+ into another obstack. */\n+\n+class copying_token_printer : public token_printer\n+{\n+public:\n+ copying_token_printer (obstack &dst_obstack,\n+\t\t\t pp_token_list &dst_token_list)\n+ : m_dst_obstack (dst_obstack),\n+ m_dst_token_list (dst_token_list)\n+ {\n+ }\n+\n+ void\n+ print_tokens (pretty_printer *,\n+\t\tconst pp_token_list &tokens) final override\n+ {\n+ for (auto iter = tokens.m_first; iter; iter = iter->m_next)\n+ switch (iter->m_kind)\n+\t{\n+\tdefault:\n+\t gcc_unreachable ();\n+\n+\tcase pp_token::kind::text:\n+\t {\n+\t const pp_token_text *sub = as_a <const pp_token_text *> (iter);\n+\t /* Copy the text, with null terminator. */\n+\t obstack_grow (&m_dst_obstack, sub->m_value.get (),\n+\t\t\t strlen (sub->m_value.get ()) + 1);\n+\t m_dst_token_list.push_back_text\n+\t (label_text::borrow (XOBFINISH (&m_dst_obstack,\n+\t\t\t\t\t const char *)));\n+\t }\n+\t break;\n+\n+\tcase pp_token::kind::begin_color:\n+\t {\n+\t pp_token_begin_color *sub = as_a <pp_token_begin_color *> (iter);\n+\t /* Copy the color, with null terminator. */\n+\t obstack_grow (&m_dst_obstack, sub->m_value.get (),\n+\t\t\t strlen (sub->m_value.get ()) + 1);\n+\t m_dst_token_list.push_back<pp_token_begin_color>\n+\t (label_text::borrow (XOBFINISH (&m_dst_obstack,\n+\t\t\t\t\t const char *)));\n+\t }\n+\t break;\n+\tcase pp_token::kind::end_color:\n+\t m_dst_token_list.push_back<pp_token_end_color> ();\n+\t break;\n+\n+\tcase pp_token::kind::begin_quote:\n+\t m_dst_token_list.push_back<pp_token_begin_quote> ();\n+\t break;\n+\tcase pp_token::kind::end_quote:\n+\t m_dst_token_list.push_back<pp_token_end_quote> ();\n+\t break;\n+\n+\tcase pp_token::kind::begin_url:\n+\t {\n+\t pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter);\n+\t /* Copy the URL, with null terminator. */\n+\t obstack_grow (&m_dst_obstack, sub->m_value.get (),\n+\t\t\t strlen (sub->m_value.get ()) + 1);\n+\t m_dst_token_list.push_back<pp_token_begin_url>\n+\t (label_text::borrow (XOBFINISH (&m_dst_obstack,\n+\t\t\t\t\t const char *)));\n+\t }\n+\t break;\n+\tcase pp_token::kind::end_url:\n+\t m_dst_token_list.push_back<pp_token_end_url> ();\n+\t break;\n+\n+\tcase pp_token::kind::event_id:\n+\t {\n+\t pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);\n+\t m_dst_token_list.push_back<pp_token_event_id> (sub->m_event_id);\n+\t }\n+\t break;\n+\n+\tcase pp_token::kind::custom_data:\n+\t /* These should have been eliminated by replace_custom_tokens. */\n+\t gcc_unreachable ();\n+\t break;\n+\t}\n+ }\n+\n+private:\n+ obstack &m_dst_obstack;\n+ pp_token_list &m_dst_token_list;\n+};\n+\n+pretty_print_token_buffer::pretty_print_token_buffer ()\n+: m_obstack (std::make_unique<auto_obstack> ()),\n+ m_tokens (*m_obstack.get ())\n+{\n+}\n+\n+/* Capture GMSGID and ARGS as a sequence of pretty_print tokens. */\n+\n+pretty_print_token_buffer::pretty_print_token_buffer (const char *gmsgid,\n+\t\t\t\t\t\t va_list *args)\n+: m_obstack (std::make_unique<auto_obstack> ()),\n+ m_tokens (*m_obstack.get ())\n+{\n+ text_info text (gmsgid, args, errno);\n+ pretty_printer pp;\n+ pp.set_output_stream (nullptr);\n+ copying_token_printer tok_printer (*m_obstack.get (), m_tokens);\n+ pp.set_token_printer (&tok_printer);\n+ pp_format (&pp, &text);\n+ pp_output_formatted_text (&pp, nullptr);\n+}\n+\n+pretty_print_token_buffer::\n+pretty_print_token_buffer (pretty_print_token_buffer &&other)\n+: m_obstack (std::move (other.m_obstack)),\n+ m_tokens (std::move (other.m_tokens))\n+{\n+}\n+\n+/* Convert to text, dropping colorization, URLs, etc. */\n+\n+std::string\n+pretty_print_token_buffer::to_string () const\n+{\n+ std::string result;\n+\n+ for (auto iter = m_tokens.m_first; iter; iter = iter->m_next)\n+ switch (iter->m_kind)\n+ {\n+ default:\n+\tgcc_unreachable ();\n+\n+ case pp_token::kind::text:\n+\t{\n+\t pp_token_text *sub = as_a <pp_token_text *> (iter);\n+\t result += sub->m_value.get ();\n+\t}\n+\tbreak;\n+\n+ case pp_token::kind::begin_color:\n+ case pp_token::kind::end_color:\n+\t// Skip\n+\tbreak;\n+\n+ case pp_token::kind::begin_quote:\n+\tresult += open_quote;\n+\tbreak;\n+\n+ case pp_token::kind::end_quote:\n+\tresult += close_quote;\n+\tbreak;\n+\n+ case pp_token::kind::begin_url:\n+ case pp_token::kind::end_url:\n+\t// Skip\n+\tbreak;\n+\n+ case pp_token::kind::event_id:\n+\t{\n+\t pp_token_event_id *sub = as_a <pp_token_event_id *> (iter);\n+\t gcc_assert (sub->m_event_id.known_p ());\n+\t result += '(';\n+\t result += std::to_string (sub->m_event_id.one_based ());\n+\t result += ')';\n+\t}\n+\tbreak;\n+\n+ case pp_token::kind::custom_data:\n+\t/* We don't have a way of handling custom_data tokens here. */\n+\tgcc_unreachable ();\n+\tbreak;\n+ }\n+\n+ return result;\n+}\n+\n+// class pp_token_buffer_element : public pp_element\n+\n+void\n+pp_token_buffer_element::add_to_phase_2 (pp_markup::context &ctxt)\n+{\n+ for (auto iter = m_token_buf.m_tokens.m_first; iter; iter = iter->m_next)\n+ switch (iter->m_kind)\n+ {\n+ default:\n+\tgcc_unreachable ();\n+\n+ case pp_token::kind::text:\n+\t{\n+\t const pp_token_text *sub = as_a <const pp_token_text *> (iter);\n+\t pp_string (&ctxt.m_pp, sub->m_value.get ());\n+\t ctxt.push_back_any_text ();\n+\t}\n+\tbreak;\n+\n+ case pp_token::kind::begin_color:\n+\t{\n+\t const pp_token_begin_color *sub\n+\t = as_a <const pp_token_begin_color *> (iter);\n+\t gcc_assert (sub->m_value.get ());\n+\t ctxt.begin_highlight_color (sub->m_value.get ());\n+\t}\n+\tbreak;\n+\n+ case pp_token::kind::end_color:\n+\tctxt.end_highlight_color ();\n+\tbreak;\n+\n+ case pp_token::kind::begin_quote:\n+\tctxt.begin_quote ();\n+\tbreak;\n+\n+ case pp_token::kind::end_quote:\n+\tctxt.end_quote ();\n+\tbreak;\n+\n+ case pp_token::kind::begin_url:\n+\t{\n+\t const pp_token_begin_url *sub\n+\t = as_a <const pp_token_begin_url *> (iter);\n+\t gcc_assert (sub->m_value.get ());\n+\t ctxt.begin_url (sub->m_value.get ());\n+\t}\n+\tbreak;\n+\n+ case pp_token::kind::end_url:\n+\tctxt.end_url ();\n+\tbreak;\n+\n+ case pp_token::kind::event_id:\n+\t{\n+\t const pp_token_event_id *sub\n+\t = as_a <const pp_token_event_id *> (iter);\n+\t gcc_assert (sub->m_event_id.known_p ());\n+\t ctxt.add_event_id (sub->m_event_id);\n+\t}\n+\tbreak;\n+\n+ case pp_token::kind::custom_data:\n+\t/* We don't have a way of handling custom_data tokens here. */\n+\tgcc_unreachable ();\n+\tbreak;\n+ }\n+}\n+\n+#if CHECKING_P\n+\n+namespace selftest {\n+\n+static pretty_print_token_buffer\n+pp_printf_to_buf (const char *fmt, ...)\n+{\n+ va_list args;\n+ va_start (args, fmt);\n+\n+ pretty_print_token_buffer buf (fmt, &args);\n+\n+ va_end (args);\n+\n+ return buf;\n+}\n+\n+static void\n+test_empty ()\n+{\n+ pretty_print_token_buffer buf;\n+ pp_token_buffer_element e (buf);\n+ pretty_printer pp;\n+ pp_printf (&pp, \"before %e after\", &e);\n+ ASSERT_STREQ (pp_formatted_text (&pp), \"before after\");\n+}\n+\n+static void\n+test_print ()\n+{\n+ pretty_print_token_buffer buf\n+ = pp_printf_to_buf (\"x: %qs y: %qs\", \"foo\", \"bar\");\n+\n+ // Check that the individual tokens are captured in \"buf\".\n+ pp_token *tok0 = buf.m_tokens.m_first;\n+ ASSERT_EQ (tok0->m_kind, pp_token::kind::text);\n+ ASSERT_STREQ (((pp_token_text *)tok0)->m_value.get (),\n+\t\t\"x: \");\n+\n+ pp_token *tok1 = tok0->m_next;\n+ ASSERT_EQ (tok1->m_kind, pp_token::kind::begin_quote);\n+\n+ pp_token *tok2 = tok1->m_next;\n+ ASSERT_EQ (tok2->m_kind, pp_token::kind::text);\n+ ASSERT_STREQ (((pp_token_text *)tok2)->m_value.get (),\n+\t\t\"foo\");\n+\n+ pp_token *tok3 = tok2->m_next;\n+ ASSERT_EQ (tok3->m_kind, pp_token::kind::end_quote);\n+\n+ pp_token *tok4 = tok3->m_next;\n+ ASSERT_EQ (tok4->m_kind, pp_token::kind::text);\n+ ASSERT_STREQ (((pp_token_text *)tok4)->m_value.get (),\n+\t\t\" y: \");\n+\n+ pp_token *tok5 = tok4->m_next;\n+ ASSERT_EQ (tok5->m_kind, pp_token::kind::begin_quote);\n+\n+ pp_token *tok6 = tok5->m_next;\n+ ASSERT_EQ (tok6->m_kind, pp_token::kind::text);\n+ ASSERT_STREQ (((pp_token_text *)tok6)->m_value.get (),\n+\t\t\"bar\");\n+\n+ pp_token *tok7 = tok6->m_next;\n+ ASSERT_EQ (tok7->m_kind, pp_token::kind::end_quote);\n+ ASSERT_EQ (tok7->m_next, nullptr);\n+\n+\n+ // Check that we can replay buf via pp_token_buffer_element\n+ pp_token_buffer_element e (buf);\n+ pretty_printer pp;\n+ pp_printf (&pp, \"before %e after\", &e);\n+ ASSERT_STREQ (pp_formatted_text (&pp), \"before x: 'foo' y: 'bar' after\");\n+}\n+\n+/* Run all of the selftests within this file. */\n+\n+void\n+pretty_print_token_buffer_cc_tests ()\n+{\n+ test_empty ();\n+ test_print ();\n+}\n+\n+} // namespace selftest\n+\n+#endif /* CHECKING_P */\ndiff --git a/gcc/pretty-print-token-buffer.h b/gcc/pretty-print-token-buffer.h\nnew file mode 100644\nindex 00000000000..cab691d2c3f\n--- /dev/null\n+++ b/gcc/pretty-print-token-buffer.h\n@@ -0,0 +1,70 @@\n+/* Capturing the results of pretty_print for later playback.\n+ Copyright (C) 2023-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_PRETTY_PRINT_TOKEN_BUFFER_H\n+#define GCC_PRETTY_PRINT_TOKEN_BUFFER_H\n+\n+#include \"pretty-print-format-impl.h\"\n+#include \"auto-obstack.h\"\n+#include \"pretty-print-markup.h\"\n+\n+/* A class for capturing the results of pretty-printing as tokens,\n+ potentially for playback into a different pretty-printer. */\n+\n+class pretty_print_token_buffer\n+{\n+public:\n+ pretty_print_token_buffer ();\n+ pretty_print_token_buffer (const char *gmsgid,\n+\t\t\t va_list *args);\n+\n+ pretty_print_token_buffer (const pretty_print_token_buffer &) = delete;\n+ pretty_print_token_buffer (pretty_print_token_buffer &&);\n+\n+ ~pretty_print_token_buffer () = default;\n+\n+ std::string to_string () const;\n+\n+ void dump (FILE *out) const { m_tokens.dump (out); }\n+ void DEBUG_FUNCTION dump () const { dump (stderr); }\n+\n+ std::unique_ptr<auto_obstack> m_obstack;\n+ pp_token_list m_tokens;\n+};\n+\n+/* A pp_element subclass for use with \"%e\" that replays the buffered tokens\n+ from TOKEN_BUF in another formatting call. */\n+\n+class pp_token_buffer_element : public pp_element\n+{\n+public:\n+ pp_token_buffer_element (const pretty_print_token_buffer &token_buf)\n+ : m_token_buf (token_buf)\n+ {\n+ }\n+\n+ void\n+ add_to_phase_2 (pp_markup::context &ctxt) final override;\n+\n+private:\n+ const pretty_print_token_buffer &m_token_buf;\n+};\n+\n+#endif /* GCC_PRETTY_PRINT_TOKEN_BUFFER_H */\ndiff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc\nindex 7ead010360f..86b2340e9b9 100644\n--- a/gcc/selftest-run-tests.cc\n+++ b/gcc/selftest-run-tests.cc\n@@ -68,6 +68,7 @@ selftest::run_tests ()\n hash_set_tests_cc_tests ();\n vec_cc_tests ();\n pretty_print_cc_tests ();\n+ pretty_print_token_buffer_cc_tests ();\n wide_int_cc_tests ();\n ggc_tests_cc_tests ();\n sreal_cc_tests ();\ndiff --git a/gcc/selftest.h b/gcc/selftest.h\nindex 462786dab2f..e3e86ffaf0f 100644\n--- a/gcc/selftest.h\n+++ b/gcc/selftest.h\n@@ -246,6 +246,7 @@ extern void ordered_hash_map_tests_cc_tests ();\n extern void path_coverage_cc_tests ();\n extern void predict_cc_tests ();\n extern void pretty_print_cc_tests ();\n+extern void pretty_print_token_buffer_cc_tests ();\n extern void pub_sub_cc_tests ();\n extern void range_op_tests ();\n extern void range_tests ();\n", "prefixes": [ "pushed:", "r17-169" ] }