In r15-3752-g48261bd26df624 I added a test plugin that overrode the
regular output, instead emitting diagnostics in crude HTML form.

In r15-4760-g0b73e9382ab51c I added support for multiple kinds of
diagnostic output simultaneously, adding
 -fdiagnostics-add-output=DIAGNOSTICS-OUTPUT-SPEC
 -fdiagnostics-set-output=DIAGNOSTICS-OUTPUT-SPEC
for adding/changing the kind of diagnostics output, supporting
"text" and "sarif" output schemes.

This patch promotes the HTML output code from the test plugins so
that it is available from "-fdiagnostics-add-output=", using a
new "experimental-html" scheme, to allow simultaneous text, sarif
and html output, and to make it easier to experiment with.  The
patch adds Python-based testing of the emitted HTML.

The patch does not affect the generated HTML, which is still crude, and
not yet ready for end-users.  I hope to improve it in followups.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r16-487-g1a2c62212bd912.

gcc/ChangeLog:
        PR other/116792
        * Makefile.in (OBJS-libcommon): Add diagnostic-format-html.o.
        * diagnostic-format-html.cc: Move here from
        testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc.
        Simplify includes.  Rename "xhtml" to "html" throughout.
        (write_escaped_text): Drop.
        (class xhtml_stream_output_format): Drop.
        (class html_file_output_format): Reimplement using
        diagnostic_output_file.
        (diagnostic_output_format_init_xhtml): Drop.
        (diagnostic_output_format_init_xhtml_stderr): Drop.
        (diagnostic_output_format_init_xhtml_file): Drop.
        (diagnostic_output_format_open_html_file): New.
        (make_html_sink): New.
        (xhtml_format_selftests): Convert to...
        (diagnostic_format_html_cc_tests): ...this.
        (plugin_is_GPL_compatible): Drop.
        (plugin_init): Drop.
        * diagnostic-format-html.h: New file.
        * doc/invoke.texi (-fdiagnostics-add-output=): Add
        "experimental-html" scheme.
        * opts-diagnostic.cc: Include "diagnostic-format-html.h".
        (class html_scheme_handler): New.
        (output_factory::output_factory): Add html_scheme_handler.
        (html_scheme_handler::make_sink): New.
        * selftest-run-tests.cc (selftest::run_tests): Call the new
        selftests.
        * selftest.h (selftest::diagnostic_format_html_cc_tests): New
        decl.

gcc/testsuite/ChangeLog:
        PR other/116792
        * gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc: Move to
        gcc/diagnostic-format-html.cc.
        * gcc.dg/html-output/html-output.exp: New support script.
        * gcc.dg/html-output/missing-semicolon.c: New test.
        * gcc.dg/html-output/missing-semicolon.py: New test script.
        * gcc.dg/plugin/diagnostic-test-xhtml-1.c: Deleted test.
        * gcc.dg/plugin/plugin.exp (plugin_test_list): Drop moved plugin
        and its deleted test.
        * lib/gcc-dg.exp (load_lib): Add load_lib of scanhtml.exp.
        * lib/htmltest.py: New support script.
        * lib/scanhtml.exp: New support script, based on scansarif.exp.

libatomic/ChangeLog:
        PR other/116792
        * testsuite/lib/libatomic.exp: Add load_lib of scanhtml.exp.

libgomp/ChangeLog:
        PR other/116792
        * testsuite/lib/libgomp.exp: Add load_lib of scanhtml.exp.

libitm/ChangeLog:
        PR other/116792
        * testsuite/lib/libitm.exp: Add load_lib of scanhtml.exp.

libphobos/ChangeLog:
        PR other/116792
        * testsuite/lib/libphobos-dg.exp: Add load_lib of scanhtml.exp.

libvtv/ChangeLog:
        PR other/116792
        * testsuite/lib/libvtv-dg.exp: Add load_lib of scanhtml.exp.
---
 gcc/Makefile.in                               |   1 +
 ...ml_format.cc => diagnostic-format-html.cc} | 323 +++++++-----------
 gcc/diagnostic-format-html.h                  |  37 ++
 gcc/doc/invoke.texi                           |  18 +-
 gcc/opts-diagnostic.cc                        |  60 ++++
 gcc/selftest-run-tests.cc                     |   1 +
 gcc/selftest.h                                |   1 +
 .../gcc.dg/html-output/html-output.exp        |  31 ++
 .../gcc.dg/html-output/missing-semicolon.c    |  13 +
 .../gcc.dg/html-output/missing-semicolon.py   |  84 +++++
 .../gcc.dg/plugin/diagnostic-test-xhtml-1.c   |  19 --
 gcc/testsuite/gcc.dg/plugin/plugin.exp        |   2 -
 gcc/testsuite/lib/gcc-dg.exp                  |   1 +
 gcc/testsuite/lib/htmltest.py                 |   9 +
 gcc/testsuite/lib/scanhtml.exp                |  90 +++++
 libatomic/testsuite/lib/libatomic.exp         |   1 +
 libgomp/testsuite/lib/libgomp.exp             |   1 +
 libitm/testsuite/lib/libitm.exp               |   1 +
 libphobos/testsuite/lib/libphobos-dg.exp      |   1 +
 libvtv/testsuite/lib/libvtv-dg.exp            |   1 +
 20 files changed, 479 insertions(+), 216 deletions(-)
 rename gcc/{testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc => 
diagnostic-format-html.cc} (72%)
 create mode 100644 gcc/diagnostic-format-html.h
 create mode 100644 gcc/testsuite/gcc.dg/html-output/html-output.exp
 create mode 100644 gcc/testsuite/gcc.dg/html-output/missing-semicolon.c
 create mode 100644 gcc/testsuite/gcc.dg/html-output/missing-semicolon.py
 delete mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-xhtml-1.c
 create mode 100644 gcc/testsuite/lib/htmltest.py
 create mode 100644 gcc/testsuite/lib/scanhtml.exp

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 55b4cd7dbed3..e3af923e0e04 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1850,6 +1850,7 @@ OBJS = \
 # Objects in libcommon.a, potentially used by all host binaries and with
 # no target dependencies.
 OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \
