diff mbox series

RFC: add taxonomy IDs to diagnostics (CERT C, CWE, etc)

Message ID 1509655888-48129-1-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series RFC: add taxonomy IDs to diagnostics (CERT C, CWE, etc) | expand

Commit Message

David Malcolm Nov. 2, 2017, 8:51 p.m. UTC
We currently identify our diagnostics via command-line options, and by
the text of the option itself.

This patch adds a way to supply metadata with a diagnostic, classifying
the problem being reported, according to one of the software problem
taxonomies e.g. "INT15-C" within the CERT C Secure Coding Standard,
or "CWE-681" within the Common Weakness Enumeration (CWE).

The patch tags some of our diagnostics with CERT C IDs.

For example:

t.c: In function 'f1':
t.c:9:20: warning: division 'sizeof (int *) / sizeof (int)' does not
compute the number of array elements [-Wsizeof-pointer-div] [ARR01-C]
   i = sizeof array / sizeof *array;  /* { dg-warning "does not compute the number of array elements" } */
                    ^
t.c:6:10: note: first 'sizeof' operand was declared here
 f1 (int *array)
     ~~~~~^~~~~

Note the " [ARR01-C]" appended after the "[-Wsizeof-pointer-div]"
above.  The "ARR01-C" is colorized (assuming colorization is enabled).

Such metadata IDs can be useful for categorizing problems, or for
searching for helpful recommendations for addressing the diagnostic.

For example, if I search for on Google for "-Wsizeof-pointer-div",
I get no results (owing to the leading dash having meaning for
Google); if I drop the leading dash, I get a number of
different pages describing the implementation of the warning.

If I search instead for "ARR01-C", the first hit takes me to
the article about that issue within the SEI CERT C Coding Standard,
giving lots of useful information about the problem and how to fix it.

The new output can be suppressed using a new -fno-diagnostics-show-id
flag.

Implementation-wise, the patch replaces the "int opt" taken by our
internal APIs (like warning_at), in place of a "class diag_id" which
can be implicitly constructed from an "int opt", so no changes are
needed at callsites that emit diagnostics, until ID tags are added,
so e.g.:

  if (warning_at (body_loc, OPT_Wmultistatement_macros,
                  "macro expands to multiple statements"))
    ...

continues to compile, but can be converted to:

  if (warning_at (body_loc,
                  diag_id (OPT_Wmultistatement_macros, "PRE10-C"),
                  "macro expands to multiple statements"))
    ...

I didn't touch the Fortran error API.

Some known unknowns/questions:
- is this useful?  (I think so)
- if we implement this, should we go through the existing
  diagnostics tagging them?  if so, what taxonomy/taxonomies should we use?
  CERT vs CWE etc
- should the ID be tagged with the taxonomy it comes from? (so e.g.
  "ARR01-C" could be tagged as being from "CERT C", somehow).  How
  would this be presented to the end-user? Maybe:
    [-Wsizeof-pointer-div] [CERT-C: ARR01-C]
- could/should we support multiple taxonomies e.g. CERT vs CWE e.g.
    "[CERT-C: ARR01C] [CWE: CWE-467]" or somesuch
- if so, do we want taxonomies to be "pluggable"?  consider the
  use-case of a plugin that implements, say, the C++ Core Guidelines,
  and hence could print stuff like:
    "[c++-core-guidelines: C.128]" or somesuch
- are there license/trademark issues here?

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

Thoughts?

gcc/c-family/ChangeLog:
	* c-common.c (c_cpp_error): Provide NULL for new id parameter of
	diagnostic_set_info_translated.
	* c-warn.c (warn_for_multistatement_macros): Identify the
	diagnostic as "PRE10-C".

gcc/c/ChangeLog:
	* c-decl.c (warn_defaults_to): Convert param from int to
	const diag_id &, and pass on taxonomy id to the diagnostic_info.
	* c-errors.c (pedwarn_c99): Likewise.
	(pedwarn_c90): Likewise.
	* c-parser.c (c_parser_binary_expression): Mark
	OPT_Wsizeof_pointer_div warning as "ARR01-C".
	* c-tree.h (pedwarn_c90): Convert param from int to
	const diag_id &.
	(pedwarn_c99): Likewise.
	* c-typeck.c (c_expr_sizeof_expr): Mark OPT_Wsizeof_array_argument
	warning as "ARR01-C".

gcc/cp/ChangeLog:
	* cp-tree.h (pedwarn_cxx98): Convert param from int to
	const diag_id &.
	* error.c (pedwarn_cxx98): Likewise; pass on taxonomy id to the
	diagnostic_info.
	* typeck.c (cxx_sizeof_expr): Mark OPT_Wsizeof_array_argument
	warning as "ARR01-C".
	(cp_build_binary_op): Likewise for OPT_Wsizeof_pointer_div
	warning.

gcc/ChangeLog:
	* common.opt (fdiagnostics-show-id): New option.
	* diagnostic-core.h (class diag_id): New class.
	(warning): Convert param from int to const diag_id &.
	(warning_n): Likewise.
	(warning_at): Likewise.
	(pedwarn): Likewise.
	(emit_diagnostic): Likewise.
	(emit_diagnostic_valist): Likewise.
	* diagnostic.c (diagnostic_initialize): Initialize new "show_id"
	field.
	(diagnostic_set_info_translated): Add param "taxonomy_id" and
	use it to initialize new field of same name.
	(diagnostic_set_info): Add param "taxonomy_id" and pass through to
	diagnostic_set_info_translated.
	(print_taxonomy_information): New function.
	(diagnostic_report_diagnostic): Call it.
	(diagnostic_append_note): Pass NULL for new taxonomy_id param.
	(diagnostic_impl): Convert param from int to const diag_id &; pass
	id through to diagnostic_set_info.
	(diagnostic_n_impl): Likewise.
	(emit_diagnostic): Convert param from int to const diag_id &.
	(emit_diagnostic_valist): Likewise.
	(warning): Likewise.
	(warning_at): Likewise.
	(warning_n): Likewise.
	(pedwarn): Likewise.
	(selftest::assert_print_taxonomy_information): New function.
	(selftest::test_print_taxonomy_information): New function.
	(selftest::diagnostic_c_tests): Call it.
	* diagnostic.h (struct diagnostic_info): New field "taxonomy_id".
	(struct diagnostic_context): New field "show_id".
	(diagnostic_set_info): Add new "const char *" param.
	(diagnostic_set_info_translated): Likewise.
	* doc/invoke.texi (Diagnostic Message Formatting Options): Add
	-fno-diagnostics-show-id.
	(-fno-diagnostics-show-id): New option.
	* gimple-ssa-sprintf.c (get_format_string): Update fmtwarn for
	change of format_warning_at_substring signature.
	* opts.c (common_handle_option): Handle OPT_fdiagnostics_show_id.
	* rtl-error.c (diagnostic_for_asm): Add NULL for new "taxonomy_id" param
	of diagnostic_set_info.
	* substring-locations.c (format_warning_va): Convert param from
	int to const diag_id &.  Use it for taxonomy_id param in call to
	diagnostic_set_info.
	(format_warning_at_substring): Convert param from int to
	const diag_id &.
	* substring-locations.h (format_warning_va): Likewise.
	(format_warning_at_substring): Likewise.
	* toplev.c (general_init): Initialize global_dc->show_id.

gcc/fortran/ChangeLog:
	* cpp.c (cb_cpp_error): Add NULL for new "taxonomy_id" param of
	diagnostic_set_info_translated.
	* error.c (gfc_warning): Likewise for new param of
	diagnostic_set_info.
	(gfc_warning_now_at): Likewise.
	(gfc_warning_now): Likewise.
	(gfc_warning_internal): Likewise.
	(gfc_error_now): Likewise.
	(gfc_fatal_error): Likewise.
	(gfc_error_opt): Likewise.
	(gfc_internal_error): Likewise.
---
 gcc/c-family/c-common.c   |   2 +-
 gcc/c-family/c-warn.c     |   3 +-
 gcc/c/c-decl.c            |  10 ++--
 gcc/c/c-errors.c          |  27 +++++-----
 gcc/c/c-parser.c          |   3 +-
 gcc/c/c-tree.h            |   4 +-
 gcc/c/c-typeck.c          |   2 +-
 gcc/common.opt            |   4 ++
 gcc/cp/cp-tree.h          |   2 +-
 gcc/cp/error.c            |   7 +--
 gcc/cp/typeck.c           |   6 ++-
 gcc/diagnostic-core.h     |  53 +++++++++++++++-----
 gcc/diagnostic.c          | 122 +++++++++++++++++++++++++++++++++-------------
 gcc/diagnostic.h          |  13 ++++-
 gcc/doc/invoke.texi       |  15 +++++-
 gcc/fortran/cpp.c         |   2 +-
 gcc/fortran/error.c       |  18 ++++---
 gcc/gimple-ssa-sprintf.c  |   2 +-
 gcc/opts.c                |   4 ++
 gcc/rtl-error.c           |   2 +-
 gcc/substring-locations.c |  13 ++---
 gcc/substring-locations.h |   8 ++-
 gcc/toplev.c              |   2 +
 23 files changed, 229 insertions(+), 95 deletions(-)

Comments

Martin Sebor Nov. 2, 2017, 9:28 p.m. UTC | #1
On 11/02/2017 02:51 PM, David Malcolm wrote:
> We currently identify our diagnostics via command-line options, and by
> the text of the option itself.
> 
> This patch adds a way to supply metadata with a diagnostic, classifying
> the problem being reported, according to one of the software problem
> taxonomies e.g. "INT15-C" within the CERT C Secure Coding Standard,
> or "CWE-681" within the Common Weakness Enumeration (CWE).
> 
> The patch tags some of our diagnostics with CERT C IDs.
> 
> For example:
> 
> t.c: In function 'f1':
> t.c:9:20: warning: division 'sizeof (int *) / sizeof (int)' does not
> compute the number of array elements [-Wsizeof-pointer-div] [ARR01-C]
>     i = sizeof array / sizeof *array;  /* { dg-warning "does not compute the number of array elements" } */
>                      ^
> t.c:6:10: note: first 'sizeof' operand was declared here
>   f1 (int *array)
>       ~~~~~^~~~~
> 
> Note the " [ARR01-C]" appended after the "[-Wsizeof-pointer-div]"
> above.  The "ARR01-C" is colorized (assuming colorization is enabled).
> 
> Such metadata IDs can be useful for categorizing problems, or for
> searching for helpful recommendations for addressing the diagnostic.
> 
> For example, if I search for on Google for "-Wsizeof-pointer-div",
> I get no results (owing to the leading dash having meaning for
> Google); if I drop the leading dash, I get a number of
> different pages describing the implementation of the warning.
> 
> If I search instead for "ARR01-C", the first hit takes me to
> the article about that issue within the SEI CERT C Coding Standard,
> giving lots of useful information about the problem and how to fix it.
> 
> The new output can be suppressed using a new -fno-diagnostics-show-id
> flag.
> 
> Implementation-wise, the patch replaces the "int opt" taken by our
> internal APIs (like warning_at), in place of a "class diag_id" which
> can be implicitly constructed from an "int opt", so no changes are
> needed at callsites that emit diagnostics, until ID tags are added,
> so e.g.:
> 
>    if (warning_at (body_loc, OPT_Wmultistatement_macros,
>                    "macro expands to multiple statements"))
>      ...
> 
> continues to compile, but can be converted to:
> 
>    if (warning_at (body_loc,
>                    diag_id (OPT_Wmultistatement_macros, "PRE10-C"),
>                    "macro expands to multiple statements"))
>      ...
> 
> I didn't touch the Fortran error API.
> 
> Some known unknowns/questions:
> - is this useful?  (I think so)
> - if we implement this, should we go through the existing
>    diagnostics tagging them?  if so, what taxonomy/taxonomies should we use?
>    CERT vs CWE etc
> - should the ID be tagged with the taxonomy it comes from? (so e.g.
>    "ARR01-C" could be tagged as being from "CERT C", somehow).  How
>    would this be presented to the end-user? Maybe:
>      [-Wsizeof-pointer-div] [CERT-C: ARR01-C]
> - could/should we support multiple taxonomies e.g. CERT vs CWE e.g.
>      "[CERT-C: ARR01C] [CWE: CWE-467]" or somesuch
> - if so, do we want taxonomies to be "pluggable"?  consider the
>    use-case of a plugin that implements, say, the C++ Core Guidelines,
>    and hence could print stuff like:
>      "[c++-core-guidelines: C.128]" or somesuch
> - are there license/trademark issues here?
> 
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> 
> Thoughts?

I think it would be useful with some additional (likely substantial)
effort.  My concern (and a pet peeve) with the CERT IDs is that they
are not stable but tend to change from one release of the CERT coding
standard to the next.  To avoid the problem of GCC getting out of sync
with the current CERT standard we would need to maintain a mapping.
Another consideration is that the CERT C and C++ coding standards
don't always have the same ids and C++-specific aspects of certain
problems have their own C++ ids distinct from the C ones (e.g.,
EXP53-CPP. Do not read uninitialized memory vs EXP33-C. Do not read
uninitialized memory).  This implies a finer-grained classification
than a straightforward mapping from GCC OPT_Wfoo enums to CERT or
CWE ids can support).

