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