On Wed, 2019-12-04 at 10:36 -0700, Martin Sebor wrote:
> On 11/15/19 6:22 PM, David Malcolm wrote:
> > This patch adds support for associating a diagnostic with an
> > optional
> > diagnostic_metadata object, so that plugins can add extra data to
> > their
> > diagnostics (e.g. mapping a diagnostic to a taxonomy or coding
> > standard
> > such as from CERT or MISRA).
> >
> > Currently this only supports associating a CWE identifier with a
> > diagnostic (which is what I'm using for the analyzer warnings later
> > in
> > the patch kit), but adding a diagnostic_metadata class allows for
> > future
> > growth in this area without an explosion of further "warning_at"
> > overloads
> > for all of the different kinds of custom data that a plugin might
> > want to
> > add.
>
> We discussed this in the past so I'll be repeating some of my
> comments from that thread. I like the feature at a high level,
> but I'm not sure I see how to make it work in a robust way.
>
> There is no one-to-one mapping between GCC warnings and any of
> these classifications. A single GCC warning might map to several
> CERT or MISRA guidelines, and a single guideline might map to two
> or more different GCC warnings. This is an M to N mapping times
> the number of coding standards/classifications. I haven't looked
> at the patch kit in enough detail to understand how it tries to
> handle it. Can you explain?
The patch kit gives the ability to (optionally) specify a single CWE
identifier when emitting a diagnostic.
The patch kit uses this in various places for its new warnings for the
cases where there is a well-defined CWE weakness identifier (and
doesn't otherwise).
It doesn't attempt to classify any existing warnings.
It doesn't attempt to support other classifications in this patch, but
it does introduce a diagnostic_metadata object that could gain this
functionality at some later time, if we come up with a scheme we're
happy with (a slight violation of YAGNI, but it's such a pain touching
all the diagnostic fns that I prefer to do it once).
> My other concern here is that these guidelines evolve. New ones
> are being added, existing ones moved or broken up, etc. Does
> the infrastructure cope with this evolution (e.g., by reading
> the mapping from a file)?
Let's cross that bridge when we come to it. If it becomes a problem,
then we can come up with a fix (e.g. a command-line option to specify
the CWE version).
Dave
> Martin
>
> > gcc/ChangeLog:
> > * common.opt (fdiagnostics-show-metadata): New option.
> > * diagnostic-core.h (class diagnostic_metadata): New forward
> > decl.
> > (warning_at): Add overload taking a const diagnostic_metadata
> > &.
> > (emit_diagnostic_valist): Add overload taking a
> > const diagnostic_metadata *.
> > * diagnostic-format-json.cc: Include "diagnostic-metadata.h".
> > (json_from_metadata): New function.
> > (json_end_diagnostic): Call it to add "metadata" child for
> > diagnostics with metadata.
> > (diagnostic_output_format_init): Clear context->show_metadata.
> > * diagnostic-metadata.h: New file.
> > * diagnostic.c: Include "diagnostic-metadata.h".
> > (diagnostic_impl): Add const diagnostic_metadata * param.
> > (diagnostic_n_impl): Likewise.
> > (diagnostic_initialize): Initialize context->show_metadata.
> > (diagnostic_set_info_translated): Initialize diagnostic-
> > >metadata.
> > (get_cwe_url): New function.
> > (print_any_metadata): New function.
> > (diagnostic_report_diagnostic): Call print_any_metadata if the
> > diagnostic has non-NULL metadata.
> > (emit_diagnostic): Pass NULL as the metadata in the call to
> > diagnostic_impl.
> > (emit_diagnostic_valist): Likewise.
> > (emit_diagnostic_valist): New overload taking a
> > const diagnostic_metadata *.
> > (inform): Pass NULL as the metadata in the call to
> > diagnostic_impl.
> > (inform_n): Likewise for diagnostic_n_impl.
> > (warning): Likewise.
> > (warning_at): Likewise. Add overload that takes a
> > const diagnostic_metadata &.
> > (warning_n): Pass NULL as the metadata in the call to
> > diagnostic_n_impl.
> > (pedwarn): Likewise for diagnostic_impl.
> > (permerror): Likewise.
> > (error): Likewise.
> > (error_n): Likewise.
> > (error_at): Likewise.
> > (sorry): Likewise.
> > (sorry_at): Likewise.
> > (fatal_error): Likewise.
> > (internal_error): Likewise.
> > (internal_error_no_backtrace): Likewise.
> > * diagnostic.h (diagnostic_info::metadata): New field.
> > (diagnostic_context::show_metadata): New field.
> > * doc/invoke.texi (-fno-diagnostics-show-metadata): New option.
> > * opts.c (common_handle_option): Handle
> > OPT_fdiagnostics_show_metadata.
> > * toplev.c (general_init): Initialize global_dc->show_metadata.
> > ---
> > gcc/common.opt | 4 ++
> > gcc/diagnostic-core.h | 10 +++
> > gcc/diagnostic-format-json.cc | 23 +++++++
> > gcc/diagnostic-metadata.h | 42 +++++++++++++
> > gcc/diagnostic.c | 142
> > +++++++++++++++++++++++++++++++++---------
> > gcc/diagnostic.h | 7 +++
> > gcc/doc/invoke.texi | 8 +++
> > gcc/opts.c | 4 ++
> > gcc/toplev.c | 2 +
> > 9 files changed, 211 insertions(+), 31 deletions(-)
> > create mode 100644 gcc/diagnostic-metadata.h
> >
> > diff --git a/gcc/common.opt b/gcc/common.opt
> > index 3c024b3..228df32 100644
> > --- a/gcc/common.opt
> > +++ b/gcc/common.opt
> > @@ -1334,6 +1334,10 @@ fdiagnostics-show-option
> > Common Var(flag_diagnostics_show_option) Init(1)
> > Amend appropriate diagnostic messages with the command line
> > option that controls them.
> >
> > +fdiagnostics-show-metadata
> > +Common Var(flag_diagnostics_show_metadata) Init(1)
> > +Print additional metadata for diagnostic messages, where
> > available.
> > +
> > fdiagnostics-minimum-margin-width=
> > Common Joined UInteger Var(diagnostics_minimum_margin_width)
> > Init(6)
> > Set minimum width of left margin of source code when showing
> > source.
> > diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
> > index efafde4..2e7f120 100644
> > --- a/gcc/diagnostic-core.h
> > +++ b/gcc/diagnostic-core.h
> > @@ -45,6 +45,9 @@ class auto_diagnostic_group
> > ~auto_diagnostic_group ();
> > };
> >
> > +/* Forward decl. */
> > +class diagnostic_metadata; /* See diagnostic-metadata.h. */
> > +
> > extern const char *progname;
> >
> > extern const char *trim_filename (const char *);
> > @@ -78,6 +81,9 @@ extern bool warning_at (location_t, int, const
> > char *, ...)
> > ATTRIBUTE_GCC_DIAG(3,4);
> > extern bool warning_at (rich_location *, int, const char *, ...)
> > ATTRIBUTE_GCC_DIAG(3,4);
> > +extern bool warning_at (rich_location *, const diagnostic_metadata
> > &, int,
> > + const char *, ...)
> > + ATTRIBUTE_GCC_DIAG(4,5);
> > extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
> > extern void error_n (location_t, unsigned HOST_WIDE_INT, const
> > char *,
> > const char *, ...)
> > @@ -109,6 +115,10 @@ extern bool emit_diagnostic (diagnostic_t,
> > rich_location *, int,
> > const char *, ...)
> > ATTRIBUTE_GCC_DIAG(4,5);
> > extern bool emit_diagnostic_valist (diagnostic_t, location_t,
> > int, const char *,
> > va_list *) ATTRIBUTE_GCC_DIAG
> > (4,0);
> > +extern bool emit_diagnostic_valist (diagnostic_t, rich_location *,
> > + const diagnostic_metadata
> > *metadata,
> > + int, const char *, va_list *)
> > + ATTRIBUTE_GCC_DIAG (5,0);
> > extern bool seen_error (void);
> >
> > #ifdef BUFSIZ
> > diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-
> > json.cc
> > index eb99952..200e844 100644
> > --- a/gcc/diagnostic-format-json.cc
> > +++ b/gcc/diagnostic-format-json.cc
> > @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not
> > see
> > #include "system.h"
> > #include "coretypes.h"
> > #include "diagnostic.h"
> > +#include "diagnostic-metadata.h"
> > #include "json.h"
> > #include "selftest.h"
> >
> > @@ -103,6 +104,19 @@ json_from_fixit_hint (const fixit_hint *hint)
> > return fixit_obj;
> > }
> >
> > +/* Generate a JSON object for METADATA. */
> > +
> > +static json::object *
> > +json_from_metadata (const diagnostic_metadata *metadata)
> > +{
> > + json::object *metadata_obj = new json::object ();
> > +
> > + if (metadata->get_cwe ())
> > + metadata_obj->set ("cwe", new json::number (metadata->get_cwe
> > ()));
> > +
> > + return metadata_obj;
> > +}
> > +
> > /* No-op implementation of "begin_diagnostic" for JSON
> > output. */
> >
> > static void
> > @@ -211,6 +225,12 @@ json_end_diagnostic (diagnostic_context
> > *context, diagnostic_info *diagnostic,
> > TODO: functions
> > TODO: inlining information
> > TODO: macro expansion information. */
> > +
> > + if (diagnostic->metadata)
> > + {
> > + json::object *metadata_obj = json_from_metadata (diagnostic-
> > >metadata);
> > + diag_obj->set ("metadata", metadata_obj);
> > + }
> > }
> >
> > /* No-op implementation of "begin_group_cb" for JSON output. */
> > @@ -268,6 +288,9 @@ diagnostic_output_format_init
> > (diagnostic_context *context,
> > context->end_group_cb = json_end_group;
> > context->final_cb = json_final_cb;
> >
> > + /* The metadata is handled in JSON format, rather than as
> > text. */
> > + context->show_metadata = false;
> > +
> > /* The option is handled in JSON format, rather than as
> > text. */
> > context->show_option_requested = false;
> >
> > diff --git a/gcc/diagnostic-metadata.h b/gcc/diagnostic-metadata.h
> > new file mode 100644
> > index 0000000..a759d44
> > --- /dev/null
> > +++ b/gcc/diagnostic-metadata.h
> > @@ -0,0 +1,42 @@
> > +/* Additional metadata for a diagnostic.
> > + Copyright (C) 2019 Free Software Foundation, Inc.
> > + Contributed by David Malcolm <[email protected]>
> > +
> > +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_METADATA_H
> > +#define GCC_DIAGNOSTIC_METADATA_H
> > +
> > +/* A bundle of additional metadata that can be associated with a
> > + diagnostic.
> > +
> > + Currently this only supports associating a CWE identifier with
> > a
> > + diagnostic. */
> > +
> > +class diagnostic_metadata
> > +{
> > + public:
> > + diagnostic_metadata () : m_cwe (0) {}
> > +
> > + void add_cwe (int cwe) { m_cwe = cwe; }
> > + int get_cwe () const { return m_cwe; }
> > +
> > + private:
> > + int m_cwe;
> > +};
> > +
> > +#endif /* ! GCC_DIAGNOSTIC_METADATA_H */
> > diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
> > index 81e0a10..e8d0613 100644
> > --- a/gcc/diagnostic.c
> > +++ b/gcc/diagnostic.c
> > @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not
> > see
> > #include "diagnostic.h"
> > #include "diagnostic-color.h"
> > #include "diagnostic-url.h"
> > +#include "diagnostic-metadata.h"
> > #include "edit-context.h"
> > #include "selftest.h"
> > #include "selftest-diagnostic.h"
> > @@ -58,11 +59,13 @@ along with GCC; see the file COPYING3. If not
> > see
> > #define permissive_error_option(DC) ((DC)->opt_permissive)
> >
> > /* Prototypes. */
> > -static bool diagnostic_impl (rich_location *, int, const char *,
> > - va_list *, diagnostic_t)
> > ATTRIBUTE_GCC_DIAG(3,0);
> > -static bool diagnostic_n_impl (rich_location *, int, unsigned
> > HOST_WIDE_INT,
> > +static bool diagnostic_impl (rich_location *, const
> > diagnostic_metadata *,
> > + int, const char *,
> > + va_list *, diagnostic_t)
> > ATTRIBUTE_GCC_DIAG(4,0);
> > +static bool diagnostic_n_impl (rich_location *, const
> > diagnostic_metadata *,
> > + int, unsigned HOST_WIDE_INT,
> > const char *, const char *, va_list *,
> > - diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
> > + diagnostic_t) ATTRIBUTE_GCC_DIAG(6,0);
> >
> > static void error_recursion (diagnostic_context *)
> > ATTRIBUTE_NORETURN;
> > static void real_abort (void) ATTRIBUTE_NORETURN;
> > @@ -183,6 +186,7 @@ diagnostic_initialize (diagnostic_context
> > *context, int n_opts)
> > diagnostic_set_caret_max_width (context, pp_line_cutoff
> > (context->printer));
> > for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES;
> > i++)
> > context->caret_chars[i] = '^';
> > + context->show_metadata = false;
> > context->show_option_requested = false;
> > context->abort_on_error = false;
> > context->show_column = false;
> > @@ -300,6 +304,7 @@ diagnostic_set_info_translated (diagnostic_info
> > *diagnostic, const char *msg,
> > diagnostic->message.format_spec = msg;
> > diagnostic->message.m_richloc = richloc;
> > diagnostic->richloc = richloc;
> > + diagnostic->metadata = NULL;
> > diagnostic->kind = kind;
> > diagnostic->option_index = 0;
> > }
> > @@ -899,6 +904,47 @@ update_effective_level_from_pragmas
> > (diagnostic_context *context,
> > return diag_class;
> > }
> >
> > +/* Generate a URL string describing CWE. The caller is
> > responsible for
> > + freeing the string. */
> > +
> > +static char *
> > +get_cwe_url (int cwe)
> > +{
> > + return xasprintf ("
> > https://cwe.mitre.org/data/definitions/%i.html", cwe);
> > +}
> > +
> > +/* If DIAGNOSTIC has metadata, print it.
> > +
> > + For example, if the diagnostic metadata associates it with CWE-
> > 119,
> > + " [CWE-119]" will be printed, suitably colorized, and with a
> > URL of a
> > + description of the security issue. */
> > +
> > +static void
> > +print_any_metadata (diagnostic_context *context,
> > + const diagnostic_info *diagnostic)
> > +{
> > + if (diagnostic->metadata == NULL)
> > + return;
> > +
> > + int cwe = diagnostic->metadata->get_cwe ();
> > + if (cwe)
> > + {
> > + pretty_printer *pp = context->printer;
> > + char *saved_prefix = pp_take_prefix (context->printer);
> > + pp_string (pp, " [");
> > + pp_string (pp, colorize_start (pp_show_color (pp),
> > + diagnostic_kind_color[diagnostic-
> > >kind]));
> > + char *cwe_url = get_cwe_url (cwe);
> > + pp_begin_url (pp, cwe_url);
> > + free (cwe_url);
> > + pp_printf (pp, "CWE-%i", cwe);
> > + pp_set_prefix (context->printer, saved_prefix);
> > + pp_end_url (pp);
> > + pp_string (pp, colorize_stop (pp_show_color (pp)));
> > + pp_character (pp, ']');
> > + }
> > +}
> > +
> > /* Print any metadata about the option used to control DIAGNOSTIC
> > to CONTEXT's
> > printer, e.g. " [-Werror=uninitialized]".
> > Subroutine of diagnostic_report_diagnostic. */
> > @@ -1059,6 +1105,8 @@ diagnostic_report_diagnostic
> > (diagnostic_context *context,
> > pp_format (context->printer, &diagnostic->message);
> > (*diagnostic_starter (context)) (context, diagnostic);
> > pp_output_formatted_text (context->printer);
> > + if (context->show_metadata)
> > + print_any_metadata (context, diagnostic);
> > if (context->show_option_requested)
> > print_option_information (context, diagnostic,
> > orig_diag_kind);
> > (*diagnostic_finalizer (context)) (context, diagnostic,
> > orig_diag_kind);
> > @@ -1190,8 +1238,8 @@ diagnostic_append_note (diagnostic_context
> > *context,
> > permerror, error, error_at, error_at, sorry, fatal_error,
> > internal_error,
> > and internal_error_no_backtrace, as documented and defined
> > below. */
> > static bool
> > -diagnostic_impl (rich_location *richloc, int opt,
> > - const char *gmsgid,
> > +diagnostic_impl (rich_location *richloc, const diagnostic_metadata
> > *metadata,
> > + int opt, const char *gmsgid,
> > va_list *ap, diagnostic_t kind)
> > {
> > diagnostic_info diagnostic;
> > @@ -1207,13 +1255,15 @@ diagnostic_impl (rich_location *richloc,
> > int opt,
> > if (kind == DK_WARNING || kind == DK_PEDWARN)
> > diagnostic.option_index = opt;
> > }
> > + diagnostic.metadata = metadata;
> > return diagnostic_report_diagnostic (global_dc, &diagnostic);
> > }
> >
> > /* Implement inform_n, warning_n, and error_n, as documented and
> > defined below. */
> > static bool
> > -diagnostic_n_impl (rich_location *richloc, int opt, unsigned
> > HOST_WIDE_INT n,
> > +diagnostic_n_impl (rich_location *richloc, const
> > diagnostic_metadata *metadata,
> > + int opt, unsigned HOST_WIDE_INT n,
> > const char *singular_gmsgid,
> > const char *plural_gmsgid,
> > va_list *ap, diagnostic_t kind)
> > @@ -1233,6 +1283,7 @@ diagnostic_n_impl (rich_location *richloc,
> > int opt, unsigned HOST_WIDE_INT n,
> > diagnostic_set_info_translated (&diagnostic, text, ap, richloc,
> > kind);
> > if (kind == DK_WARNING)
> > diagnostic.option_index = opt;
> > + diagnostic.metadata = metadata;
> > return diagnostic_report_diagnostic (global_dc, &diagnostic);
> > }
> >
> > @@ -1246,7 +1297,7 @@ emit_diagnostic (diagnostic_t kind,
> > location_t location, int opt,
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, location);
> > - bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap, kind);
> > + bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap,
> > kind);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1260,7 +1311,7 @@ emit_diagnostic (diagnostic_t kind,
> > rich_location *richloc, int opt,
> > auto_diagnostic_group d;
> > va_list ap;
> > va_start (ap, gmsgid);
> > - bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, kind);
> > + bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, &ap,
> > kind);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1272,7 +1323,18 @@ emit_diagnostic_valist (diagnostic_t kind,
> > location_t location, int opt,
> > const char *gmsgid, va_list *ap)
> > {
> > rich_location richloc (line_table, location);
> > - return diagnostic_impl (&richloc, opt, gmsgid, ap, kind);
> > + return diagnostic_impl (&richloc, NULL, opt, gmsgid, ap, kind);
> > +}
> > +
> > +/* Wrapper around diagnostic_impl taking a va_list parameter. */
> > +
> > +bool
> > +emit_diagnostic_valist (diagnostic_t kind, rich_location *richloc,
> > + const diagnostic_metadata *metadata,
> > + int opt,
> > + const char *gmsgid, va_list *ap)
> > +{
> > + return diagnostic_impl (richloc, metadata, opt, gmsgid, ap,
> > kind);
> > }
> >
> > /* An informative note at LOCATION. Use this for additional
> > details on an error
> > @@ -1284,7 +1346,7 @@ inform (location_t location, const char
> > *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, location);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_NOTE);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_NOTE);
> > va_end (ap);
> > }
> >
> > @@ -1297,7 +1359,7 @@ inform (rich_location *richloc, const char
> > *gmsgid, ...)
> > auto_diagnostic_group d;
> > va_list ap;
> > va_start (ap, gmsgid);
> > - diagnostic_impl (richloc, -1, gmsgid, &ap, DK_NOTE);
> > + diagnostic_impl (richloc, NULL, -1, gmsgid, &ap, DK_NOTE);
> > va_end (ap);
> > }
> >
> > @@ -1311,7 +1373,7 @@ inform_n (location_t location, unsigned
> > HOST_WIDE_INT n,
> > va_start (ap, plural_gmsgid);
> > auto_diagnostic_group d;
> > rich_location richloc (line_table, location);
> > - diagnostic_n_impl (&richloc, -1, n, singular_gmsgid,
> > plural_gmsgid,
> > + diagnostic_n_impl (&richloc, NULL, -1, n, singular_gmsgid,
> > plural_gmsgid,
> > &ap, DK_NOTE);
> > va_end (ap);
> > }
> > @@ -1326,7 +1388,7 @@ warning (int opt, const char *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, input_location);
> > - bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap,
> > DK_WARNING);
> > + bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap,
> > DK_WARNING);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1342,7 +1404,7 @@ warning_at (location_t location, int opt,
> > const char *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, location);
> > - bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap,
> > DK_WARNING);
> > + bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap,
> > DK_WARNING);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1357,7 +1419,25 @@ warning_at (rich_location *richloc, int opt,
> > const char *gmsgid, ...)
> > auto_diagnostic_group d;
> > va_list ap;
> > va_start (ap, gmsgid);
> > - bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap,
> > DK_WARNING);
> > + bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, &ap,
> > DK_WARNING);
> > + va_end (ap);
> > + return ret;
> > +}
> > +
> > +/* Same as "warning at" above, but using METADATA. */
> > +
> > +bool
> > +warning_at (rich_location *richloc, const diagnostic_metadata
> > &metadata,
> > + int opt, const char *gmsgid, ...)
> > +{
> > + gcc_assert (richloc);
> > +
> > + auto_diagnostic_group d;
> > + va_list ap;
> > + va_start (ap, gmsgid);
> > + bool ret
> > + = diagnostic_impl (richloc, &metadata, opt, gmsgid, &ap,
> > + DK_WARNING);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1373,7 +1453,7 @@ warning_n (rich_location *richloc, int opt,
> > unsigned HOST_WIDE_INT n,
> > auto_diagnostic_group d;
> > va_list ap;
> > va_start (ap, plural_gmsgid);
> > - bool ret = diagnostic_n_impl (richloc, opt, n,
> > + bool ret = diagnostic_n_impl (richloc, NULL, opt, n,
> > singular_gmsgid, plural_gmsgid,
> > &ap, DK_WARNING);
> > va_end (ap);
> > @@ -1392,7 +1472,7 @@ warning_n (location_t location, int opt,
> > unsigned HOST_WIDE_INT n,
> > va_list ap;
> > va_start (ap, plural_gmsgid);
> > rich_location richloc (line_table, location);
> > - bool ret = diagnostic_n_impl (&richloc, opt, n,
> > + bool ret = diagnostic_n_impl (&richloc, NULL, opt, n,
> > singular_gmsgid, plural_gmsgid,
> > &ap, DK_WARNING);
> > va_end (ap);
> > @@ -1419,7 +1499,7 @@ pedwarn (location_t location, int opt, const
> > char *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, location);
> > - bool ret = diagnostic_impl (&richloc, opt, gmsgid, &ap,
> > DK_PEDWARN);
> > + bool ret = diagnostic_impl (&richloc, NULL, opt, gmsgid, &ap,
> > DK_PEDWARN);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1434,7 +1514,7 @@ pedwarn (rich_location *richloc, int opt,
> > const char *gmsgid, ...)
> > auto_diagnostic_group d;
> > va_list ap;
> > va_start (ap, gmsgid);
> > - bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap,
> > DK_PEDWARN);
> > + bool ret = diagnostic_impl (richloc, NULL, opt, gmsgid, &ap,
> > DK_PEDWARN);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1453,7 +1533,7 @@ permerror (location_t location, const char
> > *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, location);
> > - bool ret = diagnostic_impl (&richloc, -1, gmsgid, &ap,
> > DK_PERMERROR);
> > + bool ret = diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap,
> > DK_PERMERROR);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1468,7 +1548,7 @@ permerror (rich_location *richloc, const char
> > *gmsgid, ...)
> > auto_diagnostic_group d;
> > va_list ap;
> > va_start (ap, gmsgid);
> > - bool ret = diagnostic_impl (richloc, -1, gmsgid, &ap,
> > DK_PERMERROR);
> > + bool ret = diagnostic_impl (richloc, NULL, -1, gmsgid, &ap,
> > DK_PERMERROR);
> > va_end (ap);
> > return ret;
> > }
> > @@ -1482,7 +1562,7 @@ error (const char *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, input_location);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ERROR);
> > va_end (ap);
> > }
> >
> > @@ -1496,7 +1576,7 @@ error_n (location_t location, unsigned
> > HOST_WIDE_INT n,
> > va_list ap;
> > va_start (ap, plural_gmsgid);
> > rich_location richloc (line_table, location);
> > - diagnostic_n_impl (&richloc, -1, n, singular_gmsgid,
> > plural_gmsgid,
> > + diagnostic_n_impl (&richloc, NULL, -1, n, singular_gmsgid,
> > plural_gmsgid,
> > &ap, DK_ERROR);
> > va_end (ap);
> > }
> > @@ -1509,7 +1589,7 @@ error_at (location_t loc, const char *gmsgid,
> > ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, loc);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ERROR);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ERROR);
> > va_end (ap);
> > }
> >
> > @@ -1523,7 +1603,7 @@ error_at (rich_location *richloc, const char
> > *gmsgid, ...)
> > auto_diagnostic_group d;
> > va_list ap;
> > va_start (ap, gmsgid);
> > - diagnostic_impl (richloc, -1, gmsgid, &ap, DK_ERROR);
> > + diagnostic_impl (richloc, NULL, -1, gmsgid, &ap, DK_ERROR);
> > va_end (ap);
> > }
> >
> > @@ -1537,7 +1617,7 @@ sorry (const char *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, input_location);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_SORRY);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_SORRY);
> > va_end (ap);
> > }
> >
> > @@ -1549,7 +1629,7 @@ sorry_at (location_t loc, const char *gmsgid,
> > ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, loc);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_SORRY);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_SORRY);
> > va_end (ap);
> > }
> >
> > @@ -1571,7 +1651,7 @@ fatal_error (location_t loc, const char
> > *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, loc);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_FATAL);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_FATAL);
> > va_end (ap);
> >
> > gcc_unreachable ();
> > @@ -1588,7 +1668,7 @@ internal_error (const char *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, input_location);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ICE);
> > va_end (ap);
> >
> > gcc_unreachable ();
> > @@ -1604,7 +1684,7 @@ internal_error_no_backtrace (const char
> > *gmsgid, ...)
> > va_list ap;
> > va_start (ap, gmsgid);
> > rich_location richloc (line_table, input_location);
> > - diagnostic_impl (&richloc, -1, gmsgid, &ap, DK_ICE_NOBT);
> > + diagnostic_impl (&richloc, NULL, -1, gmsgid, &ap, DK_ICE_NOBT);
> > va_end (ap);
> >
> > gcc_unreachable ();
> > diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
> > index 2fb75e6..0e4b6ad 100644
> > --- a/gcc/diagnostic.h
> > +++ b/gcc/diagnostic.h
> > @@ -46,6 +46,10 @@ struct diagnostic_info
> > /* The location at which the diagnostic is to be reported. */
> > rich_location *richloc;
> >
> > + /* An optional bundle of metadata associated with the diagnostic
> > + (or NULL). */
> > + const diagnostic_metadata *metadata;
> > +
> > /* Auxiliary data for client. */
> > void *x_data;
> > /* The kind of diagnostic it is about. */
> > @@ -126,6 +130,9 @@ struct diagnostic_context
> > /* Character used for caret diagnostics. */
> > char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
> >
> > + /* True if we should print any metadata associated with
> > diagnostics. */
> > + bool show_metadata;
> > +
> > /* True if we should print the command line option which
> > controls
> > each diagnostic, if known. */
> > bool show_option_requested;
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index fc92913..209e2c6 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -279,6 +279,7 @@ Objective-C and Objective-C++ Dialects}.
> > -fno-diagnostics-show-option -fno-diagnostics-show-caret @gol
> > -fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers
> > @gol
> > -fdiagnostics-nn-line-numbers @gol
> > +-fno-diagnostics-show-metadata @gol
> > -fdiagnostics-minimum-margin-width=@var{width} @gol
> > -fdiagnostics-parseable-fixits -fdiagnostics-generate-patch @gol
> > -fdiagnostics-show-template-tree -fno-elide-type @gol
> > @@ -4012,6 +4013,13 @@ as the types of expressions:
> > This option suppresses the printing of these labels (in the
> > example above,
> > the vertical bars and the ``char *'' and ``long int'' text).
> >
> > +@item -fno-diagnostics-show-metadata
> > +@opindex fno-diagnostics-show-metadata
> > +@opindex fdiagnostics-show-metadata
> > +Diagnostics can optionally contain @url{
> > https://cwe.mitre.org/index.html, CWE}
> > +metadata. By default, if this information is present, it will be
> > printed with
> > +the diagnostic. This option suppresses the printing of this
> > metadata.
> > +
> > @item -fno-diagnostics-show-line-numbers
> > @opindex fno-diagnostics-show-line-numbers
> > @opindex fdiagnostics-show-line-numbers
> > diff --git a/gcc/opts.c b/gcc/opts.c
> > index 9928d01..0caaf04 100644
> > --- a/gcc/opts.c
> > +++ b/gcc/opts.c
> > @@ -2491,6 +2491,10 @@ common_handle_option (struct gcc_options
> > *opts,
> > dc->parseable_fixits_p = value;
> > break;
> >
> > + case OPT_fdiagnostics_show_metadata:
> > + dc->show_metadata = value;
> > + break;
> > +
> > case OPT_fdiagnostics_show_option:
> > dc->show_option_requested = value;
> > break;
> > diff --git a/gcc/toplev.c b/gcc/toplev.c
> > index 2d0a390..7136164 100644
> > --- a/gcc/toplev.c
> > +++ b/gcc/toplev.c
> > @@ -1102,6 +1102,8 @@ general_init (const char *argv0, bool
> > init_signals)
> > = global_options_init.x_flag_diagnostics_show_line_numbers;
> > global_dc->use_nn_for_line_numbers_p
> > = global_options_init.x_flag_diagnostics_nn_line_numbers;
> > + global_dc->show_metadata
> > + = global_options_init.x_flag_diagnostics_show_metadata;
> > global_dc->show_option_requested
> > = global_options_init.x_flag_diagnostics_show_option;
> > global_dc->min_margin_width
> >