In contrast to CERT, I have the impression that the CWE ids are more
stable (I don't know for certain that they're guaranteed to be).  By
their sheer number I would expect them to provide a finer-grained
mapping that, if used to tag GCC diagnostiscs, could then be used to
map them to other standards (and even GCC's own OPT_Wfoo ids).  This 
would suggest using CWE as the primary ID and mapping that to
everything else.  But I'm pretty sure this would require a lot of
effort to get right, and keep in sync as existing GCC warnings are
tweaked and enhanced.

Sorry if this sounds discouraging.  I like the idea but I worry
about the implementation and maintenance challenges.

Martin

PS A couple of other popular standards to consider are MISRA C and
C++ and the Lockheed Martin JSF C++ coding standard.

> 
> gcc/c-family/ChangeLog:
> 	* c-common.c (c_cpp_error): Provide NULL for new id parameter of
> 	diagnostic_set_info_translated.
> 	* c-warn.c (warn_for_multistatement_macros): Identify the
> 	diagnostic as "PRE10-C".
> 
> gcc/c/ChangeLog:
> 	* c-decl.c (warn_defaults_to): Convert param from int to
> 	const diag_id &, and pass on taxonomy id to the diagnostic_info.
> 	* c-errors.c (pedwarn_c99): Likewise.
> 	(pedwarn_c90): Likewise.
> 	* c-parser.c (c_parser_binary_expression): Mark
> 	OPT_Wsizeof_pointer_div warning as "ARR01-C".
> 	* c-tree.h (pedwarn_c90): Convert param from int to
> 	const diag_id &.
> 	(pedwarn_c99): Likewise.
> 	* c-typeck.c (c_expr_sizeof_expr): Mark OPT_Wsizeof_array_argument
> 	warning as "ARR01-C".
> 
> gcc/cp/ChangeLog:
> 	* cp-tree.h (pedwarn_cxx98): Convert param from int to
> 	const diag_id &.
> 	* error.c (pedwarn_cxx98): Likewise; pass on taxonomy id to the
> 	diagnostic_info.
> 	* typeck.c (cxx_sizeof_expr): Mark OPT_Wsizeof_array_argument
> 	warning as "ARR01-C".
> 	(cp_build_binary_op): Likewise for OPT_Wsizeof_pointer_div
> 	warning.
> 
> gcc/ChangeLog:
> 	* common.opt (fdiagnostics-show-id): New option.
> 	* diagnostic-core.h (class diag_id): New class.
> 	(warning): Convert param from int to const diag_id &.
> 	(warning_n): Likewise.
> 	(warning_at): Likewise.
> 	(pedwarn): Likewise.
> 	(emit_diagnostic): Likewise.
> 	(emit_diagnostic_valist): Likewise.
> 	* diagnostic.c (diagnostic_initialize): Initialize new "show_id"
> 	field.
> 	(diagnostic_set_info_translated): Add param "taxonomy_id" and
> 	use it to initialize new field of same name.
> 	(diagnostic_set_info): Add param "taxonomy_id" and pass through to
> 	diagnostic_set_info_translated.
> 	(print_taxonomy_information): New function.
> 	(diagnostic_report_diagnostic): Call it.
> 	(diagnostic_append_note): Pass NULL for new taxonomy_id param.
> 	(diagnostic_impl): Convert param from int to const diag_id &; pass
> 	id through to diagnostic_set_info.
> 	(diagnostic_n_impl): Likewise.
> 	(emit_diagnostic): Convert param from int to const diag_id &.
> 	(emit_diagnostic_valist): Likewise.
> 	(warning): Likewise.
> 	(warning_at): Likewise.
> 	(warning_n): Likewise.
> 	(pedwarn): Likewise.
> 	(selftest::assert_print_taxonomy_information): New function.
> 	(selftest::test_print_taxonomy_information): New function.
> 	(selftest::diagnostic_c_tests): Call it.
> 	* diagnostic.h (struct diagnostic_info): New field "taxonomy_id".
> 	(struct diagnostic_context): New field "show_id".
> 	(diagnostic_set_info): Add new "const char *" param.
> 	(diagnostic_set_info_translated): Likewise.
> 	* doc/invoke.texi (Diagnostic Message Formatting Options): Add
> 	-fno-diagnostics-show-id.
> 	(-fno-diagnostics-show-id): New option.
> 	* gimple-ssa-sprintf.c (get_format_string): Update fmtwarn for
> 	change of format_warning_at_substring signature.
> 	* opts.c (common_handle_option): Handle OPT_fdiagnostics_show_id.
> 	* rtl-error.c (diagnostic_for_asm): Add NULL for new "taxonomy_id" param
> 	of diagnostic_set_info.
> 	* substring-locations.c (format_warning_va): Convert param from
> 	int to const diag_id &.  Use it for taxonomy_id param in call to
> 	diagnostic_set_info.
> 	(format_warning_at_substring): Convert param from int to
> 	const diag_id &.
> 	* substring-locations.h (format_warning_va): Likewise.
> 	(format_warning_at_substring): Likewise.
> 	* toplev.c (general_init): Initialize global_dc->show_id.
> 
> gcc/fortran/ChangeLog:
> 	* cpp.c (cb_cpp_error): Add NULL for new "taxonomy_id" param of
> 	diagnostic_set_info_translated.
> 	* error.c (gfc_warning): Likewise for new param of
> 	diagnostic_set_info.
> 	(gfc_warning_now_at): Likewise.
> 	(gfc_warning_now): Likewise.
> 	(gfc_warning_internal): Likewise.
> 	(gfc_error_now): Likewise.
> 	(gfc_fatal_error): Likewise.
> 	(gfc_error_opt): Likewise.
> 	(gfc_internal_error): Likewise.
> ---
>   gcc/c-family/c-common.c   |   2 +-
>   gcc/c-family/c-warn.c     |   3 +-
>   gcc/c/c-decl.c            |  10 ++--
>   gcc/c/c-errors.c          |  27 +++++-----
>   gcc/c/c-parser.c          |   3 +-
>   gcc/c/c-tree.h            |   4 +-
>   gcc/c/c-typeck.c          |   2 +-
>   gcc/common.opt            |   4 ++
>   gcc/cp/cp-tree.h          |   2 +-
>   gcc/cp/error.c            |   7 +--
>   gcc/cp/typeck.c           |   6 ++-
>   gcc/diagnostic-core.h     |  53 +++++++++++++++-----
>   gcc/diagnostic.c          | 122 +++++++++++++++++++++++++++++++++-------------
>   gcc/diagnostic.h          |  13 ++++-
>   gcc/doc/invoke.texi       |  15 +++++-
>   gcc/fortran/cpp.c         |   2 +-
>   gcc/fortran/error.c       |  18 ++++---
>   gcc/gimple-ssa-sprintf.c  |   2 +-
>   gcc/opts.c                |   4 ++
>   gcc/rtl-error.c           |   2 +-
>   gcc/substring-locations.c |  13 ++---
>   gcc/substring-locations.h |   8 ++-
>   gcc/toplev.c              |   2 +
>   23 files changed, 229 insertions(+), 95 deletions(-)
> 
> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
> index 24077c7..bae124d 100644
> --- a/gcc/c-family/c-common.c
> +++ b/gcc/c-family/c-common.c
> @@ -6069,7 +6069,7 @@ c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
>     if (done_lexing)
>       richloc->set_range (line_table, 0, input_location, true);
>     diagnostic_set_info_translated (&diagnostic, msg, ap,
> -				  richloc, dlevel);
> +				  richloc, dlevel, NULL);
>     diagnostic_override_option_index (&diagnostic,
>                                       c_option_controlling_cpp_error (reason));
>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> index 09ef685..f28f294 100644
> --- a/gcc/c-family/c-warn.c
> +++ b/gcc/c-family/c-warn.c
> @@ -2562,7 +2562,8 @@ warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
>   	return;
>       }
>   
> -  if (warning_at (body_loc, OPT_Wmultistatement_macros,
> +  if (warning_at (body_loc,
> +		  diag_id (OPT_Wmultistatement_macros, "PRE10-C"),
>   		  "macro expands to multiple statements"))
>       inform (guard_loc, "some parts of macro expansion are not guarded by "
>   	    "this %qs clause", guard_tinfo_to_string (keyword));
> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> index d95a2b6..ea35990 100644
> --- a/gcc/c/c-decl.c
> +++ b/gcc/c/c-decl.c
> @@ -599,7 +599,7 @@ static tree grokdeclarator (const struct c_declarator *,
>   			    bool *, enum deprecated_states);
>   static tree grokparms (struct c_arg_info *, bool);
>   static void layout_array_type (tree);
> -static void warn_defaults_to (location_t, int, const char *, ...)
> +static void warn_defaults_to (location_t, const diag_id &, const char *, ...)
>       ATTRIBUTE_GCC_DIAG(3,4);
>   
>   /* T is a statement.  Add it to the statement-tree.  This is the
> @@ -5473,7 +5473,8 @@ warn_variable_length_array (tree name, tree size)
>   /* Print warning about defaulting to int if necessary.  */
>   
>   static void
> -warn_defaults_to (location_t location, int opt, const char *gmsgid, ...)
> +warn_defaults_to (location_t location, const diag_id &di, const char *gmsgid,
> +		  ...)
>   {
>     diagnostic_info diagnostic;
>     va_list ap;
> @@ -5481,8 +5482,9 @@ warn_defaults_to (location_t location, int opt, const char *gmsgid, ...)
>   
>     va_start (ap, gmsgid);
>     diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
> -                       flag_isoc99 ? DK_PEDWARN : DK_WARNING);
> -  diagnostic.option_index = opt;
> +		       flag_isoc99 ? DK_PEDWARN : DK_WARNING,
> +		       di.get_id ());
> +  diagnostic.option_index = di.get_option ();
>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (ap);
>   }
> diff --git a/gcc/c/c-errors.c b/gcc/c/c-errors.c
> index aa9ce42..6b9c425 100644
> --- a/gcc/c/c-errors.c
> +++ b/gcc/c/c-errors.c
> @@ -32,7 +32,7 @@ along with GCC; see the file COPYING3.  If not see
>      when C11 is specified.  */
>   
>   bool
> -pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
> +pedwarn_c99 (location_t location, const diag_id &di, const char *gmsgid, ...)
>   {
>     diagnostic_info diagnostic;
>     va_list ap;
> @@ -46,7 +46,7 @@ pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
>       {
>         diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>   			   (pedantic && !flag_isoc11)
> -			   ? DK_PEDWARN : DK_WARNING);
> +			   ? DK_PEDWARN : DK_WARNING, di.get_id ());
>         diagnostic.option_index = OPT_Wc99_c11_compat;
>         warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
>       }
> @@ -56,8 +56,9 @@ pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
>     /* For -pedantic outside C11, issue a pedwarn.  */
>     else if (pedantic && !flag_isoc11)
>       {
> -      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
> -      diagnostic.option_index = opt;
> +      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN,
> +			   di.get_id ());
> +      diagnostic.option_index = di.get_option ();
>         warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
>       }
>     va_end (ap);
> @@ -72,7 +73,7 @@ pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
>      when C99 is specified.  (There is no flag_c90.)  */
>   
>   bool
> -pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
> +pedwarn_c90 (location_t location, const diag_id &di, const char *gmsgid, ...)
>   {
>     diagnostic_info diagnostic;
>     va_list ap;
> @@ -81,17 +82,18 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
>   
>     va_start (ap, gmsgid);
>     /* Warnings such as -Wvla are the most specific ones.  */
> -  if (opt != OPT_Wpedantic)
> +  if (di.get_option () != OPT_Wpedantic)
>       {
> -      int opt_var = *(int *) option_flag_var (opt, &global_options);
> +      int opt_var = *(int *) option_flag_var (di.get_option (),
> +					      &global_options);
>         if (opt_var == 0)
>           goto out;
>         else if (opt_var > 0)
>   	{
>   	  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>   			       (pedantic && !flag_isoc99)
> -			       ? DK_PEDWARN : DK_WARNING);
> -	  diagnostic.option_index = opt;
> +			       ? DK_PEDWARN : DK_WARNING, di.get_id ());
> +	  diagnostic.option_index = di.get_option ();
>   	  diagnostic_report_diagnostic (global_dc, &diagnostic);
>   	  warned = true;
>   	  goto out;
> @@ -103,7 +105,7 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
>       {
>         diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>   			   (pedantic && !flag_isoc99)
> -			   ? DK_PEDWARN : DK_WARNING);
> +			   ? DK_PEDWARN : DK_WARNING, di.get_id ());
>         diagnostic.option_index = OPT_Wc90_c99_compat;
>         diagnostic_report_diagnostic (global_dc, &diagnostic);
>       }
> @@ -113,8 +115,9 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
>     /* For -pedantic outside C99, issue a pedwarn.  */
>     else if (pedantic && !flag_isoc99)
>       {
> -      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
> -      diagnostic.option_index = opt;
> +      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN,
> +			   di.get_id ());
> +      diagnostic.option_index = di.get_option ();
>         diagnostic_report_diagnostic (global_dc, &diagnostic);
>         warned = true;
>       }
> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index 7bca5f1..0405a4a 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -6989,7 +6989,8 @@ c_parser_binary_expression (c_parser *parser, struct c_expr *after,
>   		&& !(TREE_CODE (first_arg) == PARM_DECL			      \
>   		     && C_ARRAY_PARAMETER (first_arg)			      \
>   		     && warn_sizeof_array_argument))			      \
> -	      if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div,	      \
> +	      if (warning_at (stack[sp].loc,				      \
> +			      diag_id (OPT_Wsizeof_pointer_div, "ARR01-C"),   \
>   			      "division %<sizeof (%T) / sizeof (%T)%> does "  \
>   			      "not compute the number of array elements",     \
>   			      type0, type1))				      \
> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
> index 1135647..c4d7921 100644
> --- a/gcc/c/c-tree.h
> +++ b/gcc/c/c-tree.h
> @@ -756,9 +756,9 @@ extern void c_bind (location_t, tree, bool);
>   extern bool tag_exists_p (enum tree_code, tree);
>   
>   /* In c-errors.c */
> -extern bool pedwarn_c90 (location_t, int opt, const char *, ...)
> +extern bool pedwarn_c90 (location_t, const diag_id &, const char *, ...)
>       ATTRIBUTE_GCC_DIAG(3,4);
> -extern bool pedwarn_c99 (location_t, int opt, const char *, ...)
> +extern bool pedwarn_c99 (location_t, const diag_id &, const char *, ...)
>       ATTRIBUTE_GCC_DIAG(3,4);
>   
>   extern void
> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
> index 4bdc48a..394b556 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -2905,7 +2905,7 @@ c_expr_sizeof_expr (location_t loc, struct c_expr expr)
>         if (TREE_CODE (expr.value) == PARM_DECL
>   	  && C_ARRAY_PARAMETER (expr.value))
>   	{
> -	  if (warning_at (loc, OPT_Wsizeof_array_argument,
> +	  if (warning_at (loc, diag_id (OPT_Wsizeof_array_argument, "ARR01-C"),
>   			  "%<sizeof%> on array function parameter %qE will "
>   			  "return size of %qT", expr.value,
>   			  TREE_TYPE (expr.value)))
> diff --git a/gcc/common.opt b/gcc/common.opt
> index f8f2ed3..4c13205 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1268,6 +1268,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-id
> +Common Var(flag_diagnostics_show_id) Init(1)
> +Amend appropriate diagnostic messages with an identifier within a problem taxonomy.
> +
>   fdisable-
>   Common Joined RejectNegative Var(common_deferred_options) Defer
>   -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization pass.
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 257c877..3ff2703 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6222,7 +6222,7 @@ extern const char *language_to_string		(enum languages);
>   extern const char *class_key_or_enum_as_string	(tree);
>   extern void maybe_warn_variadic_templates       (void);
>   extern void maybe_warn_cpp0x			(cpp0x_warn_str str);
> -extern bool pedwarn_cxx98                       (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
> +extern bool pedwarn_cxx98                       (location_t, const diag_id &, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
>   extern location_t location_of                   (tree);
>   extern void qualified_name_lookup_error		(tree, tree, tree,
>   						 location_t);
> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> index 2537713..80e45bf 100644
> --- a/gcc/cp/error.c
> +++ b/gcc/cp/error.c
> @@ -4181,7 +4181,7 @@ maybe_warn_variadic_templates (void)
>      diagnostics for constructs that are invalid C++98, but valid
>      C++0x.  */
>   bool
> -pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
> +pedwarn_cxx98 (location_t location, const diag_id &di, const char *gmsgid, ...)
>   {
>     diagnostic_info diagnostic;
>     va_list ap;
> @@ -4190,8 +4190,9 @@ pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
>   
>     va_start (ap, gmsgid);
>     diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
> -		       (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
> -  diagnostic.option_index = opt;
> +		       (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING,
> +		       di.get_id ());
> +  diagnostic.option_index = di.get_option ();
>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (ap);
>     return ret;
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index 285d8d2..5b279df 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -1637,7 +1637,8 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain)
>         && DECL_ARRAY_PARAMETER_P (e)
>         && (complain & tf_warning))
>       {
> -      if (warning (OPT_Wsizeof_array_argument, "%<sizeof%> on array function "
> +      if (warning (diag_id (OPT_Wsizeof_array_argument, "ARR01-C"),
> +		   "%<sizeof%> on array function "
>   		   "parameter %qE will return size of %qT", e, TREE_TYPE (e)))
>   	inform (DECL_SOURCE_LOCATION (e), "declared here");
>       }
> @@ -4374,7 +4375,8 @@ cp_build_binary_op (location_t location,
>   		   && DECL_ARRAY_PARAMETER_P (first_arg)
>   		   && warn_sizeof_array_argument)
>   	      && (complain & tf_warning))
> -	    if (warning_at (location, OPT_Wsizeof_pointer_div,
> +	    if (warning_at (location,
> +			    diag_id (OPT_Wsizeof_pointer_div, "ARR01-C"),
>   			    "division %<sizeof (%T) / sizeof (%T)%> does "
>   			    "not compute the number of array elements",
>   			    type0, type1))
> diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
> index 24025f1..7b23cf6 100644
> --- a/gcc/diagnostic-core.h
> +++ b/gcc/diagnostic-core.h
> @@ -36,6 +36,36 @@ typedef enum
>     DK_POP
>   } diagnostic_t;
>   
> +/* A class for describing a diagnostic.
> +
> +   It wraps:
> +
> +   (a) one of the OPT_W* from options.h, describing the command-line
> +   option controlling it (if any), and,
> +
> +   (b) optionally, an ID from a problem taxonomy (such as "PRE10-C" from the
> +   CERT C Secure Coding Standard, or "CWE-681" from the Common Weakness
> +   Enumeration).
> +
> +   It is in this header so that users of the simple diagnostic API (e.g.
> +   warning_at) can pass in OPT_W* flags and have them be implicitly
> +   converted to diag_id.  */
> +
> +class diag_id
> +{
> + public:
> +  /* Pass one of the OPT_W* from options.h as the first parameter.  */
> +  diag_id (int opt) : m_opt (opt), m_id (NULL) {}
> +  diag_id (int opt, const char *id) : m_opt (opt), m_id (id) {}
> +
> +  int get_option () const { return m_opt; }
> +  const char *get_id () const { return m_id; }
> +
> + private:
> +  int m_opt;
> +  const char *m_id;
> +};
> +
>   extern const char *progname;
>   
>   extern const char *trim_filename (const char *);
> @@ -57,16 +87,15 @@ extern void internal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2)
>        ATTRIBUTE_NORETURN;
>   extern void internal_error_no_backtrace (const char *, ...)
>        ATTRIBUTE_GCC_DIAG(1,2) ATTRIBUTE_NORETURN;
> -/* Pass one of the OPT_W* from options.h as the first parameter.  */
> -extern bool warning (int, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
> -extern bool warning_n (location_t, int, int, const char *, const char *, ...)
> +extern bool warning (const diag_id &, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
> +extern bool warning_n (location_t, const diag_id &, int, const char *, const char *, ...)
>       ATTRIBUTE_GCC_DIAG(4,6) ATTRIBUTE_GCC_DIAG(5,6);
> -extern bool warning_n (rich_location *, int, int, const char *,
> +extern bool warning_n (rich_location *, const diag_id &, int, const char *,
>   		       const char *, ...)
>       ATTRIBUTE_GCC_DIAG(4, 6) ATTRIBUTE_GCC_DIAG(5, 6);
> -extern bool warning_at (location_t, int, const char *, ...)
> +extern bool warning_at (location_t, const diag_id &, const char *, ...)
>       ATTRIBUTE_GCC_DIAG(3,4);
> -extern bool warning_at (rich_location *, int, const char *, ...)
> +extern bool warning_at (rich_location *, const diag_id &, const char *, ...)
>       ATTRIBUTE_GCC_DIAG(3,4);
>   extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
>   extern void error_n (location_t, int, const char *, const char *, ...)
> @@ -76,10 +105,9 @@ extern void error_at (rich_location *, const char *, ...)
>     ATTRIBUTE_GCC_DIAG(2,3);
>   extern void fatal_error (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3)
>        ATTRIBUTE_NORETURN;
> -/* Pass one of the OPT_W* from options.h as the second parameter.  */
> -extern bool pedwarn (location_t, int, const char *, ...)
> +extern bool pedwarn (location_t, const diag_id &, const char *, ...)
>        ATTRIBUTE_GCC_DIAG(3,4);
> -extern bool pedwarn (rich_location *, int, const char *, ...)
> +extern bool pedwarn (rich_location *, const diag_id &, const char *, ...)
>        ATTRIBUTE_GCC_DIAG(3,4);
>   extern bool permerror (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
>   extern bool permerror (rich_location *, const char *,
> @@ -90,10 +118,11 @@ extern void inform (rich_location *, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
>   extern void inform_n (location_t, int, const char *, const char *, ...)
>       ATTRIBUTE_GCC_DIAG(3,5) ATTRIBUTE_GCC_DIAG(4,5);
>   extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
> -extern bool emit_diagnostic (diagnostic_t, location_t, int,
> +extern bool emit_diagnostic (diagnostic_t, location_t, const diag_id &,
>   			     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, location_t, const diag_id &,
> +				    const char *, va_list *)
> +  ATTRIBUTE_GCC_DIAG (4,0);
>   extern bool seen_error (void);
>   
>   #ifdef BUFSIZ
> diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
> index 813bca6..a687b5e 100644
> --- a/gcc/diagnostic.c
> +++ b/gcc/diagnostic.c
> @@ -49,10 +49,10 @@ 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 *,
> +static bool diagnostic_impl (rich_location *, const diag_id &, const char *,
>   			     va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(3,0);
> -static bool diagnostic_n_impl (rich_location *, int, int, const char *,
> -			       const char *, va_list *,
> +static bool diagnostic_n_impl (rich_location *, const diag_id &, int,
> +			       const char *, const char *, va_list *,
>   			       diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
>   
>   static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
> @@ -153,6 +153,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
>     for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
>       context->caret_chars[i] = '^';
>     context->show_option_requested = false;
> +  context->show_id = false;
>     context->abort_on_error = false;
>     context->show_column = false;
>     context->pedantic_errors = false;
> @@ -252,7 +253,7 @@ diagnostic_finish (diagnostic_context *context)
>   void
>   diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
>   				va_list *args, rich_location *richloc,
> -				diagnostic_t kind)
> +				diagnostic_t kind, const char *taxonomy_id)
>   {
>     gcc_assert (richloc);
>     diagnostic->message.err_no = errno;
> @@ -262,6 +263,7 @@ diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
>     diagnostic->richloc = richloc;
>     diagnostic->kind = kind;
>     diagnostic->option_index = 0;
> +  diagnostic->taxonomy_id = taxonomy_id;
>   }
>   
>   /* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
> @@ -269,10 +271,11 @@ diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
>   void
>   diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
>   		     va_list *args, rich_location *richloc,
> -		     diagnostic_t kind)
> +		     diagnostic_t kind, const char *taxonomy_id)
>   {
>     gcc_assert (richloc);
> -  diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind);
> +  diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind,
> +				  taxonomy_id);
>   }
>   
>   static const char *const diagnostic_kind_color[] = {
> @@ -859,6 +862,26 @@ print_option_information (diagnostic_context *context,
>       }
>   }
>   
> +/* Print any metadata identifying DIAGNOSTIC within a problem taxonomy
> +   (such as CWE) to CONTEXT's printer, e.g. " [CWE-681]".
> +   Subroutine of diagnostic_report_diagnostic.  */
> +
> +static void
> +print_taxonomy_information (diagnostic_context *context,
> +			    const diagnostic_info *diagnostic)
> +{
> +  if (diagnostic->taxonomy_id == NULL)
> +    return;
> +
> +  pretty_printer *pp = context->printer;
> +  pp_string (pp, " [");
> +  pp_string (pp, colorize_start (pp_show_color (pp),
> +				 diagnostic_kind_color[diagnostic->kind]));
> +  pp_string (pp, diagnostic->taxonomy_id);
> +  pp_string (pp, colorize_stop (pp_show_color (pp)));
> +  pp_character (pp, ']');
> +}
> +
>   /* Report a diagnostic message (an error or a warning) as specified by
>      DC.  This function is *the* subroutine in terms of which front-ends
>      should implement their specific diagnostic handling modules.  The
> @@ -974,6 +997,8 @@ diagnostic_report_diagnostic (diagnostic_context *context,
>     pp_output_formatted_text (context->printer);
>     if (context->show_option_requested)
>       print_option_information (context, diagnostic, orig_diag_kind);
> +  if (context->show_id)
> +    print_taxonomy_information (context, diagnostic);
>     (*diagnostic_finalizer (context)) (context, diagnostic);
>     if (context->parseable_fixits_p)
>       {
> @@ -1055,7 +1080,7 @@ diagnostic_append_note (diagnostic_context *context,
>     rich_location richloc (line_table, location);
>   
>     va_start (ap, gmsgid);
> -  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
> +  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE, NULL);
>     if (context->inhibit_notes_p)
>       {
>         va_end (ap);
> @@ -1076,7 +1101,7 @@ 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,
> +diagnostic_impl (rich_location *richloc, const diag_id &di,
>   		 const char *gmsgid,
>   		 va_list *ap, diagnostic_t kind)
>   {
> @@ -1084,14 +1109,16 @@ diagnostic_impl (rich_location *richloc, int opt,
>     if (kind == DK_PERMERROR)
>       {
>         diagnostic_set_info (&diagnostic, gmsgid, ap, richloc,
> -			   permissive_error_kind (global_dc));
> +			   permissive_error_kind (global_dc),
> +			   di.get_id ());
>         diagnostic.option_index = permissive_error_option (global_dc);
>       }
>     else
>       {
> -      diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind);
> +      diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind,
> +			   di.get_id ());
>         if (kind == DK_WARNING || kind == DK_PEDWARN)
> -	diagnostic.option_index = opt;
> +	diagnostic.option_index = di.get_option ();
>       }
>     return diagnostic_report_diagnostic (global_dc, &diagnostic);
>   }
> @@ -1099,7 +1126,7 @@ diagnostic_impl (rich_location *richloc, int opt,
>   /* Implement inform_n, warning_n, and error_n, as documented and
>      defined below.  */
>   static bool
> -diagnostic_n_impl (rich_location *richloc, int opt, int n,
> +diagnostic_n_impl (rich_location *richloc, const diag_id &di, int n,
>   		   const char *singular_gmsgid,
>   		   const char *plural_gmsgid,
>   		   va_list *ap, diagnostic_t kind)
> @@ -1107,22 +1134,22 @@ diagnostic_n_impl (rich_location *richloc, int opt, int n,
>     diagnostic_info diagnostic;
>     diagnostic_set_info_translated (&diagnostic,
>                                     ngettext (singular_gmsgid, plural_gmsgid, n),
> -                                  ap, richloc, kind);
> +                                  ap, richloc, kind, di.get_id ());
>     if (kind == DK_WARNING)
> -    diagnostic.option_index = opt;
> +    diagnostic.option_index = di.get_option ();
>     return diagnostic_report_diagnostic (global_dc, &diagnostic);
>   }
>   
>   /* Wrapper around diagnostic_impl taking a variable argument list.  */
>   
>   bool
> -emit_diagnostic (diagnostic_t kind, location_t location, int opt,
> +emit_diagnostic (diagnostic_t kind, location_t location, const diag_id &di,
>   		 const char *gmsgid, ...)
>   {
>     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, di, gmsgid, &ap, kind);
>     va_end (ap);
>     return ret;
>   }
> @@ -1130,11 +1157,12 @@ emit_diagnostic (diagnostic_t kind, location_t location, int opt,
>   /* Wrapper around diagnostic_impl taking a va_list parameter.  */
>   
>   bool
> -emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
> +emit_diagnostic_valist (diagnostic_t kind, location_t location,
> +			const diag_id &di,
>   			const char *gmsgid, va_list *ap)
>   {
>     rich_location richloc (line_table, location);
> -  return diagnostic_impl (&richloc, opt, gmsgid, ap, kind);
> +  return diagnostic_impl (&richloc, di, gmsgid, ap, kind);
>   }
>   
>   /* An informative note at LOCATION.  Use this for additional details on an error
> @@ -1179,12 +1207,12 @@ inform_n (location_t location, int n, const char *singular_gmsgid,
>      to the relevant language specification but is likely to be buggy anyway.
>      Returns true if the warning was printed, false if it was inhibited.  */
>   bool
> -warning (int opt, const char *gmsgid, ...)
> +warning (const diag_id &di, 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, di, gmsgid, &ap, DK_WARNING);
>     va_end (ap);
>     return ret;
>   }
> @@ -1194,12 +1222,12 @@ warning (int opt, const char *gmsgid, ...)
>      Returns true if the warning was printed, false if it was inhibited.  */
>   
>   bool
> -warning_at (location_t location, int opt, const char *gmsgid, ...)
> +warning_at (location_t location, const diag_id &di, 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, di, gmsgid, &ap, DK_WARNING);
>     va_end (ap);
>     return ret;
>   }
> @@ -1207,13 +1235,14 @@ warning_at (location_t location, int opt, const char *gmsgid, ...)
>   /* Same as "warning at" above, but using RICHLOC.  */
>   
>   bool
> -warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
> +warning_at (rich_location *richloc, const diag_id &di,
> +	    const char *gmsgid, ...)
>   {
>     gcc_assert (richloc);
>   
>     va_list ap;
>     va_start (ap, gmsgid);
> -  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_WARNING);
> +  bool ret = diagnostic_impl (richloc, di, gmsgid, &ap, DK_WARNING);
>     va_end (ap);
>     return ret;
>   }
> @@ -1221,14 +1250,14 @@ warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
>   /* Same as warning_n plural variant below, but using RICHLOC.  */
>   
>   bool
> -warning_n (rich_location *richloc, int opt, int n,
> +warning_n (rich_location *richloc, const diag_id &di, int n,
>   	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
>   {
>     gcc_assert (richloc);
>   
>     va_list ap;
>     va_start (ap, plural_gmsgid);
> -  bool ret = diagnostic_n_impl (richloc, opt, n,
> +  bool ret = diagnostic_n_impl (richloc, di, n,
>   				singular_gmsgid, plural_gmsgid,
>   				&ap, DK_WARNING);
>     va_end (ap);
> @@ -1240,13 +1269,13 @@ warning_n (rich_location *richloc, int opt, int n,
>      Returns true if the warning was printed, false if it was inhibited.  */
>   
>   bool
> -warning_n (location_t location, int opt, int n, const char *singular_gmsgid,
> -	   const char *plural_gmsgid, ...)
> +warning_n (location_t location, const diag_id &di, int n,
> +	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
>   {
>     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, di, n,
>   				singular_gmsgid, plural_gmsgid,
>   				&ap, DK_WARNING);
>     va_end (ap);
> @@ -1267,12 +1296,12 @@ warning_n (location_t location, int opt, int n, const char *singular_gmsgid,
>      Returns true if the warning was printed, false if it was inhibited.  */
>   
>   bool
> -pedwarn (location_t location, int opt, const char *gmsgid, ...)
> +pedwarn (location_t location, const diag_id &di, 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, di, gmsgid, &ap, DK_PEDWARN);
>     va_end (ap);
>     return ret;
>   }
> @@ -1280,13 +1309,13 @@ pedwarn (location_t location, int opt, const char *gmsgid, ...)
>   /* Same as pedwarn above, but using RICHLOC.  */
>   
>   bool
> -pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
> +pedwarn (rich_location *richloc, const diag_id &di, const char *gmsgid, ...)
>   {
>     gcc_assert (richloc);
>   
>     va_list ap;
>     va_start (ap, gmsgid);
> -  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
> +  bool ret = diagnostic_impl (richloc, di, gmsgid, &ap, DK_PEDWARN);
>     va_end (ap);
>     return ret;
>   }
> @@ -1667,6 +1696,32 @@ test_diagnostic_get_location_text ()
>     progname = old_progname;
>   }
>   
> +/* Verify that print_taxonomy_information prints EXPECTED, given ID.  */
> +
> +static void
> +assert_print_taxonomy_information (const char *expected, const char *id)
> +{
> +  test_diagnostic_context dc;
> +  diagnostic_info diagnostic;
> +
> +  diagnostic.kind = DK_WARNING;
> +
> +  pretty_printer *pp = dc.printer;
> +
> +  diagnostic.taxonomy_id = id;
> +  print_taxonomy_information (&dc, &diagnostic);
> +  ASSERT_STREQ (expected, pp_formatted_text (pp));
> +}
> +
> +/* Verify that print_taxonomy_information works as expected.  */
> +
> +static void
> +test_print_taxonomy_information ()
> +{
> +  assert_print_taxonomy_information ("", NULL);
> +  assert_print_taxonomy_information (" [CWE-681]", "CWE-681");
> +}
> +
>   /* Run all of the selftests within this file.  */
>   
>   void
> @@ -1678,6 +1733,7 @@ diagnostic_c_tests ()
>     test_print_parseable_fixits_remove ();
>     test_print_parseable_fixits_replace ();
>     test_diagnostic_get_location_text ();
> +  test_print_taxonomy_information ();
>   }
>   
>   } // namespace selftest
> diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
> index dbd1703..70fbc4c 100644
> --- a/gcc/diagnostic.h
> +++ b/gcc/diagnostic.h
> @@ -41,6 +41,10 @@ struct diagnostic_info
>     diagnostic_t kind;
>     /* Which OPT_* directly controls this diagnostic.  */
>     int option_index;
> +  /* An optional ID from a problem taxonomy (such as "PRE10-C" from the
> +     CERT C Secure Coding Standard, or "CWE-681" from the Common Weakness
> +     Enumeration).  */
> +  const char *taxonomy_id;
>   };
>   
>   /* Each time a diagnostic's classification is changed with a pragma,
> @@ -117,6 +121,10 @@ struct diagnostic_context
>        each diagnostic, if known.  */
>     bool show_option_requested;
>   
> +  /* True if we should print any identifier within a problem taxonomy
> +     for each diagnostic, if known.  */
> +  bool show_id;
> +
>     /* True if we should raise a SIGABRT on errors.  */
>     bool abort_on_error;
>   
> @@ -297,10 +305,11 @@ extern bool diagnostic_report_diagnostic (diagnostic_context *,
>   					  diagnostic_info *);
>   #ifdef ATTRIBUTE_GCC_DIAG
>   extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *,
> -				 rich_location *, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
> +				 rich_location *, diagnostic_t, const char *)
> +  ATTRIBUTE_GCC_DIAG(2,0);
>   extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
>   					    va_list *, rich_location *,
> -					    diagnostic_t)
> +					    diagnostic_t, const char *)
>        ATTRIBUTE_GCC_DIAG(2,0);
>   extern void diagnostic_append_note (diagnostic_context *, location_t,
>                                       const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 43acbcb..9562898 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -250,7 +250,8 @@ Objective-C and Objective-C++ Dialects}.
>   @gccoptlist{-fmessage-length=@var{n}  @gol
>   -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]}  @gol
>   -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]}  @gol
> --fno-diagnostics-show-option  -fno-diagnostics-show-caret @gol
> +-fno-diagnostics-show-option  -fno-diagnostics-show-id @gol
> +-fno-diagnostics-show-caret @gol
>   -fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch @gol
>   -fdiagnostics-show-template-tree -fno-elide-type @gol
>   -fno-show-column}
> @@ -3575,6 +3576,18 @@ command-line option that directly controls the diagnostic (if such an
>   option is known to the diagnostic machinery).  Specifying the
>   @option{-fno-diagnostics-show-option} flag suppresses that behavior.
>   
> +@item -fno-diagnostics-show-id
> +@opindex fno-diagnostics-show-id
> +@opindex fdiagnostics-show-id
> +By default, each diagnostic emitted can include text indicating an
> +ID within a problem taxonomy, such as `INT15-C` within the
> +CERT C Secure Coding Standard, or `CWE-681` within the
> +Common Weakness Enumeration (CWE).
> +Such IDs can be useful for categorizing problems, or for searching for
> +helpful recommendations for addressing the diagnostic.
> +Specifying the @option{-fno-diagnostics-show-id} flag suppresses that
> +behavior.
> +
>   @item -fno-diagnostics-show-caret
>   @opindex fno-diagnostics-show-caret
>   @opindex fdiagnostics-show-caret
> diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c
> index af8a69c..b657583 100644
> --- a/gcc/fortran/cpp.c
> +++ b/gcc/fortran/cpp.c
> @@ -1059,7 +1059,7 @@ cb_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
>         gcc_unreachable ();
>       }
>     diagnostic_set_info_translated (&diagnostic, msg, ap,
> -				  richloc, dlevel);
> +				  richloc, dlevel, NULL);
>     if (reason == CPP_W_WARNING_DIRECTIVE)
>       diagnostic_override_option_index (&diagnostic, OPT_Wcpp);
>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
> diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
> index 3ad1cf9..6bc9fef 100644
> --- a/gcc/fortran/error.c
> +++ b/gcc/fortran/error.c
> @@ -787,7 +787,7 @@ gfc_warning (int opt, const char *gmsgid, va_list ap)
>       }
>   
>     diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
> -		       DK_WARNING);
> +		       DK_WARNING, NULL);
>     diagnostic.option_index = opt;
>     bool ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>   
> @@ -1137,7 +1137,8 @@ gfc_warning_now_at (location_t loc, int opt, const char *gmsgid, ...)
>     bool ret;
>   
>     va_start (argp, gmsgid);
> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING);
> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING,
> +		       NULL);
>     diagnostic.option_index = opt;
>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (argp);
> @@ -1156,7 +1157,7 @@ gfc_warning_now (int opt, const char *gmsgid, ...)
>   
>     va_start (argp, gmsgid);
>     diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
> -		       DK_WARNING);
> +		       DK_WARNING, NULL);
>     diagnostic.option_index = opt;
>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (argp);
> @@ -1175,7 +1176,7 @@ gfc_warning_internal (int opt, const char *gmsgid, ...)
>   
>     va_start (argp, gmsgid);
>     diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
> -		       DK_WARNING);
> +		       DK_WARNING, NULL);
>     diagnostic.option_index = opt;
>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (argp);
> @@ -1194,7 +1195,8 @@ gfc_error_now (const char *gmsgid, ...)
>     error_buffer.flag = true;
>   
>     va_start (argp, gmsgid);
> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR);
> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR,
> +		       NULL);
>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (argp);
>   }
> @@ -1210,7 +1212,7 @@ gfc_fatal_error (const char *gmsgid, ...)
>     rich_location rich_loc (line_table, UNKNOWN_LOCATION);
>   
>     va_start (argp, gmsgid);
> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL);
> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL, NULL);
>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (argp);
>   
> @@ -1295,7 +1297,7 @@ gfc_error_opt (int opt, const char *gmsgid, va_list ap)
>         --errorcount;
>       }
>   
> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR);
> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR, NULL);
>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>   
>     if (buffered_p)
> @@ -1345,7 +1347,7 @@ gfc_internal_error (const char *gmsgid, ...)
>       exit(EXIT_FAILURE);
>   
>     va_start (argp, gmsgid);
> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE);
> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE, NULL);
>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>     va_end (argp);
>   
> diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
> index 7415413..1ca62c6 100644
> --- a/gcc/gimple-ssa-sprintf.c
> +++ b/gcc/gimple-ssa-sprintf.c
> @@ -594,7 +594,7 @@ get_format_string (tree format, location_t *ploc)
>   
>   static bool
>     (* const fmtwarn) (const substring_loc &, location_t,
> -		     const char *, int, const char *, ...)
> +		     const char *, const diag_id &, const char *, ...)
>     = format_warning_at_substring;
>   
>   /* Format length modifiers.  */
> diff --git a/gcc/opts.c b/gcc/opts.c
> index ac383d4..9bcfa75 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2098,6 +2098,10 @@ common_handle_option (struct gcc_options *opts,
>         dc->show_option_requested = value;
>         break;
>   
> +    case OPT_fdiagnostics_show_id:
> +      dc->show_id = value;
> +      break;
> +
>       case OPT_fdump_:
>         /* Deferred.  */
>         break;
> diff --git a/gcc/rtl-error.c b/gcc/rtl-error.c
> index e04bd7e..eab90ac 100644
> --- a/gcc/rtl-error.c
> +++ b/gcc/rtl-error.c
> @@ -70,7 +70,7 @@ diagnostic_for_asm (const rtx_insn *insn, const char *msg, va_list *args_ptr,
>     rich_location richloc (line_table, location_for_asm (insn));
>   
>     diagnostic_set_info (&diagnostic, msg, args_ptr,
> -		       &richloc, kind);
> +		       &richloc, kind, NULL);
>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>   }
>   
> diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
> index 7de435b..092d81f 100644
> --- a/gcc/substring-locations.c
> +++ b/gcc/substring-locations.c
> @@ -26,7 +26,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "langhooks.h"
>   #include "substring-locations.h"
>   
> -/* Emit a warning governed by option OPT, using GMSGID as the format
> +/* Emit a warning governed by option DI, using GMSGID as the format
>      string and AP as its arguments.
>   
>      Attempt to obtain precise location information within a string
> @@ -102,7 +102,7 @@ bool
>   format_warning_va (const substring_loc &fmt_loc,
>   		   location_t param_loc,
>   		   const char *corrected_substring,
> -		   int opt, const char *gmsgid, va_list *ap)
> +		   const diag_id &di, const char *gmsgid, va_list *ap)
>   {
>     bool substring_within_range = false;
>     location_t primary_loc;
> @@ -143,8 +143,9 @@ format_warning_va (const substring_loc &fmt_loc,
>       richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
>   
>     diagnostic_info diagnostic;
> -  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING);
> -  diagnostic.option_index = opt;
> +  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING,
> +		       di.get_id ());
> +  diagnostic.option_index = di.get_option ();
>     bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
>   
>     if (!err && fmt_substring_loc && !substring_within_range)
> @@ -168,12 +169,12 @@ bool
>   format_warning_at_substring (const substring_loc &fmt_loc,
>   			     location_t param_loc,
>   			     const char *corrected_substring,
> -			     int opt, const char *gmsgid, ...)
> +			     const diag_id &di, const char *gmsgid, ...)
>   {
>     va_list ap;
>     va_start (ap, gmsgid);
>     bool warned = format_warning_va (fmt_loc, param_loc, corrected_substring,
> -				   opt, gmsgid, &ap);
> +				   di, gmsgid, &ap);
>     va_end (ap);
>   
>     return warned;
> diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h
> index 3d7796d..13df498 100644
> --- a/gcc/substring-locations.h
> +++ b/gcc/substring-locations.h
> @@ -79,13 +79,17 @@ class substring_loc
>   extern bool format_warning_va (const substring_loc &fmt_loc,
>   			       location_t param_loc,
>   			       const char *corrected_substring,
> -			       int opt, const char *gmsgid, va_list *ap)
> +			       const diag_id &di,
> +			       const char *gmsgid,
> +			       va_list *ap)
>     ATTRIBUTE_GCC_DIAG (5,0);
>   
>   extern bool format_warning_at_substring (const substring_loc &fmt_loc,
>   					 location_t param_loc,
>   					 const char *corrected_substring,
> -					 int opt, const char *gmsgid, ...)
> +					 const diag_id &di,
> +					 const char *gmsgid,
> +					 ...)
>     ATTRIBUTE_GCC_DIAG (5,0);
>   
>   /* Implementation detail, for use when implementing
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index eff1690..590ab58 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_caret;
>     global_dc->show_option_requested
>       = global_options_init.x_flag_diagnostics_show_option;
> +  global_dc->show_id
> +    = global_options_init.x_flag_diagnostics_show_id;
>     global_dc->show_column
>       = global_options_init.x_flag_show_column;
>     global_dc->internal_error = internal_error_function;
>
Richard Biener Nov. 3, 2017, 9:53 a.m. UTC | #2
On Thu, Nov 2, 2017 at 10:28 PM, Martin Sebor <msebor@gmail.com> wrote:
> On 11/02/2017 02:51 PM, David Malcolm wrote:
>>
>> We currently identify our diagnostics via command-line options, and by
>> the text of the option itself.
>>
>> This patch adds a way to supply metadata with a diagnostic, classifying
>> the problem being reported, according to one of the software problem
>> taxonomies e.g. "INT15-C" within the CERT C Secure Coding Standard,
>> or "CWE-681" within the Common Weakness Enumeration (CWE).
>>
>> The patch tags some of our diagnostics with CERT C IDs.
>>
>> For example:
>>
>> t.c: In function 'f1':
>> t.c:9:20: warning: division 'sizeof (int *) / sizeof (int)' does not
>> compute the number of array elements [-Wsizeof-pointer-div] [ARR01-C]
>>     i = sizeof array / sizeof *array;  /* { dg-warning "does not compute
>> the number of array elements" } */
>>                      ^
>> t.c:6:10: note: first 'sizeof' operand was declared here
>>   f1 (int *array)
>>       ~~~~~^~~~~
>>
>> Note the " [ARR01-C]" appended after the "[-Wsizeof-pointer-div]"
>> above.  The "ARR01-C" is colorized (assuming colorization is enabled).
>>
>> Such metadata IDs can be useful for categorizing problems, or for
>> searching for helpful recommendations for addressing the diagnostic.
>>
>> For example, if I search for on Google for "-Wsizeof-pointer-div",
>> I get no results (owing to the leading dash having meaning for
>> Google); if I drop the leading dash, I get a number of
>> different pages describing the implementation of the warning.
>>
>> If I search instead for "ARR01-C", the first hit takes me to
>> the article about that issue within the SEI CERT C Coding Standard,
>> giving lots of useful information about the problem and how to fix it.
>>
>> The new output can be suppressed using a new -fno-diagnostics-show-id
>> flag.
>>
>> Implementation-wise, the patch replaces the "int opt" taken by our
>> internal APIs (like warning_at), in place of a "class diag_id" which
>> can be implicitly constructed from an "int opt", so no changes are
>> needed at callsites that emit diagnostics, until ID tags are added,
>> so e.g.:
>>
>>    if (warning_at (body_loc, OPT_Wmultistatement_macros,
>>                    "macro expands to multiple statements"))
>>      ...
>>
>> continues to compile, but can be converted to:
>>
>>    if (warning_at (body_loc,
>>                    diag_id (OPT_Wmultistatement_macros, "PRE10-C"),
>>                    "macro expands to multiple statements"))
>>      ...
>>
>> I didn't touch the Fortran error API.
>>
>> Some known unknowns/questions:
>> - is this useful?  (I think so)
>> - if we implement this, should we go through the existing
>>    diagnostics tagging them?  if so, what taxonomy/taxonomies should we
>> use?
>>    CERT vs CWE etc
>> - should the ID be tagged with the taxonomy it comes from? (so e.g.
>>    "ARR01-C" could be tagged as being from "CERT C", somehow).  How
>>    would this be presented to the end-user? Maybe:
>>      [-Wsizeof-pointer-div] [CERT-C: ARR01-C]
>> - could/should we support multiple taxonomies e.g. CERT vs CWE e.g.
>>      "[CERT-C: ARR01C] [CWE: CWE-467]" or somesuch
>> - if so, do we want taxonomies to be "pluggable"?  consider the
>>    use-case of a plugin that implements, say, the C++ Core Guidelines,
>>    and hence could print stuff like:
>>      "[c++-core-guidelines: C.128]" or somesuch
>> - are there license/trademark issues here?
>>
>> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
>>
>> Thoughts?
>
>
> I think it would be useful with some additional (likely substantial)
> effort.  My concern (and a pet peeve) with the CERT IDs is that they
> are not stable but tend to change from one release of the CERT coding
> standard to the next.  To avoid the problem of GCC getting out of sync
> with the current CERT standard we would need to maintain a mapping.
> Another consideration is that the CERT C and C++ coding standards
> don't always have the same ids and C++-specific aspects of certain
> problems have their own C++ ids distinct from the C ones (e.g.,
> EXP53-CPP. Do not read uninitialized memory vs EXP33-C. Do not read
> uninitialized memory).  This implies a finer-grained classification
> than a straightforward mapping from GCC OPT_Wfoo enums to CERT or
> CWE ids can support).
>
> In contrast to CERT, I have the impression that the CWE ids are more
> stable (I don't know for certain that they're guaranteed to be).  By
> their sheer number I would expect them to provide a finer-grained
> mapping that, if used to tag GCC diagnostiscs, could then be used to
> map them to other standards (and even GCC's own OPT_Wfoo ids).  This would
> suggest using CWE as the primary ID and mapping that to
> everything else.  But I'm pretty sure this would require a lot of
> effort to get right, and keep in sync as existing GCC warnings are
> tweaked and enhanced.
>
> Sorry if this sounds discouraging.  I like the idea but I worry
> about the implementation and maintenance challenges.

So you are suggesting we use our own (stable) IDs and for
diagnostic purposes allow a mapping to be applied?  Like
GCC_DIAG_MAP=lockheed-JSF.map g++ ....? (or via -fXYZ=...)

Sounds more useful and forward looking indeed.

I'd simply not report our own IDs if no mapping is specified then.

Richard.

> Martin
>
> PS A couple of other popular standards to consider are MISRA C and
> C++ and the Lockheed Martin JSF C++ coding standard.
>
>
>>
>> gcc/c-family/ChangeLog:
>>         * c-common.c (c_cpp_error): Provide NULL for new id parameter of
>>         diagnostic_set_info_translated.
>>         * c-warn.c (warn_for_multistatement_macros): Identify the
>>         diagnostic as "PRE10-C".
>>
>> gcc/c/ChangeLog:
>>         * c-decl.c (warn_defaults_to): Convert param from int to
>>         const diag_id &, and pass on taxonomy id to the diagnostic_info.
>>         * c-errors.c (pedwarn_c99): Likewise.
>>         (pedwarn_c90): Likewise.
>>         * c-parser.c (c_parser_binary_expression): Mark
>>         OPT_Wsizeof_pointer_div warning as "ARR01-C".
>>         * c-tree.h (pedwarn_c90): Convert param from int to
>>         const diag_id &.
>>         (pedwarn_c99): Likewise.
>>         * c-typeck.c (c_expr_sizeof_expr): Mark OPT_Wsizeof_array_argument
>>         warning as "ARR01-C".
>>
>> gcc/cp/ChangeLog:
>>         * cp-tree.h (pedwarn_cxx98): Convert param from int to
>>         const diag_id &.
>>         * error.c (pedwarn_cxx98): Likewise; pass on taxonomy id to the
>>         diagnostic_info.
>>         * typeck.c (cxx_sizeof_expr): Mark OPT_Wsizeof_array_argument
>>         warning as "ARR01-C".
>>         (cp_build_binary_op): Likewise for OPT_Wsizeof_pointer_div
>>         warning.
>>
>> gcc/ChangeLog:
>>         * common.opt (fdiagnostics-show-id): New option.
>>         * diagnostic-core.h (class diag_id): New class.
>>         (warning): Convert param from int to const diag_id &.
>>         (warning_n): Likewise.
>>         (warning_at): Likewise.
>>         (pedwarn): Likewise.
>>         (emit_diagnostic): Likewise.
>>         (emit_diagnostic_valist): Likewise.
>>         * diagnostic.c (diagnostic_initialize): Initialize new "show_id"
>>         field.
>>         (diagnostic_set_info_translated): Add param "taxonomy_id" and
>>         use it to initialize new field of same name.
>>         (diagnostic_set_info): Add param "taxonomy_id" and pass through to
>>         diagnostic_set_info_translated.
>>         (print_taxonomy_information): New function.
>>         (diagnostic_report_diagnostic): Call it.
>>         (diagnostic_append_note): Pass NULL for new taxonomy_id param.
>>         (diagnostic_impl): Convert param from int to const diag_id &; pass
>>         id through to diagnostic_set_info.
>>         (diagnostic_n_impl): Likewise.
>>         (emit_diagnostic): Convert param from int to const diag_id &.
>>         (emit_diagnostic_valist): Likewise.
>>         (warning): Likewise.
>>         (warning_at): Likewise.
>>         (warning_n): Likewise.
>>         (pedwarn): Likewise.
>>         (selftest::assert_print_taxonomy_information): New function.
>>         (selftest::test_print_taxonomy_information): New function.
>>         (selftest::diagnostic_c_tests): Call it.
>>         * diagnostic.h (struct diagnostic_info): New field "taxonomy_id".
>>         (struct diagnostic_context): New field "show_id".
>>         (diagnostic_set_info): Add new "const char *" param.
>>         (diagnostic_set_info_translated): Likewise.
>>         * doc/invoke.texi (Diagnostic Message Formatting Options): Add
>>         -fno-diagnostics-show-id.
>>         (-fno-diagnostics-show-id): New option.
>>         * gimple-ssa-sprintf.c (get_format_string): Update fmtwarn for
>>         change of format_warning_at_substring signature.
>>         * opts.c (common_handle_option): Handle OPT_fdiagnostics_show_id.
>>         * rtl-error.c (diagnostic_for_asm): Add NULL for new "taxonomy_id"
>> param
>>         of diagnostic_set_info.
>>         * substring-locations.c (format_warning_va): Convert param from
>>         int to const diag_id &.  Use it for taxonomy_id param in call to
>>         diagnostic_set_info.
>>         (format_warning_at_substring): Convert param from int to
>>         const diag_id &.
>>         * substring-locations.h (format_warning_va): Likewise.
>>         (format_warning_at_substring): Likewise.
>>         * toplev.c (general_init): Initialize global_dc->show_id.
>>
>> gcc/fortran/ChangeLog:
>>         * cpp.c (cb_cpp_error): Add NULL for new "taxonomy_id" param of
>>         diagnostic_set_info_translated.
>>         * error.c (gfc_warning): Likewise for new param of
>>         diagnostic_set_info.
>>         (gfc_warning_now_at): Likewise.
>>         (gfc_warning_now): Likewise.
>>         (gfc_warning_internal): Likewise.
>>         (gfc_error_now): Likewise.
>>         (gfc_fatal_error): Likewise.
>>         (gfc_error_opt): Likewise.
>>         (gfc_internal_error): Likewise.
>> ---
>>   gcc/c-family/c-common.c   |   2 +-
>>   gcc/c-family/c-warn.c     |   3 +-
>>   gcc/c/c-decl.c            |  10 ++--
>>   gcc/c/c-errors.c          |  27 +++++-----
>>   gcc/c/c-parser.c          |   3 +-
>>   gcc/c/c-tree.h            |   4 +-
>>   gcc/c/c-typeck.c          |   2 +-
>>   gcc/common.opt            |   4 ++
>>   gcc/cp/cp-tree.h          |   2 +-
>>   gcc/cp/error.c            |   7 +--
>>   gcc/cp/typeck.c           |   6 ++-
>>   gcc/diagnostic-core.h     |  53 +++++++++++++++-----
>>   gcc/diagnostic.c          | 122
>> +++++++++++++++++++++++++++++++++-------------
>>   gcc/diagnostic.h          |  13 ++++-
>>   gcc/doc/invoke.texi       |  15 +++++-
>>   gcc/fortran/cpp.c         |   2 +-
>>   gcc/fortran/error.c       |  18 ++++---
>>   gcc/gimple-ssa-sprintf.c  |   2 +-
>>   gcc/opts.c                |   4 ++
>>   gcc/rtl-error.c           |   2 +-
>>   gcc/substring-locations.c |  13 ++---
>>   gcc/substring-locations.h |   8 ++-
>>   gcc/toplev.c              |   2 +
>>   23 files changed, 229 insertions(+), 95 deletions(-)
>>
>> diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
>> index 24077c7..bae124d 100644
>> --- a/gcc/c-family/c-common.c
>> +++ b/gcc/c-family/c-common.c
>> @@ -6069,7 +6069,7 @@ c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int
>> level, int reason,
>>     if (done_lexing)
>>       richloc->set_range (line_table, 0, input_location, true);
>>     diagnostic_set_info_translated (&diagnostic, msg, ap,
>> -                                 richloc, dlevel);
>> +                                 richloc, dlevel, NULL);
>>     diagnostic_override_option_index (&diagnostic,
>>                                       c_option_controlling_cpp_error
>> (reason));
>>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
>> index 09ef685..f28f294 100644
>> --- a/gcc/c-family/c-warn.c
>> +++ b/gcc/c-family/c-warn.c
>> @@ -2562,7 +2562,8 @@ warn_for_multistatement_macros (location_t body_loc,
>> location_t next_loc,
>>         return;
>>       }
>>   -  if (warning_at (body_loc, OPT_Wmultistatement_macros,
>> +  if (warning_at (body_loc,
>> +                 diag_id (OPT_Wmultistatement_macros, "PRE10-C"),
>>                   "macro expands to multiple statements"))
>>       inform (guard_loc, "some parts of macro expansion are not guarded by
>> "
>>             "this %qs clause", guard_tinfo_to_string (keyword));
>> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
>> index d95a2b6..ea35990 100644
>> --- a/gcc/c/c-decl.c
>> +++ b/gcc/c/c-decl.c
>> @@ -599,7 +599,7 @@ static tree grokdeclarator (const struct c_declarator
>> *,
>>                             bool *, enum deprecated_states);
>>   static tree grokparms (struct c_arg_info *, bool);
>>   static void layout_array_type (tree);
>> -static void warn_defaults_to (location_t, int, const char *, ...)
>> +static void warn_defaults_to (location_t, const diag_id &, const char *,
>> ...)
>>       ATTRIBUTE_GCC_DIAG(3,4);
>>
>>   /* T is a statement.  Add it to the statement-tree.  This is the
>> @@ -5473,7 +5473,8 @@ warn_variable_length_array (tree name, tree size)
>>   /* Print warning about defaulting to int if necessary.  */
>>     static void
>> -warn_defaults_to (location_t location, int opt, const char *gmsgid, ...)
>> +warn_defaults_to (location_t location, const diag_id &di, const char
>> *gmsgid,
>> +                 ...)
>>   {
>>     diagnostic_info diagnostic;
>>     va_list ap;
>> @@ -5481,8 +5482,9 @@ warn_defaults_to (location_t location, int opt,
>> const char *gmsgid, ...)
>>       va_start (ap, gmsgid);
>>     diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>> -                       flag_isoc99 ? DK_PEDWARN : DK_WARNING);
>> -  diagnostic.option_index = opt;
>> +                      flag_isoc99 ? DK_PEDWARN : DK_WARNING,
>> +                      di.get_id ());
>> +  diagnostic.option_index = di.get_option ();
>>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (ap);
>>   }
>> diff --git a/gcc/c/c-errors.c b/gcc/c/c-errors.c
>> index aa9ce42..6b9c425 100644
>> --- a/gcc/c/c-errors.c
>> +++ b/gcc/c/c-errors.c
>> @@ -32,7 +32,7 @@ along with GCC; see the file COPYING3.  If not see
>>      when C11 is specified.  */
>>     bool
>> -pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
>> +pedwarn_c99 (location_t location, const diag_id &di, const char *gmsgid,
>> ...)
>>   {
>>     diagnostic_info diagnostic;
>>     va_list ap;
>> @@ -46,7 +46,7 @@ pedwarn_c99 (location_t location, int opt, const char
>> *gmsgid, ...)
>>       {
>>         diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>>                            (pedantic && !flag_isoc11)
>> -                          ? DK_PEDWARN : DK_WARNING);
>> +                          ? DK_PEDWARN : DK_WARNING, di.get_id ());
>>         diagnostic.option_index = OPT_Wc99_c11_compat;
>>         warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>       }
>> @@ -56,8 +56,9 @@ pedwarn_c99 (location_t location, int opt, const char
>> *gmsgid, ...)
>>     /* For -pedantic outside C11, issue a pedwarn.  */
>>     else if (pedantic && !flag_isoc11)
>>       {
>> -      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>> DK_PEDWARN);
>> -      diagnostic.option_index = opt;
>> +      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>> DK_PEDWARN,
>> +                          di.get_id ());
>> +      diagnostic.option_index = di.get_option ();
>>         warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>       }
>>     va_end (ap);
>> @@ -72,7 +73,7 @@ pedwarn_c99 (location_t location, int opt, const char
>> *gmsgid, ...)
>>      when C99 is specified.  (There is no flag_c90.)  */
>>     bool
>> -pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
>> +pedwarn_c90 (location_t location, const diag_id &di, const char *gmsgid,
>> ...)
>>   {
>>     diagnostic_info diagnostic;
>>     va_list ap;
>> @@ -81,17 +82,18 @@ pedwarn_c90 (location_t location, int opt, const char
>> *gmsgid, ...)
>>       va_start (ap, gmsgid);
>>     /* Warnings such as -Wvla are the most specific ones.  */
>> -  if (opt != OPT_Wpedantic)
>> +  if (di.get_option () != OPT_Wpedantic)
>>       {
>> -      int opt_var = *(int *) option_flag_var (opt, &global_options);
>> +      int opt_var = *(int *) option_flag_var (di.get_option (),
>> +                                             &global_options);
>>         if (opt_var == 0)
>>           goto out;
>>         else if (opt_var > 0)
>>         {
>>           diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>>                                (pedantic && !flag_isoc99)
>> -                              ? DK_PEDWARN : DK_WARNING);
>> -         diagnostic.option_index = opt;
>> +                              ? DK_PEDWARN : DK_WARNING, di.get_id ());
>> +         diagnostic.option_index = di.get_option ();
>>           diagnostic_report_diagnostic (global_dc, &diagnostic);
>>           warned = true;
>>           goto out;
>> @@ -103,7 +105,7 @@ pedwarn_c90 (location_t location, int opt, const char
>> *gmsgid, ...)
>>       {
>>         diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>>                            (pedantic && !flag_isoc99)
>> -                          ? DK_PEDWARN : DK_WARNING);
>> +                          ? DK_PEDWARN : DK_WARNING, di.get_id ());
>>         diagnostic.option_index = OPT_Wc90_c99_compat;
>>         diagnostic_report_diagnostic (global_dc, &diagnostic);
>>       }
>> @@ -113,8 +115,9 @@ pedwarn_c90 (location_t location, int opt, const char
>> *gmsgid, ...)
>>     /* For -pedantic outside C99, issue a pedwarn.  */
>>     else if (pedantic && !flag_isoc99)
>>       {
>> -      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>> DK_PEDWARN);
>> -      diagnostic.option_index = opt;
>> +      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>> DK_PEDWARN,
>> +                          di.get_id ());
>> +      diagnostic.option_index = di.get_option ();
>>         diagnostic_report_diagnostic (global_dc, &diagnostic);
>>         warned = true;
>>       }
>> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
>> index 7bca5f1..0405a4a 100644
>> --- a/gcc/c/c-parser.c
>> +++ b/gcc/c/c-parser.c
>> @@ -6989,7 +6989,8 @@ c_parser_binary_expression (c_parser *parser, struct
>> c_expr *after,
>>                 && !(TREE_CODE (first_arg) == PARM_DECL
>> \
>>                      && C_ARRAY_PARAMETER (first_arg)
>> \
>>                      && warn_sizeof_array_argument))
>> \
>> -             if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div,
>> \
>> +             if (warning_at (stack[sp].loc,
>> \
>> +                             diag_id (OPT_Wsizeof_pointer_div,
>> "ARR01-C"),   \
>>                               "division %<sizeof (%T) / sizeof (%T)%> does
>> "  \
>>                               "not compute the number of array elements",
>> \
>>                               type0, type1))
>> \
>> diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
>> index 1135647..c4d7921 100644
>> --- a/gcc/c/c-tree.h
>> +++ b/gcc/c/c-tree.h
>> @@ -756,9 +756,9 @@ extern void c_bind (location_t, tree, bool);
>>   extern bool tag_exists_p (enum tree_code, tree);
>>     /* In c-errors.c */
>> -extern bool pedwarn_c90 (location_t, int opt, const char *, ...)
>> +extern bool pedwarn_c90 (location_t, const diag_id &, const char *, ...)
>>       ATTRIBUTE_GCC_DIAG(3,4);
>> -extern bool pedwarn_c99 (location_t, int opt, const char *, ...)
>> +extern bool pedwarn_c99 (location_t, const diag_id &, const char *, ...)
>>       ATTRIBUTE_GCC_DIAG(3,4);
>>     extern void
>> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
>> index 4bdc48a..394b556 100644
>> --- a/gcc/c/c-typeck.c
>> +++ b/gcc/c/c-typeck.c
>> @@ -2905,7 +2905,7 @@ c_expr_sizeof_expr (location_t loc, struct c_expr
>> expr)
>>         if (TREE_CODE (expr.value) == PARM_DECL
>>           && C_ARRAY_PARAMETER (expr.value))
>>         {
>> -         if (warning_at (loc, OPT_Wsizeof_array_argument,
>> +         if (warning_at (loc, diag_id (OPT_Wsizeof_array_argument,
>> "ARR01-C"),
>>                           "%<sizeof%> on array function parameter %qE will
>> "
>>                           "return size of %qT", expr.value,
>>                           TREE_TYPE (expr.value)))
>> diff --git a/gcc/common.opt b/gcc/common.opt
>> index f8f2ed3..4c13205 100644
>> --- a/gcc/common.opt
>> +++ b/gcc/common.opt
>> @@ -1268,6 +1268,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-id
>> +Common Var(flag_diagnostics_show_id) Init(1)
>> +Amend appropriate diagnostic messages with an identifier within a problem
>> taxonomy.
>> +
>>   fdisable-
>>   Common Joined RejectNegative Var(common_deferred_options) Defer
>>   -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization
>> pass.
>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
>> index 257c877..3ff2703 100644
>> --- a/gcc/cp/cp-tree.h
>> +++ b/gcc/cp/cp-tree.h
>> @@ -6222,7 +6222,7 @@ extern const char *language_to_string
>> (enum languages);
>>   extern const char *class_key_or_enum_as_string        (tree);
>>   extern void maybe_warn_variadic_templates       (void);
>>   extern void maybe_warn_cpp0x                  (cpp0x_warn_str str);
>> -extern bool pedwarn_cxx98                       (location_t, int, const
>> char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
>> +extern bool pedwarn_cxx98                       (location_t, const
>> diag_id &, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
>>   extern location_t location_of                   (tree);
>>   extern void qualified_name_lookup_error               (tree, tree, tree,
>>                                                  location_t);
>> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
>> index 2537713..80e45bf 100644
>> --- a/gcc/cp/error.c
>> +++ b/gcc/cp/error.c
>> @@ -4181,7 +4181,7 @@ maybe_warn_variadic_templates (void)
>>      diagnostics for constructs that are invalid C++98, but valid
>>      C++0x.  */
>>   bool
>> -pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
>> +pedwarn_cxx98 (location_t location, const diag_id &di, const char
>> *gmsgid, ...)
>>   {
>>     diagnostic_info diagnostic;
>>     va_list ap;
>> @@ -4190,8 +4190,9 @@ pedwarn_cxx98 (location_t location, int opt, const
>> char *gmsgid, ...)
>>       va_start (ap, gmsgid);
>>     diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
>> -                      (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
>> -  diagnostic.option_index = opt;
>> +                      (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING,
>> +                      di.get_id ());
>> +  diagnostic.option_index = di.get_option ();
>>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (ap);
>>     return ret;
>> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
>> index 285d8d2..5b279df 100644
>> --- a/gcc/cp/typeck.c
>> +++ b/gcc/cp/typeck.c
>> @@ -1637,7 +1637,8 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain)
>>         && DECL_ARRAY_PARAMETER_P (e)
>>         && (complain & tf_warning))
>>       {
>> -      if (warning (OPT_Wsizeof_array_argument, "%<sizeof%> on array
>> function "
>> +      if (warning (diag_id (OPT_Wsizeof_array_argument, "ARR01-C"),
>> +                  "%<sizeof%> on array function "
>>                    "parameter %qE will return size of %qT", e, TREE_TYPE
>> (e)))
>>         inform (DECL_SOURCE_LOCATION (e), "declared here");
>>       }
>> @@ -4374,7 +4375,8 @@ cp_build_binary_op (location_t location,
>>                    && DECL_ARRAY_PARAMETER_P (first_arg)
>>                    && warn_sizeof_array_argument)
>>               && (complain & tf_warning))
>> -           if (warning_at (location, OPT_Wsizeof_pointer_div,
>> +           if (warning_at (location,
>> +                           diag_id (OPT_Wsizeof_pointer_div, "ARR01-C"),
>>                             "division %<sizeof (%T) / sizeof (%T)%> does "
>>                             "not compute the number of array elements",
>>                             type0, type1))
>> diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
>> index 24025f1..7b23cf6 100644
>> --- a/gcc/diagnostic-core.h
>> +++ b/gcc/diagnostic-core.h
>> @@ -36,6 +36,36 @@ typedef enum
>>     DK_POP
>>   } diagnostic_t;
>>   +/* A class for describing a diagnostic.
>> +
>> +   It wraps:
>> +
>> +   (a) one of the OPT_W* from options.h, describing the command-line
>> +   option controlling it (if any), and,
>> +
>> +   (b) optionally, an ID from a problem taxonomy (such as "PRE10-C" from
>> the
>> +   CERT C Secure Coding Standard, or "CWE-681" from the Common Weakness
>> +   Enumeration).
>> +
>> +   It is in this header so that users of the simple diagnostic API (e.g.
>> +   warning_at) can pass in OPT_W* flags and have them be implicitly
>> +   converted to diag_id.  */
>> +
>> +class diag_id
>> +{
>> + public:
>> +  /* Pass one of the OPT_W* from options.h as the first parameter.  */
>> +  diag_id (int opt) : m_opt (opt), m_id (NULL) {}
>> +  diag_id (int opt, const char *id) : m_opt (opt), m_id (id) {}
>> +
>> +  int get_option () const { return m_opt; }
>> +  const char *get_id () const { return m_id; }
>> +
>> + private:
>> +  int m_opt;
>> +  const char *m_id;
>> +};
>> +
>>   extern const char *progname;
>>     extern const char *trim_filename (const char *);
>> @@ -57,16 +87,15 @@ extern void internal_error (const char *, ...)
>> ATTRIBUTE_GCC_DIAG(1,2)
>>        ATTRIBUTE_NORETURN;
>>   extern void internal_error_no_backtrace (const char *, ...)
>>        ATTRIBUTE_GCC_DIAG(1,2) ATTRIBUTE_NORETURN;
>> -/* Pass one of the OPT_W* from options.h as the first parameter.  */
>> -extern bool warning (int, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
>> -extern bool warning_n (location_t, int, int, const char *, const char *,
>> ...)
>> +extern bool warning (const diag_id &, const char *, ...)
>> ATTRIBUTE_GCC_DIAG(2,3);
>> +extern bool warning_n (location_t, const diag_id &, int, const char *,
>> const char *, ...)
>>       ATTRIBUTE_GCC_DIAG(4,6) ATTRIBUTE_GCC_DIAG(5,6);
>> -extern bool warning_n (rich_location *, int, int, const char *,
>> +extern bool warning_n (rich_location *, const diag_id &, int, const char
>> *,
>>                        const char *, ...)
>>       ATTRIBUTE_GCC_DIAG(4, 6) ATTRIBUTE_GCC_DIAG(5, 6);
>> -extern bool warning_at (location_t, int, const char *, ...)
>> +extern bool warning_at (location_t, const diag_id &, const char *, ...)
>>       ATTRIBUTE_GCC_DIAG(3,4);
>> -extern bool warning_at (rich_location *, int, const char *, ...)
>> +extern bool warning_at (rich_location *, const diag_id &, const char *,
>> ...)
>>       ATTRIBUTE_GCC_DIAG(3,4);
>>   extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
>>   extern void error_n (location_t, int, const char *, const char *, ...)
>> @@ -76,10 +105,9 @@ extern void error_at (rich_location *, const char *,
>> ...)
>>     ATTRIBUTE_GCC_DIAG(2,3);
>>   extern void fatal_error (location_t, const char *, ...)
>> ATTRIBUTE_GCC_DIAG(2,3)
>>        ATTRIBUTE_NORETURN;
>> -/* Pass one of the OPT_W* from options.h as the second parameter.  */
>> -extern bool pedwarn (location_t, int, const char *, ...)
>> +extern bool pedwarn (location_t, const diag_id &, const char *, ...)
>>        ATTRIBUTE_GCC_DIAG(3,4);
>> -extern bool pedwarn (rich_location *, int, const char *, ...)
>> +extern bool pedwarn (rich_location *, const diag_id &, const char *, ...)
>>        ATTRIBUTE_GCC_DIAG(3,4);
>>   extern bool permerror (location_t, const char *, ...)
>> ATTRIBUTE_GCC_DIAG(2,3);
>>   extern bool permerror (rich_location *, const char *,
>> @@ -90,10 +118,11 @@ extern void inform (rich_location *, const char *,
>> ...) ATTRIBUTE_GCC_DIAG(2,3);
>>   extern void inform_n (location_t, int, const char *, const char *, ...)
>>       ATTRIBUTE_GCC_DIAG(3,5) ATTRIBUTE_GCC_DIAG(4,5);
>>   extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
>> -extern bool emit_diagnostic (diagnostic_t, location_t, int,
>> +extern bool emit_diagnostic (diagnostic_t, location_t, const diag_id &,
>>                              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, location_t, const
>> diag_id &,
>> +                                   const char *, va_list *)
>> +  ATTRIBUTE_GCC_DIAG (4,0);
>>   extern bool seen_error (void);
>>     #ifdef BUFSIZ
>> diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
>> index 813bca6..a687b5e 100644
>> --- a/gcc/diagnostic.c
>> +++ b/gcc/diagnostic.c
>> @@ -49,10 +49,10 @@ 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 *,
>> +static bool diagnostic_impl (rich_location *, const diag_id &, const char
>> *,
>>                              va_list *, diagnostic_t)
>> ATTRIBUTE_GCC_DIAG(3,0);
>> -static bool diagnostic_n_impl (rich_location *, int, int, const char *,
>> -                              const char *, va_list *,
>> +static bool diagnostic_n_impl (rich_location *, const diag_id &, int,
>> +                              const char *, const char *, va_list *,
>>                                diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
>>     static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
>> @@ -153,6 +153,7 @@ diagnostic_initialize (diagnostic_context *context,
>> int n_opts)
>>     for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
>>       context->caret_chars[i] = '^';
>>     context->show_option_requested = false;
>> +  context->show_id = false;
>>     context->abort_on_error = false;
>>     context->show_column = false;
>>     context->pedantic_errors = false;
>> @@ -252,7 +253,7 @@ diagnostic_finish (diagnostic_context *context)
>>   void
>>   diagnostic_set_info_translated (diagnostic_info *diagnostic, const char
>> *msg,
>>                                 va_list *args, rich_location *richloc,
>> -                               diagnostic_t kind)
>> +                               diagnostic_t kind, const char
>> *taxonomy_id)
>>   {
>>     gcc_assert (richloc);
>>     diagnostic->message.err_no = errno;
>> @@ -262,6 +263,7 @@ diagnostic_set_info_translated (diagnostic_info
>> *diagnostic, const char *msg,
>>     diagnostic->richloc = richloc;
>>     diagnostic->kind = kind;
>>     diagnostic->option_index = 0;
>> +  diagnostic->taxonomy_id = taxonomy_id;
>>   }
>>     /* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
>> @@ -269,10 +271,11 @@ diagnostic_set_info_translated (diagnostic_info
>> *diagnostic, const char *msg,
>>   void
>>   diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
>>                      va_list *args, rich_location *richloc,
>> -                    diagnostic_t kind)
>> +                    diagnostic_t kind, const char *taxonomy_id)
>>   {
>>     gcc_assert (richloc);
>> -  diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc,
>> kind);
>> +  diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc,
>> kind,
>> +                                 taxonomy_id);
>>   }
>>     static const char *const diagnostic_kind_color[] = {
>> @@ -859,6 +862,26 @@ print_option_information (diagnostic_context
>> *context,
>>       }
>>   }
>>   +/* Print any metadata identifying DIAGNOSTIC within a problem taxonomy
>> +   (such as CWE) to CONTEXT's printer, e.g. " [CWE-681]".
>> +   Subroutine of diagnostic_report_diagnostic.  */
>> +
>> +static void
>> +print_taxonomy_information (diagnostic_context *context,
>> +                           const diagnostic_info *diagnostic)
>> +{
>> +  if (diagnostic->taxonomy_id == NULL)
>> +    return;
>> +
>> +  pretty_printer *pp = context->printer;
>> +  pp_string (pp, " [");
>> +  pp_string (pp, colorize_start (pp_show_color (pp),
>> +
>> diagnostic_kind_color[diagnostic->kind]));
>> +  pp_string (pp, diagnostic->taxonomy_id);
>> +  pp_string (pp, colorize_stop (pp_show_color (pp)));
>> +  pp_character (pp, ']');
>> +}
>> +
>>   /* Report a diagnostic message (an error or a warning) as specified by
>>      DC.  This function is *the* subroutine in terms of which front-ends
>>      should implement their specific diagnostic handling modules.  The
>> @@ -974,6 +997,8 @@ diagnostic_report_diagnostic (diagnostic_context
>> *context,
>>     pp_output_formatted_text (context->printer);
>>     if (context->show_option_requested)
>>       print_option_information (context, diagnostic, orig_diag_kind);
>> +  if (context->show_id)
>> +    print_taxonomy_information (context, diagnostic);
>>     (*diagnostic_finalizer (context)) (context, diagnostic);
>>     if (context->parseable_fixits_p)
>>       {
>> @@ -1055,7 +1080,7 @@ diagnostic_append_note (diagnostic_context *context,
>>     rich_location richloc (line_table, location);
>>       va_start (ap, gmsgid);
>> -  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
>> +  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE,
>> NULL);
>>     if (context->inhibit_notes_p)
>>       {
>>         va_end (ap);
>> @@ -1076,7 +1101,7 @@ 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,
>> +diagnostic_impl (rich_location *richloc, const diag_id &di,
>>                  const char *gmsgid,
>>                  va_list *ap, diagnostic_t kind)
>>   {
>> @@ -1084,14 +1109,16 @@ diagnostic_impl (rich_location *richloc, int opt,
>>     if (kind == DK_PERMERROR)
>>       {
>>         diagnostic_set_info (&diagnostic, gmsgid, ap, richloc,
>> -                          permissive_error_kind (global_dc));
>> +                          permissive_error_kind (global_dc),
>> +                          di.get_id ());
>>         diagnostic.option_index = permissive_error_option (global_dc);
>>       }
>>     else
>>       {
>> -      diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind);
>> +      diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind,
>> +                          di.get_id ());
>>         if (kind == DK_WARNING || kind == DK_PEDWARN)
>> -       diagnostic.option_index = opt;
>> +       diagnostic.option_index = di.get_option ();
>>       }
>>     return diagnostic_report_diagnostic (global_dc, &diagnostic);
>>   }
>> @@ -1099,7 +1126,7 @@ diagnostic_impl (rich_location *richloc, int opt,
>>   /* Implement inform_n, warning_n, and error_n, as documented and
>>      defined below.  */
>>   static bool
>> -diagnostic_n_impl (rich_location *richloc, int opt, int n,
>> +diagnostic_n_impl (rich_location *richloc, const diag_id &di, int n,
>>                    const char *singular_gmsgid,
>>                    const char *plural_gmsgid,
>>                    va_list *ap, diagnostic_t kind)
>> @@ -1107,22 +1134,22 @@ diagnostic_n_impl (rich_location *richloc, int
>> opt, int n,
>>     diagnostic_info diagnostic;
>>     diagnostic_set_info_translated (&diagnostic,
>>                                     ngettext (singular_gmsgid,
>> plural_gmsgid, n),
>> -                                  ap, richloc, kind);
>> +                                  ap, richloc, kind, di.get_id ());
>>     if (kind == DK_WARNING)
>> -    diagnostic.option_index = opt;
>> +    diagnostic.option_index = di.get_option ();
>>     return diagnostic_report_diagnostic (global_dc, &diagnostic);
>>   }
>>     /* Wrapper around diagnostic_impl taking a variable argument list.  */
>>     bool
>> -emit_diagnostic (diagnostic_t kind, location_t location, int opt,
>> +emit_diagnostic (diagnostic_t kind, location_t location, const diag_id
>> &di,
>>                  const char *gmsgid, ...)
>>   {
>>     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, di, gmsgid, &ap, kind);
>>     va_end (ap);
>>     return ret;
>>   }
>> @@ -1130,11 +1157,12 @@ emit_diagnostic (diagnostic_t kind, location_t
>> location, int opt,
>>   /* Wrapper around diagnostic_impl taking a va_list parameter.  */
>>     bool
>> -emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
>> +emit_diagnostic_valist (diagnostic_t kind, location_t location,
>> +                       const diag_id &di,
>>                         const char *gmsgid, va_list *ap)
>>   {
>>     rich_location richloc (line_table, location);
>> -  return diagnostic_impl (&richloc, opt, gmsgid, ap, kind);
>> +  return diagnostic_impl (&richloc, di, gmsgid, ap, kind);
>>   }
>>     /* An informative note at LOCATION.  Use this for additional details
>> on an error
>> @@ -1179,12 +1207,12 @@ inform_n (location_t location, int n, const char
>> *singular_gmsgid,
>>      to the relevant language specification but is likely to be buggy
>> anyway.
>>      Returns true if the warning was printed, false if it was inhibited.
>> */
>>   bool
>> -warning (int opt, const char *gmsgid, ...)
>> +warning (const diag_id &di, 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, di, gmsgid, &ap, DK_WARNING);
>>     va_end (ap);
>>     return ret;
>>   }
>> @@ -1194,12 +1222,12 @@ warning (int opt, const char *gmsgid, ...)
>>      Returns true if the warning was printed, false if it was inhibited.
>> */
>>     bool
>> -warning_at (location_t location, int opt, const char *gmsgid, ...)
>> +warning_at (location_t location, const diag_id &di, 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, di, gmsgid, &ap, DK_WARNING);
>>     va_end (ap);
>>     return ret;
>>   }
>> @@ -1207,13 +1235,14 @@ warning_at (location_t location, int opt, const
>> char *gmsgid, ...)
>>   /* Same as "warning at" above, but using RICHLOC.  */
>>     bool
>> -warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
>> +warning_at (rich_location *richloc, const diag_id &di,
>> +           const char *gmsgid, ...)
>>   {
>>     gcc_assert (richloc);
>>       va_list ap;
>>     va_start (ap, gmsgid);
>> -  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_WARNING);
>> +  bool ret = diagnostic_impl (richloc, di, gmsgid, &ap, DK_WARNING);
>>     va_end (ap);
>>     return ret;
>>   }
>> @@ -1221,14 +1250,14 @@ warning_at (rich_location *richloc, int opt, const
>> char *gmsgid, ...)
>>   /* Same as warning_n plural variant below, but using RICHLOC.  */
>>     bool
>> -warning_n (rich_location *richloc, int opt, int n,
>> +warning_n (rich_location *richloc, const diag_id &di, int n,
>>            const char *singular_gmsgid, const char *plural_gmsgid, ...)
>>   {
>>     gcc_assert (richloc);
>>       va_list ap;
>>     va_start (ap, plural_gmsgid);
>> -  bool ret = diagnostic_n_impl (richloc, opt, n,
>> +  bool ret = diagnostic_n_impl (richloc, di, n,
>>                                 singular_gmsgid, plural_gmsgid,
>>                                 &ap, DK_WARNING);
>>     va_end (ap);
>> @@ -1240,13 +1269,13 @@ warning_n (rich_location *richloc, int opt, int n,
>>      Returns true if the warning was printed, false if it was inhibited.
>> */
>>     bool
>> -warning_n (location_t location, int opt, int n, const char
>> *singular_gmsgid,
>> -          const char *plural_gmsgid, ...)
>> +warning_n (location_t location, const diag_id &di, int n,
>> +          const char *singular_gmsgid, const char *plural_gmsgid, ...)
>>   {
>>     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, di, n,
>>                                 singular_gmsgid, plural_gmsgid,
>>                                 &ap, DK_WARNING);
>>     va_end (ap);
>> @@ -1267,12 +1296,12 @@ warning_n (location_t location, int opt, int n,
>> const char *singular_gmsgid,
>>      Returns true if the warning was printed, false if it was inhibited.
>> */
>>     bool
>> -pedwarn (location_t location, int opt, const char *gmsgid, ...)
>> +pedwarn (location_t location, const diag_id &di, 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, di, gmsgid, &ap, DK_PEDWARN);
>>     va_end (ap);
>>     return ret;
>>   }
>> @@ -1280,13 +1309,13 @@ pedwarn (location_t location, int opt, const char
>> *gmsgid, ...)
>>   /* Same as pedwarn above, but using RICHLOC.  */
>>     bool
>> -pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
>> +pedwarn (rich_location *richloc, const diag_id &di, const char *gmsgid,
>> ...)
>>   {
>>     gcc_assert (richloc);
>>       va_list ap;
>>     va_start (ap, gmsgid);
>> -  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
>> +  bool ret = diagnostic_impl (richloc, di, gmsgid, &ap, DK_PEDWARN);
>>     va_end (ap);
>>     return ret;
>>   }
>> @@ -1667,6 +1696,32 @@ test_diagnostic_get_location_text ()
>>     progname = old_progname;
>>   }
>>   +/* Verify that print_taxonomy_information prints EXPECTED, given ID.
>> */
>> +
>> +static void
>> +assert_print_taxonomy_information (const char *expected, const char *id)
>> +{
>> +  test_diagnostic_context dc;
>> +  diagnostic_info diagnostic;
>> +
>> +  diagnostic.kind = DK_WARNING;
>> +
>> +  pretty_printer *pp = dc.printer;
>> +
>> +  diagnostic.taxonomy_id = id;
>> +  print_taxonomy_information (&dc, &diagnostic);
>> +  ASSERT_STREQ (expected, pp_formatted_text (pp));
>> +}
>> +
>> +/* Verify that print_taxonomy_information works as expected.  */
>> +
>> +static void
>> +test_print_taxonomy_information ()
>> +{
>> +  assert_print_taxonomy_information ("", NULL);
>> +  assert_print_taxonomy_information (" [CWE-681]", "CWE-681");
>> +}
>> +
>>   /* Run all of the selftests within this file.  */
>>     void
>> @@ -1678,6 +1733,7 @@ diagnostic_c_tests ()
>>     test_print_parseable_fixits_remove ();
>>     test_print_parseable_fixits_replace ();
>>     test_diagnostic_get_location_text ();
>> +  test_print_taxonomy_information ();
>>   }
>>     } // namespace selftest
>> diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
>> index dbd1703..70fbc4c 100644
>> --- a/gcc/diagnostic.h
>> +++ b/gcc/diagnostic.h
>> @@ -41,6 +41,10 @@ struct diagnostic_info
>>     diagnostic_t kind;
>>     /* Which OPT_* directly controls this diagnostic.  */
>>     int option_index;
>> +  /* An optional ID from a problem taxonomy (such as "PRE10-C" from the
>> +     CERT C Secure Coding Standard, or "CWE-681" from the Common Weakness
>> +     Enumeration).  */
>> +  const char *taxonomy_id;
>>   };
>>     /* Each time a diagnostic's classification is changed with a pragma,
>> @@ -117,6 +121,10 @@ struct diagnostic_context
>>        each diagnostic, if known.  */
>>     bool show_option_requested;
>>   +  /* True if we should print any identifier within a problem taxonomy
>> +     for each diagnostic, if known.  */
>> +  bool show_id;
>> +
>>     /* True if we should raise a SIGABRT on errors.  */
>>     bool abort_on_error;
>>   @@ -297,10 +305,11 @@ extern bool diagnostic_report_diagnostic
>> (diagnostic_context *,
>>                                           diagnostic_info *);
>>   #ifdef ATTRIBUTE_GCC_DIAG
>>   extern void diagnostic_set_info (diagnostic_info *, const char *,
>> va_list *,
>> -                                rich_location *, diagnostic_t)
>> ATTRIBUTE_GCC_DIAG(2,0);
>> +                                rich_location *, diagnostic_t, const char
>> *)
>> +  ATTRIBUTE_GCC_DIAG(2,0);
>>   extern void diagnostic_set_info_translated (diagnostic_info *, const
>> char *,
>>                                             va_list *, rich_location *,
>> -                                           diagnostic_t)
>> +                                           diagnostic_t, const char *)
>>        ATTRIBUTE_GCC_DIAG(2,0);
>>   extern void diagnostic_append_note (diagnostic_context *, location_t,
>>                                       const char *, ...)
>> ATTRIBUTE_GCC_DIAG(3,4);
>> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
>> index 43acbcb..9562898 100644
>> --- a/gcc/doc/invoke.texi
>> +++ b/gcc/doc/invoke.texi
>> @@ -250,7 +250,8 @@ Objective-C and Objective-C++ Dialects}.
>>   @gccoptlist{-fmessage-length=@var{n}  @gol
>>   -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]}  @gol
>>   -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]}  @gol
>> --fno-diagnostics-show-option  -fno-diagnostics-show-caret @gol
>> +-fno-diagnostics-show-option  -fno-diagnostics-show-id @gol
>> +-fno-diagnostics-show-caret @gol
>>   -fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch @gol
>>   -fdiagnostics-show-template-tree -fno-elide-type @gol
>>   -fno-show-column}
>> @@ -3575,6 +3576,18 @@ command-line option that directly controls the
>> diagnostic (if such an
>>   option is known to the diagnostic machinery).  Specifying the
>>   @option{-fno-diagnostics-show-option} flag suppresses that behavior.
>>   +@item -fno-diagnostics-show-id
>> +@opindex fno-diagnostics-show-id
>> +@opindex fdiagnostics-show-id
>> +By default, each diagnostic emitted can include text indicating an
>> +ID within a problem taxonomy, such as `INT15-C` within the
>> +CERT C Secure Coding Standard, or `CWE-681` within the
>> +Common Weakness Enumeration (CWE).
>> +Such IDs can be useful for categorizing problems, or for searching for
>> +helpful recommendations for addressing the diagnostic.
>> +Specifying the @option{-fno-diagnostics-show-id} flag suppresses that
>> +behavior.
>> +
>>   @item -fno-diagnostics-show-caret
>>   @opindex fno-diagnostics-show-caret
>>   @opindex fdiagnostics-show-caret
>> diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c
>> index af8a69c..b657583 100644
>> --- a/gcc/fortran/cpp.c
>> +++ b/gcc/fortran/cpp.c
>> @@ -1059,7 +1059,7 @@ cb_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED,
>> int level, int reason,
>>         gcc_unreachable ();
>>       }
>>     diagnostic_set_info_translated (&diagnostic, msg, ap,
>> -                                 richloc, dlevel);
>> +                                 richloc, dlevel, NULL);
>>     if (reason == CPP_W_WARNING_DIRECTIVE)
>>       diagnostic_override_option_index (&diagnostic, OPT_Wcpp);
>>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>> diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
>> index 3ad1cf9..6bc9fef 100644
>> --- a/gcc/fortran/error.c
>> +++ b/gcc/fortran/error.c
>> @@ -787,7 +787,7 @@ gfc_warning (int opt, const char *gmsgid, va_list ap)
>>       }
>>       diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
>> -                      DK_WARNING);
>> +                      DK_WARNING, NULL);
>>     diagnostic.option_index = opt;
>>     bool ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>   @@ -1137,7 +1137,8 @@ gfc_warning_now_at (location_t loc, int opt, const
>> char *gmsgid, ...)
>>     bool ret;
>>       va_start (argp, gmsgid);
>> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
>> DK_WARNING);
>> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING,
>> +                      NULL);
>>     diagnostic.option_index = opt;
>>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (argp);
>> @@ -1156,7 +1157,7 @@ gfc_warning_now (int opt, const char *gmsgid, ...)
>>       va_start (argp, gmsgid);
>>     diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
>> -                      DK_WARNING);
>> +                      DK_WARNING, NULL);
>>     diagnostic.option_index = opt;
>>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (argp);
>> @@ -1175,7 +1176,7 @@ gfc_warning_internal (int opt, const char *gmsgid,
>> ...)
>>       va_start (argp, gmsgid);
>>     diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
>> -                      DK_WARNING);
>> +                      DK_WARNING, NULL);
>>     diagnostic.option_index = opt;
>>     ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (argp);
>> @@ -1194,7 +1195,8 @@ gfc_error_now (const char *gmsgid, ...)
>>     error_buffer.flag = true;
>>       va_start (argp, gmsgid);
>> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR);
>> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR,
>> +                      NULL);
>>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (argp);
>>   }
>> @@ -1210,7 +1212,7 @@ gfc_fatal_error (const char *gmsgid, ...)
>>     rich_location rich_loc (line_table, UNKNOWN_LOCATION);
>>       va_start (argp, gmsgid);
>> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL);
>> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL,
>> NULL);
>>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (argp);
>>   @@ -1295,7 +1297,7 @@ gfc_error_opt (int opt, const char *gmsgid,
>> va_list ap)
>>         --errorcount;
>>       }
>>   -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR);
>> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR,
>> NULL);
>>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>>       if (buffered_p)
>> @@ -1345,7 +1347,7 @@ gfc_internal_error (const char *gmsgid, ...)
>>       exit(EXIT_FAILURE);
>>       va_start (argp, gmsgid);
>> -  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE);
>> +  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE,
>> NULL);
>>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>>     va_end (argp);
>>   diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
>> index 7415413..1ca62c6 100644
>> --- a/gcc/gimple-ssa-sprintf.c
>> +++ b/gcc/gimple-ssa-sprintf.c
>> @@ -594,7 +594,7 @@ get_format_string (tree format, location_t *ploc)
>>     static bool
>>     (* const fmtwarn) (const substring_loc &, location_t,
>> -                    const char *, int, const char *, ...)
>> +                    const char *, const diag_id &, const char *, ...)
>>     = format_warning_at_substring;
>>     /* Format length modifiers.  */
>> diff --git a/gcc/opts.c b/gcc/opts.c
>> index ac383d4..9bcfa75 100644
>> --- a/gcc/opts.c
>> +++ b/gcc/opts.c
>> @@ -2098,6 +2098,10 @@ common_handle_option (struct gcc_options *opts,
>>         dc->show_option_requested = value;
>>         break;
>>   +    case OPT_fdiagnostics_show_id:
>> +      dc->show_id = value;
>> +      break;
>> +
>>       case OPT_fdump_:
>>         /* Deferred.  */
>>         break;
>> diff --git a/gcc/rtl-error.c b/gcc/rtl-error.c
>> index e04bd7e..eab90ac 100644
>> --- a/gcc/rtl-error.c
>> +++ b/gcc/rtl-error.c
>> @@ -70,7 +70,7 @@ diagnostic_for_asm (const rtx_insn *insn, const char
>> *msg, va_list *args_ptr,
>>     rich_location richloc (line_table, location_for_asm (insn));
>>       diagnostic_set_info (&diagnostic, msg, args_ptr,
>> -                      &richloc, kind);
>> +                      &richloc, kind, NULL);
>>     diagnostic_report_diagnostic (global_dc, &diagnostic);
>>   }
>>   diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
>> index 7de435b..092d81f 100644
>> --- a/gcc/substring-locations.c
>> +++ b/gcc/substring-locations.c
>> @@ -26,7 +26,7 @@ along with GCC; see the file COPYING3.  If not see
>>   #include "langhooks.h"
>>   #include "substring-locations.h"
>>   -/* Emit a warning governed by option OPT, using GMSGID as the format
>> +/* Emit a warning governed by option DI, using GMSGID as the format
>>      string and AP as its arguments.
>>        Attempt to obtain precise location information within a string
>> @@ -102,7 +102,7 @@ bool
>>   format_warning_va (const substring_loc &fmt_loc,
>>                    location_t param_loc,
>>                    const char *corrected_substring,
>> -                  int opt, const char *gmsgid, va_list *ap)
>> +                  const diag_id &di, const char *gmsgid, va_list *ap)
>>   {
>>     bool substring_within_range = false;
>>     location_t primary_loc;
>> @@ -143,8 +143,9 @@ format_warning_va (const substring_loc &fmt_loc,
>>       richloc.add_fixit_replace (fmt_substring_range,
>> corrected_substring);
>>       diagnostic_info diagnostic;
>> -  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING);
>> -  diagnostic.option_index = opt;
>> +  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING,
>> +                      di.get_id ());
>> +  diagnostic.option_index = di.get_option ();
>>     bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
>>       if (!err && fmt_substring_loc && !substring_within_range)
>> @@ -168,12 +169,12 @@ bool
>>   format_warning_at_substring (const substring_loc &fmt_loc,
>>                              location_t param_loc,
>>                              const char *corrected_substring,
>> -                            int opt, const char *gmsgid, ...)
>> +                            const diag_id &di, const char *gmsgid, ...)
>>   {
>>     va_list ap;
>>     va_start (ap, gmsgid);
>>     bool warned = format_warning_va (fmt_loc, param_loc,
>> corrected_substring,
>> -                                  opt, gmsgid, &ap);
>> +                                  di, gmsgid, &ap);
>>     va_end (ap);
>>       return warned;
>> diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h
>> index 3d7796d..13df498 100644
>> --- a/gcc/substring-locations.h
>> +++ b/gcc/substring-locations.h
>> @@ -79,13 +79,17 @@ class substring_loc
>>   extern bool format_warning_va (const substring_loc &fmt_loc,
>>                                location_t param_loc,
>>                                const char *corrected_substring,
>> -                              int opt, const char *gmsgid, va_list *ap)
>> +                              const diag_id &di,
>> +                              const char *gmsgid,
>> +                              va_list *ap)
>>     ATTRIBUTE_GCC_DIAG (5,0);
>>     extern bool format_warning_at_substring (const substring_loc &fmt_loc,
>>                                          location_t param_loc,
>>                                          const char *corrected_substring,
>> -                                        int opt, const char *gmsgid, ...)
>> +                                        const diag_id &di,
>> +                                        const char *gmsgid,
>> +                                        ...)
>>     ATTRIBUTE_GCC_DIAG (5,0);
>>     /* Implementation detail, for use when implementing
>> diff --git a/gcc/toplev.c b/gcc/toplev.c
>> index eff1690..590ab58 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_caret;
>>     global_dc->show_option_requested
>>       = global_options_init.x_flag_diagnostics_show_option;
>> +  global_dc->show_id
>> +    = global_options_init.x_flag_diagnostics_show_id;
>>     global_dc->show_column
>>       = global_options_init.x_flag_show_column;
>>     global_dc->internal_error = internal_error_function;
>>
>
diff mbox series

Patch

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 24077c7..bae124d 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -6069,7 +6069,7 @@  c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
   if (done_lexing)
     richloc->set_range (line_table, 0, input_location, true);
   diagnostic_set_info_translated (&diagnostic, msg, ap,
-				  richloc, dlevel);
+				  richloc, dlevel, NULL);
   diagnostic_override_option_index (&diagnostic,
                                     c_option_controlling_cpp_error (reason));
   ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 09ef685..f28f294 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -2562,7 +2562,8 @@  warn_for_multistatement_macros (location_t body_loc, location_t next_loc,
 	return;
     }
 
-  if (warning_at (body_loc, OPT_Wmultistatement_macros,
+  if (warning_at (body_loc,
+		  diag_id (OPT_Wmultistatement_macros, "PRE10-C"),
 		  "macro expands to multiple statements"))
     inform (guard_loc, "some parts of macro expansion are not guarded by "
 	    "this %qs clause", guard_tinfo_to_string (keyword));
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index d95a2b6..ea35990 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -599,7 +599,7 @@  static tree grokdeclarator (const struct c_declarator *,
 			    bool *, enum deprecated_states);
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
-static void warn_defaults_to (location_t, int, const char *, ...)
+static void warn_defaults_to (location_t, const diag_id &, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
 
 /* T is a statement.  Add it to the statement-tree.  This is the
@@ -5473,7 +5473,8 @@  warn_variable_length_array (tree name, tree size)
 /* Print warning about defaulting to int if necessary.  */
 
 static void
