aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-family
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2024-07-13 10:34:51 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2024-07-13 10:34:51 -0400
commit7d73c01ce6d1ab28157a7dadcd3be14f96a7c8f3 (patch)
tree19ff9b197aa6635ad127839f17933febd9503132 /gcc/c-family
parentabf3964711f05b6858d9775c3595ec2b45483e14 (diff)
downloadgcc-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.cc17
-rw-r--r--gcc/c-family/c-common.h6
-rw-r--r--gcc/c-family/c-format.cc229
-rw-r--r--gcc/c-family/c-format.h1
-rw-r--r--gcc/c-family/c-type-mismatch.cc10
-rw-r--r--gcc/c-family/c-type-mismatch.h3
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, &param_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, &param_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: