On Mon, Aug 20, 2018 at 11:10 PM David Malcolm <dmalc...@redhat.com> wrote:
>
> We often emit logically-related groups of diagnostics.
>
> A relatively simple case is this:
>
>   if (warning_at (body_loc, OPT_Wmultistatement_macros,
>                   "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));
>
> where the "note" diagnostic issued by the "inform" call
> is guarded by the -Wmultistatement_macros warning.
>
> More complicated examples can be seen in the C++ frontend,
> where e.g. print_z_candidates can lead to numerous "note"
> diagnostics being emitted.
>
> I'm looking at various ways to improve how we handle such related
> diagnostics, but, prior to this patch, there was no explicit
> relationship between these diagnostics: the diagnostics subsystem
> had no way of "knowing" that these were related.
>
> This patch introduces a simple way to group the diagnostics:
> an auto_diagnostic_group class: all diagnostics emitted within
> the lifetime of an auto_diagnostic_group instance are logically
> grouped.
>
> Hence in the above example, the two diagnostics can be grouped
> by simply adding an auto_diagnostic_group instance:
>
>   auto_diagnostic_group d;
>   if (warning_at (body_loc, OPT_Wmultistatement_macros,
>                   "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));
>
> Some more awkard cases are of the form:
>
>   if (some_condition
>       && warning_at (...)
>       && more_conditions)
>     inform (...);
>
> which thus need restructuring to:
>
>   if (some_condition)
>     {
>       auto_diagnostic_group d;
>       warning_at (...);
>       if (more_conditions)
>         inform (...);
>     }
>
> so that the lifetime of the auto_diagnostic_group groups the
> warning_at and the inform call.
>
> Nesting is handled by simply tracking a nesting depth within the
> diagnostic_context.: all diagnostics are treated as grouped until the
> final auto_diagnostic_group is popped.
>
> diagnostic.c uses this internally, so that all diagnostics are part of
> a group - those that are "by themselves" are treated as being part of
> a group with one element.
>
> The diagnostic_context gains optional callbacks for displaying the
> start of a group (when the first diagnostic is emitted within it), and
> the end of a group (for when the group was non-empty); these callbacks
> are unused by default, but a test plugin demonstrates them (and verifies
> that the machinery is working).
>
> As noted above, I'm looking at various ways to use the grouping to
> improve how we output the diagnostics.
>
> FWIW, I experimented with a more involved implementation, of the form:
>
>   diagnostic_group d;
>   if (d.warning_at (body_loc, OPT_Wmultistatement_macros,
>                     "macro expands to multiple statements"))
>     d.inform (guard_loc, "some parts of macro expansion are not guarded by "
>               "this %qs clause", guard_tinfo_to_string (keyword));
>
> which had the advantage of allowing auto-detection of the places where
> groups were needed (by converting ::warning_at's return type to bool),
> but it was a much more invasive patch, especially when dealing with
> the places in the C++ frontend that can emit numerous notes after
> an error or warning (and thus having to pass the group around)
> Hence I went with this simpler approach.

IMHO a shame because the

  auto_diagnostic_group d;

stuff really looks unrelated and it's probably easy enough to not notice
errors with it.

I'd have used

  if (diagnostic_group d = warning_at (...))
    d.inform (...);

for the common idiom so we'd be able to elide the conditionals.  That is
diagnostic_group initializes from a bool, converts to a bool and the
forwarder methods do nothing if it was initialized from false.

Richard.

>
> Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu; adds
> 4 PASS results to gcc.sum.
>
> Committed to trunk as r263675.
>
> gcc/c-family/ChangeLog:
>         PR other/84889
>         * c-attribs.c (common_handle_aligned_attribute): Add
>         auto_diagnostic_group instance.
>         * c-indentation.c (warn_for_misleading_indentation): Likewise.
>         * c-opts.c (c_common_post_options): Likewise.
>         * c-warn.c (warn_logical_not_parentheses): Likewise.
>         (warn_duplicated_cond_add_or_warn): Likewise.
>         (warn_for_multistatement_macros): Likewise.
>
> gcc/c/ChangeLog:
>         PR other/84889
>         * c-decl.c (pushtag): Add auto_diagnostic_group instance.
>         (diagnose_mismatched_decls): Likewise, in various places.
>         (warn_if_shadowing): Likewise.
>         (implicit_decl_warning): Likewise.
>         (implicitly_declare): Likewise.
>         (undeclared_variable): Likewise.
>         (declare_label): Likewise.
>         (grokdeclarator): Likewise.
>         (start_function): Likewise.
>         * c-parser.c (c_parser_declaration_or_fndef): Likewise.
>         (c_parser_parameter_declaration): Likewise.
>         (c_parser_binary_expression): Likewise.
>         * c-typeck.c (c_expr_sizeof_expr): Likewise.
>         (parser_build_binary_op): Likewise.
>         (build_unary_op): Likewise.
>         (error_init): Likewise.
>         (pedwarn_init): Likewise.
>         (warning_init): Likewise.
>         (convert_for_assignment): Likewise.
>
> gcc/cp/ChangeLog:
>         PR other/84889
>         * call.c (build_user_type_conversion_1): Add auto_diagnostic_group
>         instance(s).
>         (print_error_for_call_failure): Likewise.
>         (build_op_call_1): Likewise.
>         (build_conditional_expr_1): Likewise.
>         (build_new_op_1): Likewise.
>         (build_op_delete_call): Likewise.
>         (convert_like_real): Likewise.
>         (build_over_call): Likewise.
>         (build_new_method_call_1): Likewise.
>         (joust): Likewise.
>         * class.c (check_tag): Likewise.
>         (finish_struct_anon_r): Likewise.
>         (one_inherited_ctor): Likewise.
>         (finalize_literal_type_property): Likewise.
>         (explain_non_literal_class): Likewise.
>         (find_flexarrays): Likewise.
>         (resolve_address_of_overloaded_function): Likewise.
>         * constexpr.c (ensure_literal_type_for_constexpr_object): Likewise.
>         (is_valid_constexpr_fn): Likewise.
>         (cx_check_missing_mem_inits): Likewise.
>         * cp-gimplify.c (cp_genericize_r): Likewise.
>         * cvt.c (maybe_warn_nodiscard): Likewise.
>         * decl.c (warn_extern_redeclared_static): Likewise.
>         (check_redeclaration_exception_specification): Likewise.
>         (check_no_redeclaration_friend_default_args): Likewise.
>         (duplicate_decls): Likewise.
>         (redeclaration_error_message): Likewise.
>         (warn_misplaced_attr_for_class_type): Likewise.
>         * decl2.c (finish_static_data_member_decl): Likewise.
>         (no_linkage_error): Likewise.
>         (cp_warn_deprecated_use): Likewise.
>         * error.c (qualified_name_lookup_error): Likewise.
>         * friend.c (make_friend_class): Likewise.
>         (do_friend): Likewise.
>         * init.c (perform_member_init): Likewise.
>         (build_new_1): Likewise.
>         (build_vec_delete_1): Likewise.
>         (build_delete): Likewise.
>         * lex.c (unqualified_name_lookup_error): Likewise.
>         * name-lookup.c (check_extern_c_conflict): Likewise.
>         (inform_shadowed): New function.
>         (check_local_shadow): Add auto_diagnostic_group instances,
>         replacing goto "inform_shadowed" label with call to subroutine.
>         (set_local_extern_decl_linkage): Add auto_diagnostic_group
>         instance(s).
>         * parser.c (cp_parser_diagnose_invalid_type_name): Likewise.
>         (cp_parser_namespace_name): Likewise.
>         * pt.c (check_specialization_namespace): Likewise.
>         (check_template_variable): Likewise.
>         (warn_spec_missing_attributes): Likewise.
>         (check_explicit_specialization): Likewise.
>         (process_partial_specialization): Likewise.
>         (lookup_template_class_1): Likewise.
>         (finish_template_variable): Likewise.
>         (do_auto_deduction): Likewise.
>         * search.c (check_final_overrider): Likewise.
>         (look_for_overrides_r): Likewise.
>         * tree.c (maybe_warn_parm_abi): Likewise.
>         * typeck.c (cxx_sizeof_expr): Likewise.
>         (cp_build_function_call_vec): Likewise.
>         (cp_build_binary_op): Likewise.
>         (convert_for_assignment): Likewise.
>         (maybe_warn_about_returning_address_of_local): Likewise.
>         * typeck2.c (abstract_virtuals_error_sfinae): Likewise.
>         (check_narrowing): Likewise.
>
> gcc/ChangeLog:
>         PR other/84889
>         * attribs.c (diag_attr_exclusions): Add auto_diagnostic_group 
> instance.
>         (decl_attributes): Likewise.
>         * calls.c (maybe_warn_nonstring_arg): Add auto_diagnostic_group
>         instance.
>         * cgraphunit.c (maybe_diag_incompatible_alias): Likewise.
>         * diagnostic-core.h (class auto_diagnostic_group): New class.
>         * diagnostic.c (diagnostic_initialize): Initialize the new fields.
>         (diagnostic_report_diagnostic): Handle the first diagnostics within
>         a group.
>         (emit_diagnostic): Add auto_diagnostic_group instance.
>         (inform): Likewise.
>         (inform_n): Likewise.
>         (warning): Likewise.
>         (warning_at): Likewise.
>         (warning_n): Likewise.
>         (pedwarn): Likewise.
>         (permerror): Likewise.
>         (error): Likewise.
>         (error_n): Likewise.
>         (error_at): Likewise.
>         (sorry): Likewise.
>         (fatal_error): Likewise.
>         (internal_error): Likewise.
>         (internal_error_no_backtrace): Likewise.
>         (auto_diagnostic_group::auto_diagnostic_group): New ctor.
>         (auto_diagnostic_group::~auto_diagnostic_group): New dtor.
>         * diagnostic.h (struct diagnostic_context): Add fields
>         "diagnostic_group_nesting_depth",
>         "diagnostic_group_emission_count", "begin_group_cb",
>         "end_group_cb".
>         * gimple-ssa-isolate-paths.c (find_implicit_erroneous_behavior):
>         Add auto_diagnostic_group instance(s).
>         (find_explicit_erroneous_behavior): Likewise.
>         * gimple-ssa-warn-alloca.c (pass_walloca::execute): Likewise.
>         * gimple-ssa-warn-restrict.c (maybe_diag_offset_bounds): Likewise.
>         * gimplify.c (warn_implicit_fallthrough_r): Likewise.
>         (gimplify_va_arg_expr): Likewise.
>         * hsa-gen.c (HSA_SORRY_ATV): Likewise.
>         (HSA_SORRY_AT): Likewise.
>         * ipa-devirt.c (compare_virtual_tables): Likewise.
>         (warn_odr): Likewise.
>         * multiple_target.c (expand_target_clones): Likewise.
>         * opts-common.c (cmdline_handle_error): Likewise.
>         * reginfo.c (globalize_reg): Likewise.
>         * substring-locations.c (format_warning_n_va): Likewise.
>         * tree-inline.c (expand_call_inline): Likewise.
>         * tree-ssa-ccp.c (pass_post_ipa_warn::execute): Likewise.
>         * tree-ssa-loop-niter.c
>         (do_warn_aggressive_loop_optimizations): Likewise.
>         * tree-ssa-uninit.c (warn_uninit): Likewise.
>         * tree.c (warn_deprecated_use): Likewise.
>
> gcc/testsuite/ChangeLog:
>         PR other/84889
>         * gcc.dg/plugin/diagnostic-group-test-1.c: New test.
>         * gcc.dg/plugin/diagnostic_group_plugin.c: New test.
>         * gcc.dg/plugin/plugin.exp (plugin_test_list): Add the new tests.
> ---
>  gcc/attribs.c                                      |   3 +-
>  gcc/c-family/c-attribs.c                           |   1 +
>  gcc/c-family/c-indentation.c                       |   1 +
>  gcc/c-family/c-opts.c                              |   1 +
>  gcc/c-family/c-warn.c                              |   3 +
>  gcc/c/c-decl.c                                     |  44 +++-
>  gcc/c/c-parser.c                                   |  22 +-
>  gcc/c/c-typeck.c                                   |  78 ++++---
>  gcc/calls.c                                        |   1 +
>  gcc/cgraphunit.c                                   |  17 +-
>  gcc/cp/call.c                                      |  29 ++-
>  gcc/cp/class.c                                     |  75 ++++---
>  gcc/cp/constexpr.c                                 |  21 +-
>  gcc/cp/cp-gimplify.c                               |  15 +-
>  gcc/cp/cvt.c                                       |   3 +
>  gcc/cp/decl.c                                      |  28 ++-
>  gcc/cp/decl2.c                                     |   3 +
>  gcc/cp/error.c                                     |   2 +
>  gcc/cp/friend.c                                    |   4 +
>  gcc/cp/init.c                                      |  48 +++--
>  gcc/cp/lex.c                                       |   1 +
>  gcc/cp/name-lookup.c                               |  35 +--
>  gcc/cp/parser.c                                    |   6 +
>  gcc/cp/pt.c                                        |   8 +
>  gcc/cp/search.c                                    |  10 +
>  gcc/cp/tree.c                                      |   2 +
>  gcc/cp/typeck.c                                    |  49 +++--
>  gcc/cp/typeck2.c                                   |   2 +
>  gcc/diagnostic-core.h                              |   9 +
>  gcc/diagnostic.c                                   |  60 ++++++
>  gcc/diagnostic.h                                   |  17 ++
>  gcc/gimple-ssa-isolate-paths.c                     |  26 ++-
>  gcc/gimple-ssa-warn-alloca.c                       |  50 +++--
>  gcc/gimple-ssa-warn-restrict.c                     |   2 +
>  gcc/gimplify.c                                     |   2 +
>  gcc/hsa-gen.c                                      |   2 +
>  gcc/ipa-devirt.c                                   |  39 ++--
>  gcc/multiple_target.c                              |   1 +
>  gcc/opts-common.c                                  |   1 +
>  gcc/reginfo.c                                      |   1 +
>  gcc/substring-locations.c                          |   1 +
>  .../gcc.dg/plugin/diagnostic-group-test-1.c        |  26 +++
>  .../gcc.dg/plugin/diagnostic_group_plugin.c        | 234 
> +++++++++++++++++++++
>  gcc/testsuite/gcc.dg/plugin/plugin.exp             |   2 +
>  gcc/tree-inline.c                                  |   1 +
>  gcc/tree-ssa-ccp.c                                 |   1 +
>  gcc/tree-ssa-loop-niter.c                          |   1 +
>  gcc/tree-ssa-uninit.c                              |   1 +
>  gcc/tree.c                                         |   2 +
>  49 files changed, 797 insertions(+), 194 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-group-test-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c
>
> diff --git a/gcc/attribs.c b/gcc/attribs.c
> index efc879b..64700b6 100644
> --- a/gcc/attribs.c
> +++ b/gcc/attribs.c
> @@ -430,7 +430,7 @@ diag_attr_exclusions (tree last_decl, tree node, tree 
> attrname,
>
>           /* Print a note?  */
>           bool note = last_decl != NULL_TREE;
> -
> +         auto_diagnostic_group d;
>           if (TREE_CODE (node) == FUNCTION_DECL
>               && DECL_BUILT_IN (node))
>             note &= warning (OPT_Wattributes,
> @@ -587,6 +587,7 @@ decl_attributes (tree *node, tree attributes, int flags,
>           /* This is a c++11 attribute that appertains to a
>              type-specifier, outside of the definition of, a class
>              type.  Ignore it.  */
> +         auto_diagnostic_group d;
>           if (warning (OPT_Wattributes, "attribute ignored"))
>             inform (input_location,
>                     "an attribute that appertains to a type-specifier "
> diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
> index 9da9c27..5454e09 100644
> --- a/gcc/c-family/c-attribs.c
> +++ b/gcc/c-family/c-attribs.c
> @@ -1881,6 +1881,7 @@ common_handle_aligned_attribute (tree *node, tree name, 
> tree args, int flags,
>        bitalign /= BITS_PER_UNIT;
>
>        bool diagd = true;
> +      auto_diagnostic_group d;
>        if (DECL_USER_ALIGN (decl) || DECL_USER_ALIGN (last_decl))
>         diagd = warning (OPT_Wattributes,
>                           "ignoring attribute %<%E (%u)%> because it 
> conflicts "
> diff --git a/gcc/c-family/c-indentation.c b/gcc/c-family/c-indentation.c
> index 436d61b..cff5aec 100644
> --- a/gcc/c-family/c-indentation.c
> +++ b/gcc/c-family/c-indentation.c
> @@ -609,6 +609,7 @@ warn_for_misleading_indentation (const token_indent_info 
> &guard_tinfo,
>                                               body_tinfo,
>                                               next_tinfo))
>      {
> +      auto_diagnostic_group d;
>        if (warning_at (guard_tinfo.location, OPT_Wmisleading_indentation,
>                       "this %qs clause does not guard...",
>                       guard_tinfo_to_string (guard_tinfo.keyword)))
> diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
> index cb69fb3..ec05771 100644
> --- a/gcc/c-family/c-opts.c
> +++ b/gcc/c-family/c-opts.c
> @@ -931,6 +931,7 @@ c_common_post_options (const char **pfilename)
>        warn_abi_version = latest_abi_version;
>        if (flag_abi_version == latest_abi_version)
>         {
> +         auto_diagnostic_group d;
>           if (warning (OPT_Wabi, "-Wabi won't warn about anything"))
>             {
>               inform (input_location, "-Wabi warns about differences "
> diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
> index d34d667..ca259aa 100644
> --- a/gcc/c-family/c-warn.c
> +++ b/gcc/c-family/c-warn.c
> @@ -491,6 +491,7 @@ warn_logical_not_parentheses (location_t location, enum 
> tree_code code,
>        && integer_zerop (rhs))
>      return;
>
> +  auto_diagnostic_group d;
>    if (warning_at (location, OPT_Wlogical_not_parentheses,
>                   "logical not is only applied to the left hand side of "
>                   "comparison")
> @@ -2232,6 +2233,7 @@ warn_duplicated_cond_add_or_warn (location_t loc, tree 
> cond, vec<tree> **chain)
>    FOR_EACH_VEC_ELT (**chain, ix, t)
>      if (operand_equal_p (cond, t, 0))
>        {
> +       auto_diagnostic_group d;
>         if (warning_at (loc, OPT_Wduplicated_cond,
>                         "duplicated %<if%> condition"))
>           inform (EXPR_LOCATION (t), "previously used here");
> @@ -2601,6 +2603,7 @@ warn_for_multistatement_macros (location_t body_loc, 
> location_t next_loc,
>         return;
>      }
>
> +  auto_diagnostic_group d;
>    if (warning_at (body_loc, OPT_Wmultistatement_macros,
>                   "macro expands to multiple statements"))
>      inform (guard_loc, "some parts of macro expansion are not guarded by "
> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> index 1bbccdd..9524977 100644
> --- a/gcc/c/c-decl.c
> +++ b/gcc/c/c-decl.c
> @@ -1571,6 +1571,7 @@ pushtag (location_t loc, tree name, tree type)
>           && (TYPE_MAIN_VARIANT (TREE_TYPE (b->decl))
>               != TYPE_MAIN_VARIANT (type)))
>         {
> +         auto_diagnostic_group d;
>           if (warning_at (loc, OPT_Wc___compat,
>                           ("using %qD as both a typedef and a tag is "
>                            "invalid in C++"), b->decl)
> @@ -1823,8 +1824,6 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>                            tree *newtypep, tree *oldtypep)
>  {
>    tree newtype, oldtype;
> -  bool pedwarned = false;
> -  bool warned = false;
>    bool retval = true;
>
>  #define DECL_EXTERN_INLINE(DECL) (DECL_DECLARED_INLINE_P (DECL)  \
> @@ -1847,6 +1846,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>             && DECL_BUILT_IN (olddecl)
>             && !C_DECL_DECLARED_BUILTIN (olddecl)))
>         {
> +         auto_diagnostic_group d;
>           error ("%q+D redeclared as different kind of symbol", newdecl);
>           locate_old_decl (olddecl);
>         }
> @@ -1864,11 +1864,16 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>       given scope.  */
>    if (TREE_CODE (olddecl) == CONST_DECL)
>      {
> +      auto_diagnostic_group d;
>        error ("redeclaration of enumerator %q+D", newdecl);
>        locate_old_decl (olddecl);
>        return false;
>      }
>
> +  bool pedwarned = false;
> +  bool warned = false;
> +  auto_diagnostic_group d;
> +
>    if (!comptypes (oldtype, newtype))
>      {
>        if (TREE_CODE (olddecl) == FUNCTION_DECL
> @@ -2052,6 +2057,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>                   )
>                   && same_translation_unit_p (newdecl, olddecl))
>                 {
> +                 auto_diagnostic_group d;
>                   error ("redefinition of %q+D", newdecl);
>                   locate_old_decl (olddecl);
>                   return false;
> @@ -2062,11 +2068,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>          the argument types must be checked specially.  */
>        else if (DECL_INITIAL (olddecl)
>                && !prototype_p (oldtype) && prototype_p (newtype)
> -              && TYPE_ACTUAL_ARG_TYPES (oldtype)
> -              && !validate_proto_after_old_defn (newdecl, newtype, oldtype))
> +              && TYPE_ACTUAL_ARG_TYPES (oldtype))
>         {
> -         locate_old_decl (olddecl);
> -         return false;
> +         auto_diagnostic_group d;
> +         if (!validate_proto_after_old_defn (newdecl, newtype, oldtype))
> +           {
> +             locate_old_decl (olddecl);
> +             return false;
> +           }
>         }
>        /* A non-static declaration (even an "extern") followed by a
>          static declaration is undefined behavior per C99 6.2.2p3-5,7.
> @@ -2087,6 +2096,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>           if (!DECL_IS_BUILTIN (olddecl)
>               && !DECL_EXTERN_INLINE (olddecl))
>             {
> +             auto_diagnostic_group d;
>               error ("static declaration of %q+D follows "
>                      "non-static declaration", newdecl);
>               locate_old_decl (olddecl);
> @@ -2097,6 +2107,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>         {
>           if (DECL_CONTEXT (olddecl))
>             {
> +             auto_diagnostic_group d;
>               error ("non-static declaration of %q+D follows "
>                      "static declaration", newdecl);
>               locate_old_decl (olddecl);
> @@ -2121,6 +2132,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>                                         DECL_ATTRIBUTES (olddecl)) != NULL;
>           if (newa != olda)
>             {
> +             auto_diagnostic_group d;
>               error_at (input_location, "%<gnu_inline%> attribute present on 
> %q+D",
>                         newa ? newdecl : olddecl);
>               error_at (DECL_SOURCE_LOCATION (newa ? olddecl : newdecl),
> @@ -2141,6 +2153,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>         }
>        else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P 
> (olddecl))
>         {
> +         auto_diagnostic_group d;
>           if (DECL_THREAD_LOCAL_P (newdecl))
>             error ("thread-local declaration of %q+D follows "
>                    "non-thread-local declaration", newdecl);
> @@ -2155,6 +2168,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>        /* Multiple initialized definitions are not allowed (6.9p3,5).  */
>        if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
>         {
> +         auto_diagnostic_group d;
>           error ("redefinition of %q+D", newdecl);
>           locate_old_decl (olddecl);
>           return false;
> @@ -2175,6 +2189,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>             {
>               if (!DECL_FILE_SCOPE_P (olddecl))
>                 {
> +                 auto_diagnostic_group d;
>                   error ("extern declaration of %q+D follows "
>                          "declaration with no linkage", newdecl);
>                   locate_old_decl (olddecl);
> @@ -2189,6 +2204,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>             }
>           else
>             {
> +             auto_diagnostic_group d;
>               if (TREE_PUBLIC (newdecl))
>                 error ("non-static declaration of %q+D follows "
>                        "static declaration", newdecl);
> @@ -2211,12 +2227,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>             }
>           else if (DECL_EXTERNAL (olddecl))
>             {
> +             auto_diagnostic_group d;
>               error ("declaration of %q+D with no linkage follows "
>                      "extern declaration", newdecl);
>               locate_old_decl (olddecl);
>             }
>           else
>             {
> +             auto_diagnostic_group d;
>               error ("redeclaration of %q+D with no linkage", newdecl);
>               locate_old_decl (olddecl);
>             }
> @@ -2263,6 +2281,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
>        if (TREE_CODE (newdecl) == PARM_DECL
>           && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl)))
>         {
> +         auto_diagnostic_group d;
>           error ("redefinition of parameter %q+D", newdecl);
>           locate_old_decl (olddecl);
>           return false;
> @@ -2778,7 +2797,6 @@ warn_if_shadowing (tree new_decl)
>                                              DECL_SOURCE_LOCATION (b->decl))))
>        {
>         tree old_decl = b->decl;
> -       bool warned = false;
>
>         if (old_decl == error_mark_node)
>           {
> @@ -2786,7 +2804,10 @@ warn_if_shadowing (tree new_decl)
>                      "non-variable", new_decl);
>             break;
>           }
> -       else if (TREE_CODE (old_decl) == PARM_DECL)
> +
> +       bool warned = false;
> +       auto_diagnostic_group d;
> +       if (TREE_CODE (old_decl) == PARM_DECL)
>           {
>             enum opt_code warning_code;
>
> @@ -3123,6 +3144,7 @@ implicit_decl_warning (location_t loc, tree id, tree 
> olddecl)
>      return;
>
>    bool warned;
> +  auto_diagnostic_group d;
>    name_hint hint;
>    if (!olddecl)
>      hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME, loc);
> @@ -3435,6 +3457,7 @@ implicitly_declare (location_t loc, tree functionid)
>             {
>               if (!comptypes (newtype, TREE_TYPE (decl)))
>                 {
> +                 auto_diagnostic_group d;
>                   error_at (loc, "incompatible implicit declaration of "
>                             "function %qD", decl);
>                   locate_old_decl (decl);
> @@ -3487,6 +3510,7 @@ undeclared_variable (location_t loc, tree id)
>    static bool already = false;
>    struct c_scope *scope;
>
> +  auto_diagnostic_group d;
>    if (current_function_decl == NULL_TREE)
>      {
>        name_hint guessed_id = lookup_name_fuzzy (id, FUZZY_LOOKUP_NAME, loc);
> @@ -3686,6 +3710,7 @@ declare_label (tree name)
>       at this scope */
>    if (b && B_IN_CURRENT_SCOPE (b))
>      {
> +      auto_diagnostic_group d;
>        error ("duplicate label declaration %qE", name);
>        locate_old_decl (b->decl);
>
> @@ -3784,6 +3809,7 @@ define_label (location_t location, tree name)
>           || (DECL_CONTEXT (label) != current_function_decl
>               && C_DECLARED_LABEL_FLAG (label))))
>      {
> +      auto_diagnostic_group d;
>        error_at (location, "duplicate label %qD", label);
>        locate_old_decl (label);
>        return NULL_TREE;
> @@ -6720,6 +6746,7 @@ grokdeclarator (const struct c_declarator *declarator,
>                   || (current_scope == file_scope && B_IN_EXTERNAL_SCOPE (b)))
>               && TYPE_MAIN_VARIANT (b->decl) != TYPE_MAIN_VARIANT (type))
>             {
> +             auto_diagnostic_group d;
>               if (warning_at (declarator->id_loc, OPT_Wc___compat,
>                               ("using %qD as both a typedef and a tag is "
>                                "invalid in C++"), decl)
> @@ -8794,6 +8821,7 @@ start_function (struct c_declspecs *declspecs, struct 
> c_declarator *declarator,
>         {
>           if (stdarg_p (TREE_TYPE (old_decl)))
>             {
> +             auto_diagnostic_group d;
>               warning_at (loc, 0, "%q+D defined as variadic function "
>                           "without prototype", decl1);
>               locate_old_decl (old_decl);
> diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
> index 5ad4f57..0d5dbea 100644
> --- a/gcc/c/c-parser.c
> +++ b/gcc/c/c-parser.c
> @@ -1814,6 +1814,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
> fndef_ok,
>         }
>        else
>         {
> +         auto_diagnostic_group d;
>           name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME,
>                                               here);
>           if (hint)
> @@ -4058,6 +4059,7 @@ c_parser_parameter_declaration (c_parser *parser, tree 
> attrs)
>        c_parser_set_source_position_from_token (token);
>        if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
>         {
> +         auto_diagnostic_group d;
>           name_hint hint = lookup_name_fuzzy (token->value,
>                                               FUZZY_LOOKUP_TYPENAME,
>                                               token->location);
> @@ -6873,14 +6875,18 @@ 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,         
> \
> -                             "division %<sizeof (%T) / sizeof (%T)%> does "  
> \
> -                             "not compute the number of array elements",     
> \
> -                             type0, type1))                                  
> \
> -               if (DECL_P (first_arg))                                       
> \
> -                 inform (DECL_SOURCE_LOCATION (first_arg),                   
> \
> -                         "first %<sizeof%> operand was declared here");      
> \
> -         }                                                                   
> \
> +             {                                                         \
> +               auto_diagnostic_group d;                                      
>   \
> +               if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \
> +                                 "division %<sizeof (%T) / sizeof (%T)%> " \
> +                                 "does not compute the number of array " \
> +                                 "elements",                           \
> +                                 type0, type1))                        \
> +                 if (DECL_P (first_arg))                               \
> +                   inform (DECL_SOURCE_LOCATION (first_arg),           \
> +                             "first %<sizeof%> operand was declared here"); \
> +             }                                                         \
> +         }                                                             \
>         break;                                                                
> \
>        default:                                                               
> \
>         break;                                                                
> \
> diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
> index 726ea83..54c7967 100644
> --- a/gcc/c/c-typeck.c
> +++ b/gcc/c/c-typeck.c
> @@ -2906,6 +2906,7 @@ c_expr_sizeof_expr (location_t loc, struct c_expr expr)
>        if (TREE_CODE (expr.value) == PARM_DECL
>           && C_ARRAY_PARAMETER (expr.value))
>         {
> +         auto_diagnostic_group d;
>           if (warning_at (loc, OPT_Wsizeof_array_argument,
>                           "%<sizeof%> on array function parameter %qE will "
>                           "return size of %qT", expr.value,
> @@ -3735,19 +3736,27 @@ parser_build_binary_op (location_t location, enum 
> tree_code code,
>                     "comparison with string literal results in unspecified 
> behavior");
>        /* Warn for ptr == '\0', it's likely that it should've been ptr[0].  */
>        if (POINTER_TYPE_P (type1)
> -          && null_pointer_constant_p (arg2.value)
> -          && char_type_p (type2)
> -          && warning_at (location, OPT_Wpointer_compare,
> -                         "comparison between pointer and zero character "
> -                         "constant"))
> -       inform (arg1.get_start (), "did you mean to dereference the 
> pointer?");
> +         && null_pointer_constant_p (arg2.value)
> +         && char_type_p (type2))
> +       {
> +         auto_diagnostic_group d;
> +         if (warning_at (location, OPT_Wpointer_compare,
> +                           "comparison between pointer and zero character "
> +                           "constant"))
> +           inform (arg1.get_start (),
> +                     "did you mean to dereference the pointer?");
> +       }
>        else if (POINTER_TYPE_P (type2)
>                && null_pointer_constant_p (arg1.value)
> -              && char_type_p (type1)
> -              && warning_at (location, OPT_Wpointer_compare,
> -                             "comparison between pointer and zero character "
> -                             "constant"))
> -       inform (arg2.get_start (), "did you mean to dereference the 
> pointer?");
> +              && char_type_p (type1))
> +       {
> +         auto_diagnostic_group d;
> +         if (warning_at (location, OPT_Wpointer_compare,
> +                           "comparison between pointer and zero character "
> +                           "constant"))
> +           inform (arg2.get_start (),
> +                     "did you mean to dereference the pointer?");
> +       }
>      }
>    else if (TREE_CODE_CLASS (code) == tcc_comparison
>            && (code1 == STRING_CST || code2 == STRING_CST))
> @@ -4288,13 +4297,16 @@ build_unary_op (location_t location, enum tree_code 
> code, tree xarg,
>             e = TREE_OPERAND (e, 1);
>
>           if ((TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE
> -              || truth_value_p (TREE_CODE (e)))
> -             && warning_at (location, OPT_Wbool_operation,
> -                            "%<~%> on a boolean expression"))
> +              || truth_value_p (TREE_CODE (e))))
>             {
> -             gcc_rich_location richloc (location);
> -             richloc.add_fixit_insert_before (location, "!");
> -             inform (&richloc, "did you mean to use logical not?");
> +             auto_diagnostic_group d;
> +             if (warning_at (location, OPT_Wbool_operation,
> +                               "%<~%> on a boolean expression"))
> +               {
> +                 gcc_rich_location richloc (location);
> +                 richloc.add_fixit_insert_before (location, "!");
> +                 inform (&richloc, "did you mean to use logical not?");
> +               }
>             }
>           if (!noconvert)
>             arg = default_conversion (arg);
> @@ -6197,6 +6209,8 @@ error_init (location_t loc, const char *gmsgid)
>  {
>    char *ofwhat;
>
> +  auto_diagnostic_group d;
> +
>    /* The gmsgid may be a format string with %< and %>. */
>    error_at (loc, gmsgid);
>    ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
> @@ -6216,7 +6230,7 @@ pedwarn_init (location_t loc, int opt, const char 
> *gmsgid, ...)
>       it was defined to make sure macros defined in system headers
>       but used incorrectly elsewhere are diagnosed.  */
>    source_location exploc = expansion_point_location_if_in_system_header 
> (loc);
> -
> +  auto_diagnostic_group d;
>    va_list ap;
>    va_start (ap, gmsgid);
>    bool warned = emit_diagnostic_valist (DK_PEDWARN, exploc, opt, gmsgid, 
> &ap);
> @@ -6238,6 +6252,8 @@ warning_init (location_t loc, int opt, const char 
> *gmsgid)
>    char *ofwhat;
>    bool warned;
>
> +  auto_diagnostic_group d;
> +
>    /* Use the location where a macro was expanded rather than where
>       it was defined to make sure macros defined in system headers
>       but used incorrectly elsewhere are diagnosed.  */
> @@ -6379,8 +6395,11 @@ convert_for_assignment (location_t location, 
> location_t expr_loc, tree type,
>      switch (errtype)                                                     \
>        {                                                                  \
>        case ic_argpass:                                                   \
> -        if (pedwarn (PLOC, OPT, AR, parmnum, rname))                    \
> -          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);    \
> +       {                                                               \
> +         auto_diagnostic_group d;                                            
>   \
> +         if (pedwarn (PLOC, OPT, AR, parmnum, rname))          \
> +           inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \
> +       }                                                               \
>          break;                                                           \
>        case ic_assign:                                                    \
>          pedwarn (LOCATION, OPT, AS);                                     \
> @@ -6405,8 +6424,11 @@ convert_for_assignment (location_t location, 
> location_t expr_loc, tree type,
>      switch (errtype)                                                     \
>        {                                                                  \
>        case ic_argpass:                                                   \
> -        if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))             \
> -          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);    \
> +       {                                                               \
> +       auto_diagnostic_group d;                                              
>   \
> +       if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS))             \
> +         inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);     \
> +       }                                                               \
>          break;                                                           \
>        case ic_assign:                                                    \
>          pedwarn (LOCATION, OPT, AS, QUALS);                             \
> @@ -6431,8 +6453,11 @@ convert_for_assignment (location_t location, 
> location_t expr_loc, tree type,
>      switch (errtype)                                                     \
>        {                                                                  \
>        case ic_argpass:                                                   \
> -        if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))           \
> -          inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype);      \
> +       {                                                               \
> +         auto_diagnostic_group d;                                            
>   \
> +         if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS))        \
> +           inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \
> +       }                                                               \
>          break;                                                           \
>        case ic_assign:                                                    \
>          warning_at (LOCATION, OPT, AS, QUALS);                           \
> @@ -6925,6 +6950,7 @@ convert_for_assignment (location_t location, location_t 
> expr_loc, tree type,
>                   {
>                   case ic_argpass:
>                     {
> +                     auto_diagnostic_group d;
>                       range_label_for_type_mismatch rhs_label (rhstype, type);
>                       gcc_rich_location richloc (expr_loc, &rhs_label);
>                       if (pedwarn (&richloc, OPT_Wpointer_sign,
> @@ -6984,6 +7010,7 @@ convert_for_assignment (location_t location, location_t 
> expr_loc, tree type,
>             {
>             case ic_argpass:
>               {
> +               auto_diagnostic_group d;
>                 range_label_for_type_mismatch rhs_label (rhstype, type);
>                 gcc_rich_location richloc (expr_loc, &rhs_label);
>                 if (pedwarn (&richloc, OPT_Wincompatible_pointer_types,
> @@ -7031,6 +7058,7 @@ convert_for_assignment (location_t location, location_t 
> expr_loc, tree type,
>           {
>           case ic_argpass:
>             {
> +             auto_diagnostic_group d;
>               range_label_for_type_mismatch rhs_label (rhstype, type);
>               gcc_rich_location richloc (expr_loc, &rhs_label);
>               if (pedwarn (&richloc, OPT_Wint_conversion,
> @@ -7066,6 +7094,7 @@ convert_for_assignment (location_t location, location_t 
> expr_loc, tree type,
>         {
>         case ic_argpass:
>           {
> +           auto_diagnostic_group d;
>             range_label_for_type_mismatch rhs_label (rhstype, type);
>             gcc_rich_location richloc (expr_loc, &rhs_label);
>             if (pedwarn (&richloc, OPT_Wint_conversion,
> @@ -7109,6 +7138,7 @@ convert_for_assignment (location_t location, location_t 
> expr_loc, tree type,
>      {
>      case ic_argpass:
>        {
> +       auto_diagnostic_group d;
>         range_label_for_type_mismatch rhs_label (rhstype, type);
>         gcc_rich_location richloc (expr_loc, &rhs_label);
>         error_at (&richloc, "incompatible type for argument %d of %qE", 
> parmnum,
> diff --git a/gcc/calls.c b/gcc/calls.c
> index 384c023..0fb10b1 100644
> --- a/gcc/calls.c
> +++ b/gcc/calls.c
> @@ -1773,6 +1773,7 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
>
>        bool warned = false;
>
> +      auto_diagnostic_group d;
>        if (wi::ltu_p (asize, wibnd))
>         {
>           if (bndrng[0] == bndrng[1])
> diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
> index 462e247..208798f 100644
> --- a/gcc/cgraphunit.c
> +++ b/gcc/cgraphunit.c
> @@ -1358,6 +1358,7 @@ maybe_diag_incompatible_alias (tree alias, tree target)
>         {
>           funcptr = build_pointer_type (funcptr);
>
> +         auto_diagnostic_group d;
>           if (warning_at (DECL_SOURCE_LOCATION (target),
>                           OPT_Wattribute_alias,
>                           "%<ifunc%> resolver for %qD should return %qT",
> @@ -1365,12 +1366,16 @@ maybe_diag_incompatible_alias (tree alias, tree 
> target)
>             inform (DECL_SOURCE_LOCATION (alias),
>                     "resolver indirect function declared here");
>         }
> -      else if (warning_at (DECL_SOURCE_LOCATION (alias),
> -                          OPT_Wattribute_alias,
> -                          "%qD alias between functions of incompatible "
> -                          "types %qT and %qT", alias, altype, targtype))
> -       inform (DECL_SOURCE_LOCATION (target),
> -               "aliased declaration here");
> +      else
> +       {
> +         auto_diagnostic_group d;
> +         if (warning_at (DECL_SOURCE_LOCATION (alias),
> +                           OPT_Wattribute_alias,
> +                           "%qD alias between functions of incompatible "
> +                           "types %qT and %qT", alias, altype, targtype))
> +           inform (DECL_SOURCE_LOCATION (target),
> +                     "aliased declaration here");
> +       }
>      }
>  }
>
> diff --git a/gcc/cp/call.c b/gcc/cp/call.c
> index 16bb6bf..1f72ac8 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -3968,6 +3968,7 @@ build_user_type_conversion_1 (tree totype, tree expr, 
> int flags,
>      {
>        if (complain & tf_error)
>         {
> +         auto_diagnostic_group d;
>           error ("conversion from %qH to %qI is ambiguous",
>                  fromtype, totype);
>           print_z_candidates (location_of (expr), candidates);
> @@ -4280,6 +4281,7 @@ print_error_for_call_failure (tree fn, vec<tree, va_gc> 
> *args,
>    if (targs)
>      name = lookup_template_function (name, targs);
>
> +  auto_diagnostic_group d;
>    if (!any_strictly_viable (candidates))
>      error_at (loc, "no matching function for call to %<%D(%A)%>",
>               name, build_tree_list_vec (args));
> @@ -4590,6 +4592,7 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, 
> tsubst_flags_t complain)
>      {
>        if (complain & tf_error)
>          {
> +          auto_diagnostic_group d;
>            error ("no match for call to %<(%T) (%A)%>", TREE_TYPE (obj),
>                  build_tree_list_vec (*args));
>            print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
> @@ -4603,6 +4606,7 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, 
> tsubst_flags_t complain)
>         {
>            if (complain & tf_error)
>              {
> +              auto_diagnostic_group d;
>                error ("call of %<(%T) (%A)%> is ambiguous",
>                       TREE_TYPE (obj), build_tree_list_vec (*args));
>                print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
> @@ -5229,6 +5233,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, 
> tree arg2, tree arg3,
>         {
>            if (complain & tf_error)
>              {
> +              auto_diagnostic_group d;
>                op_error (loc, COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
>                print_z_candidates (loc, candidates);
>              }
> @@ -5860,6 +5865,7 @@ build_new_op_1 (location_t loc, enum tree_code code, 
> int flags, tree arg1,
>                   {
>                     /* ... Otherwise, report the more generic
>                        "no matching operator found" error */
> +                   auto_diagnostic_group d;
>                     op_error (loc, code, code2, arg1, arg2, arg3, FALSE);
>                     print_z_candidates (loc, candidates);
>                   }
> @@ -5875,6 +5881,7 @@ build_new_op_1 (location_t loc, enum tree_code code, 
> int flags, tree arg1,
>         {
>           if (complain & tf_error)
>             {
> +             auto_diagnostic_group d;
>               op_error (loc, code, code2, arg1, arg2, arg3, TRUE);
>               print_z_candidates (loc, candidates);
>             }
> @@ -6311,14 +6318,18 @@ build_op_delete_call (enum tree_code code, tree addr, 
> tree size,
>              -Wc++14-compat.  */
>           else if (!flag_sized_deallocation)
>             {
> -             if ((complain & tf_warning)
> -                 && warning (OPT_Wc__14_compat, msg1))
> -               inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
> +             if (complain & tf_warning)
> +               {
> +                 auto_diagnostic_group d;
> +                 if (warning (OPT_Wc__14_compat, msg1))
> +                   inform (DECL_SOURCE_LOCATION (fn), msg2, fn);
> +               }
>               goto ok;
>             }
>
>           if (complain & tf_warning_or_error)
>             {
> +             auto_diagnostic_group d;
>               if (permerror (input_location, msg1))
>                 {
>                   /* Only mention C++14 for namespace-scope delete.  */
> @@ -6712,6 +6723,7 @@ convert_like_real (conversion *convs, tree expr, tree 
> fn, int argnum,
>         {
>           if (t->kind == ck_user && t->cand->reason)
>             {
> +             auto_diagnostic_group d;
>               complained = permerror (loc, "invalid user-defined conversion "
>                                       "from %qH to %qI", TREE_TYPE (expr),
>                                       totype);
> @@ -6795,6 +6807,7 @@ convert_like_real (conversion *convs, tree expr, tree 
> fn, int argnum,
>             if (CONSTRUCTOR_NELTS (expr) == 0
>                 && FUNCTION_FIRST_USER_PARMTYPE (convfn) != void_list_node)
>               {
> +               auto_diagnostic_group d;
>                 if (pedwarn (loc, 0, "converting to %qT from initializer list 
> "
>                              "would use explicit constructor %qD",
>                              totype, convfn))
> @@ -6973,6 +6986,7 @@ convert_like_real (conversion *convs, tree expr, tree 
> fn, int argnum,
>         {
>           if (complain & tf_error)
>             {
> +             auto_diagnostic_group d;
>               maybe_print_user_conv_context (convs);
>               if (fn)
>                 inform (DECL_SOURCE_LOCATION (fn),
> @@ -7025,6 +7039,7 @@ convert_like_real (conversion *convs, tree expr, tree 
> fn, int argnum,
>        expr = build_temp (expr, totype, flags, &diag_kind, complain);
>        if (diag_kind && complain)
>         {
> +         auto_diagnostic_group d;
>           maybe_print_user_conv_context (convs);
>           if (fn)
>             inform (DECL_SOURCE_LOCATION (fn),
> @@ -7040,6 +7055,7 @@ convert_like_real (conversion *convs, tree expr, tree 
> fn, int argnum,
>         if (convs->bad_p && !next_conversion (convs)->bad_p)
>           {
>             tree extype = TREE_TYPE (expr);
> +           auto_diagnostic_group d;
>             if (TYPE_REF_IS_RVALUE (ref_type)
>                 && lvalue_p (expr))
>               error_at (loc, "cannot bind rvalue reference of type %qH to "
> @@ -7931,6 +7947,7 @@ build_over_call (struct z_candidate *cand, int flags, 
> tsubst_flags_t complain)
>         {
>           if (complain & tf_error)
>             {
> +             auto_diagnostic_group d;
>               if (permerror (input_location, "passing %qT as %<this%> "
>                              "argument discards qualifiers",
>                              TREE_TYPE (argtype)))
> @@ -9212,6 +9229,7 @@ build_new_method_call_1 (tree instance, tree fns, 
> vec<tree, va_gc> **args,
>
>        basetype = DECL_CONTEXT (fn);
>        name = constructor_name (basetype);
> +      auto_diagnostic_group d;
>        if (permerror (input_location,
>                      "cannot call constructor %<%T::%D%> directly",
>                      basetype, name))
> @@ -9350,6 +9368,7 @@ build_new_method_call_1 (tree instance, tree fns, 
> vec<tree, va_gc> **args,
>      {
>        if (complain & tf_error)
>         {
> +         auto_diagnostic_group d;
>           if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
>             cxx_incomplete_type_error (instance, basetype);
>           else if (optype)
> @@ -9393,6 +9412,7 @@ build_new_method_call_1 (tree instance, tree fns, 
> vec<tree, va_gc> **args,
>               arglist = build_tree_list_vec (user_args);
>               if (skip_first_for_error)
>                 arglist = TREE_CHAIN (arglist);
> +             auto_diagnostic_group d;
>               if (!any_strictly_viable (candidates))
>                 error ("no matching function for call to %<%s(%A)%>",
>                        pretty_name, arglist);
> @@ -10299,6 +10319,7 @@ joust (struct z_candidate *cand1, struct z_candidate 
> *cand2, bool warn,
>           tree source = source_type (w->convs[0]);
>           if (INDIRECT_TYPE_P (source))
>             source = TREE_TYPE (source);
> +         auto_diagnostic_group d;
>           if (warning (OPT_Wconversion, "choosing %qD over %qD", w->fn, l->fn)
>               && warning (OPT_Wconversion, "  for conversion from %qH to %qI",
>                           source, w->second_conv->type))
> @@ -10526,6 +10547,7 @@ joust (struct z_candidate *cand1, struct z_candidate 
> *cand2, bool warn,
>                 {
>                   if (complain & tf_error)
>                     {
> +                     auto_diagnostic_group d;
>                       if (permerror (input_location,
>                                      "default argument mismatch in "
>                                      "overload resolution"))
> @@ -10577,6 +10599,7 @@ tweak:
>             return 0;
>           if (warn)
>             {
> +             auto_diagnostic_group d;
>               pedwarn (input_location, 0,
>               "ISO C++ says that these are ambiguous, even "
>               "though the worst conversion for the first is better than "
> diff --git a/gcc/cp/class.c b/gcc/cp/class.c
> index 7b10b20..e11173d 100644
> --- a/gcc/cp/class.c
> +++ b/gcc/cp/class.c
> @@ -1331,6 +1331,7 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
>        /* Otherwise we're diagnosing missing tags.  */
>        if (TREE_CODE (p->t) == FUNCTION_DECL)
>         {
> +         auto_diagnostic_group d;
>           if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
>                        "that %qT (used in its return type) has",
>                        p->t, tag, *tp))
> @@ -1338,12 +1339,14 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data 
> *p)
>         }
>        else if (VAR_P (p->t))
>         {
> +         auto_diagnostic_group d;
>           if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
>                        "that %qT (used in its type) has", p->t, tag, *tp))
>             inform (location_of (*tp), "%qT declared here", *tp);
>         }
>        else if (TYPE_P (p->subob))
>         {
> +         auto_diagnostic_group d;
>           if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
>                        "that base %qT has", p->t, tag, p->subob))
>             inform (location_of (p->subob), "%qT declared here",
> @@ -1351,6 +1354,7 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
>         }
>        else
>         {
> +         auto_diagnostic_group d;
>           if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
>                        "that %qT (used in the type of %qD) has",
>                        p->t, tag, *tp, p->subob))
> @@ -2904,20 +2908,24 @@ finish_struct_anon_r (tree field, bool complain)
>         {
>           /* We already complained about static data members in
>              finish_static_data_member_decl.  */
> -         if (!VAR_P (elt)
> -             && permerror (DECL_SOURCE_LOCATION (elt),
> -                           TREE_CODE (TREE_TYPE (field)) == UNION_TYPE
> -                           ? "%q#D invalid; an anonymous union may "
> -                           "only have public non-static data members"
> -                           : "%q#D invalid; an anonymous struct may "
> -                           "only have public non-static data members", elt))
> +         if (!VAR_P (elt))
>             {
> -             static bool hint;
> -             if (flag_permissive && !hint)
> +             auto_diagnostic_group d;
> +             if (permerror (DECL_SOURCE_LOCATION (elt),
> +                            TREE_CODE (TREE_TYPE (field)) == UNION_TYPE
> +                            ? "%q#D invalid; an anonymous union may "
> +                            "only have public non-static data members"
> +                            : "%q#D invalid; an anonymous struct may "
> +                            "only have public non-static data members", elt))
>                 {
> -                 hint = true;
> -                 inform (DECL_SOURCE_LOCATION (elt),
> -                         "this flexibility is deprecated and will be 
> removed");
> +                 static bool hint;
> +                 if (flag_permissive && !hint)
> +                   {
> +                     hint = true;
> +                     inform (DECL_SOURCE_LOCATION (elt),
> +                             "this flexibility is deprecated and will be "
> +                             "removed");
> +                   }
>                 }
>             }
>         }
> @@ -3107,6 +3115,7 @@ one_inherited_ctor (tree ctor, tree t, tree using_decl)
>    one_inheriting_sig (t, ctor, new_parms, i);
>    if (parms == NULL_TREE)
>      {
> +      auto_diagnostic_group d;
>        if (warning (OPT_Winherited_variadic_ctor,
>                    "the ellipsis in %qD is not inherited", ctor))
>         inform (DECL_SOURCE_LOCATION (ctor), "%qD declared here", ctor);
> @@ -5399,11 +5408,14 @@ finalize_literal_type_property (tree t)
>           && !DECL_CONSTRUCTOR_P (fn))
>         {
>           DECL_DECLARED_CONSTEXPR_P (fn) = false;
> -         if (!DECL_GENERATED_P (fn)
> -             && pedwarn (DECL_SOURCE_LOCATION (fn), OPT_Wpedantic,
> -                         "enclosing class of %<constexpr%> non-static member 
> "
> -                         "function %q+#D is not a literal type", fn))
> -           explain_non_literal_class (t);
> +         if (!DECL_GENERATED_P (fn))
> +           {
> +             auto_diagnostic_group d;
> +             if (pedwarn (DECL_SOURCE_LOCATION (fn), OPT_Wpedantic,
> +                            "enclosing class of %<constexpr%> non-static "
> +                            "member function %q+#D is not a literal type", 
> fn))
> +               explain_non_literal_class (t);
> +           }
>         }
>  }
>
> @@ -5425,6 +5437,7 @@ explain_non_literal_class (tree t)
>      /* Already explained.  */
>      return;
>
> +  auto_diagnostic_group d;
>    inform (UNKNOWN_LOCATION, "%q+T is not literal because:", t);
>    if (cxx_dialect < cxx17 && LAMBDA_TYPE_P (t))
>      inform (UNKNOWN_LOCATION,
> @@ -6626,17 +6639,20 @@ find_flexarrays (tree t, flexmems_t *fmem, bool 
> base_p,
>  static void
>  diagnose_invalid_flexarray (const flexmems_t *fmem)
>  {
> -  if (fmem->array && fmem->enclosing
> -      && pedwarn (l

Reply via email to