-warn_defaults_to (location_t location, int opt, const char *gmsgid, ...)
+warn_defaults_to (location_t location, const diag_id &di, const char *gmsgid,
+		  ...)
 {
   diagnostic_info diagnostic;
   va_list ap;
@@ -5481,8 +5482,9 @@  warn_defaults_to (location_t location, int opt, const char *gmsgid, ...)
 
   va_start (ap, gmsgid);
   diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
-                       flag_isoc99 ? DK_PEDWARN : DK_WARNING);
-  diagnostic.option_index = opt;
+		       flag_isoc99 ? DK_PEDWARN : DK_WARNING,
+		       di.get_id ());
+  diagnostic.option_index = di.get_option ();
   diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (ap);
 }
diff --git a/gcc/c/c-errors.c b/gcc/c/c-errors.c
index aa9ce42..6b9c425 100644
--- a/gcc/c/c-errors.c
+++ b/gcc/c/c-errors.c
@@ -32,7 +32,7 @@  along with GCC; see the file COPYING3.  If not see
    when C11 is specified.  */
 
 bool
-pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
+pedwarn_c99 (location_t location, const diag_id &di, const char *gmsgid, ...)
 {
   diagnostic_info diagnostic;
   va_list ap;
@@ -46,7 +46,7 @@  pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
     {
       diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
 			   (pedantic && !flag_isoc11)
-			   ? DK_PEDWARN : DK_WARNING);
+			   ? DK_PEDWARN : DK_WARNING, di.get_id ());
       diagnostic.option_index = OPT_Wc99_c11_compat;
       warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
     }
