]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add support for grouping of related diagnostics (PR other/84889)
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 20 Aug 2018 21:06:46 +0000 (21:06 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Mon, 20 Aug 2018 21:06:46 +0000 (21:06 +0000)
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.

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.

From-SVN: r263675

54 files changed:
gcc/ChangeLog
gcc/attribs.c
gcc/c-family/ChangeLog
gcc/c-family/c-attribs.c
gcc/c-family/c-indentation.c
gcc/c-family/c-opts.c
gcc/c-family/c-warn.c
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/c/c-typeck.c
gcc/calls.c
gcc/cgraphunit.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/constexpr.c
gcc/cp/cp-gimplify.c
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/friend.c
gcc/cp/init.c
gcc/cp/lex.c
gcc/cp/name-lookup.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/search.c
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/diagnostic-core.h
gcc/diagnostic.c
gcc/diagnostic.h
gcc/gimple-ssa-isolate-paths.c
gcc/gimple-ssa-warn-alloca.c
gcc/gimple-ssa-warn-restrict.c
gcc/gimplify.c
gcc/hsa-gen.c
gcc/ipa-devirt.c
gcc/multiple_target.c
gcc/opts-common.c
gcc/reginfo.c
gcc/substring-locations.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/plugin/diagnostic-group-test-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/plugin.exp
gcc/tree-inline.c
gcc/tree-ssa-ccp.c
gcc/tree-ssa-loop-niter.c
gcc/tree-ssa-uninit.c
gcc/tree.c

index eb7ac76f675b13fa16079af7ba924ce1750822e8..515ea8a087a21bf568c37ca851552342d9a712f9 100644 (file)
@@ -1,3 +1,58 @@
+2018-08-20  David Malcolm  <dmalcolm@redhat.com>
+
+       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.
+
 2018-08-20  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/87014
index efc879ba47674f606231213ee210fc93ae7a64a3..64700b6c8ce332d38c1dbbec744e14e4467c8d77 100644 (file)
@@ -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 "
index 9ff4728fd67bac1a68439577b846d32bbfcd547e..aa52815cc751b29498b9fe782ac81405a6b06287 100644 (file)
@@ -1,3 +1,14 @@
+2018-08-20  David Malcolm  <dmalcolm@redhat.com>
+
+       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.
+
 2018-08-20  Nathan Sidwell  <nathan@acm.org>
 
        * c-ada-spec.c (macro_length, dump_ada_macros): Adjust macro parm
index 9da9c2765e34737dae7a44eb4e72854ba8fa8458..5454e09adbcbb6f9a992f6f38f3e2d17c86a0ede 100644 (file)
@@ -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 "
index 436d61b3c9af0a0632e7ba18a0c53266c1f00171..cff5aec23c23ab173fea705023be8174e4eac7f2 100644 (file)
@@ -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)))
index cb69fb3513c7cb544c6252461fb384629b6607d6..ec0577139d098184f952d3bb306ca2fba0f99dfb 100644 (file)
@@ -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 "
index d34d6672937c539c394caee44369e983ab4315d5..ca259aa7bd0ca59e83d29eeae3d41d76bde221e0 100644 (file)
@@ -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 "
index 7bde11c1f1959c2eead755bc7b170704c54660f4..e943f0aac4a93a3158bf483c73ed0c9675098fcf 100644 (file)
@@ -1,3 +1,26 @@
+2018-08-20  David Malcolm  <dmalcolm@redhat.com>
+
+       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.
+
 2018-08-15  David Malcolm  <dmalcolm@redhat.com>
 
        * c-objc-common.c: Include "gcc-rich-location.h".
index 1bbccddab31de598516ecacb3f43370951a408d0..95249779e3c8350c2286f0ead1858d20f2b374ef 100644 (file)
@@ -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);
index 5ad4f57a4fe7883651cb46c44e60128c64ca16ed..0d5dbea8f6770120e4c2360f11eed290e81b69bd 100644 (file)
@@ -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;                                                                \
index 726ea832ae1056e47499bd717c6ab226aa26eeac..54c7967a06b84bc185d2601f25154506b1866147 100644 (file)
@@ -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,
index 384c0238748d1748d3f0b12438ae4d5009cf70ec..0fb10b182b1a34c4e9c4f786e592397a646f7eef 100644 (file)
@@ -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])
index 462e247328ea988bbfa51fa0b639cfab89fed229..208798f0dc7a8e636e91ff7bb70a1f5cff4c97cc 100644 (file)
@@ -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");
+       }
     }
 }
 
index d8be93089b4c6e555d5acad45f84d4b795c51e2a..28c09740aa697071a6b424d57348854e302cc14a 100644 (file)
@@ -1,3 +1,73 @@
+2018-08-20  David Malcolm  <dmalcolm@redhat.com>
+
+       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.
+
 2018-08-17  David Malcolm  <dmalcolm@redhat.com>
 
        * typeck.c (string_conv_p): Extract location from EXP and use it
