Ping for https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659796.html

For clarity's sake, here's the full patch with the adjustment I
mentioned earlier:

-- >8 --

This patch goes through all .cc files in gcc/cp and adds in any
auto_diagnostic_groups that seem to be missing by looking for any
'inform' calls that aren't grouped with their respective error/warning.
Now with SARIF output support this seems to be a bit more important.

The patch isn't complete; I've tried to also track helper functions used
for diagnostics to group them, but some may have been missed.
Additionally there are a few functions that are definitely missing
groupings but I wasn't able to see an obvious way to add them without
potentially grouping together unrelated messages.

This list includes:

- lazy_load_{binding,pendings} "during load of {binding,pendings} for"
- cp_finish_decomp "in initialization of structured binding variable"
- require_deduced_type "using __builtin_source_location"
- convert_nontype_argument "in template argument for type %qT"
- coerce_template_params "so any instantiation with a non-empty parameter pack"
- tsubst_default_argument "when instantiating default argument"
- invalid_nontype_parm_type_p "invalid template non-type parameter"

gcc/cp/ChangeLog:

        * class.cc (add_method): Add missing auto_diagnostic_group.
        (handle_using_decl): Likewise.
        (maybe_warn_about_overly_private_class): Likewise.
        (check_field_decl): Likewise.
        (check_field_decls): Likewise.
        (resolve_address_of_overloaded_function): Likewise.
        (note_name_declared_in_class): Likewise.
        * constraint.cc (associate_classtype_constraints): Likewise.
        (diagnose_trait_expr): Clean up whitespace.
        * coroutines.cc (find_coro_traits_template_decl): Add missing
        auto_diagnostic_group.
        (coro_promise_type_found_p): Likewise.
        (coro_diagnose_throwing_fn): Likewise.
        * cvt.cc (build_expr_type_conversion): Likewise.
        * decl.cc (validate_constexpr_redeclaration): Likewise.
        (duplicate_function_template_decls): Likewise.
        (duplicate_decls): Likewise.
        (lookup_label_1): Likewise.
        (check_previous_goto_1): Likewise.
        (check_goto_1): Likewise.
        (make_typename_type): Likewise.
        (make_unbound_class_template): Likewise.
        (check_tag_decl): Likewise.
        (start_decl): Likewise.
        (maybe_commonize_var): Likewise.
        (check_for_uninitialized_const_var): Likewise.
        (reshape_init_class): Likewise.
        (check_initializer): Likewise.
        (cp_finish_decl): Likewise.
        (find_decomp_class_base): Likewise.
        (cp_finish_decomp): Likewise.
        (expand_static_init): Likewise.
        (grokfndecl): Likewise.
        (grokdeclarator): Likewise.
        (check_elaborated_type_specifier): Likewise.
        (lookup_and_check_tag): Likewise.
        (xref_tag): Likewise.
        (cxx_simulate_enum_decl): Likewise.
        (finish_function): Likewise.
        * decl2.cc (check_classfn): Likewise.
        (record_mangling): Likewise.
        (mark_used): Likewise.
        * error.cc (qualified_name_lookup_error): Likewise.
        * except.cc (build_throw): Likewise.
        * init.cc (get_nsdmi): Likewise.
        (diagnose_uninitialized_cst_or_ref_member_1): Likewise.
        (warn_placement_new_too_small): Likewise.
        (build_new_1): Likewise.
        (build_vec_delete_1): Likewise.
        (build_delete): Likewise.
        * lambda.cc (add_capture): Likewise.
        (add_default_capture): Likewise.
        * lex.cc (unqualified_fn_lookup_error): Likewise.
        * method.cc (synthesize_method): Likewise.
        (defaulted_late_check): Likewise.
        * module.cc (trees_in::is_matching_decl): Likewise.
        (trees_in::read_enum_def): Likewise.
        (module_state::check_not_purview): Likewise.
        (module_state::deferred_macro): Likewise.
        (module_state::read_config): Likewise.
        (module_state::check_read): Likewise.
        (declare_module): Likewise.
        (init_modules): Likewise.
        * name-lookup.cc (diagnose_name_conflict): Likewise.
        (lookup_using_decl): Likewise.
        (set_decl_namespace): Likewise.
        (finish_using_directive): Likewise.
        (push_namespace): Likewise.
        (add_imported_namespace): Likewise.
        * parser.cc (cp_parser_check_for_definition_in_return_type): Likewise.
        (cp_parser_userdef_numeric_literal): Likewise.
        (cp_parser_nested_name_specifier_opt): Likewise.
        (cp_parser_new_expression): Likewise.
        (cp_parser_binary_expression): Likewise.
        (cp_parser_lambda_introducer): Likewise.
        (cp_parser_module_declaration): Likewise.
        (cp_parser_import_declaration): Likewise, removing gotos to
        support this.
        (cp_parser_declaration): Add missing auto_diagnostic_group.
        (cp_parser_decl_specifier_seq): Likewise.
        (cp_parser_template_id): Likewise.
        (cp_parser_template_name): Likewise.
        (cp_parser_explicit_specialization): Likewise.
        (cp_parser_placeholder_type_specifier): Likewise.
        (cp_parser_elaborated_type_specifier): Likewise.
        (cp_parser_enum_specifier): Likewise.
        (cp_parser_asm_definition): Likewise.
        (cp_parser_init_declarator): Likewise.
        (cp_parser_direct_declarator): Likewise.
        (cp_parser_class_head): Likewise.
        (cp_parser_member_declaration): Likewise.
        (cp_parser_lookup_name): Likewise.
        (cp_parser_explicit_template_declaration): Likewise.
        (cp_parser_check_class_key): Likewise.
        * pt.cc (maybe_process_partial_specialization): Likewise.
        (determine_specialization): Likewise.
        (check_for_bare_parameter_packs): Likewise.
        (check_template_shadow): Likewise.
        (process_partial_specialization): Likewise.
        (push_template_decl): Likewise.
        (redeclare_class_template): Likewise.
        (convert_nontype_argument_function): Likewise.
        (check_valid_ptrmem_cst_expr): Likewise.
        (convert_nontype_argument): Likewise.
        (convert_template_argument): Likewise.
        (coerce_template_parms): Likewise.
        (tsubst_qualified_id): Likewise.
        (tsubst_expr): Likewise.
        (most_specialized_partial_spec): Likewise.
        (do_class_deduction): Likewise.
        (do_auto_deduction): Likewise.
        * search.cc (lookup_member): Likewise.
        * semantics.cc (finish_non_static_data_member): Likewise.
        (process_outer_var_ref): Likewise.
        (finish_id_expression_1): Likewise.
        (finish_offsetof): Likewise.
        (omp_reduction_lookup): Likewise.
        (finish_omp_clauses): Likewise.
        * tree.cc (check_abi_tag_redeclaration): Likewise.
        (check_abi_tag_args): Likewise.
        * typeck.cc (invalid_nonstatic_memfn_p): Likewise.
        (complain_about_unrecognized_member): Likewise.
        (finish_class_member_access_expr): Likewise.
        (error_args_num): Likewise.
        (warn_for_null_address): Likewise.
        (cp_build_binary_op): Likewise.
        (build_x_unary_op): Likewise.
        (cp_build_unary_op): Likewise.
        (build_static_cast): Likewise.
        (cp_build_modify_expr): Likewise.
        (get_delta_difference): Likewise.
        (convert_for_assignment): Widen scope of auto_diagnostic_group.
        (check_return_expr): Add missing auto_diagnostic_group.
        * typeck2.cc (cxx_incomplete_type_diagnostic): Likewise.

Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
Reviewed-by: Marek Polacek <pola...@redhat.com>
---
 gcc/cp/class.cc       |  12 +++++
 gcc/cp/constraint.cc  |  21 +++++----
 gcc/cp/coroutines.cc  |   3 ++
 gcc/cp/cvt.cc         |   1 +
 gcc/cp/decl.cc        |  59 +++++++++++++++++++++--
 gcc/cp/decl2.cc       |   3 ++
 gcc/cp/error.cc       |   2 +
 gcc/cp/except.cc      |   1 +
 gcc/cp/init.cc        |   8 ++++
 gcc/cp/lambda.cc      |   3 ++
 gcc/cp/lex.cc         |   1 +
 gcc/cp/method.cc      |   3 ++
 gcc/cp/module.cc      |   8 ++++
 gcc/cp/name-lookup.cc |   7 +++
 gcc/cp/parser.cc      | 107 ++++++++++++++++++++++++++++--------------
 gcc/cp/pt.cc          |  65 ++++++++++++++++++-------
 gcc/cp/search.cc      |   1 +
 gcc/cp/semantics.cc   |   9 ++++
 gcc/cp/tree.cc        |   3 ++
 gcc/cp/typeck.cc      |  79 +++++++++++++++++++------------
 gcc/cp/typeck2.cc     |   1 +
 21 files changed, 303 insertions(+), 94 deletions(-)

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index fb6c3370950..950d83b0ea4 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -1431,6 +1431,7 @@ add_method (tree type, tree method, bool via_using)
                continue;
            }
 
+         auto_diagnostic_group d;
          error_at (DECL_SOURCE_LOCATION (method),
                    "%q#D conflicts with version inherited from %qT",
                    method, basef);