@@ -56,8 +56,9 @@  pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
   /* For -pedantic outside C11, issue a pedwarn.  */
   else if (pedantic && !flag_isoc11)
     {
-      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
-      diagnostic.option_index = opt;
+      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN,
+			   di.get_id ());
+      diagnostic.option_index = di.get_option ();
       warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
     }
   va_end (ap);
@@ -72,7 +73,7 @@  pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
    when C99 is specified.  (There is no flag_c90.)  */
 
 bool
-pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
+pedwarn_c90 (location_t location, const diag_id &di, const char *gmsgid, ...)
 {
   diagnostic_info diagnostic;
   va_list ap;
@@ -81,17 +82,18 @@  pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
 
   va_start (ap, gmsgid);
   /* Warnings such as -Wvla are the most specific ones.  */
-  if (opt != OPT_Wpedantic)
+  if (di.get_option () != OPT_Wpedantic)
     {
-      int opt_var = *(int *) option_flag_var (opt, &global_options);
+      int opt_var = *(int *) option_flag_var (di.get_option (),
+					      &global_options);
       if (opt_var == 0)
         goto out;
       else if (opt_var > 0)
 	{
 	  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
 			       (pedantic && !flag_isoc99)
-			       ? DK_PEDWARN : DK_WARNING);
-	  diagnostic.option_index = opt;
+			       ? DK_PEDWARN : DK_WARNING, di.get_id ());
+	  diagnostic.option_index = di.get_option ();
 	  diagnostic_report_diagnostic (global_dc, &diagnostic);
 	  warned = true;
 	  goto out;
@@ -103,7 +105,7 @@  pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
     {
       diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
 			   (pedantic && !flag_isoc99)
-			   ? DK_PEDWARN : DK_WARNING);
+			   ? DK_PEDWARN : DK_WARNING, di.get_id ());
       diagnostic.option_index = OPT_Wc90_c99_compat;
       diagnostic_report_diagnostic (global_dc, &diagnostic);
     }
