aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/class.c
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2018-08-20 21:06:46 +0000
committerDavid Malcolm <dmalcolm@gcc.gnu.org>2018-08-20 21:06:46 +0000
commit097f82ec9d19ccb5420c8df98cf35e1898b4fdab (patch)
tree083d8bf17b0bcd664af40648942c7c901ba1ed58 /gcc/cp/class.c
parenta31505a339c847f0073c0ce9223a2b3c9bec6cef (diff)
downloadgcc-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/cp/class.c')
-rw-r--r--gcc/cp/class.c75
1 files changed, 47 insertions, 28 deletions
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 7b10b20..e11173d 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -1331,6 +1331,7 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
/* Otherwise we're diagnosing missing tags. */
if (TREE_CODE (p->t) == FUNCTION_DECL)
{
+ auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
"that %qT (used in its return type) has",
p->t, tag, *tp))
@@ -1338,12 +1339,14 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
}
else if (VAR_P (p->t))
{
+ auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qD inherits the %E ABI tag "
"that %qT (used in its type) has", p->t, tag, *tp))
inform (location_of (*tp), "%qT declared here", *tp);
}
else if (TYPE_P (p->subob))
{
+ auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
"that base %qT has", p->t, tag, p->subob))
inform (location_of (p->subob), "%qT declared here",
@@ -1351,6 +1354,7 @@ check_tag (tree tag, tree id, tree *tp, abi_tag_data *p)
}
else
{
+ auto_diagnostic_group d;
if (warning (OPT_Wabi_tag, "%qT does not have the %E ABI tag "
"that %qT (used in the type of %qD) has",
p->t, tag, *tp, p->subob))
@@ -2904,20 +2908,24 @@ finish_struct_anon_r (tree field, bool complain)
{
/* We already complained about static data members in
finish_static_data_member_decl. */
- if (!VAR_P (elt)
- && permerror (DECL_SOURCE_LOCATION (elt),
- TREE_CODE (TREE_TYPE (field)) == UNION_TYPE
- ? "%q#D invalid; an anonymous union may "
- "only have public non-static data members"
- : "%q#D invalid; an anonymous struct may "
- "only have public non-static data members", elt))
+ if (!VAR_P (elt))
{
- static bool hint;
- if (flag_permissive && !hint)
+ auto_diagnostic_group d;
+ if (permerror (DECL_SOURCE_LOCATION (elt),
+ TREE_CODE (TREE_TYPE (field)) == UNION_TYPE
+ ? "%q#D invalid; an anonymous union may "
+ "only have public non-static data members"
+ : "%q#D invalid; an anonymous struct may "
+ "only have public non-static data members", elt))
{
- hint = true;
- inform (DECL_SOURCE_LOCATION (elt),
- "this flexibility is deprecated and will be removed");
+ static bool hint;
+ if (flag_permissive && !hint)
+ {
+ hint = true;
+ inform (DECL_SOURCE_LOCATION (elt),
+ "this flexibility is deprecated and will be "
+ "removed");
+ }
}
}
}
@@ -3107,6 +3115,7 @@ one_inherited_ctor (tree ctor, tree t, tree using_decl)
one_inheriting_sig (t, ctor, new_parms, i);
if (parms == NULL_TREE)
{
+ auto_diagnostic_group d;
if (warning (OPT_Winherited_variadic_ctor,
"the ellipsis in %qD is not inherited", ctor))
inform (DECL_SOURCE_LOCATION (ctor), "%qD declared here", ctor);
@@ -5399,11 +5408,14 @@ finalize_literal_type_property (tree t)
&& !DECL_CONSTRUCTOR_P (fn))
{
DECL_DECLARED_CONSTEXPR_P (fn) = false;
- if (!DECL_GENERATED_P (fn)
- && pedwarn (DECL_SOURCE_LOCATION (fn), OPT_Wpedantic,
- "enclosing class of %<constexpr%> non-static member "
- "function %q+#D is not a literal type", fn))
- explain_non_literal_class (t);
+ if (!DECL_GENERATED_P (fn))
+ {
+ auto_diagnostic_group d;
+ if (pedwarn (DECL_SOURCE_LOCATION (fn), OPT_Wpedantic,
+ "enclosing class of %<constexpr%> non-static "
+ "member function %q+#D is not a literal type", fn))
+ explain_non_literal_class (t);
+ }
}
}
@@ -5425,6 +5437,7 @@ explain_non_literal_class (tree t)
/* Already explained. */
return;
+ auto_diagnostic_group d;
inform (UNKNOWN_LOCATION, "%q+T is not literal because:", t);
if (cxx_dialect < cxx17 && LAMBDA_TYPE_P (t))
inform (UNKNOWN_LOCATION,
@@ -6626,17 +6639,20 @@ find_flexarrays (tree t, flexmems_t *fmem, bool base_p,
static void
diagnose_invalid_flexarray (const flexmems_t *fmem)
{
- if (fmem->array && fmem->enclosing
- && pedwarn (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)
{