aboutsummaryrefslogtreecommitdiff
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
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>
-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
-rw-r--r--gcc/c/c-objc-common.cc30
-rw-r--r--gcc/c/c-typeck.cc46
-rw-r--r--gcc/common.opt4
-rw-r--r--gcc/common.opt.urls3
-rw-r--r--gcc/coretypes.h2
-rw-r--r--gcc/cp/call.cc75
-rw-r--r--gcc/cp/cp-tree.h13
-rw-r--r--gcc/cp/error.cc107
-rw-r--r--gcc/cp/typeck.cc20
-rw-r--r--gcc/diagnostic-color.cc4
-rw-r--r--gcc/diagnostic-format-json.cc1
-rw-r--r--gcc/diagnostic-format-sarif.cc1
-rw-r--r--gcc/diagnostic-highlight-colors.h56
-rw-r--r--gcc/diagnostic-path.cc2
-rw-r--r--gcc/diagnostic-show-locus.cc58
-rw-r--r--gcc/diagnostic.h4
-rw-r--r--gcc/doc/invoke.texi51
-rw-r--r--gcc/doc/ux.texi87
-rw-r--r--gcc/gcc-rich-location.cc12
-rw-r--r--gcc/gcc-rich-location.h20
-rw-r--r--gcc/gcc.cc4
-rw-r--r--gcc/lto-wrapper.cc7
-rw-r--r--gcc/opts-common.cc2
-rw-r--r--gcc/opts-global.cc5
-rw-r--r--gcc/opts.cc5
-rw-r--r--gcc/pretty-print-markup.h75
-rw-r--r--gcc/pretty-print.cc113
-rw-r--r--gcc/pretty-print.h18
-rw-r--r--gcc/substring-locations.cc21
-rw-r--r--gcc/substring-locations.h3
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-highlight-colors.C34
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-no-highlight-colors.C29
-rw-r--r--gcc/testsuite/g++.dg/plugin/plugin.exp1
-rw-r--r--gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C20
-rw-r--r--gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C8
-rw-r--r--gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-highlight-colors.C32
-rw-r--r--gcc/testsuite/g++.dg/plugin/show-template-tree-color.C8
-rw-r--r--gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-1.C200
-rw-r--r--gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-2.C52
-rw-r--r--gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-3.C54
-rw-r--r--gcc/testsuite/gcc.dg/bad-binary-ops-highlight-colors.c35
-rw-r--r--gcc/testsuite/gcc.dg/bad-binary-ops-no-highlight-colors.c30
-rw-r--r--gcc/testsuite/gcc.dg/format/colors.c27
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c2
-rw-r--r--gcc/toplev.cc2
-rw-r--r--gcc/tree-pretty-print-markup.h84
-rw-r--r--libcpp/include/rich-location.h14
-rw-r--r--libcpp/line-map.cc29
54 files changed, 1580 insertions, 196 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:
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index 1025e0e..fde9ae6 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "c-family/c-pretty-print.h"
#include "tree-pretty-print.h"
+#include "tree-pretty-print-markup.h"
#include "gimple-pretty-print.h"
#include "langhooks.h"
#include "c-objc-common.h"
@@ -222,7 +223,8 @@ get_aka_type (tree type)
/* Print T to CPP. */
static void
-print_type (c_pretty_printer *cpp, tree t, bool *quoted)
+print_type (c_pretty_printer *cpp, tree t, bool *quoted,
+ const char *highlight_color = nullptr)
{
if (t == error_mark_node)
{
@@ -230,6 +232,9 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted)
return;
}
+ if (!pp_show_highlight_colors (cpp))
+ highlight_color = nullptr;
+
gcc_assert (TYPE_P (t));
struct obstack *ob = pp_buffer (cpp)->obstack;
char *p = (char *) obstack_base (ob);
@@ -249,6 +254,7 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted)
tree aka_type = get_aka_type (t);
if (aka_type != t)
{
+ const bool show_color = pp_show_color (cpp);
c_pretty_printer cpp2;
/* Print the stripped version into a temporary printer. */
cpp2.type_id (aka_type);
@@ -264,22 +270,38 @@ print_type (c_pretty_printer *cpp, tree t, bool *quoted)
/* They're not, print the stripped version now. */
if (*quoted)
- pp_end_quote (cpp, pp_show_color (cpp));
+ pp_end_quote (cpp, show_color);
pp_c_whitespace (cpp);
pp_left_brace (cpp);
pp_c_ws_string (cpp, _("aka"));
pp_c_whitespace (cpp);
+ pp_string (cpp, colorize_stop (show_color));
if (*quoted)
- pp_begin_quote (cpp, pp_show_color (cpp));
+ pp_begin_quote (cpp, show_color);
+ if (highlight_color)
+ pp_string (cpp, colorize_start (show_color, highlight_color));
cpp->type_id (aka_type);
if (*quoted)
- pp_end_quote (cpp, pp_show_color (cpp));
+ pp_end_quote (cpp, show_color);
pp_right_brace (cpp);
/* No further closing quotes are needed. */
*quoted = false;
}
}
+/* Implementation of pp_markup::element_quoted_type::print_type
+ for C/ObjC. */
+
+void
+pp_markup::element_quoted_type::print_type (pp_markup::context &ctxt)
+{
+ c_pretty_printer *cpp = (c_pretty_printer *) ctxt.m_pp.clone ();
+ cpp->set_padding (pp_none);
+ ::print_type (cpp, m_type, &ctxt.m_quoted, m_highlight_color);
+ pp_string (&ctxt.m_pp, pp_formatted_text (cpp));
+ delete cpp;
+}
+
/* Called during diagnostic message formatting process to print a
source-level entity onto BUFFER. The meaning of the format specifiers
is as follows:
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 36f88fcd..574114d 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
#include "asan.h"
#include "realmpfr.h"
+#include "tree-pretty-print-markup.h"
/* Possible cases of implicit conversions. Used to select diagnostic messages
and control folding initializers in convert_for_assignment. */
@@ -3482,6 +3483,14 @@ inform_declaration (tree decl)
inform (DECL_SOURCE_LOCATION (decl), "declared here");
}
+/* C implementation of callback for use when checking param types. */
+
+static bool
+comp_parm_types (tree wanted_type, tree actual_type)
+{
+ return comptypes (wanted_type, actual_type);
+}
+
/* Build a function call to function FUNCTION with parameters PARAMS.
If FUNCTION is the result of resolving an overloaded target built-in,
ORIG_FUNDECL is the original function decl, otherwise it is null.
@@ -3601,7 +3610,8 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
/* Check that the arguments to the function are valid. */
bool warned_p = check_function_arguments (loc, fundecl, fntype,
- nargs, argarray, &arg_loc);
+ nargs, argarray, &arg_loc,
+ comp_parm_types);
if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED
&& !VOID_TYPE_P (return_type))
@@ -7204,7 +7214,10 @@ get_fndecl_argument_location (tree fndecl, int argnum)
to FUNDECL, for types EXPECTED_TYPE and ACTUAL_TYPE.
Attempt to issue the note at the pertinent parameter of the decl;
failing that issue it at the location of FUNDECL; failing that
- issue it at PLOC. */
+ issue it at PLOC.
+ Use highlight_colors::actual for the ACTUAL_TYPE
+ and highlight_colors::expected for EXPECTED_TYPE and the
+ parameter of FUNDECL*/
static void
inform_for_arg (tree fundecl, location_t ploc, int parmnum,
@@ -7216,9 +7229,13 @@ inform_for_arg (tree fundecl, location_t ploc, int parmnum,
else
loc = ploc;
- inform (loc,
- "expected %qT but argument is of type %qT",
- expected_type, actual_type);
+ gcc_rich_location richloc (loc, nullptr, highlight_colors::expected);
+
+ pp_markup::element_expected_type elem_expected_type (expected_type);
+ pp_markup::element_actual_type elem_actual_type (actual_type);
+ inform (&richloc,
+ "expected %e but argument is of type %e",
+ &elem_expected_type, &elem_actual_type);
}
/* Issue a warning when an argument of ARGTYPE is passed to a built-in
@@ -8027,7 +8044,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{
auto_diagnostic_group d;
range_label_for_type_mismatch rhs_label (rhstype, type);
- gcc_rich_location richloc (expr_loc, &rhs_label);
+ gcc_rich_location richloc (expr_loc, &rhs_label,
+ highlight_colors::actual);
if (pedwarn (&richloc, OPT_Wpointer_sign,
"pointer targets in passing argument %d of "
"%qE differ in signedness", parmnum, rname))
@@ -8088,7 +8106,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{
auto_diagnostic_group d;
range_label_for_type_mismatch rhs_label (rhstype, type);
- gcc_rich_location richloc (expr_loc, &rhs_label);
+ gcc_rich_location richloc (expr_loc, &rhs_label,
+ highlight_colors::actual);
if (permerror_opt (&richloc, OPT_Wincompatible_pointer_types,
"passing argument %d of %qE from "
"incompatible pointer type",
@@ -8168,7 +8187,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{
auto_diagnostic_group d;
range_label_for_type_mismatch rhs_label (rhstype, type);
- gcc_rich_location richloc (expr_loc, &rhs_label);
+ gcc_rich_location richloc (expr_loc, &rhs_label,
+ highlight_colors::actual);
if (permerror_opt (&richloc, OPT_Wint_conversion,
"passing argument %d of %qE makes pointer "
"from integer without a cast", parmnum, rname))
@@ -8207,7 +8227,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{
auto_diagnostic_group d;
range_label_for_type_mismatch rhs_label (rhstype, type);
- gcc_rich_location richloc (expr_loc, &rhs_label);
+ gcc_rich_location richloc (expr_loc, &rhs_label,
+ highlight_colors::actual);
if (permerror_opt (&richloc, OPT_Wint_conversion,
"passing argument %d of %qE makes integer from "
"pointer without a cast", parmnum, rname))
@@ -8257,7 +8278,8 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{
auto_diagnostic_group d;
range_label_for_type_mismatch rhs_label (rhstype, type);
- gcc_rich_location richloc (expr_loc, &rhs_label);
+ gcc_rich_location richloc (expr_loc, &rhs_label,
+ highlight_colors::actual);
const char msg[] = G_("incompatible type for argument %d of %qE");
if (warnopt)
warning_at (expr_loc, warnopt, msg, parmnum, rname);
@@ -13462,8 +13484,8 @@ build_binary_op (location_t location, enum tree_code code,
maybe_range_label_for_tree_type_mismatch
label_for_op0 (orig_op0, orig_op1),
label_for_op1 (orig_op1, orig_op0);
- richloc.maybe_add_expr (orig_op0, &label_for_op0);
- richloc.maybe_add_expr (orig_op1, &label_for_op1);
+ richloc.maybe_add_expr (orig_op0, &label_for_op0, highlight_colors::lhs);
+ richloc.maybe_add_expr (orig_op1, &label_for_op1, highlight_colors::rhs);
binary_op_error (&richloc, code, type0, type1);
return error_mark_node;
}
diff --git a/gcc/common.opt b/gcc/common.opt
index c4bda3b..ea39f87 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1507,6 +1507,10 @@ fdiagnostics-show-rules
Common Var(flag_diagnostics_show_rules) Init(1)
Print any rules associated with diagnostic messages.
+fdiagnostics-show-highlight-colors
+Common Var(flag_diagnostics_show_highlight_colors) Init(1)
+Use color within diagnostic messages to highlight pertinent information.
+
fdiagnostics-path-format=
Common Joined RejectNegative Var(flag_diagnostics_path_format) Enum(diagnostic_path_format) Init(DPF_INLINE_EVENTS)
Specify how to print any control-flow path associated with a diagnostic.
diff --git a/gcc/common.opt.urls b/gcc/common.opt.urls
index 0e71bce..b917f90 100644
--- a/gcc/common.opt.urls
+++ b/gcc/common.opt.urls
@@ -582,6 +582,9 @@ UrlSuffix(gcc/Diagnostic-Message-Formatting-Options.html#index-fdiagnostics-show
fdiagnostics-show-rules
UrlSuffix(gcc/Diagnostic-Message-Formatting-Options.html#index-fdiagnostics-show-rules)
+fdiagnostics-show-highlight-colors
+UrlSuffix(gcc/Diagnostic-Message-Formatting-Options.html#index-fdiagnostics-show-highlight-colors)
+
fdiagnostics-path-format=
UrlSuffix(gcc/Diagnostic-Message-Formatting-Options.html#index-fdiagnostics-path-format)
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 00c1c58..0544bb8 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -162,6 +162,8 @@ class diagnostic_context;
class pretty_printer;
class diagnostic_event_id_t;
typedef const char * (*diagnostic_input_charset_callback)(const char *);
+namespace pp_markup { class element; }
+typedef pp_markup::element pp_element;
template<typename T> struct array_traits;
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 83070b2..a5d3426 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "decl.h"
#include "c-family/c-type-mismatch.h"
#include "tristate.h"
+#include "tree-pretty-print-markup.h"
/* The various kinds of conversion. */
@@ -4760,7 +4761,8 @@ implicit_conversion_error (location_t loc, tree type, tree expr)
else
{
range_label_for_type_mismatch label (TREE_TYPE (expr), type);
- gcc_rich_location rich_loc (loc, &label);
+ gcc_rich_location rich_loc (loc, &label,
+ highlight_colors::percent_h);
error_at (&rich_loc, "could not convert %qE from %qH to %qI",
expr, TREE_TYPE (expr), type);
}
@@ -5446,6 +5448,19 @@ build_op_call (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
return result;
}
+/* Subroutine for preparing format strings suitable for the error
+ function. It concatenates a prefix (controlled by MATCH), ERRMSG,
+ and SUFFIX. */
+
+static const char *
+concat_op_error_string (bool match, const char *errmsg, const char *suffix)
+{
+ return concat (match
+ ? G_("ambiguous overload for ")
+ : G_("no match for "),
+ errmsg, suffix, nullptr);
+}
+
/* Called by op_error to prepare format strings suitable for the error
function. It concatenates a prefix (controlled by MATCH), ERRMSG,
and a suffix (controlled by NTYPES). */
@@ -5453,19 +5468,24 @@ build_op_call (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
static const char *
op_error_string (const char *errmsg, int ntypes, bool match)
{
- const char *msg;
-
- const char *msgp = concat (match ? G_("ambiguous overload for ")
- : G_("no match for "), errmsg, NULL);
-
+ const char *suffix;
if (ntypes == 3)
- msg = concat (msgp, G_(" (operand types are %qT, %qT, and %qT)"), NULL);
+ suffix = G_(" (operand types are %qT, %qT, and %qT)");
else if (ntypes == 2)
- msg = concat (msgp, G_(" (operand types are %qT and %qT)"), NULL);
+ suffix = G_(" (operand types are %qT and %qT)");
else
- msg = concat (msgp, G_(" (operand type is %qT)"), NULL);
+ suffix = G_(" (operand type is %qT)");
+ return concat_op_error_string (match, errmsg, suffix);
+}
- return msg;
+/* Similar to op_error_string, but a special-case for binary ops that
+ use %e for the args, rather than %qT. */
+
+static const char *
+binop_error_string (const char *errmsg, bool match)
+{
+ return concat_op_error_string (match, errmsg,
+ G_(" (operand types are %e and %e)"));
}
static void
@@ -5536,9 +5556,13 @@ op_error (const op_location_t &loc,
if (flag_diagnostics_show_caret)
{
binary_op_rich_location richloc (loc, arg1, arg2, true);
+ pp_markup::element_quoted_type element_0
+ (TREE_TYPE (arg1), highlight_colors::lhs);
+ pp_markup::element_quoted_type element_1
+ (TREE_TYPE (arg2), highlight_colors::rhs);
error_at (&richloc,
- op_error_string (G_("%<operator%s%>"), 2, match),
- opname, TREE_TYPE (arg1), TREE_TYPE (arg2));
+ binop_error_string (G_("%<operator%s%>"), match),
+ opname, &element_0, &element_1);
}
else
error_at (loc, op_error_string (G_("%<operator%s%> in %<%E %s %E%>"),
@@ -8370,11 +8394,16 @@ get_fndecl_argument_location (tree fndecl, int argnum)
wrong). */
void
-maybe_inform_about_fndecl_for_bogus_argument_init (tree fn, int argnum)
+maybe_inform_about_fndecl_for_bogus_argument_init (tree fn, int argnum,
+ const char *highlight_color)
{
if (fn)
- inform (get_fndecl_argument_location (fn, argnum),
- " initializing argument %P of %qD", argnum, fn);
+ {
+ gcc_rich_location richloc (get_fndecl_argument_location (fn, argnum));
+ richloc.set_highlight_color (highlight_color);
+ inform (&richloc,
+ " initializing argument %P of %qD", argnum, fn);
+ }
}
/* Maybe warn about C++20 Conversions to arrays of unknown bound. C is
@@ -8523,7 +8552,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
if (!complained && expr != error_mark_node)
{
range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
- gcc_rich_location richloc (loc, &label);
+ gcc_rich_location richloc (loc, &label, highlight_colors::percent_h);
complained = permerror (&richloc,
"invalid conversion from %qH to %qI",
TREE_TYPE (expr), totype);
@@ -8535,7 +8564,8 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
else
expr = cp_convert (totype, expr, complain);
if (complained == 1)
- maybe_inform_about_fndecl_for_bogus_argument_init (fn, argnum);
+ maybe_inform_about_fndecl_for_bogus_argument_init
+ (fn, argnum, highlight_colors::percent_i);
return expr;
}
@@ -10380,7 +10410,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
}
warned_p = check_function_arguments (input_location, fn, TREE_TYPE (fn),
- nargs, fargs, NULL);
+ nargs, fargs, NULL,
+ cp_comp_parm_types);
}
if (DECL_INHERITED_CTOR (fn))
@@ -11460,12 +11491,14 @@ complain_about_bad_argument (location_t arg_loc,
arg_loc = input_location;
label = NULL;
}
- gcc_rich_location richloc (arg_loc, label);
+ gcc_rich_location richloc (arg_loc, label, highlight_colors::percent_h);
error_at (&richloc,
"cannot convert %qH to %qI",
from_type, to_type);
- maybe_inform_about_fndecl_for_bogus_argument_init (fndecl,
- parmnum);
+ maybe_inform_about_fndecl_for_bogus_argument_init
+ (fndecl,
+ parmnum,
+ highlight_colors::percent_i);
}
/* Subroutine of build_new_method_call_1, for where there are no viable
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 208947c..c1a371bc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6773,7 +6773,8 @@ extern location_t get_fndecl_argument_location (tree, int);
extern void complain_about_bad_argument (location_t arg_loc,
tree from_type, tree to_type,
tree fndecl, int parmnum);
-extern void maybe_inform_about_fndecl_for_bogus_argument_init (tree, int);
+extern void maybe_inform_about_fndecl_for_bogus_argument_init (tree, int,
+ const char * = nullptr);
extern tree perform_dguide_overload_resolution (tree, const vec<tree, va_gc> *,
tsubst_flags_t);
@@ -8183,6 +8184,7 @@ extern bool comp_except_specs (const_tree, const_tree, int);
extern bool comptypes (tree, tree, int);
extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
extern bool similar_type_p (tree, tree);
+extern bool cp_comp_parm_types (tree, tree);
extern bool next_common_initial_sequence (tree &, tree &);
extern bool layout_compatible_type_p (tree, tree);
extern bool compparms (const_tree, const_tree);
@@ -9057,6 +9059,15 @@ name_independent_decl_p (tree decl)
&& !DECL_EXTERNAL (decl));
}
+namespace highlight_colors {
+
+/* Color names for highlighting "%qH" vs "%qI" values,
+ and ranges corresponding to them. */
+extern const char *const percent_h;
+extern const char *const percent_i;
+
+} // namespace highlight_colors
+
#if CHECKING_P
namespace selftest {
extern void run_cp_tests (void);
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 1f36563a..e35448f 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "cxx-pretty-print.h"
#include "tree-pretty-print.h"
+#include "tree-pretty-print-markup.h"
#include "gimple-pretty-print.h"
#include "c-family/c-objc.h"
#include "ubsan.h"
@@ -62,7 +63,8 @@ static const char *decl_to_string (tree, int, bool);
static const char *fndecl_to_string (tree, int);
static const char *op_to_string (bool, enum tree_code);
static const char *parm_to_string (int);
-static const char *type_to_string (tree, int, bool, bool *, bool);
+static const char *type_to_string (tree, int, bool, bool *, bool,
+ const char * = nullptr);
static void dump_alias_template_specialization (cxx_pretty_printer *, tree, int);
static void dump_type (cxx_pretty_printer *, tree, int);
@@ -109,6 +111,11 @@ static void cp_print_error_function (diagnostic_context *,
static bool cp_printer (pretty_printer *, text_info *, const char *,
int, bool, bool, bool, bool *, const char **);
+/* Color names for highlighting "%qH" vs "%qI" values,
+ and ranges corresponding to them. */
+const char *const highlight_colors::percent_h = "highlight-a";
+const char *const highlight_colors::percent_i = "highlight-b";
+
/* Struct for handling %H or %I, which require delaying printing the
type until a postprocessing stage. */
@@ -3405,12 +3412,12 @@ op_to_string (bool assop, enum tree_code p)
pp_format, or is not needed due to QUOTE being NULL (for template arguments
within %H and %I).
- SHOW_COLOR is used to determine the colorization of any quotes that
- are added. */
+ SHOW_COLOR and HIGHLIGHT_COLOR are used to determine the colorization of
+ any quotes that are added. */
static const char *
type_to_string (tree typ, int verbose, bool postprocessed, bool *quote,
- bool show_color)
+ bool show_color, const char *highlight_color)
{
int flags = 0;
if (verbose)
@@ -3421,7 +3428,11 @@ type_to_string (tree typ, int verbose, bool postprocessed, bool *quote,
pp_show_color (cxx_pp) = show_color;
if (postprocessed && quote && *quote)
- pp_begin_quote (cxx_pp, show_color);
+ {
+ pp_begin_quote (cxx_pp, show_color);
+ if (show_color && highlight_color)
+ pp_string (cxx_pp, colorize_start (show_color, highlight_color));
+ }
struct obstack *ob = pp_buffer (cxx_pp)->obstack;
int type_start, type_len;
@@ -3447,6 +3458,8 @@ type_to_string (tree typ, int verbose, bool postprocessed, bool *quote,
pp_cxx_whitespace (cxx_pp);
if (quote && *quote)
pp_begin_quote (cxx_pp, show_color);
+ if (highlight_color)
+ pp_string (cxx_pp, colorize_start (show_color, highlight_color));
/* And remember the start of the aka dump. */
aka_start = obstack_object_size (ob);
dump_type (cxx_pp, aka, flags);
@@ -3476,6 +3489,8 @@ type_to_string (tree typ, int verbose, bool postprocessed, bool *quote,
if (quote && *quote)
{
+ if (show_color && highlight_color)
+ pp_string (cxx_pp, colorize_stop (show_color));
pp_end_quote (cxx_pp, show_color);
*quote = false;
}
@@ -4100,13 +4115,17 @@ arg_to_string (tree arg, bool verbose)
print_template_tree_comparison.
Print a representation of ARG (an expression or type) to PP,
- colorizing it as "type-diff" if PP->show_color. */
+ colorizing it if PP->show_color, using HIGHLIGHT_COLOR,
+ or "type-diff" if the latter is NULL. */
static void
-print_nonequal_arg (pretty_printer *pp, tree arg, bool verbose)
+print_nonequal_arg (pretty_printer *pp, tree arg, bool verbose,
+ const char *highlight_color)
{
+ if (!highlight_color)
+ highlight_color = "type-diff";
pp_printf (pp, "%r%s%R",
- "type-diff",
+ highlight_color,
(arg
? arg_to_string (arg, verbose)
: G_("(no argument)")));
@@ -4158,7 +4177,9 @@ print_nonequal_arg (pretty_printer *pp, tree arg, bool verbose)
static void
print_template_differences (pretty_printer *pp, tree type_a, tree type_b,
- bool verbose, int indent)
+ bool verbose, int indent,
+ const char *highlight_color_a,
+ const char *highlight_color_b)
{
if (indent)
newline_and_indent (pp, indent);
@@ -4209,19 +4230,20 @@ print_template_differences (pretty_printer *pp, tree type_a, tree type_b,
{
int new_indent = indent ? indent + 2 : 0;
if (comparable_template_types_p (arg_a, arg_b))
- print_template_differences (pp, arg_a, arg_b, verbose, new_indent);
+ print_template_differences (pp, arg_a, arg_b, verbose, new_indent,
+ highlight_color_a, highlight_color_b);
else
if (indent)
{
newline_and_indent (pp, indent + 2);
pp_character (pp, '[');
- print_nonequal_arg (pp, arg_a, verbose);
+ print_nonequal_arg (pp, arg_a, verbose, highlight_color_a);
pp_string (pp, " != ");
- print_nonequal_arg (pp, arg_b, verbose);
+ print_nonequal_arg (pp, arg_b, verbose, highlight_color_b);
pp_character (pp, ']');
}
else
- print_nonequal_arg (pp, arg_a, verbose);
+ print_nonequal_arg (pp, arg_a, verbose, highlight_color_a);
}
}
pp_printf (pp, ">");
@@ -4247,13 +4269,16 @@ print_template_differences (pretty_printer *pp, tree type_a, tree type_b,
static const char *
type_to_string_with_compare (tree type, tree peer, bool verbose,
- bool show_color)
+ bool show_color,
+ const char *this_highlight_color,
+ const char *peer_highlight_color)
{
pretty_printer inner_pp;
pretty_printer *pp = &inner_pp;
pp_show_color (pp) = show_color;
- print_template_differences (pp, type, peer, verbose, 0);
+ print_template_differences (pp, type, peer, verbose, 0,
+ this_highlight_color, peer_highlight_color);
return pp_ggc_formatted_text (pp);
}
@@ -4291,9 +4316,13 @@ type_to_string_with_compare (tree type, tree peer, bool verbose,
static void
print_template_tree_comparison (pretty_printer *pp, tree type_a, tree type_b,
- bool verbose, int indent)
+ bool verbose, int indent,
+ const char *highlight_color_a,
+ const char *highlight_color_b)
{
- print_template_differences (pp, type_a, type_b, verbose, indent);
+ print_template_differences (pp, type_a, type_b, verbose, indent,
+ highlight_color_a,
+ highlight_color_b);
}
/* Subroutine for use in a format_postprocessor::handle
@@ -4345,6 +4374,11 @@ cxx_format_postprocessor::handle (pretty_printer *pp)
been present. */
if (m_type_a.m_tree || m_type_b.m_tree)
{
+ const bool show_highlight_colors = pp_show_highlight_colors (pp);
+ const char *percent_h
+ = show_highlight_colors ? highlight_colors::percent_h : nullptr;
+ const char *percent_i
+ = show_highlight_colors ? highlight_colors::percent_i : nullptr;
/* Avoid reentrancy issues by working with a copy of
m_type_a and m_type_b, resetting them now. */
deferred_printed_type type_a = m_type_a;
@@ -4362,19 +4396,22 @@ cxx_format_postprocessor::handle (pretty_printer *pp)
if (comparable_template_types_p (type_a.m_tree, type_b.m_tree))
{
- type_a_text
- = type_to_string_with_compare (type_a.m_tree, type_b.m_tree,
- type_a.m_verbose, show_color);
- type_b_text
- = type_to_string_with_compare (type_b.m_tree, type_a.m_tree,
- type_b.m_verbose, show_color);
+ type_a_text = type_to_string_with_compare
+ (type_a.m_tree, type_b.m_tree,
+ type_a.m_verbose, show_color,
+ percent_h, percent_i);
+ type_b_text = type_to_string_with_compare
+ (type_b.m_tree, type_a.m_tree,
+ type_b.m_verbose, show_color,
+ percent_i, percent_h);
if (flag_diagnostics_show_template_tree)
{
pretty_printer inner_pp;
pp_show_color (&inner_pp) = pp_show_color (pp);
print_template_tree_comparison
- (&inner_pp, type_a.m_tree, type_b.m_tree, type_a.m_verbose, 2);
+ (&inner_pp, type_a.m_tree, type_b.m_tree, type_a.m_verbose, 2,
+ percent_h, percent_i);
append_formatted_chunk (pp, pp_ggc_formatted_text (&inner_pp));
}
}
@@ -4384,9 +4421,11 @@ cxx_format_postprocessor::handle (pretty_printer *pp)
provided), they are printed normally, and no difference tree
is printed. */
type_a_text = type_to_string (type_a.m_tree, type_a.m_verbose,
- true, &type_a.m_quote, show_color);
+ true, &type_a.m_quote, show_color,
+ percent_h);
type_b_text = type_to_string (type_b.m_tree, type_b.m_verbose,
- true, &type_b.m_quote, show_color);
+ true, &type_b.m_quote, show_color,
+ percent_i);
}
if (type_a.m_quote)
@@ -4438,6 +4477,19 @@ defer_phase_2_of_type_diff (deferred_printed_type *deferred,
*deferred = deferred_printed_type (type, buffer_ptr, verbose, quote);
}
+/* Implementation of pp_markup::element_quoted_type::print_type
+ for C++/ObjC++. */
+
+void
+pp_markup::element_quoted_type::print_type (pp_markup::context &ctxt)
+{
+ const char *highlight_color
+ = pp_show_highlight_colors (&ctxt.m_pp) ? m_highlight_color : nullptr;
+ const char *result
+ = type_to_string (m_type, false, false, &ctxt.m_quoted,
+ pp_show_color (&ctxt.m_pp), highlight_color);
+ pp_string (&ctxt.m_pp, result);
+}
/* Called from output_format -- during diagnostic message processing --
to handle C++ specific format specifier with the following meanings:
@@ -4748,7 +4800,8 @@ range_label_for_type_mismatch::get_text (unsigned /*range_idx*/) const
if (m_other_type
&& comparable_template_types_p (m_labelled_type, m_other_type))
result = type_to_string_with_compare (m_labelled_type, m_other_type,
- verbose, show_color);
+ verbose, show_color,
+ nullptr, nullptr);
else
result = type_to_string (m_labelled_type, verbose, true, NULL, show_color);
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 5519d77..5041a70 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4346,6 +4346,18 @@ cp_build_function_call_nary (tree function, tsubst_flags_t complain, ...)
return ret;
}
+/* C++ implementation of callback for use when checking param types. */
+
+bool
+cp_comp_parm_types (tree wanted_type, tree actual_type)
+{
+ if (TREE_CODE (wanted_type) == POINTER_TYPE
+ && TREE_CODE (actual_type) == POINTER_TYPE)
+ return same_or_base_type_p (TREE_TYPE (wanted_type),
+ TREE_TYPE (actual_type));
+ return false;
+}
+
/* Build a function call using a vector of arguments.
If FUNCTION is the result of resolving an overloaded target built-in,
ORIG_FNDECL is the original function decl, otherwise it is null.
@@ -4457,7 +4469,8 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
/* Check for errors in format strings and inappropriately
null parameters. */
bool warned_p = check_function_arguments (input_location, fndecl, fntype,
- nargs, argarray, NULL);
+ nargs, argarray, NULL,
+ cp_comp_parm_types);
ret = build_cxx_call (function, nargs, argarray, complain, orig_fndecl);
@@ -10380,7 +10393,10 @@ convert_for_assignment (tree type, tree rhs,
else
{
range_label_for_type_mismatch label (rhstype, type);
- gcc_rich_location richloc (rhs_loc, has_loc ? &label : NULL);
+ gcc_rich_location richloc
+ (rhs_loc,
+ has_loc ? &label : NULL,
+ has_loc ? highlight_colors::percent_h : NULL);
auto_diagnostic_group d;
switch (errtype)
diff --git a/gcc/diagnostic-color.cc b/gcc/diagnostic-color.cc
index 184419c..8b195d0 100644
--- a/gcc/diagnostic-color.cc
+++ b/gcc/diagnostic-color.cc
@@ -102,7 +102,9 @@ static const color_default gcc_color_defaults[] =
{ "diff-insert", SGR_SEQ (COLOR_FG_GREEN) },
{ "type-diff", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN) },
{ "valid", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN) },
- { "invalid", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED) }
+ { "invalid", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_RED) },
+ { "highlight-a", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN) },
+ { "highlight-b", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_BLUE) }
};
class diagnostic_color_dict
diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index 8f2ff6c..4dc0f26 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -401,6 +401,7 @@ diagnostic_output_format_init_json (diagnostic_context *context)
/* Don't colorize the text. */
pp_show_color (context->printer) = false;
+ context->set_show_highlight_colors (false);
}
/* Populate CONTEXT in preparation for JSON output to stderr. */
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 2745c72..2254769 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -2033,6 +2033,7 @@ diagnostic_output_format_init_sarif (diagnostic_context *context)
/* Don't colorize the text. */
pp_show_color (context->printer) = false;
+ context->set_show_highlight_colors (false);
}
/* Populate CONTEXT in preparation for SARIF output to stderr. */
diff --git a/gcc/diagnostic-highlight-colors.h b/gcc/diagnostic-highlight-colors.h
new file mode 100644
index 0000000..66acfc8
--- /dev/null
+++ b/gcc/diagnostic-highlight-colors.h
@@ -0,0 +1,56 @@
+/* Symbolic names for highlighting colors in diagnostics.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTIC_HIGHLIGHT_COLORS_H
+#define GCC_DIAGNOSTIC_HIGHLIGHT_COLORS_H
+
+/* Symbolic names for highlight colors in diagnostics, so that e.g.
+ in
+
+warning: format `%i' expects argument of type `int',
+ but argument 2 has type `const char *' [-Wformat=]
+ 279 | printf("hello " INT_FMT " world", msg);
+ | ^~~~~~~~ ~~~
+ | |
+ | const char *
+note: format string is defined here
+ 278 | #define INT_FMT "%i"
+ | ~^
+ | |
+ | int
+ | %s
+
+ we can refer to the color of "int" as highlight_colors::expected
+ and the color of "const char *" as highlight_colors::actual
+ to help get consistent contrasting colorization, both for the types
+ within the diagnostic messages, and the underlined ranges. */
+
+namespace highlight_colors {
+
+/* Color names for expressing "expected" vs "actual" values. */
+extern const char *const expected;
+extern const char *const actual;
+
+/* Color names for expressing "LHS" vs "RHS" values in a binary operation. */
+extern const char *const lhs;
+extern const char *const rhs;
+
+} // namespace highlight_colors
+
+#endif /* ! GCC_DIAGNOSTIC_HIGHLIGHT_COLORS_H */
diff --git a/gcc/diagnostic-path.cc b/gcc/diagnostic-path.cc
index f279aea..b497d89d 100644
--- a/gcc/diagnostic-path.cc
+++ b/gcc/diagnostic-path.cc
@@ -518,7 +518,7 @@ struct event_range
m_stack_depth (initial_event.get_stack_depth ()),
m_start_idx (start_idx), m_end_idx (start_idx),
m_path_label (ctxt, path, start_idx),
- m_richloc (initial_event.get_location (), &m_path_label),
+ m_richloc (initial_event.get_location (), &m_path_label, nullptr),
m_thread_id (initial_event.get_thread_id ()),
m_per_thread_summary (t),
m_show_event_links (show_event_links)
diff --git a/gcc/diagnostic-show-locus.cc b/gcc/diagnostic-show-locus.cc
index abd0182..d0fc2ff 100644
--- a/gcc/diagnostic-show-locus.cc
+++ b/gcc/diagnostic-show-locus.cc
@@ -88,12 +88,24 @@ class colorizer
{
public:
colorizer (pretty_printer *pp,
+ const rich_location &richloc,
diagnostic_t diagnostic_kind);
~colorizer ();
void set_range (int range_idx)
{
- /* Normally we emphasize the primary location, then alternate between
+ /* If we have a specific highlight color for the range, use it. */
+ if (pp_show_highlight_colors (m_pp))
+ {
+ const location_range *const loc_range = m_richloc.get_range (range_idx);
+ if (loc_range->m_highlight_color)
+ {
+ set_named_color (loc_range->m_highlight_color);
+ return;
+ }
+ }
+
+ /* Otherwise, we emphasize the primary location, then alternate between
two colors for the secondary locations.
But if we're printing a run of events in a diagnostic path, that
makes no sense, so print all of them with the same colorization. */
@@ -106,6 +118,7 @@ class colorizer
void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
void set_fixit_insert () { set_state (STATE_FIXIT_INSERT); }
void set_fixit_delete () { set_state (STATE_FIXIT_DELETE); }
+ void set_named_color (const char *color);
private:
void set_state (int state);
@@ -117,8 +130,10 @@ class colorizer
static const int STATE_NORMAL_TEXT = -1;
static const int STATE_FIXIT_INSERT = -2;
static const int STATE_FIXIT_DELETE = -3;
+ static const int STATE_NAMED_COLOR = -4;
pretty_printer *m_pp;
+ const rich_location &m_richloc;
diagnostic_t m_diagnostic_kind;
int m_current_state;
const char *m_range1;
@@ -520,8 +535,10 @@ class layout
different kinds of things we might need to print. */
colorizer::colorizer (pretty_printer *pp,
+ const rich_location &richloc,
diagnostic_t diagnostic_kind) :
m_pp (pp),
+ m_richloc (richloc),
m_diagnostic_kind (diagnostic_kind),
m_current_state (STATE_NORMAL_TEXT)
{
@@ -540,6 +557,17 @@ colorizer::~colorizer ()
finish_state (m_current_state);
}
+/* Update state, changing to the specific named color and printing its
+ color codes. */
+
+void
+colorizer::set_named_color (const char *color)
+{
+ finish_state (m_current_state);
+ m_current_state = STATE_NAMED_COLOR;
+ pp_string (m_pp, colorize_start (pp_show_color (m_pp), color));
+}
+
/* Update state, printing color codes if necessary if there's a state
change. */
@@ -572,6 +600,10 @@ colorizer::begin_state (int state)
pp_string (m_pp, m_fixit_delete);
break;
+ case STATE_NAMED_COLOR:
+ /* Should be handled by colorizer::set_named_color. */
+ gcc_unreachable ();
+
case 0:
/* Make range 0 be the same color as the "kind" text
(error vs warning vs note). */
@@ -1304,7 +1336,7 @@ layout::layout (const diagnostic_context &context,
m_exploc (m_file_cache,
richloc.get_expanded_location (0), m_policy,
LOCATION_ASPECT_CARET),
- m_colorizer (m_pp, diagnostic_kind),
+ m_colorizer (m_pp, richloc, diagnostic_kind),
m_diagnostic_path_p (diagnostic_kind == DK_DIAGNOSTIC_PATH),
m_layout_ranges (richloc.get_num_locations ()),
m_fixit_hints (richloc.get_num_fixit_hints ()),
@@ -4012,7 +4044,7 @@ test_one_liner_labels ()
text_range_label label0 ("0");
text_range_label label1 ("1");
text_range_label label2 ("2");
- gcc_rich_location richloc (foo, &label0);
+ gcc_rich_location richloc (foo, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4042,7 +4074,7 @@ test_one_liner_labels ()
text_range_label label0 ("label 0");
text_range_label label1 ("label 1");
text_range_label label2 ("label 2");
- gcc_rich_location richloc (foo, &label0);
+ gcc_rich_location richloc (foo, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4063,7 +4095,7 @@ test_one_liner_labels ()
text_range_label label0 ("aaaaa");
text_range_label label1 ("bbbb");
text_range_label label2 ("c");
- gcc_rich_location richloc (foo, &label0);
+ gcc_rich_location richloc (foo, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4082,7 +4114,7 @@ test_one_liner_labels ()
text_range_label label0 ("0");
text_range_label label1 ("1");
text_range_label label2 ("2");
- gcc_rich_location richloc (field, &label0);
+ gcc_rich_location richloc (field, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4101,7 +4133,7 @@ test_one_liner_labels ()
text_range_label label0 ("label 0");
text_range_label label1 ("label 1");
text_range_label label2 ("label 2");
- gcc_rich_location richloc (bar, &label0);
+ gcc_rich_location richloc (bar, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4128,7 +4160,7 @@ test_one_liner_labels ()
text_range_label label_0c ("label 0c");
text_range_label label_1c ("label 1c");
text_range_label label_2c ("label 2c");
- gcc_rich_location richloc (field, &label_0a);
+ gcc_rich_location richloc (field, &label_0a, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1a);
richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2a);
@@ -4161,7 +4193,7 @@ test_one_liner_labels ()
handled gracefully. */
{
text_range_label label (NULL);
- gcc_rich_location richloc (bar, &label);
+ gcc_rich_location richloc (bar, &label, nullptr);
test_diagnostic_context dc;
diagnostic_show_locus (&dc, &richloc, DK_ERROR);
@@ -4620,7 +4652,7 @@ test_one_liner_labels_utf8 ()
text_range_label label2
("\xf0\x9f\x98\x82\xcf\x80\xf0\x9f\x98\x82\xf0\x9f\x98\x82\xcf\x80"
"\xcf\x80");
- gcc_rich_location richloc (foo, &label0);
+ gcc_rich_location richloc (foo, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4648,7 +4680,7 @@ test_one_liner_labels_utf8 ()
text_range_label label0 ("label 0\xf0\x9f\x98\x82");
text_range_label label1 ("label 1\xcf\x80");
text_range_label label2 ("label 2\xcf\x80");
- gcc_rich_location richloc (foo, &label0);
+ gcc_rich_location richloc (foo, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4674,7 +4706,7 @@ test_one_liner_labels_utf8 ()
text_range_label label0 ("aaaaa\xf0\x9f\x98\x82\xcf\x80");
text_range_label label1 ("bb\xf0\x9f\x98\x82\xf0\x9f\x98\x82");
text_range_label label2 ("c");
- gcc_rich_location richloc (foo, &label0);
+ gcc_rich_location richloc (foo, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
@@ -4698,7 +4730,7 @@ test_one_liner_labels_utf8 ()
text_range_label label0 ("label 0\xf0\x9f\x98\x82");
text_range_label label1 ("label 1\xcf\x80");
text_range_label label2 ("label 2\xcf\x80");
- gcc_rich_location richloc (foo, &label0);
+ gcc_rich_location richloc (foo, &label0, nullptr);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
richloc.set_escape_on_output (true);
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 4dc4489..cb58bc6 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -466,6 +466,10 @@ public:
}
void set_show_cwe (bool val) { m_show_cwe = val; }
void set_show_rules (bool val) { m_show_rules = val; }
+ void set_show_highlight_colors (bool val)
+ {
+ pp_show_highlight_colors (printer) = val;
+ }
void set_path_format (enum diagnostic_path_format val)
{
m_path_format = val;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d10796c..d544984 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -310,7 +310,8 @@ Objective-C and Objective-C++ Dialects}.
-fno-diagnostics-show-event-links
-fno-diagnostics-show-labels -fno-diagnostics-show-line-numbers
-fno-diagnostics-show-cwe
--fno-diagnostics-show-rule
+-fno-diagnostics-show-rules
+-fno-diagnostics-show-highlight-colors
-fdiagnostics-minimum-margin-width=@var{width}
-fdiagnostics-parseable-fixits -fdiagnostics-generate-patch
-fdiagnostics-show-template-tree -fno-elide-type
@@ -5288,7 +5289,8 @@ The default @env{GCC_COLORS} is
error=01;31:warning=01;35:note=01;36:range1=32:range2=34:locus=01:\
quote=01:path=01;36:fixit-insert=32:fixit-delete=31:\
diff-filename=01:diff-hunk=32:diff-delete=31:diff-insert=32:\
-type-diff=01;32:fnname=01;32:targs=35:valid=01;31:invalid=01;32
+type-diff=01;32:fnname=01;32:targs=35:valid=01;31:invalid=01;32\
+highlight-a=01;32:highlight-b=01;34
@end smallexample
@noindent
where @samp{01;31} is bold red, @samp{01;35} is bold magenta,
@@ -5379,6 +5381,14 @@ SGR substring for highlighting valid elements within text art diagrams.
@vindex invalid GCC_COLORS @r{capability}
@item invalid=
SGR substring for highlighting invalid elements within text art diagrams.
+
+@vindex highlight-a GCC_COLORS @r{capability}
+@vindex highlight-b GCC_COLORS @r{capability}
+@item highlight-a=
+@item highlight-b=
+SGR substrings for contrasting two different things within diagnostics,
+such as a pair of mismatching types.
+See @option{-fdiagnostics-show-highlight-colors}.
@end table
@opindex fdiagnostics-urls
@@ -5504,6 +5514,43 @@ GCC itself does not do this for any of its diagnostics, but plugins may do so.
By default, if this information is present, it will be printed with
the diagnostic. This option suppresses the printing of this metadata.
+@opindex fno-diagnostics-show-highlight-colors
+@opindex fdiagnostics-show-highlight-colors
+@item -fno-diagnostics-show-highlight-colors
+
+GCC can use color for emphasis and contrast when printing diagnostic
+messages and quoting the user's source.
+
+For example, in
+
+@smallexample
+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
+@end smallexample
+
+@itemize @bullet
+@item
+the @code{%i} and @code{int} in the message and the @code{int} in the
+quoted source are colored using @code{highlight-a} (bold green by default),
+and
+@item
+the @code{const char *} in the message and in the quoted source are both
+colored using @code{highlight-b} (bold blue by default).
+@end itemize
+
+The intent is to draw the reader's eyes to the relationships between the
+various aspects of the diagnostic message and the source, using color
+to group related elements and distinguish between mismatching ones.
+
+This additional colorization is enabled by default if color printing
+is enabled (as per @option{-fdiagnostics-color=}), but it can be separately
+disabled via @option{-fno-diagnostics-show-highlight-colors}.
+
@opindex fno-diagnostics-show-line-numbers
@opindex fdiagnostics-show-line-numbers
@item -fno-diagnostics-show-line-numbers
diff --git a/gcc/doc/ux.texi b/gcc/doc/ux.texi
index 8456869..125ce8e 100644
--- a/gcc/doc/ux.texi
+++ b/gcc/doc/ux.texi
@@ -443,6 +443,93 @@ argument %d of %qE must be a pointer type
since the argument number does not refer to a numerical constant in the
source code it should not be quoted.
+@subsection Use color consistently when highlighting mismatches
+
+As of GCC 15, the diagnostics subsystem has a concept of ``highlight
+colors''. These should be used to consistently colorize both the text
+within diagnostic messages and underlined ranges of quoted source when
+highlighting mismatches, for all messages with a logically-related group
+of diagnostics.
+
+See @file{diagnostic-highlight-colors.h} for symbolic names for color
+codes, covering e.g.
+
+@itemize @bullet
+
+@item
+@code{highlight_colors::expected} versus @code{highlight_colors::actual}
+
+@item
+@code{highlight_colors::lhs} versus @code{highlight_colors::rhs}
+
+@end itemize
+
+For example, given:
+
+@smallexample
+error: invalid operands to binary + (have 'S' @{aka 'struct s'@} and 'T' @{aka 'struct t'@})
+ return callee_4a () + callee_4b ();
+ ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
+ | |
+ | T @{aka struct t@}
+ S @{aka struct s@}
+@end smallexample
+
+@itemize @bullet
+
+@item
+the text ``S @{aka struct s@}'' in the message and the left-hand label
+in the quoted source should be colorized as @code{highlight_colors::lhs}
+(which equates to the color name @code{highlight-a})
+
+@item
+the text ``T @{aka struct t@}'' in the message and the right-hand label
+in the quoted source should be colorized as @code{highlight_colors::rhs}
+(which equates to the color name @code{highlight-b})
+
+@end itemize
+
+Doing so ought to make it easier for the user to understand what the
+diagnostic is telling them.
+
+When issuing followup @code{note} diagnostics, all diagnostics within the
+group should use a consistent scheme to highlight the mismatching elements,
+so that color contrasts the differences. For example, given:
+
+@smallexample
+warning: format ‘%i’ expects argument of type ‘int’, but argument 2 has type ‘const char *’ [-Wformat=]
+ 279 | printf("hello " INT_FMT " world", msg);
+ | ^~~~~~~~ ~~~
+ | |
+ | const char *
+note: format string is defined here
+ 278 | #define INT_FMT "%i"
+ | ~^
+ | |
+ | int
+ | %s
+@end smallexample
+
+@itemize @bullet
+
+@item
+the text @code{%i} and @code{int} referring to the format string and the
+expected type due to it should be colorized as @code{highlight-a} both
+in the diagnostics message and in the range quoted in the @code{range}.
+
+@item
+the text @code{const char *} in the diagnostic message and in the quoted
+range should be colorized as @code{highlight-b}.
+
+@end itemize
+
+This can be implemented by using e.g.
+@code{highlight_colors::actual} and
+@code{highlight_colors::expected} when adding ranges to
+@code{rich_location} instances, and e.g. by using the @code{%e} format
+code for @code{pretty_printer} to use a @code{pp_element *}, and using
+appropriate member functions of pp_element to add colorization.
+
@subsection Spelling and Terminology
See the @uref{https://gcc.gnu.org/codingconventions.html#Spelling
diff --git a/gcc/gcc-rich-location.cc b/gcc/gcc-rich-location.cc
index e9d753b..568744b 100644
--- a/gcc/gcc-rich-location.cc
+++ b/gcc/gcc-rich-location.cc
@@ -42,22 +42,26 @@ along with GCC; see the file COPYING3. If not see
using LABEL if non-NULL. */
void
-gcc_rich_location::add_expr (tree expr, range_label *label)
+gcc_rich_location::add_expr (tree expr,
+ range_label *label,
+ const char *highlight_color)
{
gcc_assert (expr);
if (CAN_HAVE_RANGE_P (expr))
- add_range (EXPR_LOCATION (expr), SHOW_RANGE_WITHOUT_CARET, label);
+ add_range (EXPR_LOCATION (expr), SHOW_RANGE_WITHOUT_CARET, label,
+ highlight_color);
}
/* If T is an expression, add a range for it to the rich_location,
using LABEL if non-NULL. */
void
-gcc_rich_location::maybe_add_expr (tree t, range_label *label)
+gcc_rich_location::maybe_add_expr (tree t, range_label *label,
+ const char *highlight_color)
{
if (EXPR_P (t))
- add_expr (t, label);
+ add_expr (t, label, highlight_color);
}
/* Add a fixit hint suggesting replacing the range at MISSPELLED_TOKEN_LOC
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index d5009f3..0cd19aa 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -32,17 +32,29 @@ class gcc_rich_location : public rich_location
/* Constructors. */
/* Constructing from a location. */
- explicit gcc_rich_location (location_t loc, const range_label *label = NULL)
- : rich_location (line_table, loc, label)
+ explicit gcc_rich_location (location_t loc)
+ : rich_location (line_table, loc, nullptr, nullptr)
+ {
+ }
+
+ /* Constructing from a location with a label and a highlight color. */
+ explicit gcc_rich_location (location_t loc,
+ const range_label *label,
+ const char *highlight_color)
+ : rich_location (line_table, loc, label, highlight_color)
{
}
/* Methods for adding ranges via gcc entities. */
void
- add_expr (tree expr, range_label *label);
+ add_expr (tree expr,
+ range_label *label,
+ const char *highlight_color);
void
- maybe_add_expr (tree t, range_label *label);
+ maybe_add_expr (tree t,
+ range_label *label,
+ const char *highlight_color);
void add_fixit_misspelled_id (location_t misspelled_token_loc,
tree hint_id);
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index d80b604..00f93d00 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -4350,6 +4350,10 @@ driver_handle_option (struct gcc_options *opts,
diagnostic_urls_init (dc, value);
break;
+ case OPT_fdiagnostics_show_highlight_colors:
+ dc->set_show_highlight_colors (value);
+ break;
+
case OPT_fdiagnostics_format_:
{
const char *basename = (opts->x_dump_base_name ? opts->x_dump_base_name
diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
index 84835a8..6bfc965 100644
--- a/gcc/lto-wrapper.cc
+++ b/gcc/lto-wrapper.cc
@@ -311,6 +311,7 @@ merge_and_complain (vec<cl_decoded_option> &decoded_options,
/* Fallthru. */
case OPT_fdiagnostics_show_caret:
case OPT_fdiagnostics_show_event_links:
+ case OPT_fdiagnostics_show_highlight_colors:
case OPT_fdiagnostics_show_labels:
case OPT_fdiagnostics_show_line_numbers:
case OPT_fdiagnostics_show_option:
@@ -728,6 +729,7 @@ append_compiler_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
{
case OPT_fdiagnostics_show_caret:
case OPT_fdiagnostics_show_event_links:
+ case OPT_fdiagnostics_show_highlight_colors:
case OPT_fdiagnostics_show_labels:
case OPT_fdiagnostics_show_line_numbers:
case OPT_fdiagnostics_show_option:
@@ -788,6 +790,7 @@ append_diag_options (obstack *argv_obstack, vec<cl_decoded_option> opts)
case OPT_fdiagnostics_format_:
case OPT_fdiagnostics_show_caret:
case OPT_fdiagnostics_show_event_links:
+ case OPT_fdiagnostics_show_highlight_colors:
case OPT_fdiagnostics_show_labels:
case OPT_fdiagnostics_show_line_numbers:
case OPT_fdiagnostics_show_option:
@@ -1593,6 +1596,10 @@ run_gcc (unsigned argc, char *argv[])
diagnostic_color_init (global_dc, option->value);
break;
+ case OPT_fdiagnostics_show_highlight_colors:
+ global_dc->set_show_highlight_colors (option->value);
+ break;
+
default:
break;
}
diff --git a/gcc/opts-common.cc b/gcc/opts-common.cc
index fcabc27dd..3b37de8 100644
--- a/gcc/opts-common.cc
+++ b/gcc/opts-common.cc
@@ -1094,6 +1094,8 @@ decode_cmdline_options_to_array (unsigned int argc, const char **argv,
"-fdiagnostics-path-format=separate-events",
"-fdiagnostics-text-art-charset=none",
"-fno-diagnostics-show-event-links"
+ /* We don't put "-fno-diagnostics-show-highlight-colors" here
+ as -fdiagnostics-color=never makes it redundant. */
};
const int num_expanded = ARRAY_SIZE (expanded_args);
opt_array_len += num_expanded - 1;
diff --git a/gcc/opts-global.cc b/gcc/opts-global.cc
index 648f8fb..e2b83d0 100644
--- a/gcc/opts-global.cc
+++ b/gcc/opts-global.cc
@@ -256,11 +256,16 @@ init_options_once (void)
/* Perform language-specific options initialization. */
initial_lang_mask = lang_hooks.option_lang_mask ();
+ const bool show_highlight_colors
+ = pp_show_highlight_colors (global_dc->printer);
+
lang_hooks.initialize_diagnostics (global_dc);
/* ??? Ideally, we should do this earlier and the FEs will override
it if desired (none do it so far). However, the way the FEs
construct their pretty-printers means that all previous settings
are overriden. */
+ global_dc->set_show_highlight_colors (show_highlight_colors);
+
diagnostic_color_init (global_dc);
diagnostic_urls_init (global_dc);
}
diff --git a/gcc/opts.cc b/gcc/opts.cc
index d7e0126..be90a63 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -2992,6 +2992,10 @@ common_handle_option (struct gcc_options *opts,
dc->set_escape_format ((enum diagnostics_escape_format)value);
break;
+ case OPT_fdiagnostics_show_highlight_colors:
+ dc->set_show_highlight_colors (value);
+ break;
+
case OPT_fdiagnostics_show_cwe:
dc->set_show_cwe (value);
break;
@@ -3822,6 +3826,7 @@ gen_command_line_string (cl_decoded_option *options,
case OPT_grecord_gcc_switches:
case OPT_frecord_gcc_switches:
case OPT__output_pch:
+ case OPT_fdiagnostics_show_highlight_colors:
case OPT_fdiagnostics_show_location_:
case OPT_fdiagnostics_show_option:
case OPT_fdiagnostics_show_caret:
diff --git a/gcc/pretty-print-markup.h b/gcc/pretty-print-markup.h
new file mode 100644
index 0000000..b35632a
--- /dev/null
+++ b/gcc/pretty-print-markup.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 2024 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_PRETTY_PRINT_MARKUP_H
+#define GCC_PRETTY_PRINT_MARKUP_H
+
+#include "diagnostic-color.h"
+
+namespace pp_markup {
+
+class context
+{
+public:
+ context (pretty_printer &pp,
+ output_buffer &buf,
+ unsigned chunk_idx,
+ bool &quoted,
+ const urlifier *urlifier)
+ : m_pp (pp),
+ m_buf (buf),
+ m_chunk_idx (chunk_idx),
+ m_quoted (quoted),
+ m_urlifier (urlifier)
+ {
+ }
+
+ void begin_quote ();
+ void end_quote ();
+
+ void begin_highlight_color (const char *color_name);
+ void end_highlight_color ();
+
+ pretty_printer &m_pp;
+ output_buffer &m_buf;
+ unsigned m_chunk_idx;
+ bool &m_quoted;
+ const urlifier *m_urlifier;
+};
+
+/* Abstract base class for use in pp_format for handling "%e".
+ This can add arbitrary content to the buffer being constructed, and
+ isolates the non-typesafe part of the formatting call in one place. */
+
+class element
+{
+public:
+ virtual ~element () {}
+ virtual void add_to_phase_2 (context &ctxt) = 0;
+
+protected:
+ element () {}
+
+private:
+ DISABLE_COPY_AND_ASSIGN (element);
+};
+
+} // namespace pp_markup
+
+#endif /* GCC_PRETTY_PRINT_MARKUP_H */
diff --git a/gcc/pretty-print.cc b/gcc/pretty-print.cc
index ec44172..6471380 100644
--- a/gcc/pretty-print.cc
+++ b/gcc/pretty-print.cc
@@ -24,9 +24,11 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "intl.h"
#include "pretty-print.h"
+#include "pretty-print-markup.h"
#include "pretty-print-urlifier.h"
#include "diagnostic-color.h"
#include "diagnostic-event-id.h"
+#include "diagnostic-highlight-colors.h"
#include "selftest.h"
#if HAVE_ICONV
@@ -1321,6 +1323,8 @@ chunk_info::on_end_quote (pretty_printer *pp,
%Z: Requires two arguments - array of int, and len. Prints elements
of the array.
+ %e: Consumes a pp_element * argument.
+
Arguments can be used sequentially, or through %N$ resp. *N$
notation Nth argument after the format string. If %N$ / *N$
notation is used, it must be used for all arguments, except %m, %%,
@@ -1761,6 +1765,17 @@ pretty_printer::format (text_info *text,
begin_url (va_arg (*text->m_args_ptr, const char *));
break;
+ case 'e':
+ {
+ pp_element *element
+ = va_arg (*text->m_args_ptr, pp_element *);
+ pp_markup::context ctxt (*this, *buffer, chunk,
+ quote, /* by reference */
+ urlifier);
+ element->add_to_phase_2 (ctxt);
+ }
+ break;
+
default:
{
bool ok;
@@ -2101,6 +2116,7 @@ pretty_printer::pretty_printer (int maximum_length)
m_need_newline (false),
m_translate_identifiers (true),
m_show_color (false),
+ m_show_highlight_colors (false),
m_url_format (URL_FORMAT_NONE),
m_skipping_null_url (false)
{
@@ -2125,6 +2141,7 @@ pretty_printer::pretty_printer (const pretty_printer &other)
m_need_newline (other.m_need_newline),
m_translate_identifiers (other.m_translate_identifiers),
m_show_color (other.m_show_color),
+ m_show_highlight_colors (other.m_show_highlight_colors),
m_url_format (other.m_url_format),
m_skipping_null_url (false)
{
@@ -2260,6 +2277,15 @@ pp_string (pretty_printer *pp, const char *str)
pp_maybe_wrap_text (pp, str, str + strlen (str));
}
+/* As per pp_string, but only append the first LEN of STR. */
+
+void
+pp_string_n (pretty_printer *pp, const char *str, size_t len)
+{
+ gcc_checking_assert (str);
+ pp_maybe_wrap_text (pp, str, str + len);
+}
+
/* Append code point C to the output area of PRETTY-PRINTER, encoding it
as UTF-8. */
@@ -2710,6 +2736,55 @@ pretty_printer::end_url ()
pp_string (this, get_end_url_string (this));
}
+/* class pp_markup::context. */
+
+void
+pp_markup::context::begin_quote ()
+{
+ gcc_assert (!m_quoted);
+ pp_begin_quote (&m_pp, pp_show_color (&m_pp));
+ m_buf.cur_chunk_array->on_begin_quote (m_buf, m_chunk_idx, m_urlifier);
+ m_quoted = true;
+}
+
+void
+pp_markup::context::end_quote ()
+{
+ /* Bail out if the quotes have already been ended, such as by
+ printing a type emitting "TYPEDEF' {aka `TYPE'}". */
+ if (!m_quoted)
+ return;
+ m_buf.cur_chunk_array->on_end_quote (&m_pp, m_buf, m_chunk_idx, m_urlifier);
+ pp_end_quote (&m_pp, pp_show_color (&m_pp));
+ m_quoted = false;
+}
+
+void
+pp_markup::context::begin_highlight_color (const char *color_name)
+{
+ if (!pp_show_highlight_colors (&m_pp))
+ return;
+ pp_string (&m_pp, colorize_start (pp_show_color (&m_pp), color_name));
+}
+
+void
+pp_markup::context::end_highlight_color ()
+{
+ if (!pp_show_highlight_colors (&m_pp))
+ return;
+ const char *colorstr = colorize_stop (pp_show_color (&m_pp));
+ obstack_grow (&m_buf.chunk_obstack, colorstr, strlen (colorstr));
+}
+
+
+/* Color names for expressing "expected" vs "actual" values. */
+const char *const highlight_colors::expected = "highlight-a";
+const char *const highlight_colors::actual = "highlight-b";
+
+/* Color names for expressing "LHS" vs "RHS" values in a binary operation. */
+const char *const highlight_colors::lhs = "highlight-a";
+const char *const highlight_colors::rhs = "highlight-b";
+
#if CHECKING_P
namespace selftest {
@@ -2802,6 +2877,22 @@ assert_pp_format_colored (const location &loc, const char *expected,
(ARG1), (ARG2), (ARG3)); \
SELFTEST_END_STMT
+class test_element : public pp_element
+{
+public:
+ test_element (const char *text) : m_text (text) {}
+
+ void add_to_phase_2 (pp_markup::context &ctxt) final override
+ {
+ ctxt.begin_quote ();
+ pp_string (&ctxt.m_pp, m_text);
+ ctxt.end_quote ();
+ }
+
+private:
+ const char *m_text;
+};
+
/* Verify that pp_format works, for various format codes. */
static void
@@ -2914,6 +3005,15 @@ test_pp_format ()
int v2[] = { 0 };
ASSERT_PP_FORMAT_3 ("0 12345678", "%Z %x", v2, 1, 0x12345678);
+ /* Verify %e. */
+ {
+ test_element foo ("foo");
+ test_element bar ("bar");
+ ASSERT_PP_FORMAT_2 ("before `foo' `bar' after",
+ "before %e %e after",
+ &foo, &bar);
+ }
+
/* Verify that combinations work, along with unformatted text. */
assert_pp_format (SELFTEST_LOCATION,
"the quick brown fox jumps over the lazy dog",
@@ -3260,6 +3360,19 @@ test_urlification ()
("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
pp_formatted_text (&pp));
}
+
+ /* Example of %e. */
+ {
+ pretty_printer pp;
+ pp.set_url_format (URL_FORMAT_ST);
+ test_element elem ("-foption");
+ pp_printf_with_urlifier (&pp, &urlifier,
+ "foo %e bar",
+ &elem);
+ ASSERT_STREQ
+ ("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\' bar",
+ pp_formatted_text (&pp));
+ }
}
/* Test multibyte awareness. */
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index b41d3ce..d28814a 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -73,6 +73,10 @@ class quoting_info;
class output_buffer;
class urlifier;
+namespace pp_markup {
+ class context;
+} // namespace pp_markup
+
/* The chunk_info data structure forms a stack of the results from the
first phase of formatting (pp_format) which have not yet been
output (pp_output_formatted_text). A stack is necessary because
@@ -81,6 +85,7 @@ class urlifier;
class chunk_info
{
friend class pretty_printer;
+ friend class pp_markup::context;
public:
const char * const *get_args () const { return m_args; }
@@ -245,6 +250,7 @@ inline bool & pp_translate_identifiers (pretty_printer *pp);
inline bool & pp_show_color (pretty_printer *pp);
inline printer_fn &pp_format_decoder (pretty_printer *pp);
inline format_postprocessor *& pp_format_postprocessor (pretty_printer *pp);
+inline bool & pp_show_highlight_colors (pretty_printer *pp);
class urlifier;
@@ -271,6 +277,7 @@ public:
friend bool & pp_show_color (pretty_printer *pp);
friend printer_fn &pp_format_decoder (pretty_printer *pp);
friend format_postprocessor *& pp_format_postprocessor (pretty_printer *pp);
+ friend bool & pp_show_highlight_colors (pretty_printer *pp);
/* Default construct a pretty printer with specified
maximum line length cut off limit. */
@@ -373,6 +380,10 @@ private:
/* Nonzero means that text should be colorized. */
bool m_show_color;
+ /* True means that pertinent sections within the text should be
+ highlighted with color. */
+ bool m_show_highlight_colors;
+
/* Whether URLs should be emitted, and which terminator to use. */
diagnostic_url_format m_url_format;
@@ -441,6 +452,12 @@ pp_format_postprocessor (pretty_printer *pp)
return pp->m_format_postprocessor;
}
+inline bool &
+pp_show_highlight_colors (pretty_printer *pp)
+{
+ return pp->m_show_highlight_colors;
+}
+
/* Maximum characters per line in automatic line wrapping mode.
Zero means don't wrap lines. */
inline int &
@@ -582,6 +599,7 @@ extern void pp_indent (pretty_printer *);
extern void pp_newline (pretty_printer *);
extern void pp_character (pretty_printer *, int);
extern void pp_string (pretty_printer *, const char *);
+extern void pp_string_n (pretty_printer *, const char *, size_t);
extern void pp_unicode_character (pretty_printer *, unsigned);
extern void pp_write_text_to_stream (pretty_printer *);
diff --git a/gcc/substring-locations.cc b/gcc/substring-locations.cc
index 96473c0..00ad8ed 100644
--- a/gcc/substring-locations.cc
+++ b/gcc/substring-locations.cc
@@ -27,6 +27,15 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "substring-locations.h"
#include "gcc-rich-location.h"
+#include "diagnostic-highlight-colors.h"
+
+const char *const
+format_string_diagnostic_t::highlight_color_format_string
+ = highlight_colors::expected;
+
+const char *const
+format_string_diagnostic_t::highlight_color_param
+ = highlight_colors::actual;
/* format_string_diagnostic_t's ctor, giving information for use by
the emit_warning* member functions, as follows:
@@ -184,10 +193,12 @@ format_string_diagnostic_t::emit_warning_n_va (int opt,
primary_label = m_fmt_label;
auto_diagnostic_group d;
- gcc_rich_location richloc (primary_loc, primary_label);
+ gcc_rich_location richloc (primary_loc, primary_label,
+ highlight_color_format_string);
if (m_param_loc != UNKNOWN_LOCATION)
- richloc.add_range (m_param_loc, SHOW_RANGE_WITHOUT_CARET, m_param_label);
+ richloc.add_range (m_param_loc, SHOW_RANGE_WITHOUT_CARET, m_param_label,
+ highlight_color_param);
if (!err && m_corrected_substring && substring_within_range)
richloc.add_fixit_replace (fmt_substring_range, m_corrected_substring);
@@ -220,8 +231,10 @@ format_string_diagnostic_t::emit_warning_n_va (int opt,
if (warned)
{
/* Use fmt_label in the note for case 2. */
- rich_location substring_richloc (line_table, fmt_substring_loc,
- m_fmt_label);
+ rich_location substring_richloc
+ (line_table, fmt_substring_loc,
+ m_fmt_label,
+ highlight_color_format_string);
if (m_corrected_substring)
substring_richloc.add_fixit_replace (fmt_substring_range,
m_corrected_substring);
diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h
index 68a3b80..b286ae8 100644
--- a/gcc/substring-locations.h
+++ b/gcc/substring-locations.h
@@ -79,6 +79,9 @@ class substring_loc
class format_string_diagnostic_t
{
public:
+ static const char * const highlight_color_format_string;
+ static const char * const highlight_color_param;
+
format_string_diagnostic_t (const substring_loc &fmt_loc,
const range_label *fmt_label,
location_t param_loc,
diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-highlight-colors.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-highlight-colors.C
new file mode 100644
index 0000000..1260345
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-highlight-colors.C
@@ -0,0 +1,34 @@
+/* Verify that colorization affects both text within diagnostic messages
+ and underlined ranges of quoted source, and that the types we use
+ match up between them.
+ Also implicitly verify that -fdiagnostics-show-highlight-colors is
+ on by default. */
+
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-color=always" } */
+
+struct s {};
+struct t {};
+typedef struct s S;
+typedef struct t T;
+
+extern S callee_4a (void);
+extern T callee_4b (void);
+
+int test_4 (void)
+{
+ return callee_4a () + callee_4b ();
+
+ /* { dg-begin-multiline-output "" }
+  error: no match for 'operator+' (operand types are 'S' {aka 's'} and 'T' {aka 't'})
+ { dg-end-multiline-output "" } */
+
+ /* { dg-begin-multiline-output "" }
+ return callee_4a () + callee_4b ();
+ ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
+ | |
+ S {aka s} T {aka t}
+ { dg-end-multiline-output "" } */
+
+ /* { dg-prune-output "In function" } */
+ /* { dg-prune-output "bad-binary-ops-highlight-colors.C" } */
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-no-highlight-colors.C b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-no-highlight-colors.C
new file mode 100644
index 0000000..5b1b65a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/bad-binary-ops-no-highlight-colors.C
@@ -0,0 +1,29 @@
+/* Verify that -fno-diagnostics-show-highlight-colors works. */
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-color=always -fno-diagnostics-show-highlight-colors" } */
+
+struct s {};
+struct t {};
+typedef struct s S;
+typedef struct t T;
+
+extern S callee_4a (void);
+extern T callee_4b (void);
+
+int test_4 (void)
+{
+ return callee_4a () + callee_4b ();
+
+ /* { dg-begin-multiline-output "" }
+  error: no match for 'operator+' (operand types are 'S' {aka 's'} and 'T' {aka 't'})
+ { dg-end-multiline-output "" } */
+
+ /* { dg-begin-multiline-output "" }
+ return callee_4a () + callee_4b ();
+ ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
+ | |
+ S {aka s} T {aka t}
+ { dg-end-multiline-output "" } */
+
+ /* { dg-prune-output "In function" } */
+ /* { dg-prune-output "bad-binary-ops-no-highlight-colors.C" } */
+}
diff --git a/gcc/testsuite/g++.dg/plugin/plugin.exp b/gcc/testsuite/g++.dg/plugin/plugin.exp
index 88f9b49..b5f8743 100644
--- a/gcc/testsuite/g++.dg/plugin/plugin.exp
+++ b/gcc/testsuite/g++.dg/plugin/plugin.exp
@@ -77,6 +77,7 @@ set plugin_test_list [list \
location-overflow-test-pr100796.c } \
{ show_template_tree_color_plugin.c \
show-template-tree-color.C \
+ show-template-tree-color-no-highlight-colors.C \
show-template-tree-color-labels.C \
show-template-tree-color-no-elide-type.C } \
{ comment_plugin.c comments-1.C } \
diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
index 462e1bd..75488cb 100644
--- a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
+++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
@@ -15,11 +15,11 @@ void test_1 (vector<double> vec)
{
fn_1 (vec);
/* { dg-begin-multiline-output "" }
-could not convert 'vec' from 'vector<double>' to 'vector<int>'
- fn_1 (vec);
- ^~~
- |
- vector<double>
+could not convert 'vec' from 'vector<double>' to 'vector<int>'
+ fn_1 (vec);
+ ^~~
+ |
+ vector<double>
{ dg-end-multiline-output "" } */
// TODO: we don't yet highlight the mismatching part with color
}
@@ -28,11 +28,11 @@ void test_2 (const map<int, double> &m)
{
fn_2 (m);
/* { dg-begin-multiline-output "" }
-could not convert 'm' from 'map<[...],double>' to 'map<[...],int>'
- fn_2 (m);
- ^
- |
- map<[...],double>
+could not convert 'm' from 'map<[...],double>' to 'map<[...],int>'
+ fn_2 (m);
+ ^
+ |
+ map<[...],double>
{ dg-end-multiline-output "" } */
// TODO: we don't yet highlight the mismatching part with color
}
diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C
index cab0359..758a77f 100644
--- a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C
+++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-elide-type.C
@@ -15,16 +15,16 @@ void test ()
{
fn_1 (vector<double> ());
/* { dg-begin-multiline-output "" }
-could not convert 'vector<double>()' from 'vector<double>' to 'vector<int>'
+could not convert 'vector<double>()' from 'vector<double>' to 'vector<int>'
vector<
- [double != int]>
+ [double != int]>
{ dg-end-multiline-output "" } */
fn_2 (map<int, double>());
/* { dg-begin-multiline-output "" }
-could not convert 'map<int, double>()' from 'map<int,double>' to 'map<int,int>'
+could not convert 'map<int, double>()' from 'map<int,double>' to 'map<int,int>'
map<
int,
- [double != int]>
+ [double != int]>
{ dg-end-multiline-output "" } */
}
diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-highlight-colors.C b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-highlight-colors.C
new file mode 100644
index 0000000..5329f90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-no-highlight-colors.C
@@ -0,0 +1,32 @@
+/* Verify colorization of the output of -fdiagnostics-show-template-tree,
+ and within the %H and %I format codes, but with
+ -fno-diagnostics-show-highlight-colors.
+
+ Doing so requires a plugin; see the comments in the plugin for the
+ rationale. */
+
+// { dg-options "-fdiagnostics-show-template-tree -fdiagnostics-color=always -fno-diagnostics-show-highlight-colors" }
+
+template<typename> struct vector {};
+template<typename, typename> struct map {};
+
+void fn_1(vector<int>);
+void fn_2(map<int, int>);
+
+void test ()
+{
+ fn_1 (vector<double> ());
+ /* { dg-begin-multiline-output "" }
+could not convert 'vector<double>()' from 'vector<double>' to 'vector<int>'
+ vector<
+ [double != int]>
+ { dg-end-multiline-output "" } */
+
+ fn_2 (map<int, double>());
+ /* { dg-begin-multiline-output "" }
+could not convert 'map<int, double>()' from 'map<[...],double>' to 'map<[...],int>'
+ map<
+ [...],
+ [double != int]>
+ { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color.C b/gcc/testsuite/g++.dg/plugin/show-template-tree-color.C
index eb99a3e..cc60ba6 100644
--- a/gcc/testsuite/g++.dg/plugin/show-template-tree-color.C
+++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color.C
@@ -15,16 +15,16 @@ void test ()
{
fn_1 (vector<double> ());
/* { dg-begin-multiline-output "" }
-could not convert 'vector<double>()' from 'vector<double>' to 'vector<int>'
+could not convert 'vector<double>()' from 'vector<double>' to 'vector<int>'
vector<
- [double != int]>
+ [double != int]>
{ dg-end-multiline-output "" } */
fn_2 (map<int, double>());
/* { dg-begin-multiline-output "" }
-could not convert 'map<int, double>()' from 'map<[...],double>' to 'map<[...],int>'
+could not convert 'map<int, double>()' from 'map<[...],double>' to 'map<[...],int>'
map<
[...],
- [double != int]>
+ [double != int]>
{ dg-end-multiline-output "" } */
}
diff --git a/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-1.C b/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-1.C
new file mode 100644
index 0000000..dd41b08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-1.C
@@ -0,0 +1,200 @@
+// Test of -Wformat for GCC-specific formats
+// Copy of gcc.dg/format/gcc_diag-10.c, with class pp_element added.
+// { dg-do compile }
+// { dg-options "-Wformat" }
+
+/* Magic identifiers must be set before the attribute is used. */
+
+typedef long long __gcc_host_wide_int__;
+
+typedef struct location_s
+{
+ const char *file;
+ int line;
+} location_t;
+
+union tree_node;
+typedef union tree_node *tree;
+
+/* Define gimple as a dummy type. The typedef must be provided for
+ the C test to find the symbol. */
+typedef struct gimple gimple;
+
+/* Likewise for gimple. */
+typedef struct cgraph_node cgraph_node;
+
+/* Likewise for diagnostic_event_id_t. */
+typedef struct diagnostic_event_id_t diagnostic_event_id_t;
+
+namespace pp_markup { class element; }
+typedef pp_markup::element pp_element;
+
+#define FORMAT(kind) __attribute__ ((format (__gcc_## kind ##__, 1, 2)))
+
+void diag (const char*, ...) FORMAT (diag);
+void cdiag (const char*, ...) FORMAT (cdiag);
+void tdiag (const char*, ...) FORMAT (tdiag);
+void cxxdiag (const char*, ...) FORMAT (cxxdiag);
+void dump (const char*, ...) FORMAT (dump_printf);
+
+void test_diag (tree t, gimple *gc, diagnostic_event_id_t *event_id_ptr,
+ pp_element *elem)
+{
+ diag ("%<"); /* { dg-warning "unterminated quoting directive" } */
+ diag ("%>"); /* { dg-warning "unmatched quoting directive " } */
+ diag ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
+
+ diag ("%G", gc); /* { dg-warning "format" } */
+ diag ("%K", t); /* { dg-warning "format" } */
+ diag ("%@", event_id_ptr);
+
+ diag ("%R"); /* { dg-warning "unmatched color reset directive" } */
+ diag ("%r", ""); /* { dg-warning "unterminated color directive" } */
+ diag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
+ diag ("%r%R", "");
+ diag ("%r%r%R", "", "");
+ diag ("%r%R%r%R", "", "");
+
+ diag ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
+ diag ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
+ diag ("%<%r%R%>", "");
+
+ diag ("%e", elem);
+ diag ("%e", 42); /* { dg-warning "format" } */
+}
+
+void test_cdiag (tree t, gimple *gc)
+{
+ cdiag ("%<"); /* { dg-warning "unterminated quoting directive" } */
+ cdiag ("%>"); /* { dg-warning "unmatched quoting directive " } */
+ cdiag ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
+
+ cdiag ("%D", t); /* { dg-warning ".D. conversion used unquoted" } */
+ cdiag ("%E", t);
+ cdiag ("%F", t); /* { dg-warning ".F. conversion used unquoted" } */
+ cdiag ("%G", gc); /* { dg-warning "format" } */
+ cdiag ("%K", t); /* { dg-warning "format" } */
+
+ cdiag ("%R"); /* { dg-warning "unmatched color reset directive" } */
+ cdiag ("%r", ""); /* { dg-warning "unterminated color directive" } */
+ cdiag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
+ cdiag ("%r%R", "");
+ cdiag ("%r%r%R", "", "");
+ cdiag ("%r%R%r%R", "", "");
+
+ cdiag ("%T", t); /* { dg-warning ".T. conversion used unquoted" } */
+ cdiag ("%V", t); /* { dg-warning ".V. conversion used unquoted" } */
+
+ cdiag ("%<%D%>", t);
+ cdiag ("%<%E%>", t);
+ cdiag ("%<%F%>", t);
+ cdiag ("%<%G%>", gc); /* { dg-warning "format" } */
+ cdiag ("%<%K%>", t); /* { dg-warning "format" } */
+
+ cdiag ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
+ cdiag ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
+ cdiag ("%<%r%R%>", "");
+
+ cdiag ("%<%T%>", t);
+ cdiag ("%<%V%>", t);
+
+ cdiag ("%<%qD%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
+ cdiag ("%<%qE%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
+ cdiag ("%<%qT%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
+}
+
+void test_tdiag (tree t, gimple *gc)
+{
+ tdiag ("%<"); /* { dg-warning "unterminated quoting directive" } */
+ tdiag ("%>"); /* { dg-warning "unmatched quoting directive " } */
+ tdiag ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
+
+ tdiag ("%D", t); /* { dg-warning ".D. conversion used unquoted" } */
+ tdiag ("%E", t);
+ tdiag ("%G", gc); /* { dg-warning "format" } */
+ tdiag ("%K", t); /* { dg-warning "format" } */
+
+ tdiag ("%R"); /* { dg-warning "unmatched color reset directive" } */
+ tdiag ("%r", ""); /* { dg-warning "unterminated color directive" } */
+ tdiag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
+ tdiag ("%r%R", "");
+ tdiag ("%r%R", "");
+ tdiag ("%r%r%R", "", "");
+ tdiag ("%r%R%r%R", "", "");
+
+ tdiag ("%T", t); /* { dg-warning ".T. conversion used unquoted" } */
+
+ tdiag ("%<%D%>", t);
+ tdiag ("%<%E%>", t);
+ tdiag ("%<%G%>", gc); /* { dg-warning "format" } */
+ tdiag ("%<%K%>", t); /* { dg-warning "format" } */
+
+ tdiag ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
+ tdiag ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
+ tdiag ("%<%r%R%>", "");
+
+ tdiag ("%<%T%>", t);
+
+ tdiag ("%<%qD%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
+ tdiag ("%<%qE%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
+ tdiag ("%<%qT%>", t); /* { dg-warning ".q. flag used within a quoted sequence" } */
+}
+
+void test_cxxdiag (tree t, gimple *gc)
+{
+ cxxdiag ("%A", t); /* { dg-warning ".A. conversion used unquoted" } */
+ cxxdiag ("%D", t); /* { dg-warning ".D. conversion used unquoted" } */
+ cxxdiag ("%E", t);
+ cxxdiag ("%F", t); /* { dg-warning ".F. conversion used unquoted" } */
+ cxxdiag ("%G", gc); /* { dg-warning "format" } */
+ cxxdiag ("%K", t); /* { dg-warning "format" } */
+
+ cxxdiag ("%R"); /* { dg-warning "unmatched color reset directive" } */
+ cxxdiag ("%r", ""); /* { dg-warning "unterminated color directive" } */
+ cxxdiag ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
+ cxxdiag ("%r%R", "");
+ cxxdiag ("%r%R", "");
+ cxxdiag ("%r%r%R", "", "");
+ cxxdiag ("%r%R%r%R", "", "");
+
+ cxxdiag ("%S", t); /* { dg-warning ".S. conversion used unquoted" } */
+ cxxdiag ("%T", t); /* { dg-warning ".T. conversion used unquoted" } */
+ cxxdiag ("%V", t); /* { dg-warning ".V. conversion used unquoted" } */
+ cxxdiag ("%X", t); /* { dg-warning ".X. conversion used unquoted" } */
+
+ cxxdiag ("%<%A%>", t);
+ cxxdiag ("%<%D%>", t);
+ cxxdiag ("%<%E%>", t);
+ cxxdiag ("%<%F%>", t);
+ cxxdiag ("%<%R%>"); /* { dg-warning "unmatched color reset" } */
+ cxxdiag ("%<%r%R%>", "");
+ cxxdiag ("%<%S%>", t);
+ cxxdiag ("%<%T%>", t);
+ cxxdiag ("%<%V%>", t);
+ cxxdiag ("%<%X%>", t);
+}
+
+void test_dump (tree t, gimple *stmt, cgraph_node *node)
+{
+ dump ("%<"); /* { dg-warning "unterminated quoting directive" } */
+ dump ("%>"); /* { dg-warning "unmatched quoting directive " } */
+ dump ("%<foo%<bar%>%>"); /* { dg-warning "nested quoting directive" } */
+
+ dump ("%R"); /* { dg-warning "unmatched color reset directive" } */
+ dump ("%r", ""); /* { dg-warning "unterminated color directive" } */
+ dump ("%r%r", "", ""); /* { dg-warning "unterminated color directive" } */
+ dump ("%r%R", "");
+ dump ("%r%r%R", "", "");
+ dump ("%r%R%r%R", "", "");
+
+ dump ("%<%R%>"); /* { dg-warning "unmatched color reset directive" } */
+ dump ("%<%r%>", ""); /* { dg-warning "unterminated color directive" } */
+ dump ("%<%r%R%>", "");
+
+ dump ("%E", stmt);
+ dump ("%T", t);
+ dump ("%G", stmt);
+ dump ("%C", node);
+ dump ("%f", 1.0);
+ dump ("%4.2f", 1.0); /* { dg-warning "format" } */
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-2.C b/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-2.C
new file mode 100644
index 0000000..0cce53c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-2.C
@@ -0,0 +1,52 @@
+// Test of -Wformat for subclasses of pp_element
+// { dg-do compile }
+// { dg-options "-Wformat" }
+
+/* Magic identifiers must be set before the attribute is used. */
+
+typedef long long __gcc_host_wide_int__;
+
+typedef struct location_s
+{
+ const char *file;
+ int line;
+} location_t;
+
+union tree_node;
+typedef union tree_node *tree;
+
+/* Define gimple as a dummy type. The typedef must be provided for
+ the C test to find the symbol. */
+typedef struct gimple gimple;
+
+/* Likewise for gimple. */
+typedef struct cgraph_node cgraph_node;
+
+/* Likewise for diagnostic_event_id_t. */
+typedef struct diagnostic_event_id_t diagnostic_event_id_t;
+
+namespace pp_markup {
+class element
+{
+};
+} // namespace pp_markup
+typedef pp_markup::element pp_element;
+
+#define FORMAT(kind) __attribute__ ((format (__gcc_## kind ##__, 1, 2)))
+
+void diag (const char*, ...) FORMAT (diag);
+
+class sub_element : public pp_element
+{
+};
+
+class sub_sub_element : public sub_element
+{
+};
+
+void test_diag ()
+{
+ sub_element e1;
+ sub_sub_element e2;
+ diag ("%e %e", &e1, &e2);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-3.C b/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-3.C
new file mode 100644
index 0000000..f474778
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wformat-gcc_diag-3.C
@@ -0,0 +1,54 @@
+// Test of -Wformat for subclasses of pp_element
+// { dg-do compile }
+// { dg-options "-Wformat" }
+
+union tree_node;
+typedef union tree_node *tree;
+class rich_location;
+class pretty_printer;
+
+namespace pp_markup {
+class element {};
+
+} // namespace pp_markup
+
+typedef pp_markup::element pp_element;
+
+extern void error_at (rich_location *, const char *, ...)
+ __attribute__ ((__format__ (__gcc_cdiag__, 2, 3),
+ __nonnull__ (2)));
+
+namespace highlight_colors {
+
+extern const char *const lhs;
+extern const char *const rhs;
+
+} // namespace highlight_colors
+
+namespace pp_markup {
+
+class element_quoted_type : public element
+{
+public:
+ element_quoted_type (tree type, const char *highlight_color)
+ : m_type (type),
+ m_highlight_color (highlight_color)
+ {
+ }
+private:
+ tree m_type;
+ const char *m_highlight_color;
+};
+
+}
+
+void
+binary_op_error (rich_location *richloc, const char *opname,
+ tree type0, tree type1)
+{
+ 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);
+}
diff --git a/gcc/testsuite/gcc.dg/bad-binary-ops-highlight-colors.c b/gcc/testsuite/gcc.dg/bad-binary-ops-highlight-colors.c
new file mode 100644
index 0000000..efbcdf3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bad-binary-ops-highlight-colors.c
@@ -0,0 +1,35 @@
+/* Verify that colorization affects both text within diagnostic messages
+ and underlined ranges of quoted source, and that the types we use
+ match up between them.
+ Also implicitly verify that -fdiagnostics-show-highlight-colors is
+ on by default. */
+
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-color=always" } */
+
+struct s {};
+struct t {};
+typedef struct s S;
+typedef struct t T;
+
+extern S callee_4a (void);
+extern T callee_4b (void);
+
+int test_4 (void)
+{
+ return callee_4a () + callee_4b ();
+
+ /* { dg-begin-multiline-output "" }
+  error: invalid operands to binary + (have 'S' {aka 'struct s'} and 'T' {aka 'struct t'})
+ { dg-end-multiline-output "" } */
+
+ /* { dg-begin-multiline-output "" }
+ return callee_4a () + callee_4b ();
+ ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
+ | |
+ | T {aka struct t}
+ S {aka struct s}
+ { dg-end-multiline-output "" } */
+
+ /* { dg-prune-output "In function" } */
+ /* { dg-prune-output "bad-binary-ops-highlight-colors.c" } */
+}
diff --git a/gcc/testsuite/gcc.dg/bad-binary-ops-no-highlight-colors.c b/gcc/testsuite/gcc.dg/bad-binary-ops-no-highlight-colors.c
new file mode 100644
index 0000000..9eb22cb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bad-binary-ops-no-highlight-colors.c
@@ -0,0 +1,30 @@
+/* Verify that -fno-diagnostics-show-highlight-colors works. */
+/* { dg-options "-fdiagnostics-show-caret -fdiagnostics-color=always -fno-diagnostics-show-highlight-colors" } */
+
+struct s {};
+struct t {};
+typedef struct s S;
+typedef struct t T;
+
+extern S callee_4a (void);
+extern T callee_4b (void);
+
+int test_4 (void)
+{
+ return callee_4a () + callee_4b ();
+
+ /* { dg-begin-multiline-output "" }
+  error: invalid operands to binary + (have 'S' {aka 'struct s'} and 'T' {aka 'struct t'})
+ { dg-end-multiline-output "" } */
+
+ /* { dg-begin-multiline-output "" }
+ return callee_4a () + callee_4b ();
+ ~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
+ | |
+ | T {aka struct t}
+ S {aka struct s}
+ { dg-end-multiline-output "" } */
+
+ /* { dg-prune-output "In function" } */
+ /* { dg-prune-output "bad-binary-ops-no-highlight-colors.c" } */
+}
diff --git a/gcc/testsuite/gcc.dg/format/colors.c b/gcc/testsuite/gcc.dg/format/colors.c
new file mode 100644
index 0000000..43484b7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/format/colors.c
@@ -0,0 +1,27 @@
+/* Verify that colorization affects both text within diagnostic messages
+ and underlined ranges of quoted source, and that the types we use
+ match up between them. */
+
+/* { dg-do compile } */
+/* { dg-options "-Wformat -fdiagnostics-show-caret -fdiagnostics-color=always" } */
+
+#include "format.h"
+
+void test_mismatching_types (const char *msg)
+{
+ printf("hello %i", msg);
+
+/* { dg-begin-multiline-output "" }
+warning: format '%i' expects argument of type 'int', but argument 2 has type 'const char *' [-Wformat=]
+ { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+ printf("hello %i", msg);
+ ~^ ~~~
+ | |
+ int const char *
+ %s
+ { dg-end-multiline-output "" } */
+}
+
+/* { dg-prune-output "In function" } */
+/* { dg-prune-output "colors.c" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
index f5c6fc5..44b94da 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.c
@@ -41,7 +41,7 @@ show_tree (tree node)
return;
gcc_rich_location richloc (EXPR_LOCATION (node));
- richloc.add_expr (node, NULL);
+ richloc.add_expr (node, nullptr, nullptr);
if (richloc.get_num_locations () < 2)
{
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index f715f97..8933a89 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1048,6 +1048,8 @@ general_init (const char *argv0, bool init_signals)
= global_options_init.x_diagnostics_minimum_margin_width;
global_dc->m_show_column
= global_options_init.x_flag_show_column;
+ global_dc->set_show_highlight_colors
+ (global_options_init.x_flag_diagnostics_show_highlight_colors);
global_dc->m_internal_error = internal_error_function;
const unsigned lang_mask = lang_hooks.option_lang_mask ();
global_dc->set_option_hooks (option_enabled,
diff --git a/gcc/tree-pretty-print-markup.h b/gcc/tree-pretty-print-markup.h
new file mode 100644
index 0000000..05400d9
--- /dev/null
+++ b/gcc/tree-pretty-print-markup.h
@@ -0,0 +1,84 @@
+/* Copyright (C) 2024 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_TREE_PRETTY_PRINT_MARKUP_H
+#define GCC_TREE_PRETTY_PRINT_MARKUP_H
+
+#include "pretty-print-markup.h"
+#include "diagnostic-highlight-colors.h"
+
+namespace pp_markup {
+
+/* Concrete subclass of pp_markup::element.
+ Print a type in quotes with the given highlighting color. */
+
+class element_quoted_type : public element
+{
+public:
+ element_quoted_type (tree type, const char *highlight_color)
+ : m_type (type),
+ m_highlight_color (highlight_color)
+ {
+ }
+
+ void add_to_phase_2 (context &ctxt) override
+ {
+ ctxt.begin_quote ();
+ ctxt.begin_highlight_color (m_highlight_color);
+
+ print_type (ctxt);
+
+ ctxt.end_highlight_color ();
+ ctxt.end_quote ();
+ }
+
+ void print_type (context &ctxt);
+
+private:
+ tree m_type;
+ const char *m_highlight_color;
+};
+
+/* Concrete subclass of pp_markup::element.
+ Print a type in quotes highlighted as the "expected" type. */
+
+class element_expected_type : public element_quoted_type
+{
+public:
+ element_expected_type (tree type)
+ : element_quoted_type (type, highlight_colors::expected)
+ {
+ }
+};
+
+/* Concrete subclass of pp_markup::element.
+ Print a type in quotes highlighted as the "actual" type. */
+
+class element_actual_type : public element_quoted_type
+{
+public:
+ element_actual_type (tree type)
+ : element_quoted_type (type, highlight_colors::actual)
+ {
+ }
+};
+
+} // namespace pp_markup
+
+#endif /* GCC_TREE_PRETTY_PRINT_MARKUP_H */
diff --git a/libcpp/include/rich-location.h b/libcpp/include/rich-location.h
index cc4f888..ae4886f 100644
--- a/libcpp/include/rich-location.h
+++ b/libcpp/include/rich-location.h
@@ -69,6 +69,9 @@ struct location_range
/* If non-NULL, the label for this range. */
const range_label *m_label;
+
+ /* If non-null, the name of the color to use for this range. */
+ const char *m_highlight_color;
};
/* A partially-embedded vec for use within rich_location for storing
@@ -378,7 +381,8 @@ class rich_location
/* Constructing from a location. */
rich_location (line_maps *set, location_t loc,
- const range_label *label = NULL);
+ const range_label *label = nullptr,
+ const char *label_highlight_color = nullptr);
/* Destructor. */
~rich_location ();
@@ -393,15 +397,19 @@ class rich_location
location_t get_loc () const { return get_loc (0); }
location_t get_loc (unsigned int idx) const;
+ void set_highlight_color (const char *highlight_color);
+
void
add_range (location_t loc,
enum range_display_kind range_display_kind
= SHOW_RANGE_WITHOUT_CARET,
- const range_label *label = NULL);
+ const range_label *label = nullptr,
+ const char *highlight_color = nullptr);
void
set_range (unsigned int idx, location_t loc,
- enum range_display_kind range_display_kind);
+ enum range_display_kind range_display_kind,
+ const char *highlight_color = nullptr);
unsigned int get_num_locations () const { return m_ranges.count (); }
diff --git a/libcpp/line-map.cc b/libcpp/line-map.cc
index d5200b3..41aee98 100644
--- a/libcpp/line-map.cc
+++ b/libcpp/line-map.cc
@@ -2160,8 +2160,9 @@ line_table_dump (FILE *stream, const line_maps *set, unsigned int num_ordinary,
/* Construct a rich_location with location LOC as its initial range. */
rich_location::rich_location (line_maps *set, location_t loc,
- const range_label *label) :
- m_line_table (set),
+ const range_label *label,
+ const char *label_highlight_color)
+: m_line_table (set),
m_ranges (),
m_column_override (0),
m_have_expanded_location (false),
@@ -2171,7 +2172,7 @@ rich_location::rich_location (line_maps *set, location_t loc,
m_fixit_hints (),
m_path (NULL)
{
- add_range (loc, SHOW_RANGE_WITH_CARET, label);
+ add_range (loc, SHOW_RANGE_WITH_CARET, label, label_highlight_color);
}
/* The destructor for class rich_location. */
@@ -2244,22 +2245,34 @@ rich_location::override_column (int column)
m_have_expanded_location = false;
}
+/* Set (or clear) the highlight color of the primary location. */
+
+void
+rich_location::set_highlight_color (const char *highlight_color)
+{
+ location_range *locrange = get_range (0);
+ locrange->m_highlight_color = highlight_color;
+}
+
/* Add the given range. */
void
rich_location::add_range (location_t loc,
enum range_display_kind range_display_kind,
- const range_label *label)
+ const range_label *label,
+ const char *label_highlight_color)
{
location_range range;
range.m_loc = loc;
range.m_range_display_kind = range_display_kind;
range.m_label = label;
+ range.m_highlight_color = label_highlight_color;
m_ranges.push (range);
}
/* Add or overwrite the location given by IDX, setting its location to LOC,
- and setting its m_range_display_kind to RANGE_DISPLAY_KIND.
+ setting its m_range_display_kind to RANGE_DISPLAY_KIND, and setting
+ its m_highlight_color to HIGHLIGHT_COLOR (which may be nullptr).
It must either overwrite an existing location, or add one *exactly* on
the end of the array.
@@ -2273,19 +2286,21 @@ rich_location::add_range (location_t loc,
void
rich_location::set_range (unsigned int idx, location_t loc,
- enum range_display_kind range_display_kind)
+ enum range_display_kind range_display_kind,
+ const char *highlight_color)
{
/* We can either overwrite an existing range, or add one exactly
on the end of the array. */
linemap_assert (idx <= m_ranges.count ());
if (idx == m_ranges.count ())
- add_range (loc, range_display_kind);
+ add_range (loc, range_display_kind, nullptr, highlight_color);
else
{
location_range *locrange = get_range (idx);
locrange->m_loc = loc;
locrange->m_range_display_kind = range_display_kind;
+ locrange->m_highlight_color = highlight_color;
}
if (idx == 0)