diff options
author | David Malcolm <dmalcolm@redhat.com> | 2024-07-13 10:34:51 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2024-07-13 10:34:51 -0400 |
commit | 7d73c01ce6d1ab28157a7dadcd3be14f96a7c8f3 (patch) | |
tree | 19ff9b197aa6635ad127839f17933febd9503132 /gcc/c-family | |
parent | abf3964711f05b6858d9775c3595ec2b45483e14 (diff) | |
download | gcc-7d73c01ce6d1ab28157a7dadcd3be14f96a7c8f3.zip gcc-7d73c01ce6d1ab28157a7dadcd3be14f96a7c8f3.tar.gz gcc-7d73c01ce6d1ab28157a7dadcd3be14f96a7c8f3.tar.bz2 |
diagnostics: add highlight-a vs highlight-b in colorization and pp_markup
Since r6-4582-g8a64515099e645 (which added class rich_location), ranges
of quoted source code have been colorized using the following rules:
- the primary range used the same color of the kind of the diagnostic
i.e. "error" vs "warning" etc (defaulting to bold red and bold magenta
respectively)
- secondary ranges alternate between "range1" and "range2" (defaulting
to green and blue respectively)
This works for cases with large numbers of highlighted ranges, but is
suboptimal for common cases.
The following patch adds a pair of color names: "highlight-a" and
"highlight-b", and uses them whenever it makes sense to highlight and
contrast two different things in the source code (e.g. a type mismatch).
These are used by diagnostic-show-locus.cc for highlighting quoted
source. In addition the patch adds colorization to fragments within the
corresponding diagnostic messages themselves, using consistent
colorization between the message and the quoted source code for the two
different things being contrasted.
For example, consider:
demo.c: In function ‘test_bad_format_string_args’:
../../src/demo.c:25:18: warning: format ‘%i’ expects argument of
type ‘int’, but argument 2 has type ‘const char *’ [-Wformat=]
25 | printf("hello %i", msg);
| ~^ ~~~
| | |
| int const char *
| %s
Previously, the types within the message in quotes would be in bold but
not colorized, and the labelled ranges of quoted source code would use
bold magenta for the "int" and non-bold green for the "const char *".
With this patch:
- the "%i" and "int" in the message and the "int" in the quoted source
are all colored bold green
- the "const char *" in the message and in the quoted source are both
colored bold blue
so that the consistent use of contrasting color draws the reader's eyes
to the relationships between the diagnostic message and the source.
I've tried this with gnome-terminal with many themes, including a
variety of light versus dark backgrounds, solarized versus non-solarized
themes, etc, and it was readable in all.
My initial version of the patch used the existing %r and %R facilities
within pretty-print.cc for the messages, but this turned out to be very
uncomfortable, leading to error-prone format strings such as:
error_at (richloc,
"invalid operands to binary %s (have %<%r%T%R%> and %<%r%T%R%>)",
opname,
"highlight-a", type0,
"highlight-b", type1);
To avoid requiring monstrosities such as the above, the patch adds a new
"%e" format code to pretty-print.cc, which expects a pp_element *, where
pp_element is a new abstract base class (actually a pp_markup::element),
along with various useful subclasses. This lets the above be written
as:
pp_markup::element_quoted_type element_0 (type0, highlight_colors::lhs);
pp_markup::element_quoted_type element_1 (type1, highlight_colors::rhs);
error_at (richloc,
"invalid operands to binary %s (have %e and %e)",
opname, &element_0, &element_1);
which I feel is maintainable and clear to translators; the use of %e and
pp_element * captures the type-unsafe part of the variadic call, and the
subclasses allow for type-safety (so e.g. an element_quoted_type expects
a type and a highlighting color). This approach allows for some nice
simplifications within c-format.cc.
The patch also extends -Wformat to "teach" it about the new %e and
pp_element *. Doing so requires c-format.cc to be able to determine
if a T * is a pp_element * (i.e. if T is a subclass). To do so I added
a new comp_types callback for comparing types, where the C++ frontend
supplies a suitable implementation (and %e will always be wrong for C).
I've manually tested this on many diagnostics with both C and C++ and it
seems a subtle but significant improvement in readability.
I've added a new option -fno-diagnostics-show-highlight-colors in case
people prefer the old behavior.
gcc/c-family/ChangeLog:
* c-common.cc: Include "tree-pretty-print-markup.h".
(binary_op_error): Use pp_markup::element_quoted_type and %e.
(check_function_arguments): Add "comp_types" param and pass it to
check_function_format.
* c-common.h (check_function_arguments): Add "comp_types" param.
(check_function_format): Likewise.
* c-format.cc: Include "tree-pretty-print-markup.h".
(local_pp_element_ptr_node): New.
(PP_FORMAT_CHAR_TABLE): Add entry for %e.
(struct format_check_context): Add "m_comp_types" field.
(check_function_format): Add "comp_types" param and pass it to
check_format_info.
(check_format_info): Likewise, passing it to format_ctx's ctor.
(check_format_arg): Extract m_comp_types from format_ctx and
pass it to check_format_info_main.
(check_format_info_main): Add "comp_types" param and pass it to
arg_parser's ctor.
(class argument_parser): Add "m_comp_types" field.
(argument_parser::check_argument_type): Pass m_comp_types to
check_format_types.
(handle_subclass_of_pp_element_p): New.
(check_format_types): Add "comp_types" param, and use it to
call handle_subclass_of_pp_element_p.
(class element_format_substring): New.
(class element_expected_type_with_indirection): New.
(format_type_warning): Use element_expected_type_with_indirection
to unify the if (wanted_type_name) branches, reducing from four
emit_warning calls to two. Simplify these further using %e.
Doing so also gives suitable colorization of the text within the
diagnostics.
(init_dynamic_diag_info): Initialize local_pp_element_ptr_node.
(selftest::test_type_mismatch_range_labels): Add nullptr for new
param of gcc_rich_location label overload.
* c-format.h (T_PP_ELEMENT_PTR): New.
* c-type-mismatch.cc: Include "diagnostic-highlight-colors.h".
(binary_op_rich_location::binary_op_rich_location): Use
highlight_colors::lhs and highlight_colors::rhs for the ranges.
* c-type-mismatch.h (class binary_op_rich_location): Add comment
about highlight_colors.
gcc/c/ChangeLog:
* c-objc-common.cc: Include "tree-pretty-print-markup.h".
(print_type): Add optional "highlight_color" param and use it
to show highlight colors in "aka" text.
(pp_markup::element_quoted_type::print_type): New.
* c-typeck.cc: Include "tree-pretty-print-markup.h".
(comp_parm_types): New.
(build_function_call_vec): Pass it to check_function_arguments.
(inform_for_arg): Use %e and highlight colors to contrast actual
versus expected.
(convert_for_assignment): Use highlight_colors::actual for the
rhs_label.
(build_binary_op): Use highlight_colors::lhs and highlight_colors::rhs
for the ranges.
gcc/ChangeLog:
* common.opt (fdiagnostics-show-highlight-colors): New option.
* common.opt.urls: Regenerate.
* coretypes.h (pp_markup::element): New forward decl.
(pp_element): New typedef.
* diagnostic-color.cc (gcc_color_defaults): Add "highlight-a"
and "highlight-b".
* diagnostic-format-json.cc (diagnostic_output_format_init_json):
Disable highlight colors.
* diagnostic-format-sarif.cc (diagnostic_output_format_init_sarif):
Likewise.
* diagnostic-highlight-colors.h: New file.
* diagnostic-path.cc (struct event_range): Pass nullptr for
highlight color of m_rich_loc.
* diagnostic-show-locus.cc (colorizer::set_range): Handle ranges
with m_highlight_color.
(colorizer::STATE_NAMED_COLOR): New.
(colorizer::m_richloc): New field.
(colorizer::colorizer): Add richloc param for initializing
m_richloc.
(colorizer::set_named_color): New.
(colorizer::begin_state): Add case STATE_NAMED_COLOR.
(layout::layout): Pass richloc to m_colorizer's ctor.
(selftest::test_one_liner_labels): Pass nullptr for new param of
gcc_rich_location ctor for labels.
(selftest::test_one_liner_labels_utf8): Likewise.
* diagnostic.h (diagnostic_context::set_show_highlight_colors):
New.
* doc/invoke.texi: Add option -fdiagnostics-show-highlight-colors
and highlight-a and highlight-b color caps.
* doc/ux.texi
(Use color consistently when highlighting mismatches): New
subsection.
* gcc-rich-location.cc (gcc_rich_location::add_expr): Add
"highlight_color" param.
(gcc_rich_location::maybe_add_expr): Likewise.
* gcc-rich-location.h (gcc_rich_location::gcc_rich_location):
Split out into a pair of ctors, where if a range_label is supplied
the caller must also supply a highlight color.
(gcc_rich_location::add_expr): Add "highlight_color" param.
(gcc_rich_location::maybe_add_expr): Likewise.
* gcc.cc (driver_handle_option): Handle
OPT_fdiagnostics_show_highlight_colors.
* lto-wrapper.cc (merge_and_complain): Likewise.
(append_compiler_options): Likewise.
(append_diag_options): Likewise.
(run_gcc): Likewise.
* opts-common.cc (decode_cmdline_options_to_array): Add comment
about -fno-diagnostics-show-highlight-colors.
* opts-global.cc (init_options_once): Preserve
pp_show_highlight_colors in case the global_dc's printer is
recreated.
* opts.cc (common_handle_option): Handle
OPT_fdiagnostics_show_highlight_colors.
(gen_command_line_string): Likewise.
* pretty-print-markup.h: New file.
* pretty-print.cc: Include "pretty-print-markup.h" and
"diagnostic-highlight-colors.h".
(pretty_printer::format): Handle %e.
(pretty_printer::pretty_printer): Handle new field
m_show_highlight_colors.
(pp_string_n): New.
(pp_markup::context::begin_quote): New.
(pp_markup::context::end_quote): New.
(pp_markup::context::begin_color): New.
(pp_markup::context::end_color): New.
(highlight_colors::expected): New.
(highlight_colors::actual): New.
(highlight_colors::lhs): New.
(highlight_colors::rhs): New.
(class selftest::test_element): New.
(selftest::test_pp_format): Add tests of %e.
(selftest::test_urlification): Likewise.
* pretty-print.h (pp_markup::context): New forward decl.
(class chunk_info): Add friend class pp_markup::context.
(class pretty_printer): Add friend pp_show_highlight_colors.
(pretty_printer::m_show_highlight_colors): New field.
(pp_show_highlight_colors): New inline function.
(pp_string_n): New decl.
* substring-locations.cc: Include "diagnostic-highlight-colors.h".
(format_string_diagnostic_t::highlight_color_format_string): New.
(format_string_diagnostic_t::highlight_color_param): New.
(format_string_diagnostic_t::emit_warning_n_va): Use highlight
colors.
* substring-locations.h
(format_string_diagnostic_t::highlight_color_format_string): New.
(format_string_diagnostic_t::highlight_color_param): New.
* toplev.cc (general_init): Initialize global_dc's
show_highlight_colors.
* tree-pretty-print-markup.h: New file.
gcc/cp/ChangeLog:
* call.cc: Include "tree-pretty-print-markup.h".
(implicit_conversion_error): Use highlight_colors::percent_h for
the labelled range.
(op_error_string): Split out into...
(concat_op_error_string): ...this.
(binop_error_string): New.
(op_error): Use %e, binop_error_string, highlight_colors::lhs,
and highlight_colors::rhs.
(maybe_inform_about_fndecl_for_bogus_argument_init): Add
"highlight_color" param; use it for the richloc.
(convert_like_internal): Use highlight_colors::percent_h for the
labelled_range, and highlight_colors::percent_i for the call to
maybe_inform_about_fndecl_for_bogus_argument_init.
(build_over_call): Pass cp_comp_parm_types for new "comp_types"
param of check_function_arguments.
(complain_about_bad_argument): Use highlight_colors::percent_h for
the labelled_range, and highlight_colors::percent_i for the call
to maybe_inform_about_fndecl_for_bogus_argument_init.
* cp-tree.h (maybe_inform_about_fndecl_for_bogus_argument_init):
Add optional highlight_color param.
(cp_comp_parm_types): New decl.
(highlight_colors::const percent_h): New decl.
(highlight_colors::const percent_i): New decl.
* error.cc: Include "tree-pretty-print-markup.h".
(highlight_colors::const percent_h): New defn.
(highlight_colors::const percent_i): New defn.
(type_to_string): Add param "highlight_color" and use it.
(print_nonequal_arg): Likewise.
(print_template_differences): Add params "highlight_color_a" and
"highlight_color_b".
(type_to_string_with_compare): Add params "this_highlight_color"
and "peer_highlight_color".
(print_template_tree_comparison): Add params "highlight_color_a"
and "highlight_color_b".
(cxx_format_postprocessor::handle):
Use highlight_colors::percent_h and highlight_colors::percent_i.
(pp_markup::element_quoted_type::print_type): New.
(range_label_for_type_mismatch::get_text): Pass nullptr for new
params of type_to_string_with_compare.
* typeck.cc (cp_comp_parm_types): New.
(cp_build_function_call_vec): Pass it to check_function_arguments.
(convert_for_assignment): Use highlight_colors::percent_h for the
labelled_range.
gcc/testsuite/ChangeLog:
* g++.dg/diagnostic/bad-binary-ops-highlight-colors.C: New test.
* g++.dg/diagnostic/bad-binary-ops-no-highlight-colors.C: New test.
* g++.dg/plugin/plugin.exp (plugin_test_list): Add
show-template-tree-color-no-highlight-colors.C to
show_template_tree_color_plugin.c.
* g++.dg/plugin/show-template-tree-color-labels.C: Update expected
output to reflect use of highlight-a and highlight-b to contrast
mismatches.
* g++.dg/plugin/show-template-tree-color-no-elide-type.C:
Likewise.
* g++.dg/plugin/show-template-tree-color-no-highlight-colors.C:
New test.
* g++.dg/plugin/show-template-tree-color.C: Update expected output
to reflect use of highlight-a and highlight-b to contrast
mismatches.
* g++.dg/warn/Wformat-gcc_diag-1.C: New test.
* g++.dg/warn/Wformat-gcc_diag-2.C: New test.
* g++.dg/warn/Wformat-gcc_diag-3.C: New test.
* gcc.dg/bad-binary-ops-highlight-colors.c: New test.
* gcc.dg/format/colors.c: New test.
* gcc.dg/plugin/diagnostic_plugin_show_trees.c (show_tree): Pass
nullptr for new param of gcc_rich_location::add_expr.
libcpp/ChangeLog:
* include/rich-location.h (location_range::m_highlight_color): New
field.
(rich_location::rich_location): Add optional label_highlight_color
param.
(rich_location::set_highlight_color): New decl.
(rich_location::add_range): Add optional label_highlight_color
param.
(rich_location::set_range): Likewise.
* line-map.cc (rich_location::rich_location): Add
"label_highlight_color" param and pass it to add_range.
(rich_location::set_highlight_color): New.
(rich_location::add_range): Add "label_highlight_color" param.
(rich_location::set_range): Add "highlight_color" param.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/c-family')
-rw-r--r-- | gcc/c-family/c-common.cc | 17 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 6 | ||||
-rw-r--r-- | gcc/c-family/c-format.cc | 229 | ||||
-rw-r--r-- | gcc/c-family/c-format.h | 1 | ||||
-rw-r--r-- | gcc/c-family/c-type-mismatch.cc | 10 | ||||
-rw-r--r-- | gcc/c-family/c-type-mismatch.h | 3 |
6 files changed, 195 insertions, 71 deletions
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc index 7d752ac..e7e371f 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "debug.h" #include "tree-vector-builder.h" #include "vec-perm-indices.h" +#include "tree-pretty-print-markup.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -2961,9 +2962,11 @@ binary_op_error (rich_location *richloc, enum tree_code code, default: gcc_unreachable (); } + pp_markup::element_quoted_type element_0 (type0, highlight_colors::lhs); + pp_markup::element_quoted_type element_1 (type1, highlight_colors::rhs); error_at (richloc, - "invalid operands to binary %s (have %qT and %qT)", - opname, type0, type1); + "invalid operands to binary %s (have %e and %e)", + opname, &element_0, &element_1); } /* Given an expression as a tree, return its original type. Do this @@ -6158,11 +6161,15 @@ attribute_fallthrough_p (tree attr) The arguments in ARGARRAY may not have been folded yet (e.g. for C++, to preserve location wrappers); checks that require folded arguments - should call fold_for_warn on them. */ + should call fold_for_warn on them. + + Use the frontend-supplied COMP_TYPES when determining if + one type is a subclass of another. */ bool check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype, - int nargs, tree *argarray, vec<location_t> *arglocs) + int nargs, tree *argarray, vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)) { bool warned_p = false; @@ -6179,7 +6186,7 @@ check_function_arguments (location_t loc, const_tree fndecl, const_tree fntype, if (warn_format || warn_suggest_attribute_format) check_function_format (fndecl ? fndecl : fntype, TYPE_ATTRIBUTES (fntype), nargs, - argarray, arglocs); + argarray, arglocs, comp_types); if (warn_format) check_function_sentinel (fntype, nargs, argarray); diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 48c89b6..ccaea27 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -848,7 +848,8 @@ extern tree fname_decl (location_t, unsigned, tree); extern int check_user_alignment (const_tree, bool, bool); extern bool check_function_arguments (location_t loc, const_tree, const_tree, - int, tree *, vec<location_t> *); + int, tree *, vec<location_t> *, + bool (*comp_types) (tree, tree)); extern void check_function_arguments_recurse (void (*) (void *, tree, unsigned HOST_WIDE_INT), @@ -858,7 +859,8 @@ extern void check_function_arguments_recurse (void (*) extern bool check_builtin_function_arguments (location_t, vec<location_t>, tree, tree, int, tree *); extern void check_function_format (const_tree, tree, int, tree *, - vec<location_t> *); + vec<location_t> *, + bool (*comp_types) (tree, tree)); extern bool attribute_fallthrough_p (tree); extern tree handle_format_attribute (tree *, tree, tree, int, bool *); extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc index 5bfd2fc..07b91a1 100644 --- a/gcc/c-family/c-format.cc +++ b/gcc/c-family/c-format.cc @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "attribs.h" #include "c-family/c-type-mismatch.h" +#include "tree-pretty-print-markup.h" /* Handle attributes associated with format checking. */ @@ -66,6 +67,7 @@ struct function_format_info /* Initialized in init_dynamic_diag_info. */ static GTY(()) tree local_tree_type_node; static GTY(()) tree local_event_ptr_node; +static GTY(()) tree local_pp_element_ptr_node; static GTY(()) tree local_gimple_ptr_node; static GTY(()) tree local_cgraph_node_ptr_node; static GTY(()) tree locus; @@ -768,6 +770,7 @@ static const format_char_info asm_fprintf_char_table[] = { "p", 1, STD_C89, { T89_V, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "q", "c", NULL }, \ { "r", 1, STD_C89, { T89_C, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "//cR", NULL }, \ { "@", 1, STD_C89, { T_EVENT_PTR, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL }, \ + { "e", 1, STD_C89, { T_PP_ELEMENT_PTR, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }, "", "\"", NULL }, \ { "<", 0, STD_C89, NOARGUMENTS, "", "<", NULL }, \ { ">", 0, STD_C89, NOARGUMENTS, "", ">", NULL }, \ { "'" , 0, STD_C89, NOARGUMENTS, "", "", NULL }, \ @@ -1067,11 +1070,13 @@ struct format_check_context format_check_context (format_check_results *res, function_format_info *info, tree params, - vec<location_t> *arglocs) + vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)) : m_res (res), m_info (info), m_params (params), - m_arglocs (arglocs) + m_arglocs (arglocs), + m_comp_types (comp_types) { } @@ -1079,6 +1084,7 @@ struct format_check_context function_format_info *m_info; tree m_params; vec<location_t> *m_arglocs; + bool (*m_comp_types) (tree, tree); }; /* Return the format name (as specified in the original table) for the format @@ -1102,7 +1108,8 @@ format_flags (int format_num) } static void check_format_info (function_format_info *, tree, - vec<location_t> *); + vec<location_t> *, + bool (*comp_types) (tree, tree)); static void check_format_arg (void *, tree, unsigned HOST_WIDE_INT); static void check_format_info_main (format_check_results *, function_format_info *, const char *, @@ -1110,7 +1117,8 @@ static void check_format_info_main (format_check_results *, int, tree, unsigned HOST_WIDE_INT, object_allocator<format_wanted_type> &, - vec<location_t> *); + vec<location_t> *, + bool (*comp_types) (tree, tree)); static void init_dollar_format_checking (int, tree); static int maybe_read_dollar_number (const char **, int, @@ -1126,7 +1134,8 @@ static void check_format_types (const substring_loc &fmt_loc, const format_kind_info *fki, int offset_to_type_start, char conversion_char, - vec<location_t> *arglocs); + vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)); static void format_type_warning (const substring_loc &fmt_loc, location_t param_loc, format_wanted_type *, tree, @@ -1197,7 +1206,8 @@ decode_format_type (const char *s, bool *is_raw /* = NULL */) void check_function_format (const_tree fn, tree attrs, int nargs, - tree *argarray, vec<location_t> *arglocs) + tree *argarray, vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)) { tree a; @@ -1254,7 +1264,7 @@ check_function_format (const_tree fn, tree attrs, int nargs, int i; for (i = nargs - 1; i >= 0; i--) params = tree_cons (NULL_TREE, argarray[i], params); - check_format_info (&info, params, arglocs); + check_format_info (&info, params, arglocs, comp_types); } /* Attempt to detect whether the current function might benefit @@ -1562,7 +1572,8 @@ get_flag_spec (const format_flag_spec *spec, int flag, const char *predicates) static void check_format_info (function_format_info *info, tree params, - vec<location_t> *arglocs) + vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)) { unsigned HOST_WIDE_INT arg_num; tree format_tree; @@ -1583,7 +1594,7 @@ check_format_info (function_format_info *info, tree params, format_check_results res (input_location); - format_check_context format_ctx (&res, info, params, arglocs); + format_check_context format_ctx (&res, info, params, arglocs, comp_types); check_function_arguments_recurse (check_format_arg, &format_ctx, format_tree, arg_num, OPT_Wformat_); @@ -1674,6 +1685,7 @@ check_format_arg (void *ctx, tree format_tree, function_format_info *info = format_ctx->m_info; tree params = format_ctx->m_params; vec<location_t> *arglocs = format_ctx->m_arglocs; + bool (*comp_types) (tree, tree) = format_ctx->m_comp_types; int format_length; HOST_WIDE_INT offset; @@ -1865,7 +1877,8 @@ check_format_arg (void *ctx, tree format_tree, res->number_other++; object_allocator <format_wanted_type> fwt_pool ("format_wanted_type pool"); check_format_info_main (res, info, format_chars, fmt_param_loc, format_tree, - format_length, params, arg_num, fwt_pool, arglocs); + format_length, params, arg_num, fwt_pool, arglocs, + comp_types); } /* Support class for argument_parser and check_format_info_main. @@ -1932,7 +1945,8 @@ class argument_parser location_t format_string_loc, flag_chars_t &flag_chars, int &has_operand_number, tree first_fillin_param, object_allocator <format_wanted_type> &fwt_pool_, - vec<location_t> *arglocs); + vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)); bool read_any_dollar (); @@ -2012,6 +2026,7 @@ class argument_parser format_wanted_type *first_wanted_type; format_wanted_type *last_wanted_type; vec<location_t> *arglocs; + bool (*m_comp_types) (tree, tree); }; /* flag_chars_t's constructor. */ @@ -2163,7 +2178,8 @@ argument_parser (function_format_info *info_, const char *&format_chars_, int &has_operand_number_, tree first_fillin_param_, object_allocator <format_wanted_type> &fwt_pool_, - vec<location_t> *arglocs_) + vec<location_t> *arglocs_, + bool (*comp_types) (tree, tree)) : info (info_), fki (&format_types[info->format_type]), flag_specs (fki->flag_specs), @@ -2180,7 +2196,8 @@ argument_parser (function_format_info *info_, const char *&format_chars_, first_fillin_param (first_fillin_param_), first_wanted_type (NULL), last_wanted_type (NULL), - arglocs (arglocs_) + arglocs (arglocs_), + m_comp_types (comp_types) { } @@ -2903,7 +2920,7 @@ check_argument_type (const format_char_info *fci, ptrdiff_t offset_to_type_start = type_start - orig_format_chars; check_format_types (fmt_loc, first_wanted_type, fki, offset_to_type_start, - conversion_char, arglocs); + conversion_char, arglocs, m_comp_types); } return true; @@ -3831,7 +3848,8 @@ check_format_info_main (format_check_results *res, int format_length, tree params, unsigned HOST_WIDE_INT arg_num, object_allocator <format_wanted_type> &fwt_pool, - vec<location_t> *arglocs) + vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)) { const char * const orig_format_chars = format_chars; const tree first_fillin_param = params; @@ -3898,7 +3916,8 @@ check_format_info_main (format_check_results *res, argument_parser arg_parser (info, format_chars, format_string_cst, orig_format_chars, format_string_loc, flag_chars, has_operand_number, - first_fillin_param, fwt_pool, arglocs); + first_fillin_param, fwt_pool, arglocs, + comp_types); if (!arg_parser.read_any_dollar ()) return; @@ -4075,6 +4094,28 @@ check_format_info_main (format_check_results *res, OPT_Wformat_, "unterminated color directive"); } +/* Special-case to support inheritance for %e. + Return true for the case where we have %e with a valid + pointer to a pp_element or pp_element subclass; false + otherwise. */ + +static bool +handle_subclass_of_pp_element_p (format_wanted_type *types, + bool (*comp_types) (tree, tree)) +{ + if (types->wanted_type != local_pp_element_ptr_node) + return false; + + tree param_type = TREE_TYPE (types->param); + if (param_type == error_mark_node) + return false; + + if (comp_types (types->wanted_type, param_type)) + return true; + + return false; +} + /* Check the argument types from a single format conversion (possibly including width and precision arguments). @@ -4128,7 +4169,8 @@ check_format_types (const substring_loc &fmt_loc, format_wanted_type *types, const format_kind_info *fki, int offset_to_type_start, char conversion_char, - vec<location_t> *arglocs) + vec<location_t> *arglocs, + bool (*comp_types) (tree, tree)) { for (; types != 0; types = types->next) { @@ -4150,6 +4192,9 @@ check_format_types (const substring_loc &fmt_loc, if (types->pointer_count == 0) wanted_type = lang_hooks.types.type_promotes_to (wanted_type); + if (handle_subclass_of_pp_element_p (types, comp_types)) + continue; + wanted_type = TYPE_MAIN_VARIANT (wanted_type); cur_param = types->param; @@ -4693,6 +4738,85 @@ class range_label_for_format_type_mismatch int m_pointer_count; }; +/* Subclass of pp_element for text describing part of a format string. */ + +class element_format_substring : public pp_element +{ +public: + element_format_substring (const char *highlight_color, + const char *prefix, + int format_length, + const char *format_start) + : m_highlight_color (highlight_color), + m_prefix (prefix), + m_format_length (format_length), + m_format_start (format_start) + { + } + + void add_to_phase_2 (pp_markup::context &ctxt) final override + { + ctxt.begin_quote (); + ctxt.begin_highlight_color (m_highlight_color); + pp_string (&ctxt.m_pp, m_prefix); + pp_string_n (&ctxt.m_pp, m_format_start, m_format_length); + ctxt.end_highlight_color (); + ctxt.end_quote (); + } + +private: + const char *m_highlight_color; + const char *m_prefix; + int m_format_length; + const char *m_format_start; +}; + +/* Subclass of pp_element for text describing an optional WANTED_TYPE_NAME + with a fallback TYPE, part of an expected type with some number of + indirections. */ + +class element_expected_type_with_indirection + : public pp_markup::element_expected_type +{ +public: + element_expected_type_with_indirection (tree wanted_type, + const char *wanted_type_name, + int pointer_count) + : pp_markup::element_expected_type (wanted_type), + m_wanted_type_name (wanted_type_name), + m_pointer_count (pointer_count) + { + // m_wanted_type_name can be nullptr + } + + void add_to_phase_2 (pp_markup::context &ctxt) final override + { + indirection_suffix suffix (m_pointer_count); + char *indirection_buf = (char *) alloca (suffix.get_buffer_size ()); + suffix.fill_buffer (indirection_buf); + + ctxt.begin_quote (); + ctxt.begin_highlight_color (highlight_colors::expected); + if (m_wanted_type_name) + pp_string (&ctxt.m_pp, m_wanted_type_name); + else + { + /* Any trailing quotes should be printed within the quoted. */ + ctxt.m_quoted = false; + print_type (ctxt); + ctxt.m_quoted = true; + } + pp_string (&ctxt.m_pp, indirection_buf); + ctxt.end_highlight_color (); + ctxt.end_quote (); + } + +private: + const char *m_wanted_type_name; + tree m_wanted_type; + int m_pointer_count; +}; + /* Give a warning about a format argument of different type from that expected. The range of the diagnostic is taken from WHOLE_FMT_LOC; the caret location is based on the location of the char at TYPE->offset_loc. @@ -4753,10 +4877,6 @@ format_type_warning (const substring_loc &whole_fmt_loc, lang_hooks.decl_printable_name (TYPE_NAME (arg_type), 2))) arg_type = TYPE_MAIN_VARIANT (arg_type); - indirection_suffix suffix (pointer_count); - char *p = (char *) alloca (suffix.get_buffer_size ()); - suffix.fill_buffer (p); - /* WHOLE_FMT_LOC has the caret at the end of the range. Set the caret to be at the offset from TYPE. Subtract one from the offset for the same reason as in format_warning_at_char. */ @@ -4774,45 +4894,26 @@ format_type_warning (const substring_loc &whole_fmt_loc, offset_to_type_start, conversion_char); format_string_diagnostic_t diag (fmt_loc, &fmt_label, param_loc, ¶m_label, corrected_substring); - if (wanted_type_name) - { - if (arg_type) - diag.emit_warning - (OPT_Wformat_, - "%s %<%s%.*s%> expects argument of type %<%s%s%>, " - "but argument %d has type %qT", - gettext (kind_descriptions[kind]), - (kind == CF_KIND_FORMAT ? "%" : ""), - format_length, format_start, - wanted_type_name, p, arg_num, arg_type); - else - diag.emit_warning - (OPT_Wformat_, - "%s %<%s%.*s%> expects a matching %<%s%s%> argument", - gettext (kind_descriptions[kind]), - (kind == CF_KIND_FORMAT ? "%" : ""), - format_length, format_start, wanted_type_name, p); - } + element_format_substring elem_format_substring + (format_string_diagnostic_t::highlight_color_format_string, + (kind == CF_KIND_FORMAT ? "%" : ""), + format_length, format_start); + pp_markup::element_actual_type elem_actual_param_type (arg_type); + element_expected_type_with_indirection + elem_expected_type (wanted_type, wanted_type_name, pointer_count); + if (arg_type) + diag.emit_warning (OPT_Wformat_, + "%s %e expects argument of type %e, " + "but argument %d has type %e", + gettext (kind_descriptions[kind]), + &elem_format_substring, &elem_expected_type, + arg_num, &elem_actual_param_type); else - { - if (arg_type) - diag.emit_warning - (OPT_Wformat_, - "%s %<%s%.*s%> expects argument of type %<%T%s%>, " - "but argument %d has type %qT", - gettext (kind_descriptions[kind]), - (kind == CF_KIND_FORMAT ? "%" : ""), - format_length, format_start, - wanted_type, p, arg_num, arg_type); - else - diag.emit_warning - (OPT_Wformat_, - "%s %<%s%.*s%> expects a matching %<%T%s%> argument", - gettext (kind_descriptions[kind]), - (kind == CF_KIND_FORMAT ? "%" : ""), - format_length, format_start, wanted_type, p); - } - + diag.emit_warning (OPT_Wformat_, + "%s %e expects a matching %e argument", + gettext (kind_descriptions[kind]), + &elem_format_substring, + &elem_expected_type); free (corrected_substring); } @@ -5111,6 +5212,14 @@ init_dynamic_diag_info (void) || local_event_ptr_node == void_type_node) local_event_ptr_node = get_named_type ("diagnostic_event_id_t"); + /* Similar to the above but for pp_element*. */ + if (!local_pp_element_ptr_node + || local_pp_element_ptr_node == void_type_node) + { + if (tree pp_element_node = get_named_type ("pp_element")) + local_pp_element_ptr_node = build_pointer_type (pp_element_node); + } + /* All the GCC diag formats use the same length specs. */ dynamic_format_types[gcc_diag_format_type].length_char_specs = dynamic_format_types[gcc_tdiag_format_type].length_char_specs = @@ -5461,7 +5570,7 @@ test_type_mismatch_range_labels () integer_type_node, 1); range_label_for_type_mismatch param_label (integer_type_node, char_type_node); - gcc_rich_location richloc (fmt, &fmt_label); + gcc_rich_location richloc (fmt, &fmt_label, nullptr); richloc.add_range (param, SHOW_RANGE_WITHOUT_CARET, ¶m_label); test_diagnostic_context dc; diff --git a/gcc/c-family/c-format.h b/gcc/c-family/c-format.h index 21242d1..7b435f8 100644 --- a/gcc/c-family/c-format.h +++ b/gcc/c-family/c-format.h @@ -317,6 +317,7 @@ struct format_kind_info #define T89_G { STD_C89, NULL, &local_gimple_ptr_node } #define T_CGRAPH_NODE { STD_C89, NULL, &local_cgraph_node_ptr_node } #define T_EVENT_PTR { STD_C89, NULL, &local_event_ptr_node } +#define T_PP_ELEMENT_PTR { STD_C89, NULL, &local_pp_element_ptr_node } #define T89_T { STD_C89, NULL, &local_tree_type_node } #define T89_V { STD_C89, NULL, T_V } #define T_W &wchar_type_node diff --git a/gcc/c-family/c-type-mismatch.cc b/gcc/c-family/c-type-mismatch.cc index fae3126..8964685 100644 --- a/gcc/c-family/c-type-mismatch.cc +++ b/gcc/c-family/c-type-mismatch.cc @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "cpplib.h" #include "diagnostic.h" +#include "diagnostic-highlight-colors.h" /* Implementation of range_label::get_text for maybe_range_label_for_tree_type_mismatch. @@ -72,7 +73,8 @@ maybe_range_label_for_tree_type_mismatch::get_text (unsigned range_idx) const | arg1 type arg0 type - labelling the types of the arguments if SHOW_TYPES is true. + labelling the types of the arguments if SHOW_TYPES is true, + and using highlight_colors::lhs and highlight_colors::rhs for the ranges. Otherwise, make a 1-location rich_location using the compound location within LOC: @@ -96,8 +98,10 @@ binary_op_rich_location::binary_op_rich_location (const op_location_t &loc, if (use_operator_loc_p (loc, arg0, arg1)) { set_range (0, loc.m_operator_loc, SHOW_RANGE_WITH_CARET); - maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL); - maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL); + maybe_add_expr (arg0, show_types ? &m_label_for_arg0 : NULL, + highlight_colors::lhs); + maybe_add_expr (arg1, show_types ? &m_label_for_arg1 : NULL, + highlight_colors::rhs); } } diff --git a/gcc/c-family/c-type-mismatch.h b/gcc/c-family/c-type-mismatch.h index 58fba5d..7f0924c 100644 --- a/gcc/c-family/c-type-mismatch.h +++ b/gcc/c-family/c-type-mismatch.h @@ -98,7 +98,8 @@ class op_location_t; | arg1 type arg0 type - labelling the types of the arguments if SHOW_TYPES is true. + labelling the types of the arguments if SHOW_TYPES is true, + and using highlight_colors::lhs and highlight_colors::rhs for the ranges. Otherwise, it will fall back to a 1-location rich_location using the compound location within LOC: |