diff mbox series

c++: Add missing auto_diagnostic_groups

Message ID 66b3ff86.a70a0220.1b74f1.01fa@mx.google.com
State New
Headers show
Series c++: Add missing auto_diagnostic_groups | expand

Commit Message

Nathaniel Shead Aug. 7, 2024, 11:13 p.m. UTC
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >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 <nathanieloshead@gmail.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      |  47 +++++++++++++------
 gcc/cp/typeck2.cc     |   1 +
 21 files changed, 286 insertions(+), 79 deletions(-)

Comments

Marek Polacek Aug. 8, 2024, 7:16 p.m. UTC | #1
On Thu, Aug 08, 2024 at 09:13:05AM +1000, Nathaniel Shead wrote:
> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> index 6c22ff55b46..03c19e4a7e4 100644
> --- a/gcc/cp/error.cc
> +++ b/gcc/cp/error.cc
> @@ -4782,12 +4782,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);

I don't see why we need the second a_d_d here.

> @@ -3534,6 +3536,7 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
>        else
>  	{
>  	  /* Look up the member.  */
> +	  auto_diagnostic_group d;
>  	  access_failure_info afi;
>  	  if (processing_template_decl)
>  	    /* Even though this class member access expression is at this

I don't quite see why we need it here, either.

> @@ -10384,6 +10401,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 +10425,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;

Oh I see, it was supposed to be in the outer block.  OK.

The patch looks good to me, thanks.

Marek
Nathaniel Shead Aug. 9, 2024, 1:03 a.m. UTC | #2
On Thu, Aug 08, 2024 at 03:16:24PM -0400, Marek Polacek wrote:
> On Thu, Aug 08, 2024 at 09:13:05AM +1000, Nathaniel Shead wrote:
> > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > index 6c22ff55b46..03c19e4a7e4 100644
> > --- a/gcc/cp/error.cc
> > +++ b/gcc/cp/error.cc
> > @@ -4782,12 +4782,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);
> 
> I don't see why we need the second a_d_d here.
> 

The 'suggest_alternative_in_scoped_enum' call can register an 'inform'
to be called in 'name_hint's destructor, specifically contained within
name_hint::m_deferred (a deferred_diagnostic).

Most other uses of 'name_hint' that I could find seemed to be correctly
grouped already.

> > @@ -3534,6 +3536,7 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
> >        else
> >  	{
> >  	  /* Look up the member.  */
> > +	  auto_diagnostic_group d;
> >  	  access_failure_info afi;
> >  	  if (processing_template_decl)
> >  	    /* Even though this class member access expression is at this
> 
> I don't quite see why we need it here, either.
> 

A little later on in this block there's afi.maybe_suggest_accessor,
which emits an 'inform' with a fixit suggesting how to access the
member, which I feel should probably be part of the same group as the
error emitted from the 'lookup_member' call.

But I suppose this should be grouped more clearly, e.g.

--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3534,7 +3536,6 @@ 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
@@ -3543,12 +3544,18 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
                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;
+            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))

> > @@ -10384,6 +10401,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 +10425,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;
> 
> Oh I see, it was supposed to be in the outer block.  OK.
> 
> The patch looks good to me, thanks.
> 
> Marek
> 

Thanks, I'll wait for final approval from someone for once I've finished
bootstrap+regtest with the above adjustment.

Nathaniel
Nathaniel Shead Aug. 9, 2024, 1:10 a.m. UTC | #3
On Fri, Aug 09, 2024 at 11:03:24AM +1000, Nathaniel Shead wrote:
> On Thu, Aug 08, 2024 at 03:16:24PM -0400, Marek Polacek wrote:
> > On Thu, Aug 08, 2024 at 09:13:05AM +1000, Nathaniel Shead wrote:
> > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > > index 6c22ff55b46..03c19e4a7e4 100644
> > > --- a/gcc/cp/error.cc
> > > +++ b/gcc/cp/error.cc
> > > @@ -4782,12 +4782,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);
> > 
> > I don't see why we need the second a_d_d here.
> > 
> 
> The 'suggest_alternative_in_scoped_enum' call can register an 'inform'
> to be called in 'name_hint's destructor, specifically contained within
> name_hint::m_deferred (a deferred_diagnostic).
> 
> Most other uses of 'name_hint' that I could find seemed to be correctly
> grouped already.
> 
> > > @@ -3534,6 +3536,7 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
> > >        else
> > >  	{
> > >  	  /* Look up the member.  */
> > > +	  auto_diagnostic_group d;
> > >  	  access_failure_info afi;
> > >  	  if (processing_template_decl)
> > >  	    /* Even though this class member access expression is at this
> > 
> > I don't quite see why we need it here, either.
> > 
> 
> A little later on in this block there's afi.maybe_suggest_accessor,
> which emits an 'inform' with a fixit suggesting how to access the
> member, which I feel should probably be part of the same group as the
> error emitted from the 'lookup_member' call.
> 
> But I suppose this should be grouped more clearly, e.g.
> 
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -3534,7 +3536,6 @@ 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
> @@ -3543,12 +3544,18 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
>                 ahead of time here; we're going to redo this member lookup at
>                 instantiation time anyway.  */
>              push_deferring_access_checks (dk_no_check);

Actually it feels wrong for the p_d_a_c to not be part of this group;
here's a better incremental patch on my first submission:

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index d4fc848bfa1..e4e260645f6 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3536,22 +3536,24 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
       else
         {
           /* Look up the member.  */
-          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));
+          {
+            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))