@@ -113,8 +115,9 @@  pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
   /* For -pedantic outside C99, issue a pedwarn.  */
   else if (pedantic && !flag_isoc99)
     {
-      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
-      diagnostic.option_index = opt;
+      diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN,
+			   di.get_id ());
+      diagnostic.option_index = di.get_option ();
       diagnostic_report_diagnostic (global_dc, &diagnostic);
       warned = true;
     }
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 7bca5f1..0405a4a 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -6989,7 +6989,8 @@  c_parser_binary_expression (c_parser *parser, struct c_expr *after,
 		&& !(TREE_CODE (first_arg) == PARM_DECL			      \
 		     && C_ARRAY_PARAMETER (first_arg)			      \
 		     && warn_sizeof_array_argument))			      \
-	      if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div,	      \
+	      if (warning_at (stack[sp].loc,				      \
+			      diag_id (OPT_Wsizeof_pointer_div, "ARR01-C"),   \
 			      "division %<sizeof (%T) / sizeof (%T)%> does "  \
 			      "not compute the number of array elements",     \
 			      type0, type1))				      \
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 1135647..c4d7921 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -756,9 +756,9 @@  extern void c_bind (location_t, tree, bool);
 extern bool tag_exists_p (enum tree_code, tree);
 
 /* In c-errors.c */