+       diagnostic-format-html.o \
        diagnostic-format-json.o \
        diagnostic-format-sarif.o \
        diagnostic-format-text.o \
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc 
b/gcc/diagnostic-format-html.cc
similarity index 72%
rename from gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc
rename to gcc/diagnostic-format-html.cc
index 24c6f8ce557b..2d642dfc33cb 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc
+++ b/gcc/diagnostic-format-html.cc
@@ -1,6 +1,5 @@
-/* Verify that we can write a non-trivial diagnostic output format
-   as a plugin (XHTML).
-   Copyright (C) 2018-2024 Free Software Foundation, Inc.
+/* HTML output for diagnostics.
+   Copyright (C) 2024-2025 Free Software Foundation, Inc.
    Contributed by David Malcolm <dmalc...@redhat.com>.
 
 This file is part of GCC.
@@ -19,35 +18,21 @@ You should have received a copy of the GNU General Public 
License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
-
 #include "config.h"
-#define INCLUDE_LIST
 #define INCLUDE_MAP
-#define INCLUDE_MEMORY
 #define INCLUDE_VECTOR
 #include "system.h"
 #include "coretypes.h"
 #include "diagnostic.h"
 #include "diagnostic-metadata.h"
-#include "diagnostic-path.h"
-#include "cpplib.h"
-#include "logical-location.h"
-#include "diagnostic-client-data-hooks.h"
-#include "diagnostic-diagram.h"
-#include "text-art/canvas.h"
 #include "diagnostic-format.h"
+#include "diagnostic-format-html.h"
+#include "diagnostic-output-file.h"
 #include "diagnostic-buffer.h"
-#include "ordered-hash-map.h"
-#include "sbitmap.h"
 #include "selftest.h"
 #include "selftest-diagnostic.h"
-#include "selftest-diagnostic-show-locus.h"
-#include "text-range-label.h"
 #include "pretty-print-format-impl.h"
-#include "pretty-print-urlifier.h"
 #include "intl.h"
-#include "gcc-plugin.h"
-#include "plugin-version.h"
 
 namespace xml {
 
@@ -58,8 +43,6 @@ namespace xml {
 #  pragma GCC diagnostic ignored "-Wformat-diag"
 #endif
 
-static void write_escaped_text (const char *text);
-
 struct node
 {
   virtual ~node () {}
@@ -246,17 +229,17 @@ element::set_attr (const char *name, label_text value)
 
 } // namespace xml
 
-class xhtml_builder;
+class html_builder;
 
 /* Concrete buffering implementation subclass for HTML output.  */
 
-class diagnostic_xhtml_format_buffer : public diagnostic_per_format_buffer
+class diagnostic_html_format_buffer : public diagnostic_per_format_buffer
 {
 public:
-  friend class xhtml_builder;
-  friend class xhtml_output_format;
+  friend class html_builder;
+  friend class html_output_format;
 
-  diagnostic_xhtml_format_buffer (xhtml_builder &builder)
+  diagnostic_html_format_buffer (html_builder &builder)
   : m_builder (builder)
   {}
 
@@ -272,11 +255,11 @@ public:
   }
 
 private:
-  xhtml_builder &m_builder;
+  html_builder &m_builder;
   std::vector<std::unique_ptr<xml::element>> m_results;
 };
 
-/* A class for managing XHTML output of diagnostics.
+/* A class for managing HTML output of diagnostics.
 
    Implemented:
    - message text
@@ -291,18 +274,18 @@ private:
    - paths
 */
 
-class xhtml_builder
+class html_builder
 {
 public:
-  friend class diagnostic_xhtml_format_buffer;
+  friend class diagnostic_html_format_buffer;
 
-  xhtml_builder (diagnostic_context &context,
+  html_builder (diagnostic_context &context,
                 pretty_printer &pp,
                 const line_maps *line_maps);
 
   void on_report_diagnostic (const diagnostic_info &diagnostic,
                             diagnostic_t orig_diag_kind,
-                            diagnostic_xhtml_format_buffer *buffer);
+                            diagnostic_html_format_buffer *buffer);
   void emit_diagram (const diagnostic_diagram &diagram);
   void end_group ();
 
@@ -350,12 +333,12 @@ make_span (label_text class_)
   return span;
 }
 
-/* class diagnostic_xhtml_format_buffer : public diagnostic_per_format_buffer. 
 */
+/* class diagnostic_html_format_buffer : public diagnostic_per_format_buffer.  
*/
 
 void