index 16bb6bfd46726b68c264fde3bc484f3dca48e2fe..1f72ac863bde4ebe54d946582ba3c6d4f307db3c 100644 (file)
@@ -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 "
index 7b10b20ede5eac19ed85b22ac27e874b4a871b55..e11173d2e59bc5c08b31f44ec871ded2b819b957 100644 (file)
@@ -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 (location_of (fmem->enclosing), OPT_Wpedantic,
-                 TYPE_DOMAIN (TREE_TYPE (fmem->array))
-                 ? G_("invalid use of %q#T with a zero-size array "
-                      "in %q#D")
-                 : G_("invalid use of %q#T with a flexible array member "
-                      "in %q#T"),
-                 DECL_CONTEXT (fmem->array),
-                 DECL_CONTEXT (fmem->enclosing)))
-    inform (DECL_SOURCE_LOCATION (fmem->array),
-           "array member %q#D declared here", fmem->array);
+  if (fmem->array && fmem->enclosing)
+    {
+      auto_diagnostic_group d;
+      if (pedwarn (location_of (fmem->enclosing), OPT_Wpedantic,
+                    TYPE_DOMAIN (TREE_TYPE (fmem->array))
+                    ? G_("invalid use of %q#T with a zero-size array "
+                         "in %q#D")
+                    : G_("invalid use of %q#T with a flexible array member "
+                         "in %q#T"),
+                    DECL_CONTEXT (fmem->array),
+                    DECL_CONTEXT (fmem->enclosing)))
+       inform (DECL_SOURCE_LOCATION (fmem->array),
+                 "array member %q#D declared here", fmem->array);
+    }
 }
 
 /* Issue diagnostics for invalid flexible array members or zero-length
@@ -6671,6 +6687,7 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem)
        {
          location_t loc = DECL_SOURCE_LOCATION (fmem->array);
 
+         auto_diagnostic_group d;
          if (pedwarn (loc, OPT_Wpedantic, msg, fmem->array, t))
            {
              inform (location_of (t), "in the definition of %q#T", t);
@@ -6690,6 +6707,7 @@ diagnose_flexarrays (tree t, const flexmems_t *fmem)
          location_t loc = DECL_SOURCE_LOCATION (fmem->array);
          diagd = true;
 
+         auto_diagnostic_group d;
          error_at (loc, msg, fmem->array, t);
 
          /* In the unlikely event that the member following the flexible
@@ -7923,6 +7941,7 @@ resolve_address_of_overloaded_function (tree target_type,
       if (!(complain & tf_error))
        return error_mark_node;
 
+      auto_diagnostic_group d;
       if (permerror (input_location, "assuming pointer to member %qD", fn)
          && !explained)
        {
index ece2c8a92d996502547431a26f597063fd8b45c5..54c8b5edf8d155d12635bdfdf096fc041464a370 100644 (file)
@@ -97,6 +97,7 @@ ensure_literal_type_for_constexpr_object (tree decl)
        {
          if (DECL_DECLARED_CONSTEXPR_P (decl))
            {
+             auto_diagnostic_group d;
              error ("the type %qT of %<constexpr%> variable %qD "
                     "is not literal", type, decl);
              explain_non_literal_class (type);
@@ -106,6 +107,7 @@ ensure_literal_type_for_constexpr_object (tree decl)
            {
              if (!is_instantiation_of_constexpr (current_function_decl))
                {
+                 auto_diagnostic_group d;
                  error ("variable %qD of non-literal type %qT in %<constexpr%> "
                         "function", decl, type);
                  explain_non_literal_class (type);
@@ -200,6 +202,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
            ret = false;
            if (complain)
              {
+               auto_diagnostic_group d;
                error ("invalid type for parameter %d of %<constexpr%> "
                       "function %q+#D", DECL_PARM_INDEX (parm), fun);
                explain_non_literal_class (TREE_TYPE (parm));
@@ -222,6 +225,7 @@ is_valid_constexpr_fn (tree fun, bool complain)
          ret = false;
          if (complain)
            {
+             auto_diagnostic_group d;
              error ("invalid return type %qT of %<constexpr%> function %q+D",
                     rettype, fun);
              explain_non_literal_class (rettype);
@@ -234,11 +238,15 @@ is_valid_constexpr_fn (tree fun, bool complain)
          && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun)))
        {
          ret = false;
-         if (complain
-             && pedwarn (DECL_SOURCE_LOCATION (fun), OPT_Wpedantic,
-                         "enclosing class of %<constexpr%> non-static member "
-                         "function %q+#D is not a literal type", fun))
-           explain_non_literal_class (DECL_CONTEXT (fun));
+         if (complain)
+           {
+             auto_diagnostic_group d;
+             if (pedwarn (DECL_SOURCE_LOCATION (fun), OPT_Wpedantic,
+                            "enclosing class of %<constexpr%> non-static"
+                            " member function %q+#D is not a literal type",
+                            fun))
+               explain_non_literal_class (DECL_CONTEXT (fun));
+           }
        }
     }
   else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun)))
@@ -818,6 +826,7 @@ cx_check_missing_mem_inits (tree ctype, tree body, bool complain)
            }
          if (!complain)
            return true;
+         auto_diagnostic_group d;
          error ("member %qD must be initialized by mem-initializer "
                 "in %<constexpr%> constructor", field);
          inform (DECL_SOURCE_LOCATION (field), "declared here");
@@ -4303,6 +4312,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        {
          if (!ctx->quiet)
            {
+             auto_diagnostic_group d;
              error ("temporary of non-literal type %qT in a "
                     "constant expression", TREE_TYPE (t));
              explain_non_literal_class (TREE_TYPE (t));
@@ -5995,6 +6005,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
        {
          if (flags & tf_error)
            {
+             auto_diagnostic_group d;
              error_at (loc, "temporary of non-literal type %qT in a "
                        "constant expression", TREE_TYPE (t));
              explain_non_literal_class (TREE_TYPE (t));
index 7db4accb5043332af01f1c45b67b8ec44ce50759..f61099141026b793daab149f989ca2b14d265d48 100644 (file)
@@ -1420,12 +1420,15 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
          /* Never mind.  */;
        else if (wtd->try_block)
          {
-           if (TREE_CODE (wtd->try_block) == MUST_NOT_THROW_EXPR
-               && warning_at (loc, OPT_Wterminate,
-                              "throw will always call terminate()")
-               && cxx_dialect >= cxx11
-               && DECL_DESTRUCTOR_P (current_function_decl))
-             inform (loc, "in C++11 destructors default to noexcept");
+           if (TREE_CODE (wtd->try_block) == MUST_NOT_THROW_EXPR)
+             {
+               auto_diagnostic_group d;
+               if (warning_at (loc, OPT_Wterminate,
+                               "throw will always call terminate()")
+                   && cxx_dialect >= cxx11
+                   && DECL_DESTRUCTOR_P (current_function_decl))
+                 inform (loc, "in C++11 destructors default to noexcept");
+             }
          }
        else
          {
index da98414855626ba6b5f4dc78b8da431f109cc9e5..315b0d6a65acbeb2455478ca42e9cfae70d0089a 100644 (file)
@@ -1017,6 +1017,7 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
   if (implicit != ICV_CAST && fn
       && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
     {
+      auto_diagnostic_group d;
       if (warning_at (loc, OPT_Wunused_result,
                      "ignoring return value of %qD, "
                      "declared with attribute nodiscard", fn))
@@ -1025,6 +1026,7 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
   else if (implicit != ICV_CAST
           && lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)))
     {
+      auto_diagnostic_group d;
       if (warning_at (loc, OPT_Wunused_result,
                      "ignoring returned value of type %qT, "
                      "declared with attribute nodiscard", rettype))
@@ -1043,6 +1045,7 @@ maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
         result is used, so handle that case here.  */
       if (fn)
        {
+         auto_diagnostic_group d;
          if (warning_at (loc, OPT_Wunused_result,
                          "ignoring return value of %qD, "
                          "declared with attribute warn_unused_result",
index fa58bc4d2b3ee69254e4d4c367dc16eccab64bed..f6dbd6b11c36f907f33df89186f6d697921bbe8f 100644 (file)
@@ -1133,6 +1133,7 @@ warn_extern_redeclared_static (tree newdecl, tree olddecl)
       && DECL_ARTIFICIAL (olddecl))
     return;
 
+  auto_diagnostic_group d;
   if (permerror (DECL_SOURCE_LOCATION (newdecl),
                 "%qD was declared %<extern%> and later %<static%>", newdecl))
     inform (DECL_SOURCE_LOCATION (olddecl),
@@ -1176,6 +1177,7 @@ check_redeclaration_exception_specification (tree new_decl,
        = G_("declaration of %qF has a different exception specifier");
       bool complained = true;
       location_t new_loc = DECL_SOURCE_LOCATION (new_decl);
+      auto_diagnostic_group d;
       if (DECL_IN_SYSTEM_HEADER (old_decl))
        complained = pedwarn (new_loc, OPT_Wsystem_headers, msg, new_decl);
       else if (!flag_exceptions)
@@ -1304,6 +1306,7 @@ check_no_redeclaration_friend_default_args (tree olddecl, tree newdecl,
     if ((olddecl_hidden_friend_p && TREE_PURPOSE (t1))
        || (DECL_FRIEND_P (newdecl) && TREE_PURPOSE (t2)))
       {
+       auto_diagnostic_group d;
        if (permerror (DECL_SOURCE_LOCATION (newdecl),
                       "friend declaration of %q#D specifies default "
                       "arguments and isn't the only declaration", newdecl))
@@ -1555,6 +1558,7 @@ next_arg:;
                                    "declaration %q#D", newdecl, olddecl);
                          return error_mark_node;
                        }
+                     auto_diagnostic_group d;
                      if (permerror (newdecl_loc,
                                     "new declaration %q#D ambiguates built-in"
                                     " declaration %q#D", newdecl, olddecl)
@@ -1801,6 +1805,7 @@ next_arg:;
       const char *errmsg = redeclaration_error_message (newdecl, olddecl);
       if (errmsg)
        {
+         auto_diagnostic_group d;
          error_at (newdecl_loc, errmsg, newdecl);
          if (DECL_NAME (olddecl) != NULL_TREE)
            inform (olddecl_loc,
@@ -1815,6 +1820,7 @@ next_arg:;
               && prototype_p (TREE_TYPE (newdecl)))
        {
          /* Prototype decl follows defn w/o prototype.  */
+         auto_diagnostic_group d;
          if (warning_at (newdecl_loc, 0,
                          "prototype specified for %q#D", newdecl))
            inform (olddecl_loc,
@@ -1856,6 +1862,7 @@ next_arg:;
            }
          else
            {
+             auto_diagnostic_group d;
              error_at (newdecl_loc,
                        "conflicting declaration of %q#D with %qL linkage",
                        newdecl, DECL_LANGUAGE (newdecl));
@@ -1893,6 +1900,7 @@ next_arg:;
                    if (simple_cst_equal (TREE_PURPOSE (t1),
                                          TREE_PURPOSE (t2)) == 1)
                      {
+                       auto_diagnostic_group d;
                        if (permerror (newdecl_loc,
                                       "default argument given for parameter "
                                       "%d of %q#D", i, newdecl))
@@ -1902,6 +1910,7 @@ next_arg:;
                      }
                    else
                      {
+                       auto_diagnostic_group d;
                        error_at (newdecl_loc,
                                  "default argument given for parameter %d "
                                  "of %q#D", i, newdecl);
@@ -1977,6 +1986,7 @@ next_arg:;
          && (! DECL_TEMPLATE_SPECIALIZATION (newdecl)
              || DECL_TEMPLATE_SPECIALIZATION (olddecl)))
        {
+         auto_diagnostic_group d;
          if (warning_at (newdecl_loc,
                          OPT_Wredundant_decls,
                          "redundant redeclaration of %qD in same scope",
@@ -1990,6 +2000,7 @@ next_arg:;
        {
          if (DECL_DELETED_FN (newdecl))
            {
+             auto_diagnostic_group d;
              error_at (newdecl_loc, "deleted definition of %qD", newdecl);
              inform (olddecl_loc,
                      "previous declaration of %qD", olddecl);
@@ -2567,6 +2578,7 @@ next_arg:;
       && DECL_VISIBILITY_SPECIFIED (newdecl)
       && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
     {
+      auto_diagnostic_group d;
       if (warning_at (newdecl_loc, OPT_Wattributes,
                      "%qD: visibility attribute ignored because it "
                      "conflicts with previous declaration", newdecl))
@@ -2986,12 +2998,15 @@ redeclaration_error_message (tree newdecl, tree olddecl)
        {
          DECL_EXTERNAL (newdecl) = 1;
          /* For now, only warn with explicit -Wdeprecated.  */
-         if (global_options_set.x_warn_deprecated
-             && warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
-                            "redundant redeclaration of %<constexpr%> static "
-                            "data member %qD", newdecl))
-           inform (DECL_SOURCE_LOCATION (olddecl),
-                   "previous declaration of %qD", olddecl);
+         if (global_options_set.x_warn_deprecated)
+           {
+             auto_diagnostic_group d;
+             if (warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
+                               "redundant redeclaration of %<constexpr%> "
+                               "static data member %qD", newdecl))
+               inform (DECL_SOURCE_LOCATION (olddecl),
+                         "previous declaration of %qD", olddecl);
+           }
          return NULL;
        }
 
@@ -4753,6 +4768,7 @@ warn_misplaced_attr_for_class_type (source_location location,
 {
   gcc_assert (OVERLOAD_TYPE_P (class_type));
 
+  auto_diagnostic_group d;
   if (warning_at (location, OPT_Wattributes,
                  "attribute ignored in declaration "
                  "of %q#T", class_type))
index d67ced097daf019911dca9d7f0c572b68215fda5..a5ad0eed3ad6ed2253efe9938d743cf8762448ec 100644 (file)
@@ -764,6 +764,7 @@ finish_static_data_member_decl (tree decl,
         t = CP_TYPE_CONTEXT (t))
       if (TYPE_UNNAMED_P (t))
        {
+         auto_diagnostic_group d;
          if (permerror (DECL_SOURCE_LOCATION (decl),
                         "static data member %qD in unnamed class", decl))
            inform (DECL_SOURCE_LOCATION (TYPE_NAME (t)),
@@ -4287,6 +4288,7 @@ no_linkage_error (tree decl)
   else if (TYPE_UNNAMED_P (t))
     {
       bool d = false;
+      auto_diagnostic_group grp;
       if (cxx_dialect >= cxx11)
        d = permerror (DECL_SOURCE_LOCATION (decl), "%q#D, declared using "
                       "unnamed type, is used but never defined", decl);
@@ -5208,6 +5210,7 @@ cp_warn_deprecated_use (tree decl, tsubst_flags_t complain)
       && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
       && copy_fn_p (decl))
     {
+      auto_diagnostic_group d;
       /* Don't warn about system library classes (c++/86342).  */
       if (!DECL_IN_SYSTEM_HEADER (decl))
        warned = warning (OPT_Wdeprecated_copy,
index 355a5e82f15064003e5668a8aa3c0e53e4a4afae..452ecb954677769ff9c16b13e408cf64fbc43ee6 100644 (file)
@@ -4270,12 +4270,14 @@ qualified_name_lookup_error (tree scope, tree name,
     }
   else if (scope != global_namespace)
     {
+      auto_diagnostic_group d;
       error_at (location, "%qD is not a member of %qD", name, scope);
       if (!suggest_alternative_in_explicit_scope (location, name, scope))
        suggest_alternatives_for (location, name, false);
     }
   else
     {
+      auto_diagnostic_group d;
       error_at (location, "%<::%D%> has not been declared", name);
       suggest_alternatives_for (location, name, true);
     }
index 2c9c12fab4a9bf78ffbd2ce68870c0999efd6db1..ce85a806620c8b5e8a5f2312b616460b89416651 100644 (file)
@@ -304,6 +304,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
       if (TYPE_TEMPLATE_INFO (friend_type)
          && !PRIMARY_TEMPLATE_P (TYPE_TI_TEMPLATE (friend_type)))
        {
+         auto_diagnostic_group d;
          error ("%qT is not a template", friend_type);
          inform (location_of (friend_type), "previous declaration here");
          if (TYPE_CLASS_SCOPE_P (friend_type)
@@ -384,6 +385,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
                }
              if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl))
                {
+                 auto_diagnostic_group d;
                  error ("%qT is not a member class template of %qT",
                         name, ctype);
                  inform (DECL_SOURCE_LOCATION (decl),
@@ -393,6 +395,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
              if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL
                                         || !CLASS_TYPE_P (TREE_TYPE (decl))))
                {
+                 auto_diagnostic_group d;
                  error ("%qT is not a nested class of %qT",
                         name, ctype);
                  inform (DECL_SOURCE_LOCATION (decl),
@@ -636,6 +639,7 @@ do_friend (tree ctype, tree declarator, tree decl,
              static int explained;
              bool warned;
 
+             auto_diagnostic_group d;
              warned = warning (OPT_Wnon_template_friend, "friend declaration "
                                "%q#D declares a non-template function", decl);
              if (! explained && warned)
index 94f8fdd7bd98891faa3bb9d0eb6eca8ea4825128..15046b4257bc7aac7b561801820ff997d71e123c 100644 (file)
@@ -915,6 +915,7 @@ perform_member_init (tree member, tree init)
            {
              /* TYPE_NEEDS_CONSTRUCTING can be set just because we have a
                 vtable; still give this diagnostic.  */
+             auto_diagnostic_group d;
              if (permerror (DECL_SOURCE_LOCATION (current_function_decl),
                             "uninitialized const member in %q#T", type))
                inform (DECL_SOURCE_LOCATION (member),
@@ -932,6 +933,7 @@ perform_member_init (tree member, tree init)
          /* member traversal: note it leaves init NULL */
          if (TYPE_REF_P (type))
            {
+             auto_diagnostic_group d;
              if (permerror (DECL_SOURCE_LOCATION (current_function_decl),
                             "uninitialized reference member in %q#T", type))
                inform (DECL_SOURCE_LOCATION (member),
@@ -939,6 +941,7 @@ perform_member_init (tree member, tree init)
            }
          else if (CP_TYPE_CONST_P (type))
            {
+             auto_diagnostic_group d;
              if (permerror (DECL_SOURCE_LOCATION (current_function_decl),
                             "uninitialized const member in %q#T", type))
                  inform (DECL_SOURCE_LOCATION (member),
@@ -3255,6 +3258,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
          || CP_DECL_CONTEXT (alloc_fn) == global_namespace)
       && !aligned_allocation_fn_p (alloc_fn))
     {
+      auto_diagnostic_group d;
       if (warning (OPT_Waligned_new_, "%<new%> of type %qT with extended "
                   "alignment %d", elt_type, TYPE_ALIGN_UNIT (elt_type)))
        {
@@ -3831,16 +3835,19 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
 
   if (!COMPLETE_TYPE_P (type))
     {
-      if ((complain & tf_warning)
-         && warning (OPT_Wdelete_incomplete,
-                     "possible problem detected in invocation of "
-                     "delete [] operator:"))
-       {
-         cxx_incomplete_type_diagnostic (base, type, DK_WARNING);
-         inform (input_location, "neither the destructor nor the "
-                 "class-specific operator delete [] will be called, "
-                 "even if they are declared when the class is defined");
-       }
+      if (complain & tf_warning)
+       {
+         auto_diagnostic_group d;
+         if (warning (OPT_Wdelete_incomplete,
+                        "possible problem detected in invocation of "
+                        "delete [] operator:"))
+           {
+             cxx_incomplete_type_diagnostic (base, type, DK_WARNING);
+             inform (input_location, "neither the destructor nor the "
+                       "class-specific operator delete [] will be called, "
+                       "even if they are declared when the class is defined");
+           }
+       }
       /* This size won't actually be used.  */
       size_exp = size_one_node;
       goto no_destructor;
@@ -4712,16 +4719,19 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
          complete_type (type);
          if (!COMPLETE_TYPE_P (type))
            {
-             if ((complain & tf_warning)
-                 && warning (OPT_Wdelete_incomplete,
-                             "possible problem detected in invocation of "
-                             "delete operator:"))
+             if (complain & tf_warning)
                {
-                 cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
-                 inform (input_location,
-                         "neither the destructor nor the class-specific "
-                         "operator delete will be called, even if they are "
-                         "declared when the class is defined");
+                 auto_diagnostic_group d;
+                 if (warning (OPT_Wdelete_incomplete,
+                                "possible problem detected in invocation of "
+                                "delete operator:"))
+                   {
+                     cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
+                     inform (input_location,
+                               "neither the destructor nor the class-specific "
+                               "operator delete will be called, even if they "
+                               "are declared when the class is defined");
+                   }
                }
            }
          else if (deleting && warn_delnonvdtor
index bd5d507e97b8ee0412b26c2bd45ab19a97869671..47b99c3c46927571393f44d1a5c66df5790d06c8 100644 (file)
@@ -499,6 +499,7 @@ unqualified_name_lookup_error (tree name, location_t loc)
     {
       if (!objc_diagnose_private_ivar (name))
        {
+         auto_diagnostic_group d;
          error_at (loc, "%qD was not declared in this scope", name);
          suggest_alternatives_for (loc, name, true);
        }
index 3ba76447f98cacbd2c2477a7260861ebffefffcb..8c7f68522da492220550683c45ae8f1676b1cd0d 100644 (file)
@@ -2556,6 +2556,7 @@ check_extern_c_conflict (tree decl)
 
       if (mismatch)
        {
+         auto_diagnostic_group d;
          pedwarn (input_location, 0,
                   "conflicting C language linkage declaration %q#D", decl);
          inform (DECL_SOURCE_LOCATION (old),
@@ -2604,6 +2605,15 @@ c_linkage_bindings (tree name)
   return NULL_TREE;
 }
 
+/* Subroutine of check_local_shadow.  */
+
+static void
+inform_shadowed (tree shadowed)
+{
+  inform (DECL_SOURCE_LOCATION (shadowed),
+         "shadowed declaration is here");
+}
+
 /* DECL is being declared at a local scope.  Emit suitable shadow
    warnings.  */
 
@@ -2631,7 +2641,6 @@ check_local_shadow (tree decl)
       old_scope = binding->scope;
     }
 
-  tree shadowed = NULL_TREE;
   if (old
       && (TREE_CODE (old) == PARM_DECL
          || VAR_P (old)
@@ -2702,6 +2711,7 @@ check_local_shadow (tree decl)
               && old_scope == current_binding_level->level_chain
               && (old_scope->kind == sk_cond || old_scope->kind == sk_for))
        {
+         auto_diagnostic_group d;
          error ("redeclaration of %q#D", decl);
          inform (DECL_SOURCE_LOCATION (old),
                  "%q#D previously declared here", old);
@@ -2724,6 +2734,7 @@ check_local_shadow (tree decl)
                       || current_binding_level->level_chain->kind == sk_catch)
                   && in_function_try_handler))
        {
+         auto_diagnostic_group d;
          if (permerror (input_location, "redeclaration of %q#D", decl))
            inform (DECL_SOURCE_LOCATION (old),
                    "%q#D previously declared here", old);
@@ -2764,11 +2775,9 @@ check_local_shadow (tree decl)
       else
        msg = "declaration of %qD shadows a previous local";
 
+      auto_diagnostic_group d;
       if (warning_at (input_location, warning_code, msg, decl))
-       {
-         shadowed = old;
-         goto inform_shadowed;
-       }
+       inform_shadowed (old);
       return;
     }
 
@@ -2793,14 +2802,12 @@ check_local_shadow (tree decl)
            || TYPE_PTRFN_P (TREE_TYPE (decl))
            || TYPE_PTRMEMFUNC_P (TREE_TYPE (decl)))
          {
+           auto_diagnostic_group d;
            if (warning_at (input_location, OPT_Wshadow,
                            "declaration of %qD shadows a member of %qT",
                            decl, current_nonlambda_class_type ())
                && DECL_P (member))
-             {
-               shadowed = member;
-               goto inform_shadowed;
-             }
+             inform_shadowed (member);
          }
        return;
       }
@@ -2815,20 +2822,15 @@ check_local_shadow (tree decl)
       && !instantiating_current_function_p ())
     /* XXX shadow warnings in outer-more namespaces */
     {
+      auto_diagnostic_group d;
       if (warning_at (input_location, OPT_Wshadow,
                      "declaration of %qD shadows a global declaration",
                      decl))
-       {
-         shadowed = old;
-         goto inform_shadowed;
-       }
+       inform_shadowed (old);
       return;
     }
 
   return;
-
- inform_shadowed:
-  inform (DECL_SOURCE_LOCATION (shadowed), "shadowed declaration is here");
 }
 
 /* DECL is being pushed inside function CTX.  Set its context, if
@@ -2954,6 +2956,7 @@ set_local_extern_decl_linkage (tree decl, bool shadowed)
                       && !comptypes (TREE_TYPE (decl), TREE_TYPE (other),
                                      COMPARE_REDECLARATION)))
            {
+             auto_diagnostic_group d;
              if (permerror (DECL_SOURCE_LOCATION (decl),
                             "local external declaration %q#D", decl))
                inform (DECL_SOURCE_LOCATION (other),
index 8cfcd150705f5a79e96fdf55ddfa4cf109294f15..aa5286b24ccbb6e7c8d77bffbcc60c15d7045744 100644 (file)
@@ -3280,6 +3280,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
   to specify an argument list. Emit a useful error message.  */
   if (DECL_TYPE_TEMPLATE_P (decl))
     {
+      auto_diagnostic_group d;
       error_at (location,
                "invalid use of template-name %qE without an argument list",
                decl);
@@ -3296,6 +3297,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
   else if (!parser->scope)
     {
       /* Issue an error message.  */
+      auto_diagnostic_group d;
       name_hint hint;
       if (TREE_CODE (id) == IDENTIFIER_NODE)
        hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, location);
@@ -3370,6 +3372,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
     {
       if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
        {
+         auto_diagnostic_group d;
          if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
            error_at (location_of (id),
                      "%qE in namespace %qE does not name a template type",
@@ -3392,6 +3395,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
               && constructor_name_p (id, parser->scope))
        {
          /* A<T>::A<T>() */
+         auto_diagnostic_group d;
          error_at (location, "%<%T::%E%> names the constructor, not"
                    " the type", parser->scope, id);
          if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
@@ -3417,6 +3421,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree id,
        }
       else if (TYPE_P (parser->scope))
        {
+         auto_diagnostic_group d;
          if (!COMPLETE_TYPE_P (parser->scope))
            cxx_incomplete_type_error (location_of (id), NULL_TREE,
                                       parser->scope);
@@ -18615,6 +18620,7 @@ cp_parser_namespace_name (cp_parser* parser)
     {
       if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
        {
+         auto_diagnostic_group d;
          error_at (token->location, "%qD is not a namespace-name", identifier);
          if (namespace_decl == error_mark_node
              && parser->scope && TREE_CODE (parser->scope) == NAMESPACE_DECL)
index cbb7b8ea853de2d4fed8830deb7ad78acadbf3eb..efed9a1bf60e92a911b2f9a3495eb0a6eb68bc71 100644 (file)
@@ -800,6 +800,7 @@ check_specialization_namespace (tree tmpl)
     return true;
   else
     {
+      auto_diagnostic_group d;
       if (permerror (input_location,
                     "specialization of %qD in different namespace", tmpl))
        inform (DECL_SOURCE_LOCATION (tmpl),
@@ -2592,6 +2593,7 @@ check_template_variable (tree decl)
     }
   if (template_header_count > wanted)
     {
+      auto_diagnostic_group d;
       bool warned = pedwarn (DECL_SOURCE_LOCATION (decl), 0,
                             "too many template headers for %qD "
                             "(should be %d)",
@@ -2724,6 +2726,7 @@ warn_spec_missing_attributes (tree tmpl, tree spec, tree attrlist)
   if (!nattrs)
     return;
 
+  auto_diagnostic_group d;
   if (warning_at (DECL_SOURCE_LOCATION (spec), OPT_Wmissing_attributes,
                  "explicit specialization %q#D may be missing attributes",
                  spec))
@@ -3070,6 +3073,7 @@ check_explicit_specialization (tree declarator,
          if (TREE_CODE (decl) == FUNCTION_DECL
              && DECL_HIDDEN_FRIEND_P (tmpl))
            {
+             auto_diagnostic_group d;
              if (pedwarn (DECL_SOURCE_LOCATION (decl), 0,
                           "friend declaration %qD is not visible to "
                           "explicit specialization", tmpl))
@@ -4891,6 +4895,7 @@ process_partial_specialization (tree decl)
           && TMPL_ARGS_DEPTH (specargs) == 1
           && !get_partial_spec_bindings (maintmpl, maintmpl, specargs))
     {
+      auto_diagnostic_group d;
       if (permerror (input_location, "partial specialization %qD is not "
                     "more specialized than", decl))
        inform (DECL_SOURCE_LOCATION (maintmpl), "primary template %qD",
@@ -9354,6 +9359,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
         {
           if (complain & tf_error)
             {
+             auto_diagnostic_group d;
               error ("template constraint failure");
               diagnose_constraints (input_location, gen_tmpl, arglist);
             }
@@ -9712,6 +9718,7 @@ finish_template_variable (tree var, tsubst_flags_t complain)
     {
       if (complain & tf_error)
        {
+         auto_diagnostic_group d;
          error ("use of invalid variable template %qE", var);
          diagnose_constraints (location_of (var), templ, arglist);
        }
@@ -26888,6 +26895,7 @@ do_auto_deduction (tree type, tree init, tree auto_node,
           {
             if (complain & tf_warning_or_error)
               {
+               auto_diagnostic_group d;
                 switch (context)
                   {
                   case adc_unspecified:
index c2860b0dc9a8e20e7d4690971afcfa4953e9ee62..d700fe328f4ba1172566a3f402dc8e3cda62aec8 100644 (file)
@@ -1911,6 +1911,7 @@ check_final_overrider (tree overrider, tree basefn)
        /* GNU extension, allow trivial pointer conversions such as
           converting to void *, or qualification conversion.  */
        {
+         auto_diagnostic_group d;
          if (pedwarn (DECL_SOURCE_LOCATION (overrider), 0,
                       "invalid covariant return type for %q#D", overrider))
            inform (DECL_SOURCE_LOCATION (basefn),
@@ -1927,12 +1928,14 @@ check_final_overrider (tree overrider, tree basefn)
     {
       if (fail == 1)
        {
+         auto_diagnostic_group d;
          error ("invalid covariant return type for %q+#D", overrider);
          inform (DECL_SOURCE_LOCATION (basefn),
                  "overridden function is %q#D", basefn);
        }
       else
        {
+         auto_diagnostic_group d;
          error ("conflicting return type specified for %q+#D", overrider);
          inform (DECL_SOURCE_LOCATION (basefn),
                  "overridden function is %q#D", basefn);
@@ -1949,6 +1952,7 @@ check_final_overrider (tree overrider, tree basefn)
 
   if (!comp_except_specs (base_throw, over_throw, ce_derived))
     {
+      auto_diagnostic_group d;
       error ("looser throw specifier for %q+#F", overrider);
       inform (DECL_SOURCE_LOCATION (basefn),
              "overridden function is %q#F", basefn);
@@ -1962,6 +1966,7 @@ check_final_overrider (tree overrider, tree basefn)
       && !tx_safe_fn_type_p (base_type)
       && !tx_safe_fn_type_p (over_type))
     {
+      auto_diagnostic_group d;
       error ("conflicting type attributes specified for %q+#D", overrider);
       inform (DECL_SOURCE_LOCATION (basefn),
              "overridden function is %q#D", basefn);
@@ -1978,6 +1983,7 @@ check_final_overrider (tree overrider, tree basefn)
       && !lookup_attribute ("transaction_safe_dynamic",
                            DECL_ATTRIBUTES (basefn)))
     {
+      auto_diagnostic_group d;
       error_at (DECL_SOURCE_LOCATION (overrider),
                "%qD declared %<transaction_safe_dynamic%>", overrider);
       inform (DECL_SOURCE_LOCATION (basefn),
@@ -1988,6 +1994,7 @@ check_final_overrider (tree overrider, tree basefn)
     {
       if (DECL_DELETED_FN (overrider))
        {
+         auto_diagnostic_group d;
          error ("deleted function %q+D overriding non-deleted function",
                 overrider);
          inform (DECL_SOURCE_LOCATION (basefn),
@@ -1996,6 +2003,7 @@ check_final_overrider (tree overrider, tree basefn)
        }
       else
        {
+         auto_diagnostic_group d;
          error ("non-deleted function %q+D overriding deleted function",
                 overrider);
          inform (DECL_SOURCE_LOCATION (basefn),
@@ -2005,6 +2013,7 @@ check_final_overrider (tree overrider, tree basefn)
     }
   if (DECL_FINAL_P (basefn))
     {
+      auto_diagnostic_group d;
       error ("virtual function %q+D overriding final function", overrider);
       inform (DECL_SOURCE_LOCATION (basefn),
              "overridden function is %qD", basefn);
@@ -2089,6 +2098,7 @@ look_for_overrides_r (tree type, tree fndecl)
        {
          /* A static member function cannot match an inherited
             virtual member function.  */
+         auto_diagnostic_group d;
          error ("%q+#D cannot be declared", fndecl);
          error ("  since %q+#D declared in base class", fn);
        }
index 1cf3269d88064d95aae6c820fe3dfa4dda4fcd3d..8a1d2993f946e8c12d726d5a90696420d07a6def 100644 (file)
@@ -4031,6 +4031,7 @@ maybe_warn_parm_abi (tree t, location_t loc)
       && classtype_has_non_deleted_move_ctor (t))
     {
       bool w;
+      auto_diagnostic_group d;
       if (flag_abi_version > 12)
        w = warning_at (loc, OPT_Wabi, "-fabi-version=13 (GCC 8.2) fixes the "
                        "calling convention for %qT, which was accidentally "
@@ -4043,6 +4044,7 @@ maybe_warn_parm_abi (tree t, location_t loc)
       return;
     }
 
+  auto_diagnostic_group d;
   if (warning_at (loc, OPT_Wabi, "the calling convention for %qT changes in "
                  "-fabi-version=13 (GCC 8.2)", t))
     inform (location_of (t), " because all of its copy and move "
index 8c13ae9b19ba18e18b7988a7ece16217d6c6732a..99be38ed8f862c3674ee5270411c711e33726f11 100644 (file)
@@ -1691,6 +1691,7 @@ cxx_sizeof_expr (tree e, tsubst_flags_t complain)
       && DECL_ARRAY_PARAMETER_P (e)
       && (complain & tf_warning))
     {
+      auto_diagnostic_group d;
       if (warning (OPT_Wsizeof_array_argument, "%<sizeof%> on array function "
                   "parameter %qE will return size of %qT", e, TREE_TYPE (e)))
        inform (DECL_SOURCE_LOCATION (e), "declared here");
@@ -3699,6 +3700,7 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
           && (complain & tf_error)
           && !constraints_satisfied_p (function))
         {
+          auto_diagnostic_group d;
           error ("cannot call function %qD", function);
           location_t loc = DECL_SOURCE_LOCATION (function);
           diagnose_constraints (loc, function, NULL_TREE);
@@ -4467,13 +4469,16 @@ cp_build_binary_op (location_t location,
                   && DECL_ARRAY_PARAMETER_P (first_arg)
                   && warn_sizeof_array_argument)
              && (complain & tf_warning))
-           if (warning_at (location, OPT_Wsizeof_pointer_div,
-                           "division %<sizeof (%T) / sizeof (%T)%> does "
-                           "not compute the number of array elements",
+           {
+             auto_diagnostic_group d;
+             if (warning_at (location, 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");
+               if (DECL_P (first_arg))
+                 inform (DECL_SOURCE_LOCATION (first_arg),
+                           "first %<sizeof%> operand was declared here");
+           }
        }
 
       if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
@@ -4766,12 +4771,15 @@ cp_build_binary_op (location_t location,
          else
            result_type = type0;
 
-         if (char_type_p (TREE_TYPE (orig_op1))
-             && warning (OPT_Wpointer_compare,
-                         "comparison between pointer and zero character "
-                         "constant"))
-           inform (input_location,
-                   "did you mean to dereference the pointer?");
+         if (char_type_p (TREE_TYPE (orig_op1)))
+           {
+             auto_diagnostic_group d;
+             if (warning (OPT_Wpointer_compare,
+                            "comparison between pointer and zero character "
+                            "constant"))
+               inform (input_location,
+                         "did you mean to dereference the pointer?");
+           }
          warn_for_null_address (location, op0, complain);
        }
       else if (((code1 == POINTER_TYPE || TYPE_PTRDATAMEM_P (type1))
@@ -4786,12 +4794,15 @@ cp_build_binary_op (location_t location,
          else
            result_type = type1;
 
-         if (char_type_p (TREE_TYPE (orig_op0))
-             && warning (OPT_Wpointer_compare,
-                         "comparison between pointer and zero character "
-                         "constant"))
-           inform (input_location,
-                   "did you mean to dereference the pointer?");
+         if (char_type_p (TREE_TYPE (orig_op0)))
+           {
+             auto_diagnostic_group d;
+             if (warning (OPT_Wpointer_compare,
+                            "comparison between pointer and zero character "
+                            "constant"))
+               inform (input_location,
+                       "did you mean to dereference the pointer?");
+           }
          warn_for_null_address (location, op1, complain);
        }
       else if ((code0 == POINTER_TYPE && code1 == POINTER_TYPE)
@@ -8807,6 +8818,7 @@ convert_for_assignment (tree type, tree rhs,
                }
              else if (fndecl)
                {
+                 auto_diagnostic_group d;
                  location_t loc = cp_expr_location (rhs);
                  range_label_for_type_mismatch rhs_label (rhstype, type);
                  range_label *label = &rhs_label;
@@ -9087,6 +9099,7 @@ maybe_warn_about_returning_address_of_local (tree retval)
           || TREE_PUBLIC (whats_returned)))
     {
       bool w = false;
+      auto_diagnostic_group d;
       if (TYPE_REF_P (valtype))
        w = warning_at (loc, OPT_Wreturn_local_addr,
                        "reference to local variable %qD returned",
index 674d08762b5ae44b952aa5b83fae17474a103c52..f42f0c2bf0747b5a6f6dc6db58c5efe170738277 100644 (file)
@@ -315,6 +315,7 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
   if (!(complain & tf_error))
     return 1;
 
+  auto_diagnostic_group d;
   if (decl)
     {
       if (VAR_P (decl))
@@ -983,6 +984,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain, bool const_only)
        {
          if (complain & tf_warning_or_error)
            {
+             auto_diagnostic_group d;
              if ((!almost_ok || pedantic)
                  && pedwarn (loc, OPT_Wnarrowing,
                              "narrowing conversion of %qE from %qH to %qI",
index aa5807e17e02a19d4d8f84b5fa742d8e79e6cd8d..e4ebe005ede532b67e94387cf4dc4f8006230f96 100644 (file)
@@ -36,6 +36,15 @@ typedef enum
   DK_POP
 } diagnostic_t;
 
+/* RAII-style class for grouping related diagnostics.  */
+
+class auto_diagnostic_group
+{
+ public:
+  auto_diagnostic_group ();
+  ~auto_diagnostic_group ();
+};
+
 extern const char *progname;
 
 extern const char *trim_filename (const char *);
index 7e8bcf52dc1e533a62b853cd438afcb65fff2c06..aae0934d21a66a6a336a995eb05ee4f54167ebb2 100644 (file)
@@ -180,6 +180,10 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
   context->show_ruler_p = false;
   context->parseable_fixits_p = false;
   context->edit_context_ptr = NULL;
+  context->diagnostic_group_nesting_depth = 0;
+  context->diagnostic_group_emission_count = 0;
+  context->begin_group_cb = NULL;
+  context->end_group_cb = NULL;
 }
 
 /* Maybe initialize the color support. We require clients to do this
@@ -986,6 +990,14 @@ diagnostic_report_diagnostic (diagnostic_context *context,
   else
     ++diagnostic_kind_count (context, diagnostic->kind);
 
+  /* Is this the initial diagnostic within the stack of groups?  */
+  if (context->diagnostic_group_emission_count == 0)
+    {
+      if (context->begin_group_cb)
+       context->begin_group_cb (context);
+    }
+  context->diagnostic_group_emission_count++;
+
   diagnostic->message.x_data = &diagnostic->x_data;
   diagnostic->x_data = NULL;
   pp_format (context->printer, &diagnostic->message);
@@ -1146,6 +1158,7 @@ bool
 emit_diagnostic (diagnostic_t kind, location_t location, int opt,
                 const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
@@ -1169,6 +1182,7 @@ emit_diagnostic_valist (diagnostic_t kind, location_t location, int opt,
 void
 inform (location_t location, const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
@@ -1182,6 +1196,7 @@ inform (rich_location *richloc, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   diagnostic_impl (richloc, -1, gmsgid, &ap, DK_NOTE);
@@ -1196,6 +1211,7 @@ inform_n (location_t location, unsigned HOST_WIDE_INT n,
 {
   va_list ap;
   va_start (ap, plural_gmsgid);
+  auto_diagnostic_group d;
   rich_location richloc (line_table, location);
   diagnostic_n_impl (&richloc, -1, n, singular_gmsgid, plural_gmsgid,
                     &ap, DK_NOTE);
@@ -1208,6 +1224,7 @@ inform_n (location_t location, unsigned HOST_WIDE_INT n,
 bool
 warning (int opt, const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
@@ -1223,6 +1240,7 @@ warning (int opt, const char *gmsgid, ...)
 bool
 warning_at (location_t location, int opt, const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
@@ -1238,6 +1256,7 @@ warning_at (rich_location *richloc, int opt, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_WARNING);
@@ -1253,6 +1272,7 @@ warning_n (rich_location *richloc, int opt, unsigned HOST_WIDE_INT n,
 {
   gcc_assert (richloc);
 
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, plural_gmsgid);
   bool ret = diagnostic_n_impl (richloc, opt, n,
@@ -1270,6 +1290,7 @@ bool
 warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
           const char *singular_gmsgid, const char *plural_gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, plural_gmsgid);
   rich_location richloc (line_table, location);
@@ -1296,6 +1317,7 @@ warning_n (location_t location, int opt, unsigned HOST_WIDE_INT n,
 bool
 pedwarn (location_t location, int opt, const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
@@ -1311,6 +1333,7 @@ pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   bool ret = diagnostic_impl (richloc, opt, gmsgid, &ap, DK_PEDWARN);
@@ -1328,6 +1351,7 @@ pedwarn (rich_location *richloc, int opt, const char *gmsgid, ...)
 bool
 permerror (location_t location, const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, location);
@@ -1343,6 +1367,7 @@ permerror (rich_location *richloc, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   bool ret = diagnostic_impl (richloc, -1, gmsgid, &ap, DK_PERMERROR);
@@ -1355,6 +1380,7 @@ permerror (rich_location *richloc, const char *gmsgid, ...)
 void
 error (const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
@@ -1368,6 +1394,7 @@ void
 error_n (location_t location, unsigned HOST_WIDE_INT n,
         const char *singular_gmsgid, const char *plural_gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, plural_gmsgid);
   rich_location richloc (line_table, location);
@@ -1380,6 +1407,7 @@ error_n (location_t location, unsigned HOST_WIDE_INT n,
 void
 error_at (location_t loc, const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, loc);
@@ -1394,6 +1422,7 @@ error_at (rich_location *richloc, const char *gmsgid, ...)
 {
   gcc_assert (richloc);
 
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   diagnostic_impl (richloc, -1, gmsgid, &ap, DK_ERROR);
@@ -1406,6 +1435,7 @@ error_at (rich_location *richloc, const char *gmsgid, ...)
 void
 sorry (const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
@@ -1427,6 +1457,7 @@ seen_error (void)
 void
 fatal_error (location_t loc, const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, loc);
@@ -1443,6 +1474,7 @@ fatal_error (location_t loc, const char *gmsgid, ...)
 void
 internal_error (const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
@@ -1458,6 +1490,7 @@ internal_error (const char *gmsgid, ...)
 void
 internal_error_no_backtrace (const char *gmsgid, ...)
 {
+  auto_diagnostic_group d;
   va_list ap;
   va_start (ap, gmsgid);
   rich_location richloc (line_table, input_location);
@@ -1515,6 +1548,33 @@ fancy_abort (const char *file, int line, const char *function)
   internal_error ("in %s, at %s:%d", function, trim_filename (file), line);
 }
 
+/* class auto_diagnostic_group.  */
+
+/* Constructor: "push" this group into global_dc.  */
+
+auto_diagnostic_group::auto_diagnostic_group ()
+{
+  global_dc->diagnostic_group_nesting_depth++;
+}
+
+/* Destructor: "pop" this group from global_dc.  */
+
+auto_diagnostic_group::~auto_diagnostic_group ()
+{
+  if (--global_dc->diagnostic_group_nesting_depth == 0)
+    {
+      /* Handle the case where we've popped the final diagnostic group.
+        If any diagnostics were emitted, give the context a chance
+        to do something.  */
+      if (global_dc->diagnostic_group_emission_count > 0)
+       {
+         if (global_dc->end_group_cb)
+           global_dc->end_group_cb (global_dc);
+       }
+      global_dc->diagnostic_group_emission_count = 0;
+    }
+}
+
 /* Really call the system 'abort'.  This has to go right at the end of
    this file, so that there are no functions after it that call abort
    and get the system abort instead of our macro.  */
index fe3130bdf9d14fa6e99b8a5fdc5c4725b89f1f88..34ea03bb6947c04ca18d704b2c59e723d2cf8e0e 100644 (file)
@@ -222,6 +222,23 @@ struct diagnostic_context
   /* If non-NULL, an edit_context to which fix-it hints should be
      applied, for generating patches.  */
   edit_context *edit_context_ptr;
+
+  /* How many diagnostic_group instances are currently alive.  */
+  int diagnostic_group_nesting_depth;
+
+  /* How many diagnostics have been emitted since the bottommost
+     diagnostic_group was pushed.  */
+  int diagnostic_group_emission_count;
+
+  /* Optional callbacks for handling diagnostic groups.  */
+
+  /* If non-NULL, this will be called immediately before the first
+     time a diagnostic is emitted within a stack of groups.  */
+  void (*begin_group_cb) (diagnostic_context * context);
+
+  /* If non-NULL, this will be called when a stack of groups is
+     popped if any diagnostics were emitted within that group.  */
+  void (*end_group_cb) (diagnostic_context * context);
 };
 
 static inline void
index 131705d18279a1675bd5270e26eedeac7a26a2ac..e1fab61bedabedc078d5fcf034e2c1aaffdcc651 100644 (file)
@@ -421,12 +421,15 @@ find_implicit_erroneous_behavior (void)
                          if (gimple_return_retval (return_stmt) != lhs)
                            continue;
 
-                         if (warning_at (gimple_location (use_stmt),
-                                         OPT_Wreturn_local_addr,
-                                         "function may return address "
-                                         "of local variable"))
-                           inform (DECL_SOURCE_LOCATION(valbase),
-                                   "declared here");
+                         {
+                           auto_diagnostic_group d;
+                           if (warning_at (gimple_location (use_stmt),
+                                             OPT_Wreturn_local_addr,
+                                             "function may return address "
+                                             "of local variable"))
+                             inform (DECL_SOURCE_LOCATION(valbase),
+                                       "declared here");
+                         }
 
                          if (gimple_bb (use_stmt) == bb)
                            {
@@ -543,10 +546,13 @@ find_explicit_erroneous_behavior (void)
                      else
                        msg = N_("function may return address of "
                                 "local variable");
-
-                     if (warning_at (gimple_location (stmt),
-                                     OPT_Wreturn_local_addr, msg))
-                       inform (DECL_SOURCE_LOCATION(valbase), "declared here");
+                     {
+                       auto_diagnostic_group d;
+                       if (warning_at (gimple_location (stmt),
+                                         OPT_Wreturn_local_addr, msg))
+                         inform (DECL_SOURCE_LOCATION(valbase),
+                                 "declared here");
+                     }
                      tree zero = build_zero_cst (TREE_TYPE (val));
                      gimple_return_set_retval (return_stmt, zero);
                      update_stmt (stmt);
index 0331f66844a32986f3531c3575193e7782b1164c..434770772ae7b5c8ea74286bfb0b2b9bd2c1e988 100644 (file)
@@ -532,29 +532,37 @@ pass_walloca::execute (function *fun)
            case ALLOCA_OK:
              break;
            case ALLOCA_BOUND_MAYBE_LARGE:
-             if (warning_at (loc, wcode,
-                             is_vla ? G_("argument to variable-length array "
-                                         "may be too large")
-                             : G_("argument to %<alloca%> may be too large"))
-                 && t.limit != 0)
-               {
-                 print_decu (t.limit, buff);
-                 inform (loc, G_("limit is %wu bytes, but argument "
-                                 "may be as large as %s"),
-                         is_vla ? warn_vla_limit : warn_alloca_limit, buff);
-               }
+             {
+               auto_diagnostic_group d;
+               if (warning_at (loc, wcode,
+                               is_vla ? G_("argument to variable-length "
+                                           "array may be too large")
+                               : G_("argument to %<alloca%> may be too "
+                                    "large"))
+                   && t.limit != 0)
+                 {
+                   print_decu (t.limit, buff);
+                   inform (loc, G_("limit is %wu bytes, but argument "
+                                   "may be as large as %s"),
+                           is_vla ? warn_vla_limit : warn_alloca_limit, buff);
+                 }
+             }
              break;
            case ALLOCA_BOUND_DEFINITELY_LARGE:
-             if (warning_at (loc, wcode,
-                             is_vla ? G_("argument to variable-length array "
-                                         "is too large")
-                             : G_("argument to %<alloca%> is too large"))
-                 && t.limit != 0)
-               {
-                 print_decu (t.limit, buff);
-                 inform (loc, G_("limit is %wu bytes, but argument is %s"),
-                         is_vla ? warn_vla_limit : warn_alloca_limit, buff);
-               }
+             {
+               auto_diagnostic_group d;
+               if (warning_at (loc, wcode,
+                               is_vla ? G_("argument to variable-length"
+                                           " array is too large")
+                               : G_("argument to %<alloca%> is too large"))
+                   && t.limit != 0)
+                 {
+                   print_decu (t.limit, buff);
+                   inform (loc, G_("limit is %wu bytes, but argument is %s"),
+                             is_vla ? warn_vla_limit : warn_alloca_limit,
+                             buff);
+                 }
+             }
              break;
            case ALLOCA_BOUND_UNKNOWN:
              warning_at (loc, wcode,
index 01503d6091247a888ce692588051496f83a422f0..977dd860ef7ad94c0997184aefb7c1bdb266fec3 100644 (file)
@@ -1618,6 +1618,7 @@ maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict,
       if (DECL_P (ref.base)
          && TREE_CODE (type = TREE_TYPE (ref.base)) == ARRAY_TYPE)
        {
+         auto_diagnostic_group d;
          if (warning_at (loc, OPT_Warray_bounds,
                          "%G%qD pointer overflow between offset %s "
                          "and size %s accessing array %qD with type %qT",
@@ -1650,6 +1651,7 @@ maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict,
 
       if (DECL_P (ref.base))
        {
+         auto_diagnostic_group d;
          if ((ref.basesize < maxobjsize
               && warning_at (loc, OPT_Warray_bounds,
                              form
index 4a109aee27a681c3d1a4887f90a7c427517105e9..e35137aec2c7193f8e345b20cd3ec3e79334ce20 100644 (file)
@@ -2173,6 +2173,7 @@ warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p,
          {
            struct label_entry *l;
            bool warned_p = false;
+           auto_diagnostic_group d;
            if (!should_warn_for_implicit_fallthrough (gsi_p, label))
              /* Quiet.  */;
            else if (gimple_code (prev) == GIMPLE_LABEL
@@ -13079,6 +13080,7 @@ gimplify_va_arg_expr (tree *expr_p, gimple_seq *pre_p,
       /* Unfortunately, this is merely undefined, rather than a constraint
         violation, so we cannot make this an error.  If this call is never
         executed, the program is still strictly conforming.  */
+      auto_diagnostic_group d;
       warned = warning_at (xloc, 0,
                           "%qT is promoted to %qT when passed through %<...%>",
                           type, promoted_type);
index 173707d8b111bf52af450cd9304537cf4a47595a..6595bedac82b99ac91c7a6032bd3f1cf31f310fe 100644 (file)
@@ -69,6 +69,7 @@ along with GCC; see the file COPYING3.  If not see
   do \
   { \
     hsa_fail_cfun (); \
+    auto_diagnostic_group d; \
     if (warning_at (EXPR_LOCATION (hsa_cfun->m_decl), OPT_Whsa, \
                    HSA_SORRY_MSG)) \
       inform (location, message, __VA_ARGS__); \
@@ -81,6 +82,7 @@ along with GCC; see the file COPYING3.  If not see
   do \
   { \
     hsa_fail_cfun (); \
+    auto_diagnostic_group d; \
     if (warning_at (EXPR_LOCATION (hsa_cfun->m_decl), OPT_Whsa, \
                    HSA_SORRY_MSG)) \
       inform (location, message); \
index e99d8ccd14c423521cf3178d0100a348ef0be8c3..9564d651b2be9c5113d718918a921ad0c725eeae 100644 (file)
@@ -749,6 +749,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
          prevailing = vtable;
          vtable = tmp;
        }
+      auto_diagnostic_group d;
       if (warning_at (DECL_SOURCE_LOCATION
                        (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
                      OPT_Wodr,
@@ -790,22 +791,25 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
                     && TREE_CODE (ref1->referred->decl) == FUNCTION_DECL))
             && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL)
        {
-         if (!class_type->rtti_broken
-             && warning_at (DECL_SOURCE_LOCATION
-                             (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
-                            OPT_Wodr,
-                            "virtual table of type %qD contains RTTI "
-                            "information",
-                            DECL_CONTEXT (vtable->decl)))
+         if (!class_type->rtti_broken)
            {
-             inform (DECL_SOURCE_LOCATION
-                       (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-                     "but is prevailed by one without from other translation "
-                     "unit");
-             inform (DECL_SOURCE_LOCATION
-                       (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
-                     "RTTI will not work on this type");
-             class_type->rtti_broken = true;
+             auto_diagnostic_group d;
+             if (warning_at (DECL_SOURCE_LOCATION
+                                 (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
+                               OPT_Wodr,
+                               "virtual table of type %qD contains RTTI "
+                               "information",
+                               DECL_CONTEXT (vtable->decl)))
+               {
+                 inform (DECL_SOURCE_LOCATION
+                             (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+                           "but is prevailed by one without from other"
+                           " translation unit");
+                 inform (DECL_SOURCE_LOCATION
+                             (TYPE_NAME (DECL_CONTEXT (prevailing->decl))),
+                           "RTTI will not work on this type");
+                 class_type->rtti_broken = true;
+               }
            }
          n2++;
           end2 = !vtable->iterate_reference (n2, ref2);
@@ -831,6 +835,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
          if (DECL_SIZE (prevailing->decl) != DECL_SIZE (vtable->decl))
            {
              class_type->odr_violated = true;
+             auto_diagnostic_group d;
              if (warning_at (DECL_SOURCE_LOCATION
                                (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
                              OPT_Wodr,
@@ -859,6 +864,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
          if (TREE_CODE (ref1->referred->decl) != FUNCTION_DECL
              && TREE_CODE (ref2->referred->decl) != FUNCTION_DECL)
            {
+             auto_diagnostic_group d;
              if (warning_at (DECL_SOURCE_LOCATION
                                (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
                              OPT_Wodr,
@@ -900,6 +906,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
              vtable = tmp;
              ref1 = ref2;
            }
+         auto_diagnostic_group d;
          if (warning_at (DECL_SOURCE_LOCATION
                            (TYPE_NAME (DECL_CONTEXT (vtable->decl))),
                          OPT_Wodr,
@@ -931,6 +938,7 @@ compare_virtual_tables (varpool_node *prevailing, varpool_node *vtable)
 
       /* And in the last case we have either mistmatch in between two virtual
         methods or two virtual table pointers.  */
+      auto_diagnostic_group d;
       if (warning_at (DECL_SOURCE_LOCATION
                        (TYPE_NAME (DECL_CONTEXT (vtable->decl))), OPT_Wodr,
                      "virtual table of type %qD violates "
@@ -986,6 +994,7 @@ warn_odr (tree t1, tree t2, tree st1, tree st2,
   if (lto_location_cache::current_cache)
     lto_location_cache::current_cache->apply_location_cache ();
 
+  auto_diagnostic_group d;
   if (!warning_at (DECL_SOURCE_LOCATION (TYPE_NAME (t1)), OPT_Wodr,
                   "type %qT violates the C++ One Definition Rule",
                   t1))
index a1fe09a598318a154a23ca72d280767eccac9407..a610d9a3345201178e5cd01289c11e43c4e8fffd 100644 (file)
@@ -347,6 +347,7 @@ expand_target_clones (struct cgraph_node *node, bool definition)
   if (node->definition
       && !tree_versionable_function_p (node->decl))
     {
+      auto_diagnostic_group d;
       error_at (DECL_SOURCE_LOCATION (node->decl),
                "clones for %<target_clones%> attribute cannot be created");
       const char *reason = NULL;
index 2b5f63844fb53faa6dec9916e7486649ecdfb02c..91586022f7f9d053ab3f127779dc0c5e7f230bed 100644 (file)
@@ -1266,6 +1266,7 @@ cmdline_handle_error (location_t loc, const struct cl_option *option,
       unsigned int i;
       char *s;
 
+      auto_diagnostic_group d;
       if (e->unknown_error)
        error_at (loc, e->unknown_error, arg);
       else
index 1f36d141c73a29a0d015922b5bf804532943bd18..33befa5d350e1d89f9635bc1d7e1e905218916f6 100644 (file)
@@ -782,6 +782,7 @@ globalize_reg (tree decl, int i)
 
   if (global_regs[i])
     {
+      auto_diagnostic_group d;
       warning_at (loc, 0, 
                  "register of %qD used for multiple global register variables",
                  decl);
index 82f2f4577f0bb7cc0b1d86fb8e6971ee6d10f9cd..1981394a3f0b8c3b394a2ff411d92a88bb71662b 100644 (file)
@@ -167,6 +167,7 @@ format_warning_n_va (const substring_loc &fmt_loc,
   if (substring_within_range)
     primary_label = fmt_label;
 
+  auto_diagnostic_group d;
   gcc_rich_location richloc (primary_loc, primary_label);
 
   if (param_loc != UNKNOWN_LOCATION)
index 26cbc08e20ab36aa5234a149f96b0e1f0018c6ee..969e03658f9bbcd7ba8615c0070f33702b2b66c3 100644 (file)
@@ -1,3 +1,10 @@
+2018-08-20  David Malcolm  <dmalcolm@redhat.com>
+
+       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.
+
 2018-08-20  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR target/87014
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-group-test-1.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-group-test-1.c
new file mode 100644 (file)
index 0000000..962cba6
--- /dev/null
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+extern void __emit_warning (const char *message);
+
+static void test_1 (void)
+{
+  __emit_warning ("warning 1");
+}
+
+/* { dg-begin-multiline-output "" }
+================================= BEGIN GROUP ==============================
+PREFIX
+   __emit_warning ("warning 1");
+   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
+PREFIX: message for note
+PREFIX:  some more detail
+PREFIX:   yet more detail
+---------------------------------- END GROUP -------------------------------
+   { dg-end-multiline-output "" } */
+
+/* { dg-begin-multiline-output "" }
+================================= BEGIN GROUP ==============================
+PREFIX: an unrelated message
+---------------------------------- END GROUP -------------------------------
+   { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.c
new file mode 100644 (file)
index 0000000..3083e12
--- /dev/null
@@ -0,0 +1,234 @@
+/* { dg-options "-O" } */
+
+#include "gcc-plugin.h"
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "stringpool.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "hash-table.h"
+#include "vec.h"
+#include "ggc.h"
+#include "basic-block.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-fold.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
+#include "is-a.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "tree.h"
+#include "tree-pass.h"
+#include "intl.h"
+#include "plugin-version.h"
+#include "c-family/c-common.h"
+#include "diagnostic.h"
+#include "context.h"
+
+int plugin_is_GPL_compatible;
+
+/* A custom pass for emitting dummy warnings from the middle-end.  */
+
+const pass_data pass_data_test_groups =
+{
+  GIMPLE_PASS, /* type */
+  "test_groups", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  PROP_ssa, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_test_groups : public gimple_opt_pass
+{
+public:
+  pass_test_groups(gcc::context *ctxt)
+    : gimple_opt_pass(pass_data_test_groups, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate (function *) { return true; }
+  virtual unsigned int execute (function *);
+
+}; // class pass_test_groups
+
+/* Determine if STMT is a call with NUM_ARGS arguments to a function
+   named FUNCNAME.
+   If so, return STMT as a gcall *.  Otherwise return NULL.  */
+
+static gcall *
+check_for_named_call (gimple *stmt,
+                     const char *funcname, unsigned int num_args)
+{
+  gcc_assert (funcname);
+
+  gcall *call = dyn_cast <gcall *> (stmt);
+  if (!call)
+    return NULL;
+
+  tree fndecl = gimple_call_fndecl (call);
+  if (!fndecl)
+    return NULL;
+
+  if (strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname))
+    return NULL;
+
+  if (gimple_call_num_args (call) != num_args)
+    {
+      error_at (stmt->location, "expected number of args: %i (got %i)",
+               num_args, gimple_call_num_args (call));
+      return NULL;
+    }
+
+  return call;
+}
+
+/* Emit a warning at LOC.  */
+
+static void
+emit_warning (location_t loc)
+{
+  source_range src_range = get_range_from_loc (line_table, loc);
+  warning_at (loc, 0, "range %i:%i-%i:%i",
+             LOCATION_LINE (src_range.m_start),
+             LOCATION_COLUMN (src_range.m_start),
+             LOCATION_LINE (src_range.m_finish),
+             LOCATION_COLUMN (src_range.m_finish));
+}
+
+/* Code for simulating the emission of a warning from the middle-end.
+   Emit a warning for each call to a function named "__emit_warning".  */
+
+static void
+test_groups (gimple *stmt)
+{
+  gcall *call = check_for_named_call (stmt, "__emit_warning", 1);
+  if (!call)
+    return;
+
+  /* We expect an ADDR_EXPR with a STRING_CST inside it for the
+     initial arg.  */
+  tree t_addr_string = gimple_call_arg (call, 0);
+  if (TREE_CODE (t_addr_string) != ADDR_EXPR)
+    {
+      error_at (call->location, "string literal required for arg 1");
+      return;
+    }
+
+  tree t_string = TREE_OPERAND (t_addr_string, 0);
+  if (TREE_CODE (t_string) != STRING_CST)
+    {
+      error_at (call->location, "string literal required for arg 1");
+      return;
+    }
+
+  {
+    auto_diagnostic_group d;
+    if (warning_at (call->location, 0, "%s", call,
+                   TREE_STRING_POINTER (t_string)))
+      {
+       inform (call->location, "message for note");
+       inform (call->location, " some more detail");
+       inform (call->location, "  yet more detail");
+      }
+  }
+  inform (call->location, "an unrelated message");
+}
+
+/* Call test_groups on every statement within FUN.  */
+
+unsigned int
+pass_test_groups::execute (function *fun)
+{
+  gimple_stmt_iterator gsi;
+  basic_block bb;
+
+  FOR_EACH_BB_FN (bb, fun)
+    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+      {
+       gimple *stmt = gsi_stmt (gsi);
+       test_groups (stmt);
+      }
+
+  return 0;
+}
+
+/* Custom diagnostic callback, to avoid having the path in the
+   expected output.  */
+
+void
+test_diagnostic_starter (diagnostic_context *context,
+                        diagnostic_info *diagnostic)
+{
+  pp_set_prefix (context->printer, xstrdup ("PREFIX: "));
+}
+
+/* Custom diagnostic callback, to avoid having the path in the
+   expected output.  */
+
+void
+test_diagnostic_start_span_fn (diagnostic_context *context,
+                              expanded_location exploc)
+{
+  pp_string (context->printer, "START_SPAN_FN: ");
+  pp_newline (context->printer);
+}
+
+/* Custom diagnostic callback: loudly announce a new diagnostic group.  */
+
+static void
+test_begin_group_cb (diagnostic_context * context)
+{
+  pp_string (context->printer,
+            "================================= BEGIN GROUP ==============================");
+  pp_newline (context->printer);
+}
+
+/* Custom diagnostic callback: loudly announce the end of a
+   diagnostic group.  */
+
+static void
+test_end_group_cb (diagnostic_context * context)
+{
+  pp_string (context->printer,
+            "---------------------------------- END GROUP -------------------------------");
+  pp_newline_and_flush (context->printer);
+}
+
+/* Entrypoint for the plugin.
+   Install custom callbacks into the global_dc.
+   Create and register the custom pass.  */
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+            struct plugin_gcc_version *version)
+{
+  struct register_pass_info pass_info;
+  const char *plugin_name = plugin_info->base_name;
+  int argc = plugin_info->argc;
+  struct plugin_argument *argv = plugin_info->argv;
+
+  if (!plugin_default_version_check (version, &gcc_version))
+    return 1;
+
+  diagnostic_starter (global_dc) = test_diagnostic_starter;
+  global_dc->start_span = test_diagnostic_start_span_fn;
+  global_dc->begin_group_cb = test_begin_group_cb;
+  global_dc->end_group_cb = test_end_group_cb;
+
+  pass_info.pass = new pass_test_groups (g);
+  pass_info.reference_pass_name = "*warn_function_noreturn";
+  pass_info.ref_pass_instance_number = 1;
+  pass_info.pos_op = PASS_POS_INSERT_AFTER;
+  register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
+                    &pass_info);
+
+  return 0;
+}
index 86ab1dd8d932aeca9c881c22d61758eb2f3ba439..46246a2449ec45b609c637f18fcb44de76b93ae6 100644 (file)
@@ -69,6 +69,8 @@ set plugin_test_list [list \
     { poly-int-05_plugin.c poly-int-test-1.c } \
     { poly-int-06_plugin.c poly-int-test-1.c } \
     { poly-int-07_plugin.c poly-int-test-1.c } \
+    { diagnostic_group_plugin.c \
+         diagnostic-group-test-1.c } \
     { diagnostic_plugin_test_show_locus.c \
          diagnostic-test-show-locus-bw.c \
          diagnostic-test-show-locus-color.c \
index 21464d6e28fbe010bb020f28819bcc2a961a1fa0..2b6bb5c0e3136e28d036827994d685f93fba3849 100644 (file)
@@ -4427,6 +4427,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
               /* Avoid warnings during early inline pass. */
               && symtab->global_info_ready)
        {
+         auto_diagnostic_group d;
          if (warning (OPT_Winline, "inlining failed in call to %q+F: %s",
                       fn, _(cgraph_inline_failed_string (reason))))
            {
index 63c95318aced64ee1d0466f9236af41e7f7b07ef..d0f799eb39de067ec3ef84dab73e9181146b4b4b 100644 (file)
@@ -3454,6 +3454,7 @@ pass_post_ipa_warn::execute (function *fun)
                        continue;
 
                      location_t loc = gimple_location (stmt);
+                     auto_diagnostic_group d;
                      if (warning_at (loc, OPT_Wnonnull,
                                      "%Gargument %u null where non-null "
                                      "expected", stmt, i + 1))
index fbdf838496bc558b8b5df191bcc5416ed19d0176..7b6c91ca6daf0060657689a332baa65863a35012 100644 (file)
@@ -3231,6 +3231,7 @@ do_warn_aggressive_loop_optimizations (struct loop *loop,
   char buf[WIDE_INT_PRINT_BUFFER_SIZE];
   print_dec (i_bound, buf, TYPE_UNSIGNED (TREE_TYPE (loop->nb_iterations))
             ? UNSIGNED : SIGNED);
+  auto_diagnostic_group d;
   if (warning_at (gimple_location (stmt), OPT_Waggressive_loop_optimizations,
                  "iteration %s invokes undefined behavior", buf))
     inform (gimple_location (estmt), "within this loop");
index 8ccbc85970a412552571a1ba65f15bd12cb00036..a93610084f2a101b5399a10128b64c3f407b111d 100644 (file)
@@ -178,6 +178,7 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
   cfun_loc = DECL_SOURCE_LOCATION (cfun->decl);
   xloc = expand_location (location);
   floc = expand_location (cfun_loc);
+  auto_diagnostic_group d;
   if (warning_at (location, wc, gmsgid, expr))
     {
       TREE_NO_WARNING (expr) = 1;
index 0ec74af0c1c75a44e11d27c8a23304ec6834b2f5..dd3439f60c9649fa925bfedc551c9708fc1b4bdf 100644 (file)
@@ -12613,6 +12613,7 @@ warn_deprecated_use (tree node, tree attr)
   bool w = false;
   if (DECL_P (node))
     {
+      auto_diagnostic_group d;
       if (msg)
        w = warning (OPT_Wdeprecated_declarations,
                     "%qD is deprecated: %s", node, (const char *) msg);
@@ -12636,6 +12637,7 @@ warn_deprecated_use (tree node, tree attr)
            what = DECL_NAME (TYPE_NAME (node));
        }
 
+      auto_diagnostic_group d;
       if (what)
        {
          if (msg)