Nathaniel
Marek Polacek Aug. 9, 2024, 4:05 p.m. UTC | #4
On Fri, Aug 09, 2024 at 11:03:24AM +1000, Nathaniel Shead wrote:
> On Thu, Aug 08, 2024 at 03:16:24PM -0400, Marek Polacek wrote:
> > On Thu, Aug 08, 2024 at 09:13:05AM +1000, Nathaniel Shead wrote:
> > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > > index 6c22ff55b46..03c19e4a7e4 100644
> > > --- a/gcc/cp/error.cc
> > > +++ b/gcc/cp/error.cc
> > > @@ -4782,12 +4782,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);
> > 
> > I don't see why we need the second a_d_d here.
> > 
> 
> The 'suggest_alternative_in_scoped_enum' call can register an 'inform'
> to be called in 'name_hint's destructor, specifically contained within
> name_hint::m_deferred (a deferred_diagnostic).
> 
> Most other uses of 'name_hint' that I could find seemed to be correctly
> grouped already.

Ah okay.
 
> > > @@ -3534,6 +3536,7 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
> > >        else
> > >  	{
> > >  	  /* Look up the member.  */
> > > +	  auto_diagnostic_group d;
> > >  	  access_failure_info afi;
> > >  	  if (processing_template_decl)
> > >  	    /* Even though this class member access expression is at this
> > 
> > I don't quite see why we need it here, either.
> > 
> 
> A little later on in this block there's afi.maybe_suggest_accessor,
> which emits an 'inform' with a fixit suggesting how to access the
> member, which I feel should probably be part of the same group as the
> error emitted from the 'lookup_member' call.

Interesting.

> But I suppose this should be grouped more clearly, e.g.
> 
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -3534,7 +3536,6 @@ 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
> @@ -3543,12 +3544,18 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
>                 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;
> +            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))
> 
> > > @@ -10384,6 +10401,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 +10425,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;
> > 
> > Oh I see, it was supposed to be in the outer block.  OK.
> > 
> > The patch looks good to me, thanks.
> > 
> > Marek
> > 
> 
> Thanks, I'll wait for final approval from someone for once I've finished
> bootstrap+regtest with the above adjustment.

Nice.  Thanks for cleaning this up!

Marek
Nathaniel Shead Sept. 2, 2024, 11:43 a.m. UTC | #5
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 <nathanieloshead@gmail.com>
Reviewed-by: Marek Polacek <polacek@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);
Jason Merrill Sept. 4, 2024, 3:10 p.m. UTC | #6
On 9/2/24 7:43 AM, Nathaniel Shead wrote:
> Ping for https://gcc.gnu.org/pipermail/gcc-patches/2024-August/659796.html

OK.

> 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 <nathanieloshead@gmail.com>
> Reviewed-by: Marek Polacek <polacek@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);
diff mbox series

Patch

diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 718601756dd..49af6d9367d 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);
@@ -2550,6 +2554,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);
@@ -3818,6 +3823,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",
@@ -4134,6 +4140,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",
@@ -4212,6 +4219,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))
@@ -8916,6 +8924,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);
 
@@ -8943,6 +8952,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);
 
@@ -9400,6 +9410,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 145ec4b1d16..cde013b09ad 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -300,6 +300,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);
@@ -627,6 +628,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"
@@ -1017,6 +1019,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 86d2bfab22d..4621264f126 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1456,6 +1456,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,
@@ -1566,6 +1567,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);
@@ -1901,6 +1903,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,
@@ -1923,6 +1926,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);
 
@@ -1946,6 +1950,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,
@@ -1966,6 +1971,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);
@@ -1987,6 +1993,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,
@@ -1998,6 +2005,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);
@@ -2009,6 +2017,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,
@@ -2310,10 +2319,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
@@ -2326,6 +2338,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);
@@ -3596,6 +3609,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;
@@ -3711,6 +3725,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;
@@ -3857,6 +3872,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.  */
@@ -4530,6 +4546,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);
 	}