-diagnostic_xhtml_format_buffer::dump (FILE *out, int indent) const
+diagnostic_html_format_buffer::dump (FILE *out, int indent) const
 {
-  fprintf (out, "%*sdiagnostic_xhtml_format_buffer:\n", indent, "");
+  fprintf (out, "%*sdiagnostic_html_format_buffer:\n", indent, "");
   int idx = 0;
   for (auto &result : m_results)
     {
@@ -367,40 +350,40 @@ diagnostic_xhtml_format_buffer::dump (FILE *out, int 
indent) const
 }
 
 bool
-diagnostic_xhtml_format_buffer::empty_p () const
+diagnostic_html_format_buffer::empty_p () const
 {
   return m_results.empty ();
 }
 
 void
-diagnostic_xhtml_format_buffer::move_to (diagnostic_per_format_buffer &base)
+diagnostic_html_format_buffer::move_to (diagnostic_per_format_buffer &base)
 {
-  diagnostic_xhtml_format_buffer &dest
-    = static_cast<diagnostic_xhtml_format_buffer &> (base);
+  diagnostic_html_format_buffer &dest
+    = static_cast<diagnostic_html_format_buffer &> (base);
   for (auto &&result : m_results)
     dest.m_results.push_back (std::move (result));
   m_results.clear ();
 }
 
 void
-diagnostic_xhtml_format_buffer::clear ()
+diagnostic_html_format_buffer::clear ()
 {
   m_results.clear ();
 }
 
 void
-diagnostic_xhtml_format_buffer::flush ()
+diagnostic_html_format_buffer::flush ()
 {
   for (auto &&result : m_results)
     m_builder.m_diagnostics_element->add_child (std::move (result));
   m_results.clear ();
 }
 
-/* class xhtml_builder.  */
+/* class html_builder.  */
 
-/* xhtml_builder's ctor.  */
+/* html_builder's ctor.  */
 
-xhtml_builder::xhtml_builder (diagnostic_context &context,
+html_builder::html_builder (diagnostic_context &context,
                              pretty_printer &pp,
                              const line_maps *line_maps)
 : m_context (context),
@@ -440,12 +423,12 @@ xhtml_builder::xhtml_builder (diagnostic_context &context,
   }
 }
 
-/* Implementation of "on_report_diagnostic" for XHTML output.  */
+/* Implementation of "on_report_diagnostic" for HTML output.  */
 
 void
-xhtml_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
-                                    diagnostic_t orig_diag_kind,
-                                    diagnostic_xhtml_format_buffer *buffer)
+html_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
+                                   diagnostic_t orig_diag_kind,
+                                   diagnostic_html_format_buffer *buffer)
 {
   if (diagnostic.kind == DK_ICE || diagnostic.kind == DK_ICE_NOBT)
     {
@@ -476,13 +459,13 @@ xhtml_builder::on_report_diagnostic (const 
diagnostic_info &diagnostic,
 }
 
 std::unique_ptr<xml::element>
-xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
-                                           diagnostic_t orig_diag_kind)
+html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
+                                          diagnostic_t orig_diag_kind)
 {
-  class xhtml_token_printer : public token_printer
+  class html_token_printer : public token_printer
   {
   public:
-    xhtml_token_printer (xhtml_builder &builder,
+    html_token_printer (html_builder &builder,
                         xml::element &parent_element)
     : m_builder (builder)
     {
@@ -557,7 +540,7 @@ xhtml_builder::make_element_for_diagnostic (const 
diagnostic_info &diagnostic,
       m_open_elements.pop_back ();
     }
 
-    xhtml_builder &m_builder;
+    html_builder &m_builder;
     /* We maintain a stack of currently "open" elements.
        Children are added to the topmost open element.  */
     std::vector<xml::element *> m_open_elements;
@@ -568,7 +551,7 @@ xhtml_builder::make_element_for_diagnostic (const 
diagnostic_info &diagnostic,
   // TODO: might be nice to emulate the text output format, but colorize it
 
   auto message_span = make_span (label_text::borrow ("gcc-message"));
-  xhtml_token_printer tok_printer (*this, *message_span.get ());
+  html_token_printer tok_printer (*this, *message_span.get ());
   m_printer->set_token_printer (&tok_printer);
   pp_output_formatted_text (m_printer, m_context.get_urlifier ());
   m_printer->set_token_printer (nullptr);
@@ -642,10 +625,10 @@ xhtml_builder::make_element_for_diagnostic (const 
diagnostic_info &diagnostic,
 }
 
 /* Implementation of diagnostic_context::m_diagrams.m_emission_cb
-   for XHTML output.  */
+   for HTML output.  */
 
 void
-xhtml_builder::emit_diagram (const diagnostic_diagram &/*diagram*/)
+html_builder::emit_diagram (const diagnostic_diagram &/*diagram*/)
 {
   /* We must be within the emission of a top-level diagnostic.  */
   gcc_assert (m_cur_diagnostic_element);
@@ -653,10 +636,10 @@ xhtml_builder::emit_diagram (const diagnostic_diagram 
&/*diagram*/)
   // TODO
 }
 
-/* Implementation of "end_group_cb" for XHTML output.  */
+/* Implementation of "end_group_cb" for HTML output.  */
 
 void
-xhtml_builder::end_group ()
+html_builder::end_group ()
 {
   if (m_cur_diagnostic_element)
     m_diagnostics_element->add_child (std::move (m_cur_diagnostic_element));
@@ -668,17 +651,17 @@ xhtml_builder::end_group ()
    Flush it all to OUTF.  */
 
 void
-xhtml_builder::flush_to_file (FILE *outf)
+html_builder::flush_to_file (FILE *outf)
 {
   auto top = m_document.get ();
   top->dump (outf);
   fprintf (outf, "\n");
 }
 
-class xhtml_output_format : public diagnostic_output_format
+class html_output_format : public diagnostic_output_format
 {
 public:
-  ~xhtml_output_format ()
+  ~html_output_format ()
   {
     /* Any diagnostics should have been handled by now.
        If not, then something's gone wrong with diagnostic
@@ -690,19 +673,19 @@ public:
 
   void dump (FILE *out, int indent) const override
   {
-    fprintf (out, "%*sxhtml_output_format\n", indent, "");
+    fprintf (out, "%*shtml_output_format\n", indent, "");
     diagnostic_output_format::dump (out, indent);
   }
 
   std::unique_ptr<diagnostic_per_format_buffer>
   make_per_format_buffer () final override
   {
-    return std::make_unique<diagnostic_xhtml_format_buffer> (m_builder);
+    return std::make_unique<diagnostic_html_format_buffer> (m_builder);
   }
   void set_buffer (diagnostic_per_format_buffer *base_buffer) final override
   {
-    diagnostic_xhtml_format_buffer *buffer
-      = static_cast<diagnostic_xhtml_format_buffer *> (base_buffer);
+    diagnostic_html_format_buffer *buffer
+      = static_cast<diagnostic_html_format_buffer *> (base_buffer);
     m_buffer = buffer;
   }
 
@@ -752,66 +735,39 @@ public:
   }
 
 protected:
-  xhtml_output_format (diagnostic_context &context,
-                      const line_maps *line_maps)
+  html_output_format (diagnostic_context &context,
+                     const line_maps *line_maps)
   : diagnostic_output_format (context),
     m_builder (context, *get_printer (), line_maps),
     m_buffer (nullptr)
   {}
 
-  xhtml_builder m_builder;
-  diagnostic_xhtml_format_buffer *m_buffer;
+  html_builder m_builder;
+  diagnostic_html_format_buffer *m_buffer;
 };
 
-class xhtml_stream_output_format : public xhtml_output_format
+class html_file_output_format : public html_output_format
 {
 public:
-  xhtml_stream_output_format (diagnostic_context &context,
-                             const line_maps *line_maps,
-                             FILE *stream)
-  : xhtml_output_format (context, line_maps),
-    m_stream (stream)
-  {
-  }
-  ~xhtml_stream_output_format ()
+  html_file_output_format (diagnostic_context &context,
+                          const line_maps *line_maps,
+                          diagnostic_output_file output_file)
+  : html_output_format (context, line_maps),
+    m_output_file (std::move (output_file))
   {
-    m_builder.flush_to_file (m_stream);
+    gcc_assert (m_output_file.get_open_file ());
+    gcc_assert (m_output_file.get_filename ());
   }
-  bool machine_readable_stderr_p () const final override
+  ~html_file_output_format ()
   {
-    return m_stream == stderr;
+    m_builder.flush_to_file (m_output_file.get_open_file ());
   }
-private:
-  FILE *m_stream;
-};
-
-class xhtml_file_output_format : public xhtml_output_format
-{
-public:
-  xhtml_file_output_format (diagnostic_context &context,
-                           const line_maps *line_maps,
-                           const char *base_file_name)
-  : xhtml_output_format (context, line_maps),
-    m_base_file_name (xstrdup (base_file_name))
-  {
-  }
-  ~xhtml_file_output_format ()
+  void dump (FILE *out, int indent) const override
   {
-    char *filename = concat (m_base_file_name, ".xhtml", nullptr);
-    free (m_base_file_name);
-    m_base_file_name = nullptr;
-    FILE *outf = fopen (filename, "w");
-    if (!outf)
-      {
-       const char *errstr = xstrerror (errno);
-       fnotice (stderr, "error: unable to open '%s' for writing: %s\n",
-                filename, errstr);
-       free (filename);
-       return;
-      }
-    m_builder.flush_to_file (outf);
-    fclose (outf);
-    free (filename);
+    fprintf (out, "%*shtml_file_output_format: %s\n",
+            indent, "",
+            m_output_file.get_filename ());
+    diagnostic_output_format::dump (out, indent);
   }
   bool machine_readable_stderr_p () const final override
   {
@@ -819,68 +775,76 @@ public:
   }
 
 private:
-  char *m_base_file_name;
+  diagnostic_output_file m_output_file;
 };
 
-/* Populate CONTEXT in preparation for XHTML output (either to stderr, or
-   to a file).  */
+/* Attempt to open BASE_FILE_NAME.html for writing.
+   Return a non-null diagnostic_output_file,
+   or return a null diagnostic_output_file and complain to CONTEXT
+   using LINE_MAPS.  */
 
-static void
-diagnostic_output_format_init_xhtml (diagnostic_context &context,
-                                    std::unique_ptr<xhtml_output_format> fmt)
+diagnostic_output_file
+diagnostic_output_format_open_html_file (diagnostic_context &context,
+                                        line_maps *line_maps,
+                                        const char *base_file_name)
 {
-  /* Don't colorize the text.  */
-  pp_show_color (fmt->get_printer ()) = false;
-  context.set_show_highlight_colors (false);
-
-  context.set_output_format (std::move (fmt));
-}
-
-/* Populate CONTEXT in preparation for XHTML output to stderr.  */
+  if (!base_file_name)
+    {
+      rich_location richloc (line_maps, UNKNOWN_LOCATION);
+      context.emit_diagnostic_with_group
+       (DK_ERROR, richloc, nullptr, 0,
+        "unable to determine filename for HTML output");
+      return diagnostic_output_file ();
+    }
 
-void
-diagnostic_output_format_init_xhtml_stderr (diagnostic_context &context,
-                                           const line_maps *line_maps)
-{
-  gcc_assert (line_maps);
-  auto format = std::make_unique<xhtml_stream_output_format> (context,
-                                                             line_maps,
-                                                             stderr);
-  diagnostic_output_format_init_xhtml (context, std::move (format));
+  label_text filename = label_text::take (concat (base_file_name,
+                                                 ".html",
+                                                 nullptr));
+  FILE *outf = fopen (filename.get (), "w");
+  if (!outf)
+    {
+      rich_location richloc (line_maps, UNKNOWN_LOCATION);
+      context.emit_diagnostic_with_group
+       (DK_ERROR, richloc, nullptr, 0,
+        "unable to open %qs for HTML output: %m",
+        filename.get ());
+      return diagnostic_output_file ();
+    }
+  return diagnostic_output_file (outf, true, std::move (filename));
 }
 
-/* Populate CONTEXT in preparation for XHTML output to a file named
-   BASE_FILE_NAME.xhtml.  */
-
-void
-diagnostic_output_format_init_xhtml_file (diagnostic_context &context,
-                                         const line_maps *line_maps,
-                                         const char *base_file_name)
-{
-  gcc_assert (line_maps);
-  auto format = std::make_unique<xhtml_file_output_format> (context,
-                                                           line_maps,
-                                                           base_file_name);
-  diagnostic_output_format_init_xhtml (context, std::move (format));
+std::unique_ptr<diagnostic_output_format>
+make_html_sink (diagnostic_context &context,
+               const line_maps &line_maps,
+               diagnostic_output_file output_file)
+{
+  auto sink
+    = std::make_unique<html_file_output_format> (context,
+                                                &line_maps,
+                                                std::move (output_file));
+  sink->update_printer ();
+  return sink;
 }
 
 #if CHECKING_P
 
 namespace selftest {
 
-/* A subclass of xhtml_output_format for writing selftests.
+/* A subclass of html_output_format for writing selftests.
    The XML output is cached internally, rather than written
    out to a file.  */
 
-class test_xhtml_diagnostic_context : public test_diagnostic_context
+class test_html_diagnostic_context : public test_diagnostic_context
 {
 public:
-  test_xhtml_diagnostic_context ()
+  test_html_diagnostic_context ()
   {
-    auto format = std::make_unique<xhtml_buffered_output_format> (*this,
-                                                                 line_table);
-    m_format = format.get (); // borrowed
-    diagnostic_output_format_init_xhtml (*this, std::move (format));
+    auto sink = std::make_unique<html_buffered_output_format> (*this,
+                                                              line_table);
+    sink->update_printer ();
+    m_format = sink.get (); // borrowed
+
+    set_output_format (std::move (sink));
   }
 
   const xml::document &get_document () const
@@ -889,12 +853,12 @@ public:
   }
 
 private:
-  class xhtml_buffered_output_format : public xhtml_output_format
+  class html_buffered_output_format : public html_output_format
   {
   public:
-    xhtml_buffered_output_format (diagnostic_context &context,
-                                 const line_maps *line_maps)
-      : xhtml_output_format (context, line_maps)
+    html_buffered_output_format (diagnostic_context &context,
+                                const line_maps *line_maps)
+    : html_output_format (context, line_maps)
     {
     }
     bool machine_readable_stderr_p () const final override
@@ -903,17 +867,17 @@ private:
     }
   };
 
-  xhtml_output_format *m_format; // borrowed
+  html_output_format *m_format; // borrowed
 };
 
-  /* Test of reporting a diagnostic at UNKNOWN_LOCATION to a
-     diagnostic_context and examining the generated XML document.
-     Verify various basic properties. */
+/* Test of reporting a diagnostic at UNKNOWN_LOCATION to a
+   diagnostic_context and examining the generated XML document.
+   Verify various basic properties. */
 
 static void
 test_simple_log ()
 {
-  test_xhtml_diagnostic_context dc;
+  test_html_diagnostic_context dc;
 
   rich_location richloc (line_table, UNKNOWN_LOCATION);
   dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %i", 42);
@@ -945,8 +909,8 @@ test_simple_log ()
 
 /* Run all of the selftests within this file.  */
 
-static void
-xhtml_format_selftests ()
+void
+diagnostic_format_html_cc_tests ()
 {
   test_simple_log ();
 }
@@ -954,32 +918,3 @@ xhtml_format_selftests ()
 } // namespace selftest
 
 #endif /* CHECKING_P */
-
-/* Plugin hooks.  */
-
-int plugin_is_GPL_compatible;
-
-/* Entrypoint for the plugin.  */
-
-int
-plugin_init (struct plugin_name_args *plugin_info,
-            struct plugin_gcc_version *version)
-{
-  const char *plugin_name = plugin_info->base_name;
-  int argc = plugin_info->argc;
-  struct plugin_argument *argv = plugin_info->argv;
-
-  if (!plugin_default_version_check (version, &gcc_version))
-    return 1;
-
-  global_dc->set_output_format
-    (std::make_unique<xhtml_stream_output_format> (*global_dc,
-                                                  line_table,
-                                                  stderr));
-
-#if CHECKING_P
-  selftest::xhtml_format_selftests ();
-#endif
-
-  return 0;
-}
diff --git a/gcc/diagnostic-format-html.h b/gcc/diagnostic-format-html.h
new file mode 100644
index 000000000000..ff5edcaf1749
--- /dev/null
+++ b/gcc/diagnostic-format-html.h
@@ -0,0 +1,37 @@
+/* HTML output for diagnostics.
+   Copyright (C) 2024-2025 Free Software Foundation, Inc.
+   Contributed by David Malcolm <dmalc...@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_DIAGNOSTIC_FORMAT_HTML_H
+#define GCC_DIAGNOSTIC_FORMAT_HTML_H
+
+#include "diagnostic-format.h"
+#include "diagnostic-output-file.h"
+
+extern diagnostic_output_file
+diagnostic_output_format_open_html_file (diagnostic_context &context,
+                                        line_maps *line_maps,
+                                        const char *base_file_name);
+
+extern std::unique_ptr<diagnostic_output_format>
+make_html_sink (diagnostic_context &context,
+               const line_maps &line_maps,
+               diagnostic_output_file output_file);
+
+#endif /* ! GCC_DIAGNOSTIC_FORMAT_HTML_H */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 32bc45725de9..ecc407cc1d0e 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -6072,6 +6072,22 @@ in this release.
 
 @end table
 
+@item experimental-html
+Emit diagnostics to a file in HTML format.  This scheme is experimental,
+and may go away in future GCC releases.  The details of the output are
+also subject to change.
+
+Supported keys are:
+
+@table @gcctabopt
+
+@item file=@var{FILENAME}
+Specify the filename to write the HTML output to, potentially with a
+leading absolute or relative path.  If not specified, it defaults to
+@file{@var{source}.html}.
+
+@end table
+
 @end table
 
 For example,
@@ -6091,7 +6107,7 @@ In EBNF:
 @var{diagnostics-output-specifier} = @var{diagnostics-output-name}
                                    | @var{diagnostics-output-name}, ":", 
@var{key-value-pairs};
 
-@var{diagnostics-output-name} = "text" | "sarif";
+@var{diagnostics-output-name} = "text" | "sarif" | "experimental-html";
 
 @var{key-value-pairs} = @var{key-value-pair}
                       | @var{key-value-pair} "," @var{key-value-pairs};
diff --git a/gcc/opts-diagnostic.cc b/gcc/opts-diagnostic.cc
index 1eec0103d3b6..34c390695b95 100644
--- a/gcc/opts-diagnostic.cc
+++ b/gcc/opts-diagnostic.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "diagnostic-color.h"
 #include "diagnostic-format.h"
+#include "diagnostic-format-html.h"
 #include "diagnostic-format-text.h"
 #include "diagnostic-format-sarif.h"
 #include "selftest.h"
@@ -217,6 +218,17 @@ public:
             const scheme_name_and_params &parsed_arg) const final override;
 };
 
+class html_scheme_handler : public output_factory::scheme_handler
+{
+public:
+  html_scheme_handler () : scheme_handler ("experimental-html") {}
+
+  std::unique_ptr<diagnostic_output_format>
+  make_sink (const context &ctxt,
+            const char *unparsed_arg,
+            const scheme_name_and_params &parsed_arg) const final override;
+};
+
 /* struct context.  */
 
 void
@@ -318,6 +330,7 @@ output_factory::output_factory ()
 {
   m_scheme_handlers.push_back (std::make_unique<text_scheme_handler> ());
   m_scheme_handlers.push_back (std::make_unique<sarif_scheme_handler> ());
+  m_scheme_handlers.push_back (std::make_unique<html_scheme_handler> ());
 }
 
 const output_factory::scheme_handler *
@@ -525,6 +538,53 @@ sarif_scheme_handler::make_sink (const context &ctxt,
   return sink;
 }
 
+/* class html_scheme_handler : public output_factory::scheme_handler.  */
+
+std::unique_ptr<diagnostic_output_format>
+html_scheme_handler::make_sink (const context &ctxt,
+                               const char *unparsed_arg,
+                               const scheme_name_and_params &parsed_arg) const
+{
+  label_text filename;
+  for (auto& iter : parsed_arg.m_kvs)
+    {
+      const std::string &key = iter.first;
+      const std::string &value = iter.second;
+      if (key == "file")
+       {
+         filename = label_text::take (xstrdup (value.c_str ()));
+         continue;
+       }
+
+      /* Key not found.  */
+      auto_vec<const char *> known_keys;
+      known_keys.safe_push ("file");
+      ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (), 
known_keys);
+      return nullptr;
+    }
+
+  diagnostic_output_file output_file;
+  if (filename.get ())
+    output_file = ctxt.open_output_file (std::move (filename));
+  else
+    // Default filename
+    {
+      const char *basename = (ctxt.m_opts.x_dump_base_name
+                             ? ctxt.m_opts.x_dump_base_name
+                             : ctxt.m_opts.x_main_input_basename);
+      output_file = diagnostic_output_format_open_html_file (ctxt.m_dc,
+                                                            line_table,
+                                                            basename);
+    }
+  if (!output_file)
+    return nullptr;
+
+  auto sink = make_html_sink (ctxt.m_dc,
+                             *line_table,
+                             std::move (output_file));
+  return sink;
+}
+
 } // namespace diagnostics_output_spec
 } // namespace gcc
 
diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc
index 3c12e8a3ebd9..959e5d0a0f8d 100644
--- a/gcc/selftest-run-tests.cc
+++ b/gcc/selftest-run-tests.cc
@@ -98,6 +98,7 @@ selftest::run_tests ()
      rely on.  */
   diagnostic_color_cc_tests ();
   diagnostic_show_locus_cc_tests ();
+  diagnostic_format_html_cc_tests ();
   diagnostic_format_json_cc_tests ();
   diagnostic_format_sarif_cc_tests ();
   edit_context_cc_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index a0d247342427..7e1d94cd39ef 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -221,6 +221,7 @@ extern void bitmap_cc_tests ();
 extern void cgraph_cc_tests ();
 extern void convert_cc_tests ();
 extern void diagnostic_color_cc_tests ();
+extern void diagnostic_format_html_cc_tests ();
 extern void diagnostic_format_json_cc_tests ();
 extern void diagnostic_format_sarif_cc_tests ();
 extern void diagnostic_path_cc_tests ();
diff --git a/gcc/testsuite/gcc.dg/html-output/html-output.exp 
b/gcc/testsuite/gcc.dg/html-output/html-output.exp
new file mode 100644
index 000000000000..1f977ca1f568
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/html-output/html-output.exp
@@ -0,0 +1,31 @@
+# Copyright (C) 2012-2024 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] "" ""
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/html-output/missing-semicolon.c 
b/gcc/testsuite/gcc.dg/html-output/missing-semicolon.c
new file mode 100644
index 000000000000..c211f4f76e71
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/html-output/missing-semicolon.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-add-output=experimental-html" } */
+
+/* Verify that basics of HTML output work.  */
+
+int missing_semicolon (void)
+{
+  return 42 /* { dg-error "expected ';' before '.' token" } */
+}
+
+/* Use a Python script to verify various properties about the generated
+   .html file:
+   { dg-final { run-html-pytest missing-semicolon.c "missing-semicolon.py" } } 
*/
diff --git a/gcc/testsuite/gcc.dg/html-output/missing-semicolon.py 
b/gcc/testsuite/gcc.dg/html-output/missing-semicolon.py
new file mode 100644
index 000000000000..8687168e8841
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/html-output/missing-semicolon.py
@@ -0,0 +1,84 @@
+# Verify that basics of HTML output work.
+#
+# For reference, we expect this textual output:
+#
+# PATH/missing-semicolon.c: In function ‘missing_semicolon’:
+# PATH/missing-semicolon.c:8:12: error: expected ‘;’ before ‘}’ token
+#     8 |   return 42 /* { dg-error "expected ';' before '.' token" } */
+#       |            ^
+#       |            ;
+#     9 | }
+#       | ~           
+
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+    return html_tree_from_env()
+
+XHTML = 'http://www.w3.org/1999/xhtml'
+ns = {'xhtml': XHTML}
+
+def make_tag(local_name):
+    return f'{{{XHTML}}}' + local_name
+
+def test_basics(html_tree):
+    root = html_tree.getroot ()
+    assert root.tag == make_tag('html')
+
+    head = root.find('xhtml:head', ns)
+    assert head is not None
+
+    title = head.find('xhtml:title', ns)
+    assert title.text == 'Title goes here'
+
+    body = root.find('xhtml:body', ns)
+    assert body is not None
+
+    diag_list = body.find('xhtml:div', ns)
+    assert diag_list is not None
+    assert diag_list.attrib['class'] == 'gcc-diagnostic-list'
+
+    diag = diag_list.find('xhtml:div', ns)
+    assert diag is not None
+    assert diag.attrib['class'] == 'gcc-diagnostic'
+
+    message = diag.find('xhtml:span', ns)
+    assert message is not None
+    assert message.attrib['class'] == 'gcc-message'
+    assert message.text == "expected '"
+    assert message[0].tag == make_tag('span')
+    assert message[0].attrib['class'] == 'gcc-quoted-text'
+    assert message[0].text == ';'
+    assert message[0].tail == "' before '"
+    assert message[1].tag == make_tag('span')
+    assert message[1].attrib['class'] == 'gcc-quoted-text'
+    assert message[1].text == '}'
+    assert message[1].tail == "' token"
+
+    pre = diag.find('xhtml:pre', ns)
+    assert pre is not None
+    assert pre.attrib['class'] == 'gcc-annotated-source'
+
+# For reference, here's the generated HTML:
+"""
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html
+     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
+<html xmlns="http://www.w3.org/1999/xhtml";>
+  <head>
+    <title>Title goes here</title>
+  </head>
+  <body>
+    <div class="gcc-diagnostic-list">
+      <div class="gcc-diagnostic">
+        <span class="gcc-message">expected &apos;<span 
class="gcc-quoted-text">;</span>&apos; before &apos;<span 
class="gcc-quoted-text">}</span>&apos; token</span>
+        <pre class="gcc-annotated-source"></pre>
+      </div>
+    </div>
+  </body>
+</html>
+"""
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-xhtml-1.c 
b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-xhtml-1.c
deleted file mode 100644
index da069ff4789d..000000000000
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-xhtml-1.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/* { dg-do compile } */
-
-int missing_semicolon (void)
-{
-  return 42
-}
-
-/* Verify some properties of the generated HTML.  */
-
-/* { dg-begin-multiline-output "" }
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";>
-<html xmlns="http://www.w3.org/1999/xhtml";>
-  <head>
-   { dg-end-multiline-output "" } */
-
-/* { dg-excess-errors "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp 
b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 90c91621d0aa..26326cc2e5fd 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -76,8 +76,6 @@ set plugin_test_list [list \
          crash-test-ice-in-header-sarif-2.1.c \
          crash-test-ice-in-header-sarif-2.2.c \
          crash-test-write-though-null-sarif.c } \
-    { diagnostic_plugin_xhtml_format.cc \
-         diagnostic-test-xhtml-1.c } \
     { diagnostic_group_plugin.cc \
          diagnostic-group-test-1.c } \
     { diagnostic_plugin_test_show_locus.cc \
diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp
index 6dd8fa3fce9c..312c4b8659a4 100644
--- a/gcc/testsuite/lib/gcc-dg.exp
+++ b/gcc/testsuite/lib/gcc-dg.exp
@@ -26,6 +26,7 @@ load_lib scanipa.exp
 load_lib scanwpaipa.exp
 load_lib scanlang.exp
 load_lib scansarif.exp
+load_lib scanhtml.exp
 load_lib timeout.exp
 load_lib timeout-dg.exp
 load_lib prune.exp
diff --git a/gcc/testsuite/lib/htmltest.py b/gcc/testsuite/lib/htmltest.py
new file mode 100644
index 000000000000..b249ea691f19
--- /dev/null
+++ b/gcc/testsuite/lib/htmltest.py
@@ -0,0 +1,9 @@
+import os
+import xml.etree.ElementTree as ET
+
+def html_tree_from_env():
+    # return parsed HTML content as an ET from an HTML_PATH file
+    html_filename = os.environ['HTML_PATH']
+    html_filename += '.html'
+    print('html_filename: %r' % html_filename)
+    return ET.parse(html_filename)
diff --git a/gcc/testsuite/lib/scanhtml.exp b/gcc/testsuite/lib/scanhtml.exp
new file mode 100644
index 000000000000..6d8f39813345
--- /dev/null
+++ b/gcc/testsuite/lib/scanhtml.exp
@@ -0,0 +1,90 @@
+# Copyright (C) 2000-2025 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Various utilities for scanning HTML output, used by gcc-dg.exp and
+# g++-dg.exp.
+#
+# This is largely borrowed from scansarif.exp.
+
+proc html-pytest-format-line { args } {
+    global subdir
+
+    set testcase [lindex $args 0]
+    set pytest_script [lindex $args 1]
+    set output_line [lindex $args 2]
+
+    set index [string first "::" $output_line]
+    set test_output [string range $output_line [expr $index + 2] [string 
length $output_line]]
+
+    return "$subdir/$testcase ${pytest_script}::${test_output}"
+}
+
+# Call by dg-final to run a pytest Python script.
+# We pass filename of a test via HTML_PATH environment variable.
+
+proc run-html-pytest { args } {
+    global srcdir subdir
+    # Extract the test file name from the arguments.
+    set testcase [lindex $args 0]
+
+    verbose "Running HTML $testcase in $srcdir/$subdir" 2
+    set testcase [remote_download host $testcase]
+
+    set pytest_script [lindex $args 1]
+    if { ![check_effective_target_pytest3] } {
+      unsupported "$pytest_script pytest python3 is missing"
+      return
+    }
+
+    setenv HTML_PATH $testcase
+    set libdir "${srcdir}/lib"
+
+    # Set/prepend libdir to PYTHONPATH
+    if [info exists ::env(PYTHONPATH)] {
+       set old_PYTHONPATH $::env(PYTHONPATH)
+       setenv PYTHONPATH "${libdir}:${old_PYTHONPATH}"
+    } else {
+       setenv PYTHONPATH "${libdir}"
+    }
+    
+    verbose "PYTHONPATH=[getenv PYTHONPATH]" 2
+
+    spawn -noecho python3 -m pytest --color=no -rap -s --tb=no 
$srcdir/$subdir/$pytest_script
+
+    if [info exists old_PYTHONPATH] {
+       setenv PYTHONPATH ${old_PYTHONPATH}
+    }
+
+    set prefix "\[^\r\n\]*"
+    expect {
+      -re "FAILED($prefix)\[^\r\n\]+\r\n" {
+       set output [html-pytest-format-line $testcase $pytest_script 
$expect_out(1,string)]
+       fail $output
+       exp_continue
+      }
+      -re "ERROR($prefix)\[^\r\n\]+\r\n" {
+       set output [html-pytest-format-line $testcase $pytest_script 
$expect_out(1,string)]
+       fail $output
+       exp_continue
+      }
+      -re "PASSED($prefix)\[^\r\n\]+\r\n" {
+       set output [html-pytest-format-line $testcase $pytest_script 
$expect_out(1,string)]
+       pass $output
+       exp_continue
+      }
+    }
+}
+
diff --git a/libatomic/testsuite/lib/libatomic.exp 
b/libatomic/testsuite/lib/libatomic.exp
index 4b52a6f74876..456493c3a797 100644
--- a/libatomic/testsuite/lib/libatomic.exp
+++ b/libatomic/testsuite/lib/libatomic.exp
@@ -37,6 +37,7 @@ load_gcc_lib scandump.exp
 load_gcc_lib scanlang.exp
 load_gcc_lib scanrtl.exp
 load_gcc_lib scansarif.exp
+load_gcc_lib scanhtml.exp
 load_gcc_lib scantree.exp
 load_gcc_lib scanltrans.exp
 load_gcc_lib scanipa.exp
diff --git a/libgomp/testsuite/lib/libgomp.exp 
b/libgomp/testsuite/lib/libgomp.exp
index 54f2f708b1ba..fd475ac3fe63 100644
--- a/libgomp/testsuite/lib/libgomp.exp
+++ b/libgomp/testsuite/lib/libgomp.exp
@@ -30,6 +30,7 @@ load_gcc_lib scandump.exp
 load_gcc_lib scanlang.exp
 load_gcc_lib scanrtl.exp
 load_gcc_lib scansarif.exp
+load_gcc_lib scanhtml.exp
 load_gcc_lib scantree.exp
 load_gcc_lib scanltrans.exp
 load_gcc_lib scanoffload.exp
diff --git a/libitm/testsuite/lib/libitm.exp b/libitm/testsuite/lib/libitm.exp
index ac390d6d0dd0..0b3301537cee 100644
--- a/libitm/testsuite/lib/libitm.exp
+++ b/libitm/testsuite/lib/libitm.exp
@@ -43,6 +43,7 @@ load_gcc_lib scandump.exp
 load_gcc_lib scanlang.exp
 load_gcc_lib scanrtl.exp
 load_gcc_lib scansarif.exp
+load_gcc_lib scanhtml.exp
 load_gcc_lib scantree.exp
 load_gcc_lib scanltrans.exp
 load_gcc_lib scanipa.exp
diff --git a/libphobos/testsuite/lib/libphobos-dg.exp 
b/libphobos/testsuite/lib/libphobos-dg.exp
index 2cac87feffd4..f2c38a2cbd68 100644
--- a/libphobos/testsuite/lib/libphobos-dg.exp
+++ b/libphobos/testsuite/lib/libphobos-dg.exp
@@ -24,6 +24,7 @@ load_gcc_lib scanasm.exp
 load_gcc_lib scanlang.exp
 load_gcc_lib scanrtl.exp
 load_gcc_lib scansarif.exp
+load_gcc_lib scanhtml.exp
 load_gcc_lib scantree.exp
 load_gcc_lib scanipa.exp
 load_gcc_lib torture-options.exp
diff --git a/libvtv/testsuite/lib/libvtv-dg.exp 
b/libvtv/testsuite/lib/libvtv-dg.exp
index 454d916e556c..2a45f5cc4dbf 100644
--- a/libvtv/testsuite/lib/libvtv-dg.exp
+++ b/libvtv/testsuite/lib/libvtv-dg.exp
@@ -13,6 +13,7 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 
USA.
 
 load_gcc_lib scansarif.exp
+load_gcc_lib scanhtml.exp
 
 proc libvtv-dg-test { prog do_what extra_tool_flags } {
     return [gcc-dg-test-1 libvtv_target_compile $prog $do_what 
$extra_tool_flags]
-- 
2.26.3

Reply via email to