-extern bool pedwarn_c90 (location_t, int opt, const char *, ...)
+extern bool pedwarn_c90 (location_t, const diag_id &, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
-extern bool pedwarn_c99 (location_t, int opt, const char *, ...)
+extern bool pedwarn_c99 (location_t, const diag_id &, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
 
 extern void
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 4bdc48a..394b556 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2905,7 +2905,7 @@  c_expr_sizeof_expr (location_t loc, struct c_expr expr)
       if (TREE_CODE (expr.value) == PARM_DECL
 	  && C_ARRAY_PARAMETER (expr.value))
 	{
-	  if (warning_at (loc, OPT_Wsizeof_array_argument,
+	  if (warning_at (loc, diag_id (OPT_Wsizeof_array_argument, "ARR01-C"),
 			  "%<sizeof%> on array function parameter %qE will "
 			  "return size of %qT", expr.value,
 			  TREE_TYPE (expr.value)))
diff --git a/gcc/common.opt b/gcc/common.opt
index f8f2ed3..4c13205 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1268,6 +1268,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-id
+Common Var(flag_diagnostics_show_id) Init(1)
+Amend appropriate diagnostic messages with an identifier within a problem taxonomy.
+
 fdisable-
 Common Joined RejectNegative Var(common_deferred_options) Defer
 -fdisable-[tree|rtl|ipa]-<pass>=range1+range2 disables an optimization pass.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 257c877..3ff2703 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6222,7 +6222,7 @@  extern const char *language_to_string		(enum languages);
 extern const char *class_key_or_enum_as_string	(tree);
 extern void maybe_warn_variadic_templates       (void);
 extern void maybe_warn_cpp0x			(cpp0x_warn_str str);
-extern bool pedwarn_cxx98                       (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
+extern bool pedwarn_cxx98                       (location_t, const diag_id &, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
 extern location_t location_of                   (tree);
 extern void qualified_name_lookup_error		(tree, tree, tree,
 						 location_t);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 2537713..80e45bf 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -4181,7 +4181,7 @@  maybe_warn_variadic_templates (void)
    diagnostics for constructs that are invalid C++98, but valid
    C++0x.  */
 bool
-pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
+pedwarn_cxx98 (location_t location, const diag_id &di, const char *gmsgid, ...)
 {
   diagnostic_info diagnostic;
   va_list ap;
@@ -4190,8 +4190,9 @@  pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
 
   va_start (ap, gmsgid);
   diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
-		       (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
-  diagnostic.option_index = opt;
+		       (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING,
+		       di.get_id ());
+  diagnostic.option_index = di.get_option ();
   ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (ap);
   return ret;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 285d8d2..5b279df 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1637,7 +1637,8 @@  cxx_sizeof_expr (tree e, tsubst_flags_t complain)
       && DECL_ARRAY_PARAMETER_P (e)
       && (complain & tf_warning))
     {
-      if (warning (OPT_Wsizeof_array_argument, "%<sizeof%> on array function "
+      if (warning (diag_id (OPT_Wsizeof_array_argument, "ARR01-C"),
+		   "%<sizeof%> on array function "
 		   "parameter %qE will return size of %qT", e, TREE_TYPE (e)))
 	inform (DECL_SOURCE_LOCATION (e), "declared here");
     }
@@ -4374,7 +4375,8 @@  cp_build_binary_op (location_t location,
 		   && DECL_ARRAY_PARAMETER_P (first_arg)
 		   && warn_sizeof_array_argument)
 	      && (complain & tf_warning))
-	    if (warning_at (location, OPT_Wsizeof_pointer_div,
+	    if (warning_at (location,
+			    diag_id (OPT_Wsizeof_pointer_div, "ARR01-C"),
 			    "division %<sizeof (%T) / sizeof (%T)%> does "
 			    "not compute the number of array elements",
 			    type0, type1))
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index 24025f1..7b23cf6 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -36,6 +36,36 @@  typedef enum
   DK_POP
 } diagnostic_t;
 
+/* A class for describing a diagnostic.
+
+   It wraps:
+
+   (a) one of the OPT_W* from options.h, describing the command-line
+   option controlling it (if any), and,
+
+   (b) optionally, an ID from a problem taxonomy (such as "PRE10-C" from the
+   CERT C Secure Coding Standard, or "CWE-681" from the Common Weakness
+   Enumeration).
+
+   It is in this header so that users of the simple diagnostic API (e.g.
+   warning_at) can pass in OPT_W* flags and have them be implicitly
+   converted to diag_id.  */
+
+class diag_id
+{
+ public:
+  /* Pass one of the OPT_W* from options.h as the first parameter.  */
+  diag_id (int opt) : m_opt (opt), m_id (NULL) {}
+  diag_id (int opt, const char *id) : m_opt (opt), m_id (id) {}
+
+  int get_option () const { return m_opt; }
+  const char *get_id () const { return m_id; }
+
+ private:
+  int m_opt;
+  const char *m_id;
+};
+
 extern const char *progname;
 
 extern const char *trim_filename (const char *);
@@ -57,16 +87,15 @@  extern void internal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2)
      ATTRIBUTE_NORETURN;
 extern void internal_error_no_backtrace (const char *, ...)
      ATTRIBUTE_GCC_DIAG(1,2) ATTRIBUTE_NORETURN;
-/* Pass one of the OPT_W* from options.h as the first parameter.  */
-extern bool warning (int, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
-extern bool warning_n (location_t, int, int, const char *, const char *, ...)
+extern bool warning (const diag_id &, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
+extern bool warning_n (location_t, const diag_id &, int, const char *, const char *, ...)
     ATTRIBUTE_GCC_DIAG(4,6) ATTRIBUTE_GCC_DIAG(5,6);
-extern bool warning_n (rich_location *, int, int, const char *,
+extern bool warning_n (rich_location *, const diag_id &, int, const char *,
 		       const char *, ...)
     ATTRIBUTE_GCC_DIAG(4, 6) ATTRIBUTE_GCC_DIAG(5, 6);
-extern bool warning_at (location_t, int, const char *, ...)
+extern bool warning_at (location_t, const diag_id &, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
-extern bool warning_at (rich_location *, int, const char *, ...)
+extern bool warning_at (rich_location *, const diag_id &, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,4);
 extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
 extern void error_n (location_t, int, const char *, const char *, ...)
@@ -76,10 +105,9 @@  extern void error_at (rich_location *, const char *, ...)
   ATTRIBUTE_GCC_DIAG(2,3);
 extern void fatal_error (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3)
      ATTRIBUTE_NORETURN;
-/* Pass one of the OPT_W* from options.h as the second parameter.  */
-extern bool pedwarn (location_t, int, const char *, ...)
+extern bool pedwarn (location_t, const diag_id &, const char *, ...)
      ATTRIBUTE_GCC_DIAG(3,4);
-extern bool pedwarn (rich_location *, int, const char *, ...)
+extern bool pedwarn (rich_location *, const diag_id &, const char *, ...)
      ATTRIBUTE_GCC_DIAG(3,4);
 extern bool permerror (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
 extern bool permerror (rich_location *, const char *,
@@ -90,10 +118,11 @@  extern void inform (rich_location *, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
 extern void inform_n (location_t, int, const char *, const char *, ...)
     ATTRIBUTE_GCC_DIAG(3,5) ATTRIBUTE_GCC_DIAG(4,5);
 extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
-extern bool emit_diagnostic (diagnostic_t, location_t, int,
+extern bool emit_diagnostic (diagnostic_t, location_t, const diag_id &,
 			     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, location_t, const diag_id &,
+				    const char *, va_list *)
+  ATTRIBUTE_GCC_DIAG (4,0);
 extern bool seen_error (void);
 
 #ifdef BUFSIZ
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 813bca6..a687b5e 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -49,10 +49,10 @@  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 *,
+static bool diagnostic_impl (rich_location *, const diag_id &, const char *,
 			     va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(3,0);
-static bool diagnostic_n_impl (rich_location *, int, int, const char *,
-			       const char *, va_list *,
+static bool diagnostic_n_impl (rich_location *, const diag_id &, int,
+			       const char *, const char *, va_list *,
 			       diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
 
 static void error_recursion (diagnostic_context *) ATTRIBUTE_NORETURN;
@@ -153,6 +153,7 @@  diagnostic_initialize (diagnostic_context *context, int n_opts)
   for (i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
     context->caret_chars[i] = '^';
   context->show_option_requested = false;
+  context->show_id = false;
   context->abort_on_error = false;
   context->show_column = false;
   context->pedantic_errors = false;
@@ -252,7 +253,7 @@  diagnostic_finish (diagnostic_context *context)
 void
 diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
 				va_list *args, rich_location *richloc,
-				diagnostic_t kind)
+				diagnostic_t kind, const char *taxonomy_id)
 {
   gcc_assert (richloc);
   diagnostic->message.err_no = errno;
@@ -262,6 +263,7 @@  diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
   diagnostic->richloc = richloc;
   diagnostic->kind = kind;
   diagnostic->option_index = 0;
+  diagnostic->taxonomy_id = taxonomy_id;
 }
 
 /* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
@@ -269,10 +271,11 @@  diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
 void
 diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
 		     va_list *args, rich_location *richloc,
-		     diagnostic_t kind)
+		     diagnostic_t kind, const char *taxonomy_id)
 {
   gcc_assert (richloc);
-  diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind);
+  diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind,
+				  taxonomy_id);
 }
 
 static const char *const diagnostic_kind_color[] = {
@@ -859,6 +862,26 @@  print_option_information (diagnostic_context *context,
     }
 }
 
+/* Print any metadata identifying DIAGNOSTIC within a problem taxonomy
+   (such as CWE) to CONTEXT's printer, e.g. " [CWE-681]".
+   Subroutine of diagnostic_report_diagnostic.  */
+
+static void
+print_taxonomy_information (diagnostic_context *context,
+			    const diagnostic_info *diagnostic)
+{
+  if (diagnostic->taxonomy_id == NULL)
+    return;
+
+  pretty_printer *pp = context->printer;
+  pp_string (pp, " [");
+  pp_string (pp, colorize_start (pp_show_color (pp),
+				 diagnostic_kind_color[diagnostic->kind]));
+  pp_string (pp, diagnostic->taxonomy_id);
+  pp_string (pp, colorize_stop (pp_show_color (pp)));
+  pp_character (pp, ']');
+}
+
 /* Report a diagnostic message (an error or a warning) as specified by
    DC.  This function is *the* subroutine in terms of which front-ends
    should implement their specific diagnostic handling modules.  The
@@ -974,6 +997,8 @@  diagnostic_report_diagnostic (diagnostic_context *context,
   pp_output_formatted_text (context->printer);
   if (context->show_option_requested)
     print_option_information (context, diagnostic, orig_diag_kind);
+  if (context->show_id)
+    print_taxonomy_information (context, diagnostic);
   (*diagnostic_finalizer (context)) (context, diagnostic);
   if (context->parseable_fixits_p)
     {
@@ -1055,7 +1080,7 @@  diagnostic_append_note (diagnostic_context *context,
   rich_location richloc (line_table, location);
 
   va_start (ap, gmsgid);
-  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
+  diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE, NULL);
   if (context->inhibit_notes_p)
     {
       va_end (ap);
@@ -1076,7 +1101,7 @@  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,
+diagnostic_impl (rich_location *richloc, const diag_id &di,
 		 const char *gmsgid,
 		 va_list *ap, diagnostic_t kind)
 {
@@ -1084,14 +1109,16 @@  diagnostic_impl (rich_location *richloc, int opt,
   if (kind == DK_PERMERROR)
     {
       diagnostic_set_info (&diagnostic, gmsgid, ap, richloc,
-			   permissive_error_kind (global_dc));
+			   permissive_error_kind (global_dc),
+			   di.get_id ());
       diagnostic.option_index = permissive_error_option (global_dc);
     }
   else
     {
-      diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind);
+      diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind,
+			   di.get_id ());
       if (kind == DK_WARNING || kind == DK_PEDWARN)
-	diagnostic.option_index = opt;
+	diagnostic.option_index = di.get_option ();
     }
   return diagnostic_report_diagnostic (global_dc, &diagnostic);
 }
@@ -1099,7 +1126,7 @@  diagnostic_impl (rich_location *richloc, int opt,
 /* Implement inform_n, warning_n, and error_n, as documented and
    defined below.  */
 static bool
-diagnostic_n_impl (rich_location *richloc, int opt, int n,
+diagnostic_n_impl (rich_location *richloc, const diag_id &di, int n,
 		   const char *singular_gmsgid,
 		   const char *plural_gmsgid,
 		   va_list *ap, diagnostic_t kind)
@@ -1107,22 +1134,22 @@  diagnostic_n_impl (rich_location *richloc, int opt, int n,
   diagnostic_info diagnostic;
   diagnostic_set_info_translated (&diagnostic,
                                   ngettext (singular_gmsgid, plural_gmsgid, n),
-                                  ap, richloc, kind);
+                                  ap, richloc, kind, di.get_id ());
   if (kind == DK_WARNING)
-    diagnostic.option_index = opt;
+    diagnostic.option_index = di.get_option ();
   return diagnostic_report_diagnostic (global_dc, &diagnostic);
 }
 
 /* Wrapper around diagnostic_impl taking a variable argument list.  */
 
 bool
-emit_diagnostic (diagnostic_t kind, location_t location, int opt,
+emit_diagnostic (diagnostic_t kind, location_t location, const diag_id &di,
 		 const char *gmsgid, ...)
 {
   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, di, gmsgid, &ap, kind);
   va_end (ap);
   return ret;
 }
@@ -1130,11 +1157,12 @@  emit_diagnostic (diagnostic_t kind, location_t location, int opt,
 /* Wrapper around diagnostic_impl taking a va_list parameter.  */
 
 bool
-emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
+emit_diagnostic_valist (diagnostic_t kind, location_t location,
+			const diag_id &di,
 			const char *gmsgid, va_list *ap)
 {
   rich_location richloc (line_table, location);
-  return diagnostic_impl (&richloc, opt, gmsgid, ap, kind);
+  return diagnostic_impl (&richloc, di, gmsgid, ap, kind);
 }
 
 /* An informative note at LOCATION.  Use this for additional details on an error
@@ -1179,12 +1207,12 @@  inform_n (location_t location, int n, const char *singular_gmsgid,
    to the relevant language specification but is likely to be buggy anyway.
    Returns true if the warning was printed, false if it was inhibited.  */
 bool
-warning (int opt, const char *gmsgid, ...)
+warning (const diag_id &di, 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, di, gmsgid, &ap, DK_WARNING);
   va_end (ap);
   return ret;
 }
@@ -1194,12 +1222,12 @@  warning (int opt, const char *gmsgid, ...)
    Returns true if the warning was printed, false if it was inhibited.  */
 
 bool
-warning_at (location_t location, int opt, const char *gmsgid, ...)
+warning_at (location_t location, const diag_id &di, 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, di, gmsgid, &ap, DK_WARNING);
   va_end (ap);
   return ret;
 }
@@ -1207,13 +1235,14 @@  warning_at (location_t location, int opt, const char *gmsgid, ...)
 /* Same as "warning at" above, but using RICHLOC.  */
 
 bool
-warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
+warning_at (rich_location *richloc, const diag_id &di,
+	    const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
   va_list ap;
   va_start (ap, gmsgid);
-  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_WARNING);
+  bool ret = diagnostic_impl (richloc, di, gmsgid, &ap, DK_WARNING);
   va_end (ap);
   return ret;
 }
@@ -1221,14 +1250,14 @@  warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
 /* Same as warning_n plural variant below, but using RICHLOC.  */
 
 bool
-warning_n (rich_location *richloc, int opt, int n,
+warning_n (rich_location *richloc, const diag_id &di, int n,
 	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
 {
   gcc_assert (richloc);
 
   va_list ap;
   va_start (ap, plural_gmsgid);
-  bool ret = diagnostic_n_impl (richloc, opt, n,
+  bool ret = diagnostic_n_impl (richloc, di, n,
 				singular_gmsgid, plural_gmsgid,
 				&ap, DK_WARNING);
   va_end (ap);
@@ -1240,13 +1269,13 @@  warning_n (rich_location *richloc, int opt, int n,
    Returns true if the warning was printed, false if it was inhibited.  */
 
 bool
-warning_n (location_t location, int opt, int n, const char *singular_gmsgid,
-	   const char *plural_gmsgid, ...)
+warning_n (location_t location, const diag_id &di, int n,
+	   const char *singular_gmsgid, const char *plural_gmsgid, ...)
 {
   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, di, n,
 				singular_gmsgid, plural_gmsgid,
 				&ap, DK_WARNING);
   va_end (ap);
@@ -1267,12 +1296,12 @@  warning_n (location_t location, int opt, int n, const char *singular_gmsgid,
    Returns true if the warning was printed, false if it was inhibited.  */
 
 bool
-pedwarn (location_t location, int opt, const char *gmsgid, ...)
+pedwarn (location_t location, const diag_id &di, 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, di, gmsgid, &ap, DK_PEDWARN);
   va_end (ap);
   return ret;
 }
@@ -1280,13 +1309,13 @@  pedwarn (location_t location, int opt, const char *gmsgid, ...)
 /* Same as pedwarn above, but using RICHLOC.  */
 
 bool
-pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
+pedwarn (rich_location *richloc, const diag_id &di, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
   va_list ap;
   va_start (ap, gmsgid);
-  bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
+  bool ret = diagnostic_impl (richloc, di, gmsgid, &ap, DK_PEDWARN);
   va_end (ap);
   return ret;
 }
@@ -1667,6 +1696,32 @@  test_diagnostic_get_location_text ()
   progname = old_progname;
 }
 
+/* Verify that print_taxonomy_information prints EXPECTED, given ID.  */
+
+static void
+assert_print_taxonomy_information (const char *expected, const char *id)
+{
+  test_diagnostic_context dc;
+  diagnostic_info diagnostic;
+
+  diagnostic.kind = DK_WARNING;
+
+  pretty_printer *pp = dc.printer;
+
+  diagnostic.taxonomy_id = id;
+  print_taxonomy_information (&dc, &diagnostic);
+  ASSERT_STREQ (expected, pp_formatted_text (pp));
+}
+
+/* Verify that print_taxonomy_information works as expected.  */
+
+static void
+test_print_taxonomy_information ()
+{
+  assert_print_taxonomy_information ("", NULL);
+  assert_print_taxonomy_information (" [CWE-681]", "CWE-681");
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -1678,6 +1733,7 @@  diagnostic_c_tests ()
   test_print_parseable_fixits_remove ();
   test_print_parseable_fixits_replace ();
   test_diagnostic_get_location_text ();
+  test_print_taxonomy_information ();
 }
 
 } // namespace selftest
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index dbd1703..70fbc4c 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -41,6 +41,10 @@  struct diagnostic_info
   diagnostic_t kind;
   /* Which OPT_* directly controls this diagnostic.  */
   int option_index;
+  /* An optional ID from a problem taxonomy (such as "PRE10-C" from the
+     CERT C Secure Coding Standard, or "CWE-681" from the Common Weakness
+     Enumeration).  */
+  const char *taxonomy_id;
 };
 
 /* Each time a diagnostic's classification is changed with a pragma,
@@ -117,6 +121,10 @@  struct diagnostic_context
      each diagnostic, if known.  */
   bool show_option_requested;
 
+  /* True if we should print any identifier within a problem taxonomy
+     for each diagnostic, if known.  */
+  bool show_id;
+
   /* True if we should raise a SIGABRT on errors.  */
   bool abort_on_error;
 
@@ -297,10 +305,11 @@  extern bool diagnostic_report_diagnostic (diagnostic_context *,
 					  diagnostic_info *);
 #ifdef ATTRIBUTE_GCC_DIAG
 extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *,
-				 rich_location *, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
+				 rich_location *, diagnostic_t, const char *)
+  ATTRIBUTE_GCC_DIAG(2,0);
 extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
 					    va_list *, rich_location *,
-					    diagnostic_t)
+					    diagnostic_t, const char *)
      ATTRIBUTE_GCC_DIAG(2,0);
 extern void diagnostic_append_note (diagnostic_context *, location_t,
                                     const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 43acbcb..9562898 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -250,7 +250,8 @@  Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fmessage-length=@var{n}  @gol
 -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]}  @gol
 -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]}  @gol
--fno-diagnostics-show-option  -fno-diagnostics-show-caret @gol
+-fno-diagnostics-show-option  -fno-diagnostics-show-id @gol
+-fno-diagnostics-show-caret @gol
 -fdiagnostics-parseable-fixits  -fdiagnostics-generate-patch @gol
 -fdiagnostics-show-template-tree -fno-elide-type @gol
 -fno-show-column}
@@ -3575,6 +3576,18 @@  command-line option that directly controls the diagnostic (if such an
 option is known to the diagnostic machinery).  Specifying the
 @option{-fno-diagnostics-show-option} flag suppresses that behavior.
 
+@item -fno-diagnostics-show-id
+@opindex fno-diagnostics-show-id
+@opindex fdiagnostics-show-id
+By default, each diagnostic emitted can include text indicating an
+ID within a problem taxonomy, such as `INT15-C` within the
+CERT C Secure Coding Standard, or `CWE-681` within the
+Common Weakness Enumeration (CWE).
+Such IDs can be useful for categorizing problems, or for searching for
+helpful recommendations for addressing the diagnostic.
+Specifying the @option{-fno-diagnostics-show-id} flag suppresses that
+behavior.
+
 @item -fno-diagnostics-show-caret
 @opindex fno-diagnostics-show-caret
 @opindex fdiagnostics-show-caret
diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c
index af8a69c..b657583 100644
--- a/gcc/fortran/cpp.c
+++ b/gcc/fortran/cpp.c
@@ -1059,7 +1059,7 @@  cb_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
       gcc_unreachable ();
     }
   diagnostic_set_info_translated (&diagnostic, msg, ap,
-				  richloc, dlevel);
+				  richloc, dlevel, NULL);
   if (reason == CPP_W_WARNING_DIRECTIVE)
     diagnostic_override_option_index (&diagnostic, OPT_Wcpp);
   ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index 3ad1cf9..6bc9fef 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -787,7 +787,7 @@  gfc_warning (int opt, const char *gmsgid, va_list ap)
     }
 
   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
-		       DK_WARNING);
+		       DK_WARNING, NULL);
   diagnostic.option_index = opt;
   bool ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
 
@@ -1137,7 +1137,8 @@  gfc_warning_now_at (location_t loc, int opt, const char *gmsgid, ...)
   bool ret;
 
   va_start (argp, gmsgid);
-  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING);
+  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING,
+		       NULL);
   diagnostic.option_index = opt;
   ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (argp);
@@ -1156,7 +1157,7 @@  gfc_warning_now (int opt, const char *gmsgid, ...)
 
   va_start (argp, gmsgid);
   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
-		       DK_WARNING);
+		       DK_WARNING, NULL);
   diagnostic.option_index = opt;
   ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (argp);
@@ -1175,7 +1176,7 @@  gfc_warning_internal (int opt, const char *gmsgid, ...)
 
   va_start (argp, gmsgid);
   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
-		       DK_WARNING);
+		       DK_WARNING, NULL);
   diagnostic.option_index = opt;
   ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (argp);
@@ -1194,7 +1195,8 @@  gfc_error_now (const char *gmsgid, ...)
   error_buffer.flag = true;
 
   va_start (argp, gmsgid);
-  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR);
+  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR,
+		       NULL);
   diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (argp);
 }