@@ -4625,6 +4642,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);
@@ -5763,6 +5781,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))
@@ -5998,6 +6017,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 "
@@ -6660,6 +6680,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),
@@ -6697,6 +6718,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)
@@ -7061,6 +7083,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);
@@ -7883,6 +7906,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)
@@ -8559,6 +8583,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);
@@ -9058,6 +9083,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
@@ -9113,6 +9139,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);
@@ -9124,6 +9151,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),
@@ -9424,6 +9452,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",
@@ -9504,6 +9533,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);
@@ -10095,6 +10125,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%> "
@@ -10869,6 +10900,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");
@@ -10877,6 +10909,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");
@@ -10896,6 +10929,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;
@@ -11062,6 +11096,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);
@@ -13216,6 +13251,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 "
@@ -13287,6 +13323,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))
@@ -13448,6 +13485,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);
@@ -13499,6 +13537,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));
@@ -14735,6 +14774,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),
@@ -14801,6 +14841,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));
@@ -14846,6 +14887,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");
@@ -16357,6 +16399,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));
@@ -16371,6 +16414,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;
@@ -16378,6 +16422,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;
@@ -16435,6 +16480,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;
@@ -16444,6 +16490,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;
@@ -16494,6 +16541,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)
@@ -16630,6 +16678,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;
@@ -17613,6 +17662,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");
@@ -18698,6 +18748,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 695d5f8d790..87cf0c567de 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -908,6 +908,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)
@@ -5002,6 +5003,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);
@@ -5924,6 +5926,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 6c22ff55b46..03c19e4a7e4 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -4782,12 +4782,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 0f3e1d97c53..2eaf2bb6a74 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -11617,6 +11617,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),
@@ -12672,6 +12673,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),
@@ -14487,6 +14489,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;
@@ -17845,6 +17848,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",
@@ -18119,6 +18123,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))
@@ -18932,6 +18937,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 ();
@@ -19865,6 +19871,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"));
@@ -20509,6 +20516,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 8823ab71c60..ee3116910bc 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -2884,6 +2884,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)
@@ -6190,6 +6191,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);
@@ -6321,6 +6323,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);
@@ -6420,6 +6423,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),
@@ -8904,6 +8908,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),
@@ -9223,6 +9228,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);
@@ -9273,6 +9279,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 82f3903838e..8a5c4a8cd20 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -3500,6 +3500,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,
@@ -5082,24 +5083,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;
@@ -7155,6 +7159,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))
 		    {
@@ -9632,10 +9637,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);
 	}
     }
@@ -10431,6 +10439,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"))
@@ -11705,6 +11714,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);
@@ -11716,6 +11726,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))
@@ -15215,6 +15226,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;
@@ -15292,19 +15304,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
     {
@@ -15332,7 +15347,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)
@@ -15625,6 +15643,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,
@@ -16876,6 +16895,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],
@@ -19125,6 +19145,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"))
 	{
@@ -19164,6 +19185,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 "
@@ -19409,10 +19431,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);
@@ -20080,6 +20105,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 ();
 
@@ -20912,6 +20938,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");
 	}
@@ -21525,6 +21552,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");
@@ -21877,6 +21905,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)),
@@ -22924,6 +22953,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");
@@ -22941,6 +22971,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");
@@ -22955,6 +22986,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");
@@ -23768,12 +23800,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,
@@ -24474,6 +24507,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,
@@ -27860,6 +27894,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",
@@ -28310,6 +28345,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 "
@@ -32408,6 +32444,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);
@@ -33219,6 +33256,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
@@ -35195,6 +35233,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 2db59213c54..633b7b4f578 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))
@@ -2466,6 +2467,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)
@@ -2480,6 +2482,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);
@@ -4306,6 +4309,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)
         {
@@ -4450,6 +4454,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);
@@ -5136,7 +5141,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;
 
@@ -5190,24 +5194,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]
 
@@ -5219,6 +5228,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, "
@@ -5236,6 +5246,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");
@@ -5246,6 +5257,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.  */
@@ -6136,6 +6148,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)))
@@ -6341,6 +6354,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",
@@ -6857,6 +6871,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);
@@ -6927,6 +6942,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);
@@ -7790,6 +7806,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",
@@ -8648,6 +8665,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);
@@ -8682,6 +8700,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);
@@ -8732,6 +8751,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);
@@ -8750,6 +8770,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);
@@ -9132,6 +9153,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;
@@ -9167,6 +9189,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 "
@@ -17344,6 +17367,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);
@@ -20934,6 +20958,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 "
@@ -26366,6 +26391,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
@@ -30804,6 +30830,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,
@@ -30960,6 +30987,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)
@@ -30977,6 +31005,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);
@@ -30992,6 +31021,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,
@@ -31119,6 +31149,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 e58612660c9..d61e809ab80 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);
@@ -4243,6 +4244,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)
@@ -4263,6 +4265,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")
@@ -4498,6 +4501,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);
@@ -4904,6 +4908,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");
 	}
@@ -6316,6 +6321,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;
@@ -8388,6 +8394,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",
@@ -8610,6 +8617,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)]);
@@ -8777,6 +8785,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..d4fc848bfa1 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,6 +3536,7 @@  finish_class_member_access_expr (cp_expr object, tree name, bool template_p,
       else
 	{
 	  /* Look up the member.  */
+	  auto_diagnostic_group d;
 	  access_failure_info afi;
 	  if (processing_template_decl)
 	    /* Even though this class member access expression is at this
@@ -4504,6 +4507,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 +4956,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 +6111,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 +6125,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 +6971,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 +7506,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 +8734,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 +9694,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 +9986,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 +10401,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 +10425,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 +11168,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 30a6fbe95c9..a05b14179b3 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);