diff options
author | David Malcolm <dmalcolm@redhat.com> | 2018-08-20 21:06:46 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2018-08-20 21:06:46 +0000 |
commit | 097f82ec9d19ccb5420c8df98cf35e1898b4fdab (patch) | |
tree | 083d8bf17b0bcd664af40648942c7c901ba1ed58 /gcc/diagnostic.c | |
parent | a31505a339c847f0073c0ce9223a2b3c9bec6cef (diff) | |
download | gcc-097f82ec9d19ccb5420c8df98cf35e1898b4fdab.zip gcc-097f82ec9d19ccb5420c8df98cf35e1898b4fdab.tar.gz gcc-097f82ec9d19ccb5420c8df98cf35e1898b4fdab.tar.bz2 |
Add support for grouping of related diagnostics (PR other/84889)
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
Diffstat (limited to 'gcc/diagnostic.c')
-rw-r--r-- | gcc/diagnostic.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c index 7e8bcf5..aae0934 100644 --- a/gcc/diagnostic.c +++ b/gcc/diagnostic.c @@ -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. */ |