@@ -1210,7 +1212,7 @@  gfc_fatal_error (const char *gmsgid, ...)
   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
 
   va_start (argp, gmsgid);
-  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL);
+  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL, NULL);
   diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (argp);
 
@@ -1295,7 +1297,7 @@  gfc_error_opt (int opt, const char *gmsgid, va_list ap)
       --errorcount;
     }
 
-  diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR);
+  diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR, NULL);
   diagnostic_report_diagnostic (global_dc, &diagnostic);
 
   if (buffered_p)
@@ -1345,7 +1347,7 @@  gfc_internal_error (const char *gmsgid, ...)
     exit(EXIT_FAILURE);
 
   va_start (argp, gmsgid);
-  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE);
+  diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE, NULL);
   diagnostic_report_diagnostic (global_dc, &diagnostic);
   va_end (argp);
 
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index 7415413..1ca62c6 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -594,7 +594,7 @@  get_format_string (tree format, location_t *ploc)
 
 static bool
   (* const fmtwarn) (const substring_loc &, location_t,
-		     const char *, int, const char *, ...)
+		     const char *, const diag_id &, const char *, ...)
   = format_warning_at_substring;
 
 /* Format length modifiers.  */
diff --git a/gcc/opts.c b/gcc/opts.c
index ac383d4..9bcfa75 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2098,6 +2098,10 @@  common_handle_option (struct gcc_options *opts,
       dc->show_option_requested = value;
       break;
 
+    case OPT_fdiagnostics_show_id:
+      dc->show_id = value;
+      break;
+
     case OPT_fdump_:
       /* Deferred.  */
       break;
diff --git a/gcc/rtl-error.c b/gcc/rtl-error.c
index e04bd7e..eab90ac 100644
--- a/gcc/rtl-error.c
+++ b/gcc/rtl-error.c
@@ -70,7 +70,7 @@  diagnostic_for_asm (const rtx_insn *insn, const char *msg, va_list *args_ptr,
   rich_location richloc (line_table, location_for_asm (insn));
 
   diagnostic_set_info (&diagnostic, msg, args_ptr,
-		       &richloc, kind);
+		       &richloc, kind, NULL);
   diagnostic_report_diagnostic (global_dc, &diagnostic);
 }
 
diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
index 7de435b..092d81f 100644
--- a/gcc/substring-locations.c
+++ b/gcc/substring-locations.c
@@ -26,7 +26,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "substring-locations.h"
 
-/* Emit a warning governed by option OPT, using GMSGID as the format
+/* Emit a warning governed by option DI, using GMSGID as the format
    string and AP as its arguments.
 
    Attempt to obtain precise location information within a string
@@ -102,7 +102,7 @@  bool
 format_warning_va (const substring_loc &fmt_loc,
 		   location_t param_loc,
 		   const char *corrected_substring,
-		   int opt, const char *gmsgid, va_list *ap)
+		   const diag_id &di, const char *gmsgid, va_list *ap)
 {
   bool substring_within_range = false;
   location_t primary_loc;
@@ -143,8 +143,9 @@  format_warning_va (const substring_loc &fmt_loc,
     richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
 
   diagnostic_info diagnostic;
-  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING);
-  diagnostic.option_index = opt;
+  diagnostic_set_info (&diagnostic, gmsgid, ap, &richloc, DK_WARNING,
+		       di.get_id ());
+  diagnostic.option_index = di.get_option ();
   bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
 
   if (!err && fmt_substring_loc && !substring_within_range)
@@ -168,12 +169,12 @@  bool
 format_warning_at_substring (const substring_loc &fmt_loc,
 			     location_t param_loc,
 			     const char *corrected_substring,
-			     int opt, const char *gmsgid, ...)
+			     const diag_id &di, const char *gmsgid, ...)
 {
   va_list ap;
   va_start (ap, gmsgid);
   bool warned = format_warning_va (fmt_loc, param_loc, corrected_substring,
-				   opt, gmsgid, &ap);
+				   di, gmsgid, &ap);
   va_end (ap);
 
   return warned;
diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h
index 3d7796d..13df498 100644
--- a/gcc/substring-locations.h
+++ b/gcc/substring-locations.h
@@ -79,13 +79,17 @@  class substring_loc
 extern bool format_warning_va (const substring_loc &fmt_loc,
 			       location_t param_loc,
 			       const char *corrected_substring,
-			       int opt, const char *gmsgid, va_list *ap)
+			       const diag_id &di,
+			       const char *gmsgid,
+			       va_list *ap)
   ATTRIBUTE_GCC_DIAG (5,0);
 
 extern bool format_warning_at_substring (const substring_loc &fmt_loc,
 					 location_t param_loc,
 					 const char *corrected_substring,
-					 int opt, const char *gmsgid, ...)
+					 const diag_id &di,
+					 const char *gmsgid,
+					 ...)
   ATTRIBUTE_GCC_DIAG (5,0);
 
 /* Implementation detail, for use when implementing
diff --git a/gcc/toplev.c b/gcc/toplev.c
index eff1690..590ab58 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_caret;
   global_dc->show_option_requested
     = global_options_init.x_flag_diagnostics_show_option;
+  global_dc->show_id
+    = global_options_init.x_flag_diagnostics_show_id;
   global_dc->show_column
     = global_options_init.x_flag_show_column;
   global_dc->internal_error = internal_error_function;