@@ -1453,6 +1454,7 @@ add_method (tree type, tree method, bool via_using)
        }
       else
        {
+         auto_diagnostic_group d;
          error_at (DECL_SOURCE_LOCATION (method),
                    "%q#D cannot be overloaded with %q#D", method, fn);
          inform (DECL_SOURCE_LOCATION (fn),
@@ -1604,6 +1606,7 @@ handle_using_decl (tree using_decl, tree t)
     ;
   else if (is_overloaded_fn (old_value))
     {
+      auto_diagnostic_group d;
       error_at (DECL_SOURCE_LOCATION (using_decl), "%qD invalid in %q#T "
                "because of local method %q#D with same name",
                using_decl, t, old_value);
@@ -1613,6 +1616,7 @@ handle_using_decl (tree using_decl, tree t)
     }
   else if (!DECL_ARTIFICIAL (old_value))
     {
+      auto_diagnostic_group d;
       error_at (DECL_SOURCE_LOCATION (using_decl), "%qD invalid in %q#T "
                "because of local member %q#D with same name",
                using_decl, t, old_value);
@@ -2547,6 +2551,7 @@ maybe_warn_about_overly_private_class (tree t)
 
       if (!nonprivate_ctor)
        {
+         auto_diagnostic_group d;
          bool w = warning (OPT_Wctor_dtor_privacy,
                            "%q#T only defines private constructors and has "
                            "no friends", t);
@@ -3815,6 +3820,7 @@ check_field_decl (tree field,
       if (TREE_CODE (t) == UNION_TYPE && cxx_dialect < cxx11)
        {
          static bool warned;
+         auto_diagnostic_group d;
          int oldcount = errorcount;
          if (TYPE_NEEDS_CONSTRUCTING (type))
            error ("member %q+#D with constructor not allowed in union",
@@ -4131,6 +4137,7 @@ check_field_decls (tree t, tree *access_decls,
          if (default_init_member
              && TREE_CODE (t) == UNION_TYPE)
            {
+             auto_diagnostic_group d;
              error ("multiple fields in union %qT initialized", t);
              inform (DECL_SOURCE_LOCATION (default_init_member),
                      "initialized member %q+D declared here",
@@ -4209,6 +4216,7 @@ check_field_decls (tree t, tree *access_decls,
       && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
       && !(TYPE_HAS_COPY_CTOR (t) && TYPE_HAS_COPY_ASSIGN (t)))
     {
+      auto_diagnostic_group d;
       if (warning (OPT_Weffc__, "%q#T has pointer data members", t))
        {
          if (! TYPE_HAS_COPY_CTOR (t))
@@ -8913,6 +8921,7 @@ resolve_address_of_overloaded_function (tree target_type,
       /* There were *no* matches.  */
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          error ("no matches converting function %qD to type %q#T",
                 OVL_NAME (overload), target_type);
 
@@ -8940,6 +8949,7 @@ resolve_address_of_overloaded_function (tree target_type,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              error ("converting overloaded function %qD to type %q#T is 
ambiguous",
                     OVL_NAME (overload), target_type);
 
@@ -9397,6 +9407,8 @@ note_name_declared_in_class (tree name, tree decl)
       else
        /* Make it an error.  */
        global_dc->m_pedantic_errors = 1;
+
+      auto_diagnostic_group d;
       if (pedwarn (location_of (decl), OPT_Wchanges_meaning,
                   "declaration of %q#D changes meaning of %qD",
                   decl, OVL_NAME (decl)))
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f79407f2cdb..ebfcdefd284 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1005,6 +1005,7 @@ associate_classtype_constraints (tree type)
            }
           if (!equivalent_constraints (ci, orig_ci))
             {
+             auto_diagnostic_group d;
              error ("%qT does not match original declaration", type);
              tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
              location_t loc = DECL_SOURCE_LOCATION (tmpl);
@@ -3183,9 +3184,9 @@ diagnose_trait_expr (tree expr, tree args)
       break;
     case CPTK_IS_CONSTRUCTIBLE:
       if (!t2)
-    inform (loc, "  %qT is not default constructible", t1);
+       inform (loc, "  %qT is not default constructible", t1);
       else
-    inform (loc, "  %qT is not constructible from %qE", t1, t2);
+       inform (loc, "  %qT is not constructible from %qE", t1, t2);
       break;
     case CPTK_IS_CONVERTIBLE:
       inform (loc, "  %qT is not convertible from %qE", t2, t1);
@@ -3204,9 +3205,9 @@ diagnose_trait_expr (tree expr, tree args)
       break;
     case CPTK_IS_INVOCABLE:
       if (!t2)
-    inform (loc, "  %qT is not invocable", t1);
+       inform (loc, "  %qT is not invocable", t1);
       else
-    inform (loc, "  %qT is not invocable by %qE", t1, t2);
+       inform (loc, "  %qT is not invocable by %qE", t1, t2);
       break;
     case CPTK_IS_LAYOUT_COMPATIBLE:
       inform (loc, "  %qT is not layout compatible with %qT", t1, t2);
@@ -3233,14 +3234,14 @@ diagnose_trait_expr (tree expr, tree args)
        inform (loc, "  %qT is not nothrow constructible from %qE", t1, t2);
       break;
     case CPTK_IS_NOTHROW_CONVERTIBLE:
-         inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
+      inform (loc, "  %qT is not nothrow convertible from %qE", t2, t1);
       break;
     case CPTK_IS_NOTHROW_INVOCABLE:
-       if (!t2)
-         inform (loc, "  %qT is not nothrow invocable", t1);
-       else
-         inform (loc, "  %qT is not nothrow invocable by %qE", t1, t2);
-       break;
+      if (!t2)
+       inform (loc, "  %qT is not nothrow invocable", t1);
+      else
+       inform (loc, "  %qT is not nothrow invocable by %qE", t1, t2);
+      break;
     case CPTK_IS_OBJECT:
       inform (loc, "  %qT is not an object type", t1);
       break;
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 20bda5520c0..e605eaec7a4 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -305,6 +305,7 @@ find_coro_traits_template_decl (location_t kw)
     {
       if (!traits_error_emitted)
        {
+         auto_diagnostic_group d;
          gcc_rich_location richloc (kw);
          error_at (&richloc, "coroutines require a traits template; cannot"
                    " find %<%E::%E%>", std_node, coro_traits_identifier);
@@ -632,6 +633,7 @@ coro_promise_type_found_p (tree fndecl, location_t loc)
                                        tf_none);
       if (has_ret_void && has_ret_val)
        {
+         auto_diagnostic_group d;
          location_t ploc = DECL_SOURCE_LOCATION (fndecl);
          if (!coro_info->coro_co_return_error_emitted)
            error_at (ploc, "the coroutine promise type %qT declares both"
@@ -1025,6 +1027,7 @@ coro_diagnose_throwing_fn (tree fndecl)
 {
   if (!TYPE_NOTHROW_P (TREE_TYPE (fndecl)))
     {
+      auto_diagnostic_group d;
       location_t f_loc = cp_expr_loc_or_loc (fndecl,
                                             DECL_SOURCE_LOCATION (fndecl));
       error_at (f_loc, "the expression %qE is required to be non-throwing",
diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index 7b4bd8a9dc4..df02b8faaf5 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -1933,6 +1933,7 @@ build_expr_type_conversion (int desires, tree expr, bool 
complain)
                {
                  if (complain)
                    {
+                     auto_diagnostic_group d;
                      error ("ambiguous default type conversion from %qT",
                             basetype);
                      inform (input_location,
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 6458e96bded..7bad3047ad9 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1457,6 +1457,7 @@ validate_constexpr_redeclaration (tree old_decl, tree 
new_decl)
       if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
          || DECL_IMMEDIATE_FUNCTION_P (new_decl))
        kind = "consteval";
+      auto_diagnostic_group d;
       error_at (DECL_SOURCE_LOCATION (new_decl),
                "redeclaration %qD differs in %qs "
                "from previous declaration", new_decl,
@@ -1567,6 +1568,7 @@ duplicate_function_template_decls (tree newdecl, tree 
olddecl)
       if (template_heads_equivalent_p (newdecl, olddecl)
          && function_requirements_equivalent_p (newres, oldres))
        {
+         auto_diagnostic_group d;
          error ("ambiguating new declaration %q+#D", newdecl);
          inform (DECL_SOURCE_LOCATION (olddecl),
                  "old declaration %q#D", olddecl);
@@ -1902,6 +1904,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
            return NULL_TREE;
 
          /* There can only be one!  */
+         auto_diagnostic_group d;
          if (TREE_CODE (newdecl) == TEMPLATE_DECL
              && check_raw_literal_operator (olddecl))
            error_at (newdecl_loc,
@@ -1924,6 +1927,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
        /* One is an implicit typedef, that's ok.  */
        return NULL_TREE;
 
+      auto_diagnostic_group d;
       error ("%q#D redeclared as different kind of entity", newdecl);
       inform (olddecl_loc, "previous declaration %q#D", olddecl);
 
@@ -1947,6 +1951,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
          if (TREE_CODE (oldres) == TYPE_DECL
              || TREE_CODE (newres) == TYPE_DECL)
            {
+             auto_diagnostic_group d;
              error_at (newdecl_loc,
                        "conflicting declaration of template %q#D", newdecl);
              inform (olddecl_loc,
@@ -1967,6 +1972,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
        {
          if (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl))
            {
+             auto_diagnostic_group d;
              error_at (newdecl_loc,
                        "conflicting declaration of C function %q#D",
                        newdecl);
@@ -1988,6 +1994,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
                    // And the same constraints.
                    && equivalently_constrained (newdecl, olddecl))
            {
+             auto_diagnostic_group d;
              error_at (newdecl_loc,
                        "ambiguating new declaration of %q#D", newdecl);
              inform (olddecl_loc,
@@ -1999,6 +2006,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
        }
       else
        {
+         auto_diagnostic_group d;
          error_at (newdecl_loc, "conflicting declaration %q#D", newdecl);
          inform (olddecl_loc,
                  "previous declaration as %q#D", olddecl);
@@ -2010,6 +2018,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
     {
       /* OMP UDRs are never duplicates. */
       gcc_assert (DECL_OMP_DECLARE_REDUCTION_P (olddecl));
+      auto_diagnostic_group d;
       error_at (newdecl_loc,
                "redeclaration of %<pragma omp declare reduction%>");
       inform (olddecl_loc,
@@ -2311,10 +2320,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
     {
       if (merge_attr)
        {
-         if (diagnose_mismatched_attributes (olddecl, newdecl))
-           inform (olddecl_loc, DECL_INITIAL (olddecl)
-                   ? G_("previous definition of %qD here")
-                   : G_("previous declaration of %qD here"), olddecl);
+         {
+           auto_diagnostic_group d;
+           if (diagnose_mismatched_attributes (olddecl, newdecl))
+             inform (olddecl_loc, DECL_INITIAL (olddecl)
+                     ? G_("previous definition of %qD here")
+                     : G_("previous declaration of %qD here"), olddecl);
+         }
 
          /* [dcl.attr.noreturn]: The first declaration of a function shall
             specify the noreturn attribute if any declaration of that function
@@ -2327,6 +2339,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, 
bool was_hidden)
              && cxx11_attribute_p (a)
              && get_attribute_namespace (a) == NULL_TREE)
            {
+             auto_diagnostic_group d;
              error_at (newdecl_loc, "function %qD declared %<[[noreturn]]%> "
                        "but its first declaration was not", newdecl);
              inform (olddecl_loc, "previous declaration of %qD", olddecl);
@@ -3597,6 +3610,7 @@ lookup_label_1 (tree id, bool making_local_p)
 
       if (old->binding_level == current_binding_level)
        {
+         auto_diagnostic_group d;
          error ("local label %qE conflicts with existing label", id);
          inform (DECL_SOURCE_LOCATION (old->label_decl), "previous label");
          return NULL;
@@ -3712,6 +3726,7 @@ check_previous_goto_1 (tree decl, cp_binding_level* 
level, tree names,
                       bool exited_omp, const location_t *locus,
                       vec<tree,va_gc> *computed)
 {
+  auto_diagnostic_group d;
   cp_binding_level *b;
   bool complained = false;
   int identified = 0;
@@ -3858,6 +3873,7 @@ check_switch_goto (cp_binding_level* level)
 void
 check_goto_1 (named_label_entry *ent, bool computed)
 {
+  auto_diagnostic_group d;
   tree decl = ent->label_decl;
 
   /* If the label hasn't been defined yet, defer checking.  */
@@ -4531,6 +4547,7 @@ make_typename_type (tree context, tree name, enum 
tag_types tag_type,
     {
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          error ("lookup of %qT in %qT is ambiguous", name, context);
          print_candidates (t);
        }
@@ -4626,6 +4643,7 @@ make_unbound_class_template (tree context, tree name, 
tree parm_list,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              error ("template parameters do not match template %qD", tmpl);
              inform (DECL_SOURCE_LOCATION (tmpl),
                      "%qD declared here", tmpl);
@@ -5764,6 +5782,7 @@ check_tag_decl (cp_decl_specifier_seq *declspecs,
               No attribute-specifier-seq shall appertain to an explicit
               instantiation.  */
        {
+         auto_diagnostic_group d;
          if (warning_at (loc, OPT_Wattributes,
                          "attribute ignored in explicit instantiation %q#T",
                          declared_type))
@@ -5999,6 +6018,7 @@ start_decl (const cp_declarator *declarator,
            /* OK, specialization was already checked.  */;
          else if (variable_template_p (field) && !this_tmpl)
            {
+             auto_diagnostic_group d;
              error_at (DECL_SOURCE_LOCATION (decl),
                        "non-member-template declaration of %qD", decl);
              inform (DECL_SOURCE_LOCATION (field), "does not match "
@@ -6661,6 +6681,7 @@ maybe_commonize_var (tree decl)
                msg = G_("sorry: semantics of inline function "
                         "static data %q#D are wrong (you%'ll wind "
                         "up with multiple copies)");
+             auto_diagnostic_group d;
              if (warning_at (DECL_SOURCE_LOCATION (decl), 0,
                              msg, decl))
                inform (DECL_SOURCE_LOCATION (decl),
@@ -6698,6 +6719,7 @@ check_for_uninitialized_const_var (tree decl, bool 
constexpr_context_p,
       if (!field)
        return true;
 
+      auto_diagnostic_group d;
       bool show_notes = true;
 
       if (!constexpr_context_p || cxx_dialect >= cxx20)
@@ -7062,6 +7084,7 @@ reshape_init_class (tree type, reshape_iter *d, bool 
first_initializer_p,
                {
                  if (field && TREE_CODE (field) == TREE_LIST)
                    {
+                     auto_diagnostic_group g;
                      error ("request for member %qD is ambiguous",
                             d->cur->index);
                      print_candidates (field);
@@ -7884,6 +7907,7 @@ check_initializer (tree decl, tree init, int flags, 
vec<tree, va_gc> **cleanups)
     {
       static int explained = 0;
 
+      auto_diagnostic_group d;
       if (cxx_dialect < cxx11)
        error ("initializer invalid for static member with constructor");
       else if (cxx_dialect < cxx17)
@@ -8560,6 +8584,7 @@ cp_finish_decl (tree decl, tree init, bool 
init_const_expr_p,
          && !type_uses_auto (type)
          && !COMPLETE_TYPE_P (complete_type (type)))
        {
+         auto_diagnostic_group d;
          error_at (location_of (decl),
                    "deduced type %qT for %qD is incomplete", type, decl);
          cxx_incomplete_type_inform (type);
@@ -9059,6 +9084,7 @@ cp_finish_decl (tree decl, tree init, bool 
init_const_expr_p,
       complete_type (TREE_TYPE (decl));
       if (!omp_mappable_type (TREE_TYPE (decl)))
        {
+         auto_diagnostic_group d;
          error ("%q+D in declare target directive does not have mappable"
                 " type", decl);
          if (TREE_TYPE (decl) != error_mark_node
@@ -9114,6 +9140,7 @@ find_decomp_class_base (location_t loc, tree type, tree 
ret)
       return type;
     else if (ANON_AGGR_TYPE_P (TREE_TYPE (field)))
       {
+       auto_diagnostic_group d;
        if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
          error_at (loc, "cannot decompose class type %qT because it has an "
                         "anonymous struct member", type);
@@ -9125,6 +9152,7 @@ find_decomp_class_base (location_t loc, tree type, tree 
ret)
       }
     else if (!accessible_p (type, field, true))
       {
+       auto_diagnostic_group d;
        error_at (loc, "cannot decompose inaccessible member %qD of %qT",
                  field, type);
        inform (DECL_SOURCE_LOCATION (field),
@@ -9425,6 +9453,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp)
       if (count != eltscnt)
        {
        cnt_mismatch:
+         auto_diagnostic_group d;
          if (count > eltscnt)
            error_n (loc, count,
                     "%u name provided for structured binding",
@@ -9505,6 +9534,7 @@ cp_finish_decomp (tree decl, cp_decomp *decomp)
        }
       if (!tree_fits_uhwi_p (tsize))
        {
+         auto_diagnostic_group d;
          error_n (loc, count,
                   "%u name provided for structured binding",
                   "%u names provided for structured binding", count);
@@ -10096,6 +10126,7 @@ expand_static_init (tree decl, tree init)
   if (CP_DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl)
       && !DECL_FUNCTION_SCOPE_P (decl))
     {
+      auto_diagnostic_group d;
       location_t dloc = DECL_SOURCE_LOCATION (decl);
       if (init)
        error_at (dloc, "non-local variable %qD declared %<__thread%> "
@@ -10870,6 +10901,7 @@ grokfndecl (tree ctype,
       if (in_namespace == NULL_TREE
          && CP_DECL_CONTEXT (decl) != CP_TYPE_CONTEXT (type))
        {
+         auto_diagnostic_group d;
          error_at (location, "deduction guide %qD must be declared in the "
                              "same scope as %qT", decl, type);
          inform (location_of (type), "  declared here");
@@ -10878,6 +10910,7 @@ grokfndecl (tree ctype,
       if (DECL_CLASS_SCOPE_P (decl)
          && current_access_specifier != declared_access (TYPE_NAME (type)))
        {
+         auto_diagnostic_group d;
          error_at (location, "deduction guide %qD must have the same access "
                              "as %qT", decl, type);
          inform (location_of (type), "  declared here");
@@ -10897,6 +10930,7 @@ grokfndecl (tree ctype,
       /* [over.literal]/6: Literal operators shall not have C linkage. */
       if (DECL_LANGUAGE (decl) == lang_c)
        {
+         auto_diagnostic_group d;
          error_at (location, "literal operator with C linkage");
          maybe_show_extern_c_location ();
          return NULL_TREE;
@@ -11063,6 +11097,7 @@ grokfndecl (tree ctype,
            }
          else if (DECL_DEFAULTED_FN (old_decl))
            {
+             auto_diagnostic_group d;
              error ("definition of explicitly-defaulted %q+D", decl);
              inform (DECL_SOURCE_LOCATION (old_decl),
                      "%q#D explicitly defaulted here", old_decl);
@@ -13219,6 +13254,7 @@ grokdeclarator (const cp_declarator *declarator,
       && !diagnose_misapplied_contracts (declspecs->std_attributes))
     {
       location_t attr_loc = declspecs->locations[ds_std_attribute];
+      auto_diagnostic_group d;
       if (any_nonignored_attribute_p (declspecs->std_attributes)
          && warning_at (attr_loc, OPT_Wattributes, "attribute ignored"))
        inform (attr_loc, "an attribute that appertains to a type-specifier "
@@ -13290,6 +13326,7 @@ grokdeclarator (const cp_declarator *declarator,
               && (MAYBE_CLASS_TYPE_P (type)
                   || TREE_CODE (type) == ENUMERAL_TYPE)))
        {
+         auto_diagnostic_group d;
          if (warning_at (declarator->parenthesized, OPT_Wparentheses,
                          "unnecessary parentheses in declaration of %qs",
                          name))
@@ -13450,6 +13487,7 @@ grokdeclarator (const cp_declarator *declarator,
                      /* OK for C++11 lambdas.  */;
                    else if (cxx_dialect < cxx14)
                      {
+                       auto_diagnostic_group d;
                        error_at (typespec_loc, "%qs function uses "
                                  "%<auto%> type specifier without "
                                  "trailing return type", name);
@@ -13501,6 +13539,7 @@ grokdeclarator (const cp_declarator *declarator,
                      }
                    else if (!late_return_type)
                      {
+                       auto_diagnostic_group d;
                        error_at (declarator->id_loc, "deduction guide "
                                  "for %qT must have trailing return "
                                  "type", TREE_TYPE (tmpl));
@@ -14737,6 +14776,7 @@ grokdeclarator (const cp_declarator *declarator,
                tree tmpl = TREE_OPERAND (unqualified_id, 0);
                if (variable_template_p (tmpl))
                  {
+                   auto_diagnostic_group d;
                    error_at (id_loc, "specialization of variable template "
                              "%qD declared as function", tmpl);
                    inform (DECL_SOURCE_LOCATION (tmpl),
@@ -14803,6 +14843,7 @@ grokdeclarator (const cp_declarator *declarator,
              {
                if (unqualified_id)
                  {
+                   auto_diagnostic_group d;
                    error_at (id_loc, "field %qD has incomplete type %qT",
                              unqualified_id, type);
                    cxx_incomplete_type_inform (strip_array_types (type));
@@ -14848,6 +14889,7 @@ grokdeclarator (const cp_declarator *declarator,
                && !all_attributes_are_contracts_p (*attrlist))
              {
                *attrlist = NULL_TREE;
+               auto_diagnostic_group d;
                if (warning_at (id_loc, OPT_Wattributes, "attribute ignored"))
                  inform (id_loc, "an attribute that appertains to a friend "
                          "declaration that is not a definition is ignored");
@@ -16359,6 +16401,7 @@ check_elaborated_type_specifier (enum tag_types 
tag_code,
           && !DECL_SELF_REFERENCE_P (decl)
           && tag_code != typename_type)
     {
+      auto_diagnostic_group d;
       if (alias_template_specialization_p (type, nt_opaque))
        error ("using alias template specialization %qT after %qs",
               type, tag_name (tag_code));
@@ -16373,6 +16416,7 @@ check_elaborated_type_specifier (enum tag_types 
tag_code,
           && tag_code != enum_type
           && tag_code != typename_type)
     {
+      auto_diagnostic_group d;
       error ("%qT referred to as %qs", type, tag_name (tag_code));
       inform (location_of (type), "%qT has a previous declaration here", type);
       return error_mark_node;
@@ -16380,6 +16424,7 @@ check_elaborated_type_specifier (enum tag_types 
tag_code,
   else if (TREE_CODE (type) != ENUMERAL_TYPE
           && tag_code == enum_type)
     {
+      auto_diagnostic_group d;
       error ("%qT referred to as enum", type);
       inform (location_of (type), "%qT has a previous declaration here", type);
       return error_mark_node;
@@ -16437,6 +16482,7 @@ lookup_and_check_tag (enum tag_types tag_code, tree 
name,
 
   if (TREE_CODE (decl) == TREE_LIST)
     {
+      auto_diagnostic_group d;
       error ("reference to %qD is ambiguous", name);
       print_candidates (decl);
       return error_mark_node;
@@ -16446,6 +16492,7 @@ lookup_and_check_tag (enum tag_types tag_code, tree 
name,
       && !template_header_p
       && how == TAG_how::CURRENT_ONLY)
     {
+      auto_diagnostic_group d;
       error ("class template %qD redeclared as non-template", name);
       inform (location_of (decl), "previous declaration here");
       CLASSTYPE_ERRONEOUS (TREE_TYPE (decl)) = true;
@@ -16496,6 +16543,7 @@ lookup_and_check_tag (enum tag_types tag_code, tree 
name,
       && (!CLASSTYPE_TEMPLATE_INFO (t)
          || (!PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))))
     {
+      auto_diagnostic_group d;
       error ("%qT is not a template", t);
       inform (location_of (t), "previous declaration here");
       if (TYPE_CLASS_SCOPE_P (t)
@@ -16632,6 +16680,7 @@ xref_tag (enum tag_types tag_code, tree name,
               && CLASS_TYPE_P (t)
               && CLASSTYPE_IS_TEMPLATE (t))
        {
+         auto_diagnostic_group d;
          error ("redeclaration of %qT as a non-template", t);
          inform (location_of (t), "previous declaration %qD", t);
          return error_mark_node;
@@ -17623,6 +17672,7 @@ cxx_simulate_enum_decl (location_t loc, const char 
*name,
                              NULL_TREE, false, NULL);
   if (!OPAQUE_ENUM_P (enumtype))
     {
+      auto_diagnostic_group d;
       error_at (loc, "multiple definition of %q#T", enumtype);
       inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (enumtype)),
              "previous definition here");
@@ -18679,6 +18729,7 @@ finish_function (bool inline_p)
       else if (!current_function_returns_value
               && !current_function_returns_null)
        {
+         auto_diagnostic_group d;
          error ("no return statements in function returning %qT",
                 DECL_SAVED_AUTO_RETURN_TYPE (fndecl));
          inform (input_location, "only plain %<auto%> return type can be "
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index c67e3e0c15f..3c4f34868ee 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -911,6 +911,7 @@ check_classfn (tree ctype, tree function, tree 
template_parms)
          if (DECL_CONV_FN_P (function))
            fns = get_class_binding (ctype, conv_op_identifier);
 
+         auto_diagnostic_group d;
          error_at (DECL_SOURCE_LOCATION (function),
                    "no declaration matches %q#D", function);
          if (fns)
@@ -5120,6 +5121,7 @@ record_mangling (tree decl, bool need_warning)
     *slot = decl;
   else if (need_warning)
     {
+      auto_diagnostic_group d;
       error_at (DECL_SOURCE_LOCATION (decl),
                "mangling of %q#D as %qE conflicts with a previous mangle",
                decl, id);
@@ -6078,6 +6080,7 @@ mark_used (tree decl, tsubst_flags_t complain /* = 
tf_warning_or_error */)
            sorry ("converting lambda that uses %<...%> to function pointer");
          else if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              if (DECL_INITIAL (decl)
                  && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)
                {
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 420fad26b7b..60d1e8bdb32 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -4796,12 +4796,14 @@ qualified_name_lookup_error (tree scope, tree name,
                  scope);
       else if (TREE_CODE (decl) == TREE_LIST)
        {
+         auto_diagnostic_group d;
          error_at (location, "reference to %<%T::%D%> is ambiguous",
                    scope, name);
          print_candidates (decl);
        }
       else
        {
+         auto_diagnostic_group d;
          name_hint hint;
          if (SCOPED_ENUM_P (scope) && TREE_CODE (name) == IDENTIFIER_NODE)
            hint = suggest_alternative_in_scoped_enum (name, scope);
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index 0231bd2507d..7b4abd1f56e 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -736,6 +736,7 @@ build_throw (location_t loc, tree exp, tsubst_flags_t 
complain)
            exp = moved;
 
          /* Call the copy constructor.  */
+         auto_diagnostic_group d;
          releasing_vec exp_vec (make_tree_vector_single (exp));
          exp = build_special_member_call (object, complete_ctor_identifier,
                                           &exp_vec, TREE_TYPE (object), flags,
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 20373d26988..be7fdb40dd6 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -662,6 +662,7 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t 
complain)
     {
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          error ("default member initializer for %qD required before the end "
                 "of its enclosing class", member);
          inform (location_of (init), "defined here");
@@ -2736,6 +2737,7 @@ diagnose_uninitialized_cst_or_ref_member_1 (tree type, 
tree origin,
          ++ error_count;
          if (complain)
            {
+             auto_diagnostic_group d;
              if (DECL_CONTEXT (field) == origin)
                {
                  if (using_new)
@@ -2764,6 +2766,7 @@ diagnose_uninitialized_cst_or_ref_member_1 (tree type, 
tree origin,
          ++ error_count;
          if (complain)
            {
+             auto_diagnostic_group d;
              if (DECL_CONTEXT (field) == origin)
                {
                  if (using_new)
@@ -2890,6 +2893,8 @@ warn_placement_new_too_small (tree type, tree nelts, tree 
size, tree oper)
   bool warned = false;
   if (nelts)
     nelts = fold_for_warn (nelts);
+
+  auto_diagnostic_group d;
   if (nelts)
     if (CONSTANT_CLASS_P (nelts))
       warned = warning_at (loc, OPT_Wplacement_new_,
@@ -3408,6 +3413,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, 
tree nelts,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              error ("request for member %qD is ambiguous", fnname);
              print_candidates (fns);
            }
@@ -4125,6 +4131,7 @@ build_vec_delete_1 (location_t loc, tree base, tree 
maxindex, tree type,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              int saved_errorcount = errorcount;
              if (permerror_opt (loc, OPT_Wdelete_incomplete,
                                 "operator %<delete []%> used on "
@@ -5209,6 +5216,7 @@ build_delete (location_t loc, tree otype, tree addr,
                {
                  if (complain & tf_error)
                    {
+                     auto_diagnostic_group d;
                      int saved_errorcount = errorcount;
                      if (permerror_opt (loc, OPT_Wdelete_incomplete,
                                         "operator %<delete%> used on "
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 0770417810e..e17c00217b2 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -562,6 +562,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool 
by_reference_p,
   else if (!dependent_type_p (type)
           && variably_modified_type_p (type, NULL_TREE))
     {
+      auto_diagnostic_group d;
       sorry ("capture of variably-modified type %qT that is not an N3639 array 
"
             "of runtime bound", type);
       if (TREE_CODE (type) == ARRAY_TYPE
@@ -600,6 +601,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool 
by_reference_p,
          type = complete_type (type);
          if (!COMPLETE_TYPE_P (type))
            {
+             auto_diagnostic_group d;
              error ("capture by copy of incomplete type %qT", type);
              cxx_incomplete_type_inform (type);
              return error_mark_node;
@@ -757,6 +759,7 @@ add_default_capture (tree lambda_stack, tree id, tree 
initializer)
          && this_capture_p
          && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) == CPLD_COPY)
        {
+         auto_diagnostic_group d;
          if (warning_at (LAMBDA_EXPR_LOCATION (lambda), OPT_Wdeprecated,
                          "implicit capture of %qE via %<[=]%> is deprecated "
                          "in C++20", this_identifier))
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 1110db7f8d0..79d9490c4ad 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -807,6 +807,7 @@ unqualified_fn_lookup_error (cp_expr name_expr)
         Note that we have the exact wording of the following message in
         the manual (trouble.texi, node "Name lookup"), so they need to
         be kept in synch.  */
+      auto_diagnostic_group d;
       permerror (loc, "there are no arguments to %qD that depend on a template 
"
                 "parameter, so a declaration of %qD must be available",
                 name, name);
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 0b21656ed61..68a776d2c5a 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1787,6 +1787,7 @@ synthesize_method (tree fndecl)
   int error_count = errorcount;
   int warning_count = warningcount + werrorcount;
   special_function_kind sfk = special_function_p (fndecl);
+  auto_diagnostic_group d;
 
   /* Reset the source location, we might have been previously
      deferred, and thus have saved where we were first needed.  */
@@ -3558,6 +3559,7 @@ defaulted_late_check (tree fn)
                    TREE_TYPE (TREE_TYPE (implicit_fn)))
       || !compare_fn_params (fn, implicit_fn))
     {
+      auto_diagnostic_group d;
       error ("defaulted declaration %q+D does not match the "
             "expected signature", fn);
       inform (DECL_SOURCE_LOCATION (fn),
@@ -3593,6 +3595,7 @@ defaulted_late_check (tree fn)
     {
       if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
        {
+         auto_diagnostic_group d;
          error ("explicitly defaulted function %q+D cannot be declared "
                 "%qs because the implicit declaration is not %qs:", fn,
                 DECL_IMMEDIATE_FUNCTION_P (fn) ? "consteval" : "constexpr",
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 95c2405fcd4..647208944da 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11627,6 +11627,7 @@ trees_in::is_matching_decl (tree existing, tree decl, 
bool is_typedef)
        {
          // FIXME:QOI Might be template specialization from a module,
          // not necessarily global module
+         auto_diagnostic_group d;
          error_at (DECL_SOURCE_LOCATION (decl),
                    "conflicting global module declaration %#qD", decl);
          inform (DECL_SOURCE_LOCATION (existing),
@@ -12682,6 +12683,7 @@ trees_in::read_enum_def (tree defn, tree maybe_template)
 
       if (known || values)
        {
+         auto_diagnostic_group d;
          error_at (DECL_SOURCE_LOCATION (maybe_dup),
                    "definition of %qD does not match", maybe_dup);
          inform (DECL_SOURCE_LOCATION (defn),
@@ -14497,6 +14499,7 @@ module_state::check_not_purview (location_t from)
   if (imp == this)
     {
       /* Cannot import the current module.  */
+      auto_diagnostic_group d;
       error_at (from, "cannot import module in its own purview");
       inform (loc, "module %qs declared here", get_flatname ());
       return false;
@@ -17859,6 +17862,7 @@ module_state::deferred_macro (cpp_reader *reader, 
location_t loc,
     {
       /* If LOC is the first loc, this is the end of file check, which
         is a warning.  */
+      auto_diagnostic_group d;
       if (loc == MAP_START_LOCATION (LINEMAPS_ORDINARY_MAP_AT (line_table, 0)))
        warning_at (loc, OPT_Winvalid_imported_macros,
                    "inconsistent imported macro definition %qE",
@@ -18133,6 +18137,7 @@ module_state::read_config (module_state_config &config)
 
       /* Reject when either is non-experimental or when experimental
         major versions differ.  */
+      auto_diagnostic_group d;
       bool reject_p = ((!IS_EXPERIMENTAL (my_ver)
                        || !IS_EXPERIMENTAL (their_ver)
                        || MODULE_MAJOR (my_ver) != MODULE_MAJOR (their_ver))
@@ -18945,6 +18950,7 @@ module_state::check_read (bool outermost, bool ok)
 
   if (int e = from ()->get_error ())
     {
+      auto_diagnostic_group d;
       error_at (loc, "failed to read compiled module: %s",
                from ()->get_error (filename));
       note_cmi_name ();
@@ -19878,6 +19884,7 @@ declare_module (module_state *module, location_t 
from_loc, bool exporting_p,
   module_state *current = (*modules)[0];
   if (module_purview_p () || module->loadedness > ML_CONFIG)
     {
+      auto_diagnostic_group d;
       error_at (from_loc, module_purview_p ()
                ? G_("module already declared")
                : G_("module already imported"));
@@ -20535,6 +20542,7 @@ init_modules (cpp_reader *reader)
          || (cpp_opts->deps.style != DEPS_NONE
              && !cpp_opts->deps.need_preprocessor_output))
        {
+         auto_diagnostic_group d;
          warning (0, flag_dump_macros == 'M'
                   ? G_("macro debug output may be incomplete with modules")
                   : G_("module dependencies require preprocessing"));
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 70ad4cbf3b5..7a6cc244c15 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -2893,6 +2893,7 @@ supplement_binding (cxx_binding *binding, tree decl)
 void
 diagnose_name_conflict (tree decl, tree bval)
 {
+  auto_diagnostic_group d;
   if (TREE_CODE (decl) == TREE_CODE (bval)
       && TREE_CODE (decl) != NAMESPACE_DECL
       && !DECL_DECLARES_FUNCTION_P (decl)
@@ -6213,6 +6214,7 @@ lookup_using_decl (tree scope, name_lookup &lookup)
           /* We can (independently) have ambiguous implicit typedefs.  */
           || (lookup.type && TREE_CODE (lookup.type) == TREE_LIST))
     {
+      auto_diagnostic_group d;
       error ("reference to %qD is ambiguous", lookup.name);
       print_candidates (TREE_CODE (lookup.value) == TREE_LIST
                        ? lookup.value : lookup.type);
@@ -6344,6 +6346,7 @@ set_decl_namespace (tree decl, tree scope, bool friendp)
   if (TREE_CODE (old) == TREE_LIST)
     {
     ambiguous:
+      auto_diagnostic_group d;
       DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
       error ("reference to %qD is ambiguous", decl);
       print_candidates (old);
@@ -6443,6 +6446,7 @@ set_decl_namespace (tree decl, tree scope, bool friendp)
     {
       if (hidden_p)
        {
+         auto_diagnostic_group d;
          pedwarn (DECL_SOURCE_LOCATION (decl), 0,
                   "%qD has not been declared within %qD", decl, scope);
          inform (DECL_SOURCE_LOCATION (found),
@@ -8927,6 +8931,7 @@ finish_using_directive (tree target, tree attribs)
        if (current_binding_level->kind == sk_namespace
            && is_attribute_p ("strong", name))
          {
+           auto_diagnostic_group d;
            if (warning (0, "%<strong%> using directive no longer supported")
                && CP_DECL_CONTEXT (target) == current_namespace)
              inform (DECL_SOURCE_LOCATION (target),
@@ -9246,6 +9251,7 @@ push_namespace (tree name, bool make_inline)
 
       if (make_inline && !DECL_NAMESPACE_INLINE_P (ns))
        {
+         auto_diagnostic_group d;
          error_at (input_location,
                    "inline namespace must be specified at initial definition");
          inform (DECL_SOURCE_LOCATION (ns), "%qD defined here", ns);
@@ -9296,6 +9302,7 @@ add_imported_namespace (tree ctx, tree name, location_t 
loc, unsigned import,
     }
   else if (DECL_NAMESPACE_INLINE_P (decl) != inline_p)
     {
+      auto_diagnostic_group d;
       error_at (loc, "%s namespace %qD conflicts with reachable definition",
                inline_p ? "inline" : "non-inline", decl);
       inform (DECL_SOURCE_LOCATION (decl), "reachable %s definition here",
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index edfa5a49440..8391ce431f3 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -3504,6 +3504,7 @@ cp_parser_check_for_definition_in_return_type 
(cp_declarator *declarator,
   if (declarator
       && declarator->kind == cdk_function)
     {
+      auto_diagnostic_group d;
       error_at (type_location,
                "new types may not be defined in a return type");
       inform (type_location,
@@ -5086,24 +5087,27 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
        }
     }
 
-  bool complained
-    = emit_diagnostic (kind, input_location, opt,
-                      "unable to find numeric literal operator %qD", name);
-
-  if (!complained)
-    /* Don't inform either.  */;
-  else if (i14)
-    {
-      inform (token->location, "add %<using namespace std::complex_literals%> "
-             "(from %<<complex>%>) to enable the C++14 user-defined literal "
-             "suffixes");
-      if (ext)
-       inform (token->location, "or use %<j%> instead of %<i%> for the "
-               "GNU built-in suffix");
-    }
-  else if (!ext)
-    inform (token->location, "use %<-fext-numeric-literals%> "
-           "to enable more built-in suffixes");
+  {
+    auto_diagnostic_group d;
+    bool complained
+      = emit_diagnostic (kind, input_location, opt,
+                        "unable to find numeric literal operator %qD", name);
+
+    if (!complained)
+      /* Don't inform either.  */;
+    else if (i14)
+      {
+       inform (token->location, "add %<using namespace std::complex_literals%> 
"
+               "(from %<<complex>%>) to enable the C++14 user-defined literal "
+               "suffixes");
+       if (ext)
+         inform (token->location, "or use %<j%> instead of %<i%> for the "
+                 "GNU built-in suffix");
+      }
+    else if (!ext)
+      inform (token->location, "use %<-fext-numeric-literals%> "
+             "to enable more built-in suffixes");
+  }
 
   if (kind == DK_ERROR)
     value = error_mark_node;
@@ -7159,6 +7163,7 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
              if (TREE_CODE (tid) == TEMPLATE_ID_EXPR
                  && TREE_CODE (TREE_OPERAND (tid, 0)) != IDENTIFIER_NODE)
                {
+                 auto_diagnostic_group d;
                  tree tmpl = NULL_TREE;
                  if (is_overloaded_fn (tid))
                    {
@@ -9641,10 +9646,13 @@ cp_parser_new_expression (cp_parser* parser)
         message for this case.  */
       if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
        {
-         error_at (token->location,
-                   "array bound forbidden after parenthesized type-id");
-         inform (token->location,
-                 "try removing the parentheses around the type-id");
+         {
+           auto_diagnostic_group d;
+           error_at (token->location,
+                     "array bound forbidden after parenthesized type-id");
+           inform (token->location,
+                   "try removing the parentheses around the type-id");
+         }
          cp_parser_direct_new_declarator (parser);
        }
     }
@@ -10450,6 +10458,7 @@ cp_parser_binary_expression (cp_parser* parser, bool 
cast_p,
           && token->type == CPP_RSHIFT
           && !parser->greater_than_is_operator_p)
         {
+         auto_diagnostic_group d;
           if (warning_at (token->location, OPT_Wc__11_compat,
                          "%<>>%> operator is treated"
                          " as two right angle brackets in C++11"))
@@ -11724,6 +11733,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree 
lambda_expr)
          else if (!VAR_P (capture_init_expr)
                   && TREE_CODE (capture_init_expr) != PARM_DECL)
            {
+             auto_diagnostic_group d;
              error_at (capture_token->location,
                        "capture of non-variable %qE",
                        capture_init_expr);
@@ -11735,6 +11745,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree 
lambda_expr)
          if (VAR_P (capture_init_expr)
              && decl_storage_duration (capture_init_expr) != dk_auto)
            {
+             auto_diagnostic_group d;
              if (pedwarn (capture_token->location, 0, "capture of variable "
                           "%qD with non-automatic storage duration",
                           capture_init_expr))
@@ -15238,6 +15249,7 @@ cp_parser_module_declaration (cp_parser *parser, 
module_parse mp_state,
     }
   else if (scope != global_namespace)
     {
+      auto_diagnostic_group d;
       error_at (token->location, "module-declaration must be at global scope");
       inform (DECL_SOURCE_LOCATION (scope), "scope opened here");
       goto skip_eol;
@@ -15315,19 +15327,22 @@ cp_parser_import_declaration (cp_parser *parser, 
module_parse mp_state,
 
   if (mp_state == MP_PURVIEW || mp_state == MP_PRIVATE)
     {
+      auto_diagnostic_group d;
       error_at (token->location, "post-module-declaration"
                " imports must be contiguous");
-    note_lexer:
       inform (token->location, "perhaps insert a line break after"
              " %<import%>, or other disambiguation, to prevent this"
              " being considered a module control-line");
-    skip_eol:
       cp_parser_skip_to_pragma_eol (parser, token);
     }
   else if (current_scope () != global_namespace)
     {
+      auto_diagnostic_group d;
       error_at (token->location, "import-declaration must be at global scope");
-      goto note_lexer;
+      inform (token->location, "perhaps insert a line break after"
+             " %<import%>, or other disambiguation, to prevent this"
+             " being considered a module control-line");
+      cp_parser_skip_to_pragma_eol (parser, token);
     }
   else
     {
@@ -15355,7 +15370,10 @@ cp_parser_import_declaration (cp_parser *parser, 
module_parse mp_state,
       tree attrs = cp_parser_attributes_opt (parser);
 
       if (!mod || !cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON))
-       goto skip_eol;
+       {
+         cp_parser_skip_to_pragma_eol (parser, token);
+         return;
+       }
       cp_parser_require_pragma_eol (parser, token);
 
       if (mp_state == MP_PURVIEW_IMPORTS || mp_state == MP_PRIVATE_IMPORTS)
@@ -15648,6 +15666,7 @@ cp_parser_declaration (cp_parser* parser, tree 
prefix_attrs)
          if (!c_dialect_objc ())
            {
              location_t where = get_finish (t2->location);
+             auto_diagnostic_group d;
              warning_at (token1->location, OPT_Wattributes, "attributes are"
                          " not permitted in this position");
              where = linemap_position_for_loc_and_offset (line_table,
@@ -16899,6 +16918,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 
       if (decl_specs->std_attributes)
        {
+         auto_diagnostic_group d;
          error_at (decl_specs->locations[ds_std_attribute],
                    "standard attributes in middle of decl-specifiers");
          inform (decl_specs->locations[ds_std_attribute],
@@ -19148,6 +19168,7 @@ cp_parser_template_id (cp_parser *parser,
        }
       /* Otherwise, emit an error about the invalid digraph, but continue
         parsing because we got our argument list.  */
+      auto_diagnostic_group d;
       if (permerror (next_token->location,
                     "%<<::%> cannot begin a template-argument list"))
        {
@@ -19187,6 +19208,7 @@ cp_parser_template_id (cp_parser *parser,
              /* C++20 says that "function-name < a;" is now ill-formed.  */
              if (cp_parser_error_occurred (parser))
                {
+                 auto_diagnostic_group d;
                  error_at (token->location, "invalid template-argument-list");
                  inform (token->location, "function name as the left hand "
                          "operand of %<<%> is ill-formed in C++20; wrap the "
@@ -19432,10 +19454,13 @@ cp_parser_template_name (cp_parser* parser,
          cp_token_position start = 0;
 
          /* Explain what went wrong.  */
-         error_at (token->location, "non-template %qD used as template",
-                   identifier);
-         inform (token->location, "use %<%T::template %D%> to indicate that it 
is a template",
-                 parser->scope, identifier);
+         {
+           auto_diagnostic_group d;
+           error_at (token->location, "non-template %qD used as template",
+                     identifier);
+           inform (token->location, "use %<%T::template %D%> to indicate "
+                   "that it is a template", parser->scope, identifier);
+         }
          /* If parsing tentatively, find the location of the "<" token.  */
          if (cp_parser_simulate_error (parser))
            start = cp_lexer_token_position (parser->lexer, true);
@@ -20103,6 +20128,7 @@ cp_parser_explicit_specialization (cp_parser* parser)
   bool need_lang_pop = current_lang_name == lang_name_c;
   if (need_lang_pop)
     {
+      auto_diagnostic_group d;
       error_at (token->location, "template specialization with C linkage");
       maybe_show_extern_c_location ();
 
@@ -20935,6 +20961,7 @@ cp_parser_placeholder_type_specifier (cp_parser 
*parser, location_t loc,
     {
       if (!tentative)
        {
+         auto_diagnostic_group d;
          error_at (loc, "%qE does not constrain a type", DECL_NAME (con));
          inform (DECL_SOURCE_LOCATION (con), "concept defined here");
        }
@@ -21548,6 +21575,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
                 "attributes ignored on template instantiation");
       else if (is_friend && cxx11_attribute_p (attributes))
        {
+         auto_diagnostic_group d;
          if (warning (OPT_Wattributes, "attribute ignored"))
            inform (input_location, "an attribute that appertains to a friend "
                    "declaration that is not a definition is ignored");
@@ -21900,6 +21928,7 @@ cp_parser_enum_specifier (cp_parser* parser)
        }
       else
        {
+         auto_diagnostic_group d;
          error_at (type_start_token->location,
                    "multiple definition of %q#T", type);
          inform (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
@@ -22947,6 +22976,7 @@ cp_parser_asm_definition (cp_parser* parser)
          case RID_VOLATILE:
            if (volatile_loc)
              {
+               auto_diagnostic_group d;
                error_at (loc, "duplicate %<asm%> qualifier %qT",
                          token->u.value);
                inform (volatile_loc, "first seen here");
@@ -22964,6 +22994,7 @@ cp_parser_asm_definition (cp_parser* parser)
          case RID_INLINE:
            if (inline_loc)
              {
+               auto_diagnostic_group d;
                error_at (loc, "duplicate %<asm%> qualifier %qT",
                          token->u.value);
                inform (inline_loc, "first seen here");
@@ -22978,6 +23009,7 @@ cp_parser_asm_definition (cp_parser* parser)
          case RID_GOTO:
            if (goto_loc)
              {
+               auto_diagnostic_group d;
                error_at (loc, "duplicate %<asm%> qualifier %qT",
                          token->u.value);
                inform (goto_loc, "first seen here");
@@ -23791,12 +23823,13 @@ cp_parser_init_declarator (cp_parser* parser,
      attributes -- but ignores them.  Made a permerror in GCC 8.  */
   if (cp_parser_allow_gnu_extensions_p (parser)
       && initialization_kind == CPP_OPEN_PAREN
-      && cp_parser_attributes_opt (parser)
-      && permerror (input_location,
-                   "attributes after parenthesized initializer ignored"))
+      && cp_parser_attributes_opt (parser))
     {
       static bool hint;
-      if (flag_permissive && !hint)
+      auto_diagnostic_group d;
+      if (permerror (input_location,
+                    "attributes after parenthesized initializer ignored")
+         && flag_permissive && !hint)
        {
          hint = true;
          inform (input_location,
@@ -24496,6 +24529,7 @@ cp_parser_direct_declarator (cp_parser* parser,
                    else if (qualifying_scope
                             && CLASSTYPE_USE_TEMPLATE (name_type))
                      {
+                       auto_diagnostic_group d;
                        error_at (declarator_id_start_token->location,
                                  "invalid use of constructor as a template");
                        inform (declarator_id_start_token->location,
@@ -27890,6 +27924,7 @@ cp_parser_class_head (cp_parser* parser,
   if (type != error_mark_node
       && (COMPLETE_TYPE_P (type) || TYPE_BEING_DEFINED (type)))
     {
+      auto_diagnostic_group d;
       error_at (type_start_token->location, "redefinition of %q#T",
                type);
       inform (location_of (type), "previous definition of %q#T",
@@ -28344,6 +28379,7 @@ cp_parser_member_declaration (cp_parser* parser)
                      && cxx11_attribute_p (decl_specifiers.attributes))
                    {
                      decl_specifiers.attributes = NULL_TREE;
+                     auto_diagnostic_group d;
                      if (warning_at (decl_spec_token_start->location,
                                      OPT_Wattributes, "attribute ignored"))
                        inform (decl_spec_token_start->location, "an attribute "
@@ -32449,6 +32485,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
         cp_parser_error, so we incorporate its actions directly.  */
       if (!cp_parser_simulate_error (parser))
        {
+         auto_diagnostic_group d;
          error_at (name_location, "reference to %qD is ambiguous",
                    name);
          print_candidates (decl);
@@ -33260,6 +33297,7 @@ cp_parser_explicit_template_declaration (cp_parser* 
parser, bool member_p)
      A template ... shall not have C linkage.  */
   if (current_lang_name == lang_name_c)
     {
+      auto_diagnostic_group d;
       error_at (location, "template with C linkage");
       maybe_show_extern_c_location ();
       /* Give it C++ linkage to avoid confusing other parts of the
@@ -35236,6 +35274,7 @@ cp_parser_check_class_key (cp_parser *parser, 
location_t key_loc,
   bool seen_as_union = TREE_CODE (type) == UNION_TYPE;
   if (seen_as_union != (class_key == union_type))
     {
+      auto_diagnostic_group d;
       if (permerror (input_location, "%qs tag used in naming %q#T",
                     class_key == union_type ? "union"
                     : class_key == record_type ? "struct" : "class",
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 024fa8a5529..f60b1069d6d 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1124,6 +1124,7 @@ maybe_process_partial_specialization (tree type)
          if (current_namespace
              != decl_namespace_context (tmpl))
            {
+             auto_diagnostic_group d;
              if (permerror (input_location,
                             "specialization of %qD in different namespace",
                             type))
@@ -2471,6 +2472,7 @@ determine_specialization (tree template_id,
 
   if (templates == NULL_TREE && candidates == NULL_TREE)
     {
+      auto_diagnostic_group d;
       error ("template-id %qD for %q+D does not match any template "
             "declaration", template_id, decl);
       if (header_mismatch)
@@ -2485,6 +2487,7 @@ determine_specialization (tree template_id,
           || (candidates && TREE_CHAIN (candidates))
           || (templates && candidates))
     {
+      auto_diagnostic_group d;
       error ("ambiguous template specialization %qD for %q+D",
             template_id, decl);
       candidates = chainon (candidates, templates);
@@ -4311,6 +4314,7 @@ check_for_bare_parameter_packs (tree t, location_t loc /* 
= UNKNOWN_LOCATION */)
 
   if (parameter_packs)
     {
+      auto_diagnostic_group d;
       error_at (loc, "parameter packs not expanded with %<...%>:");
       while (parameter_packs)
         {
@@ -4455,6 +4459,7 @@ check_template_shadow (tree decl)
   if (DECL_SELF_REFERENCE_P (decl))
     return false;
 
+  auto_diagnostic_group d;
   if (DECL_TEMPLATE_PARM_P (decl))
     error ("declaration of template parameter %q+D shadows "
           "template parameter", decl);
@@ -5141,7 +5146,6 @@ process_partial_specialization (tree decl)
   int nargs = TREE_VEC_LENGTH (inner_args);
   int ntparms;
   int  i;
-  bool did_error_intro = false;
   struct template_parm_data tpd;
   struct template_parm_data tpd2;
 
@@ -5195,24 +5199,29 @@ process_partial_specialization (tree decl)
                              NULL,
                              /*include_nondeduced_p=*/false);
     }
-  for (i = 0; i < ntparms; ++i)
-    if (tpd.parms[i] == 0)
-      {
-       /* One of the template parms was not used in a deduced context in the
-          specialization.  */
-       if (!did_error_intro)
-         {
-           error ("template parameters not deducible in "
-                  "partial specialization:");
-           did_error_intro = true;
-         }
 
-       inform (input_location, "        %qD",
-               TREE_VALUE (TREE_VEC_ELT (inner_parms, i)));
-      }
+  {
+    auto_diagnostic_group d;
+    bool did_error_intro = false;
+    for (i = 0; i < ntparms; ++i)
+      if (tpd.parms[i] == 0)
+       {
+         /* One of the template parms was not used in a deduced context in the
+            specialization.  */
+         if (!did_error_intro)
+           {
+             error ("template parameters not deducible in "
+                    "partial specialization:");
+             did_error_intro = true;
+           }
 
-  if (did_error_intro)
-    return error_mark_node;
+         inform (input_location, "        %qD",
+                 TREE_VALUE (TREE_VEC_ELT (inner_parms, i)));
+       }
+
+    if (did_error_intro)
+      return error_mark_node;
+  }
 
   /* [temp.class.spec]
 
@@ -5224,6 +5233,7 @@ process_partial_specialization (tree decl)
       && (!flag_concepts
          || !strictly_subsumes (current_template_constraints (), maintmpl)))
     {
+      auto_diagnostic_group d;
       if (!flag_concepts)
         error ("partial specialization %q+D does not specialize "
               "any template arguments; to define the primary template, "
@@ -5241,6 +5251,7 @@ process_partial_specialization (tree decl)
      parameters.  */
   if (nargs < DECL_NTPARMS (maintmpl))
     {
+      auto_diagnostic_group d;
       error ("partial specialization is not more specialized than the "
             "primary template because it replaces multiple parameters "
             "with a pack expansion");
@@ -5251,6 +5262,7 @@ process_partial_specialization (tree decl)
 
   else if (nargs > DECL_NTPARMS (maintmpl))
     {
+      auto_diagnostic_group d;
       error ("too many arguments for partial specialization %qT", type);
       inform (DECL_SOURCE_LOCATION (maintmpl), "primary template here");
       /* Avoid crash below.  */
@@ -6141,6 +6153,7 @@ push_template_decl (tree decl, bool is_friend)
          (TI_ARGS (tinfo),
           TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl)))))
        {
+         auto_diagnostic_group d;
          error ("template arguments to %qD do not match original "
                 "template %qD", decl, DECL_TEMPLATE_RESULT (tmpl));
          if (!uses_template_parms (TI_ARGS (tinfo)))
@@ -6346,6 +6359,7 @@ redeclare_class_template (tree type, tree parms, tree 
cons)
 
   if (TREE_VEC_LENGTH (parms) != TREE_VEC_LENGTH (tmpl_parms))
     {
+      auto_diagnostic_group d;
       error_n (input_location, TREE_VEC_LENGTH (parms),
                "redeclared with %d template parameter",
                "redeclared with %d template parameters",
@@ -6862,6 +6876,7 @@ convert_nontype_argument_function (tree type, tree expr,
     {
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          location_t loc = cp_expr_loc_or_input_loc (expr);
          error_at (loc, "%qE is not a valid template argument for type %qT",
                    expr, type);
@@ -6932,6 +6947,7 @@ check_valid_ptrmem_cst_expr (tree type, tree expr,
     return true;
   if (complain & tf_error)
     {
+      auto_diagnostic_group d;
       location_t loc = cp_expr_loc_or_input_loc (orig_expr);
       error_at (loc, "%qE is not a valid template argument for type %qT",
                orig_expr, type);
@@ -7805,6 +7821,7 @@ convert_nontype_argument (tree type, tree expr, 
tsubst_flags_t complain)
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              error ("%qE is not a valid template argument for type %qT "
                     "because it is a pointer", expr, type);
              inform (input_location, "try using %qE instead",
@@ -8663,6 +8680,7 @@ convert_template_argument (tree parm,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              error ("type/value mismatch at argument %d in template "
                     "parameter list for %qD",
                     i + 1, in_decl);
@@ -8697,6 +8715,7 @@ convert_template_argument (tree parm,
     {
       if (in_decl && (complain & tf_error))
        {
+         auto_diagnostic_group d;
          error ("type/value mismatch at argument %d in template "
                 "parameter list for %qD",
                 i + 1, in_decl);
@@ -8747,6 +8766,7 @@ convert_template_argument (tree parm,
                {
                  if (in_decl && (complain & tf_error))
                    {
+                     auto_diagnostic_group d;
                      error ("type/value mismatch at argument %d in "
                             "template parameter list for %qD",
                             i + 1, in_decl);
@@ -8765,6 +8785,7 @@ convert_template_argument (tree parm,
                   {
                    if (in_decl && (complain & tf_error))
                       {
+                       auto_diagnostic_group d;
                         error ("constraint mismatch at argument %d in "
                                "template parameter list for %qD",
                                i + 1, in_decl);
@@ -9147,6 +9168,7 @@ coerce_template_parms (tree parms,
     bad_nargs:
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
           if (variadic_p || default_p)
             {
               nparms -= variadic_p + default_p;
@@ -9182,6 +9204,7 @@ coerce_template_parms (tree parms,
              if (PACK_EXPANSION_P (arg)
                  && !template_parameter_pack_p (parm))
                {
+                 auto_diagnostic_group d;
                  if (DECL_ALIAS_TEMPLATE_P (in_decl))
                    error_at (location_of (arg),
                              "pack expansion argument for non-pack parameter "
@@ -17373,6 +17396,7 @@ tsubst_qualified_id (tree qualified_id, tree args,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              error ("dependent-name %qE is parsed as a non-type, but "
                     "instantiation yields a type", qualified_id);
              inform (input_location, "say %<typename %E%> if a type is meant", 
qualified_id);
@@ -20965,6 +20989,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
 
                if (unq != function)
                  {
+                   auto_diagnostic_group d;
                    char const *const msg
                      = G_("%qD was not declared in this scope, "
                           "and no declarations were found by "
@@ -26400,6 +26425,7 @@ most_specialized_partial_spec (tree target, 
tsubst_flags_t complain,
       char *spaces = NULL;
       if (!(complain & tf_error))
        return error_mark_node;
+      auto_diagnostic_group d;
       if (TYPE_P (target))
        error ("ambiguous template instantiation for %q#T", target);
       else
@@ -30866,6 +30892,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, 
tree outer_targs,
        {
          /* Be permissive with equivalent alias templates.  */
          tree u = get_underlying_template (tmpl);
+         auto_diagnostic_group d;
          diagnostic_t dk = (u == tmpl) ? DK_ERROR : DK_PEDWARN;
          bool complained
            = emit_diagnostic (dk, input_location, 0,
@@ -31022,6 +31049,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, 
tree outer_targs,
     {
       if (complain & tf_warning_or_error)
        {
+         auto_diagnostic_group d;
          error ("class template argument deduction failed:");
          perform_dguide_overload_resolution (cands, args, complain);
          if (elided)
@@ -31039,6 +31067,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, 
tree outer_targs,
          if (complain & tf_warning_or_error)
            {
              // TODO: Pass down location from cp_finish_decl.
+             auto_diagnostic_group d;
              error ("class template argument deduction for %qT failed: "
                     "explicit deduction guide selected in "
                     "copy-list-initialization", type);
@@ -31054,6 +31083,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, 
tree outer_targs,
      guides, this deduction might not be what the user intended.  */
   if (fndecl != error_mark_node && !any_dguides_p && (complain & tf_warning))
     {
+      auto_diagnostic_group d;
       if ((!DECL_IN_SYSTEM_HEADER (fndecl)
           || global_dc->m_warn_system_headers)
          && warning (OPT_Wctad_maybe_unsupported,
@@ -31181,6 +31211,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
        {
           if (complain & tf_warning_or_error)
             {
+             auto_diagnostic_group d;
              if (permerror (loc, "direct-list-initialization of "
                             "%<auto%> requires exactly one element"))
                inform (loc,
diff --git a/gcc/cp/search.cc b/gcc/cp/search.cc
index 827f48e8604..60c30ecb881 100644
--- a/gcc/cp/search.cc
+++ b/gcc/cp/search.cc
@@ -1227,6 +1227,7 @@ lookup_member (tree xbasetype, tree name, int protect, 
bool want_type,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
              error ("request for member %qD is ambiguous", name);
              print_candidates (lfi.ambiguous);
            }
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 5ab2076b673..3e117c216da 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2383,6 +2383,7 @@ finish_non_static_data_member (tree decl, tree object, 
tree qualifying_scope,
     {
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          if (current_function_decl
              && DECL_STATIC_FUNCTION_P (current_function_decl))
            error ("invalid use of member %qD in static member function", decl);
@@ -4248,6 +4249,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain, bool odr_use)
     {
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          error ("%qD is not captured", decl);
          tree closure = LAMBDA_EXPR_CLOSURE (lambda_expr);
          if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) == CPLD_NONE)
@@ -4268,6 +4270,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
complain, bool odr_use)
     {
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          error (VAR_P (decl)
                 ? G_("use of local variable with automatic storage from "
                      "containing function")
@@ -4503,6 +4506,7 @@ finish_id_expression_1 (tree id_expression,
       if (TREE_CODE (decl) == TREE_LIST)
        {
          /* Ambiguous reference to base members.  */
+         auto_diagnostic_group d;
          error ("request for member %qD is ambiguous in "
                 "multiple inheritance lattice", id_expression);
          print_candidates (decl);
@@ -4909,6 +4913,7 @@ finish_offsetof (tree object_ptr, tree expr, location_t 
loc)
 
       if (DECL_P (expr))
        {
+         auto_diagnostic_group d;
          error ("cannot apply %<offsetof%> to member function %qD", expr);
          inform (DECL_SOURCE_LOCATION (expr), "declared here");
        }
@@ -6321,6 +6326,7 @@ omp_reduction_lookup (location_t loc, tree id, tree type, 
tree *baselinkp,
        return ret;
       if (!ambiguous.is_empty ())
        {
+         auto_diagnostic_group d;
          const char *str = _("candidates are:");
          unsigned int idx;
          tree udr;
@@ -8393,6 +8399,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type 
ort)
                        && !type_dependent_expression_p (t)
                        && !omp_mappable_type (TREE_TYPE (t)))
                      {
+                       auto_diagnostic_group d;
                        error_at (OMP_CLAUSE_LOCATION (c),
                                  "array section does not have mappable type "
                                  "in %qs clause",
@@ -8615,6 +8622,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type 
ort)
                                            ? TREE_TYPE (TREE_TYPE (t))
                                            : TREE_TYPE (t)))
              {
+               auto_diagnostic_group d;
                error_at (OMP_CLAUSE_LOCATION (c),
                          "%qD does not have a mappable type in %qs clause", t,
                          omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
@@ -8782,6 +8790,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type 
ort)
            }
          else if (!omp_mappable_type (TREE_TYPE (t)))
            {
+             auto_diagnostic_group d;
              error_at (OMP_CLAUSE_LOCATION (c),
                        "%qD does not have a mappable type in %qs clause", t,
                        cname);
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 31ecbb1ac79..c3a38de4f48 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5223,6 +5223,7 @@ check_abi_tag_redeclaration (const_tree decl, const_tree 
old, const_tree new_)
   if (new_ && TREE_CODE (TREE_VALUE (new_)) == TREE_LIST)
     new_ = TREE_VALUE (new_);
   bool err = false;
+  auto_diagnostic_group d;
   for (const_tree t = new_; t; t = TREE_CHAIN (t))
     {
       tree str = TREE_VALUE (t);
@@ -5276,6 +5277,7 @@ check_abi_tag_args (tree args, tree name)
            {
              if (!ISALPHA (c) && c != '_')
                {
+                 auto_diagnostic_group d;
                  error ("arguments to the %qE attribute must contain valid "
                         "identifiers", name);
                  inform (input_location, "%<%c%> is not a valid first "
@@ -5289,6 +5291,7 @@ check_abi_tag_args (tree args, tree name)
            {
              if (!ISALNUM (c) && c != '_')
                {
+                 auto_diagnostic_group d;
                  error ("arguments to the %qE attribute must contain valid "
                         "identifiers", name);
                  inform (input_location, "%<%c%> is not a valid character "
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index f26b5b2a1f4..e4e260645f6 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -2365,6 +2365,7 @@ invalid_nonstatic_memfn_p (location_t loc, tree expr, 
tsubst_flags_t complain)
        {
          if (DECL_P (expr))
            {
+             auto_diagnostic_group d;
              error_at (loc, "invalid use of non-static member function %qD",
                        expr);
              inform (DECL_SOURCE_LOCATION (expr), "declared here");
@@ -3309,6 +3310,7 @@ complain_about_unrecognized_member (tree access_path, 
tree name,
        {
          /* The guessed name isn't directly accessible, and no accessor
             member function could be found.  */
+         auto_diagnostic_group d;
          error_at (&rich_loc,
                    "%q#T has no member named %qE;"
                    " did you mean %q#D? (not accessible from this context)",
@@ -3534,21 +3536,24 @@ finish_class_member_access_expr (cp_expr object, tree 
name, bool template_p,
       else
        {
          /* Look up the member.  */
-         access_failure_info afi;
-         if (processing_template_decl)
-           /* Even though this class member access expression is at this
-              point not dependent, the member itself may be dependent, and
-              we must not potentially push a access check for a dependent
-              member onto TI_DEFERRED_ACCESS_CHECKS.  So don't check access
-              ahead of time here; we're going to redo this member lookup at
-              instantiation time anyway.  */
-           push_deferring_access_checks (dk_no_check);
-         member = lookup_member (access_path, name, /*protect=*/1,
-                                 /*want_type=*/false, complain,
-                                 &afi);
-         if (processing_template_decl)
-           pop_deferring_access_checks ();
-         afi.maybe_suggest_accessor (TYPE_READONLY (object_type));
+         {
+           auto_diagnostic_group d;
+           access_failure_info afi;
+           if (processing_template_decl)
+             /* Even though this class member access expression is at this
+                point not dependent, the member itself may be dependent, and
+                we must not potentially push a access check for a dependent
+                member onto TI_DEFERRED_ACCESS_CHECKS.  So don't check access
+                ahead of time here; we're going to redo this member lookup at
+                instantiation time anyway.  */
+             push_deferring_access_checks (dk_no_check);
+           member = lookup_member (access_path, name, /*protect=*/1,
+                                   /*want_type=*/false, complain,
+                                   &afi);
+           if (processing_template_decl)
+             pop_deferring_access_checks ();
+           afi.maybe_suggest_accessor (TYPE_READONLY (object_type));
+         }
          if (member == NULL_TREE)
            {
              if (dependentish_scope_p (object_type))
@@ -4504,6 +4509,7 @@ error_args_num (location_t loc, tree fndecl, bool 
too_many_p)
 {
   if (fndecl)
     {
+      auto_diagnostic_group d;
       if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
        {
          if (DECL_NAME (fndecl) == NULL_TREE
@@ -4952,6 +4958,7 @@ warn_for_null_address (location_t location, tree op, 
tsubst_flags_t complain)
       STRIP_NOPS (cop);
     }
 
+  auto_diagnostic_group d;
   bool warned = false;
   if (TREE_CODE (cop) == ADDR_EXPR)
     {
@@ -6106,6 +6113,7 @@ cp_build_binary_op (const op_location_t &location,
            {
              if (complain & tf_error)
                {
+                 auto_diagnostic_group d;
                  error_at (location, "comparing vectors with different "
                                      "element types");
                  inform (location, "operand types are %qT and %qT",
@@ -6119,6 +6127,7 @@ cp_build_binary_op (const op_location_t &location,
            {
              if (complain & tf_error)
                {
+                 auto_diagnostic_group d;
                  error_at (location, "comparing vectors with different "
                                      "number of elements");
                  inform (location, "operand types are %qT and %qT",
@@ -6964,6 +6973,7 @@ build_x_unary_op (location_t loc, enum tree_code code, 
cp_expr xarg,
            {
              if (complain & tf_error)
                {
+                 auto_diagnostic_group d;
                  error_at (loc, "invalid use of %qE to form a "
                            "pointer-to-member-function", xarg.get_value ());
                  if (TREE_CODE (xarg) != OFFSET_REF)
@@ -7498,10 +7508,13 @@ cp_build_unary_op (enum tree_code code, tree xarg, bool 
noconvert,
        {
          /* Warn if the expression has boolean value.  */
          if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE
-             && (complain & tf_warning)
-             && warning_at (location, OPT_Wbool_operation,
-                            "%<~%> on an expression of type %<bool%>"))
-           inform (location, "did you mean to use logical not (%<!%>)?");
+             && (complain & tf_warning))
+           {
+             auto_diagnostic_group d;
+             if (warning_at (location, OPT_Wbool_operation,
+                             "%<~%> on an expression of type %<bool%>"))
+               inform (location, "did you mean to use logical not (%<!%>)?");
+           }
          arg = cp_perform_integral_promotions (arg, complain);
        }
       else if (!noconvert && VECTOR_TYPE_P (TREE_TYPE (arg)))
@@ -8723,6 +8736,7 @@ build_static_cast (location_t loc, tree type, tree oexpr,
 
   if (complain & tf_error)
     {
+      auto_diagnostic_group d;
       error_at (loc, "invalid %<static_cast%> from type %qT to type %qT",
                TREE_TYPE (expr), type);
       if ((TYPE_PTR_P (type) || TYPE_REF_P (type))
@@ -9682,15 +9696,19 @@ cp_build_modify_expr (location_t loc, tree lhs, enum 
tree_code modifycode,
          rhs = decay_conversion (rhs, complain);
          if (rhs == error_mark_node)
            return error_mark_node;
-         rhs = stabilize_expr (rhs, &init);
-         newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain);
-         if (newrhs == error_mark_node)
-           {
-             if (complain & tf_error)
-               inform (loc, "  in evaluation of %<%Q(%#T, %#T)%>",
-                       modifycode, TREE_TYPE (lhs), TREE_TYPE (rhs));
-             return error_mark_node;
-           }
+
+         {
+           auto_diagnostic_group d;
+           rhs = stabilize_expr (rhs, &init);
+           newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain);
+           if (newrhs == error_mark_node)
+             {
+               if (complain & tf_error)
+                 inform (loc, "  in evaluation of %<%Q(%#T, %#T)%>",
+                         modifycode, TREE_TYPE (lhs), TREE_TYPE (rhs));
+               return error_mark_node;
+             }
+         }
 
          if (init)
            newrhs = build2 (COMPOUND_EXPR, TREE_TYPE (newrhs), init, newrhs);
@@ -9970,6 +9988,7 @@ get_delta_difference (tree from, tree to,
                      bool allow_inverse_p,
                      bool c_cast_p, tsubst_flags_t complain)
 {
+  auto_diagnostic_group d;
   tree result;
 
   if (same_type_ignoring_top_level_qualifiers_p (from, to))
@@ -10384,6 +10403,8 @@ convert_for_assignment (tree type, tree rhs,
        {
          if (complain & tf_error)
            {
+             auto_diagnostic_group d;
+
              /* If the right-hand side has unknown type, then it is an
                 overloaded function.  Call instantiate_type to get error
                 messages.  */
@@ -10406,7 +10427,6 @@ convert_for_assignment (tree type, tree rhs,
                    (rhs_loc,
                     has_loc ? &label : NULL,
                     has_loc ? highlight_colors::percent_h : NULL);
-                 auto_diagnostic_group d;
 
                  switch (errtype)
                    {
@@ -11150,6 +11170,7 @@ check_return_expr (tree retval, bool *no_warning, bool 
*dangling)
       if (!retval && !is_auto (pattern))
        {
          /* Give a helpful error message.  */
+         auto_diagnostic_group d;
          error ("return-statement with no value, in function returning %qT",
                 pattern);
          inform (input_location, "only plain %<auto%> return type can be "
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index a0c8f833ac1..79b397a69fa 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -302,6 +302,7 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree 
value,
   if (TREE_CODE (type) == ERROR_MARK)
     return false;
 
+  auto_diagnostic_group d;
   if (value)
     {
       STRIP_ANY_LOCATION_WRAPPER (value);
-- 
2.46.0


Reply via email to