Reimplement diagnostic_show_locus, introducing rich_location classes

gcc/ChangeLog:
	* diagnostic-color.c (color_dict): Eliminate "caret"; add "range1"
	and "range2".
	(parse_gcc_colors): Update comment to describe default GCC_COLORS.
	* diagnostic-core.h (warning_at_rich_loc): New declaration.
	(error_at_rich_loc): New declaration.
	(permerror_at_rich_loc): New declaration.
	(inform_at_rich_loc): New declaration.
	* diagnostic-show-locus.c (adjust_line): Delete.
	(struct point_state): New struct.
	(class colorizer): New class.
	(class layout_point): New class.
	(class layout_range): New class.
	(struct line_bounds): New.
	(class layout): New class.
	(colorizer::colorizer): New ctor.
	(colorizer::~colorizer): New dtor.
	(layout::layout): New ctor.
	(layout::print_source_line): New method.
	(layout::print_annotation_line): New method.
	(layout::get_state_at_point): New method.
	(layout::get_x_bound_for_row): New method.
	(diagnostic_show_locus): Reimplement in terms of class layout.
	(diagnostic_print_caret_line): Delete.
	* diagnostic.c (diagnostic_initialize): Replace
	MAX_LOCATIONS_PER_MESSAGE with rich_location::MAX_RANGES.
	(diagnostic_set_info_translated): Convert param from location_t
	to rich_location *.  Eliminate calls to set_location on the
	message in favor of storing the rich_location ptr there.
	(diagnostic_set_info): Convert param from location_t to
	rich_location *.
	(diagnostic_build_prefix): Break out array into...
	(diagnostic_kind_color): New variable.
	(diagnostic_get_color_for_kind): New function.
	(diagnostic_report_diagnostic): Colorize the option_text
	using the color for the severity.
	(diagnostic_append_note): Update for change in signature of
	diagnostic_set_info.
	(diagnostic_append_note_at_rich_loc): New function.
	(emit_diagnostic): Update for change in signature of
	diagnostic_set_info.
	(inform): Likewise.
	(inform_at_rich_loc): New function.
	(inform_n): Update for change in signature of diagnostic_set_info.
	(warning): Likewise.
	(warning_at): Likewise.
	(warning_at_rich_loc): New function.
	(warning_n): Update for change in signature of diagnostic_set_info.
	(pedwarn): Likewise.
	(permerror): Likewise.
	(permerror_at_rich_loc): New function.
	(error): Update for change in signature of diagnostic_set_info.
	(error_n): Likewise.
	(error_at): Likewise.
	(error_at_rich_loc): New function.
	(sorry): Update for change in signature of diagnostic_set_info.
	(fatal_error): Likewise.
	(internal_error): Likewise.
	(internal_error_no_backtrace): Likewise.
	(source_range::debug): New function.
	* diagnostic.h (struct diagnostic_info): Eliminate field
	"override_column".  Add field "richloc".
	(struct diagnostic_context): Add field "colorize_source_p".
	(diagnostic_override_column): Delete.
	(diagnostic_set_info): Convert param from location_t to
	rich_location *.
	(diagnostic_set_info_translated): Likewise.
	(diagnostic_append_note_at_rich_loc): New function.
	(diagnostic_num_locations): New function.
	(diagnostic_expand_location): Get the location from the
	rich_location.
	(diagnostic_print_caret_line): Delete.
	(diagnostic_get_color_for_kind): New declaration.
	* genmatch.c (linemap_client_expand_location_to_spelling_point): New.
	(error_cb): Update for change in signature of "error" callback.
	(fatal_at): Likewise.
	(warning_at): Likewise.
	* input.c (linemap_client_expand_location_to_spelling_point): New.
	* pretty-print.c (text_info::set_range): New method.
	(text_info::get_location): New method.
	* pretty-print.h (MAX_LOCATIONS_PER_MESSAGE): Eliminate this macro.
	(struct text_info): Eliminate "locations" array in favor of
	"m_richloc", a rich_location *.
	(textinfo::set_location): Add a "caret_p" param, and reimplement
	in terms of a call to set_range.
	(textinfo::get_location): Eliminate inline implementation in favor of
	an out-of-line reimplementation.
	(textinfo::set_range): New method.
	* rtl-error.c (diagnostic_for_asm): Update for change in signature
	of diagnostic_set_info.
	* tree-diagnostic.c (default_tree_printer): Update for new
	"caret_p" param for textinfo::set_location.
	* tree-pretty-print.c (percent_K_format): Likewise.

gcc/c-family/ChangeLog:
	* c-common.c (c_cpp_error): Convert parameter from location_t to
	rich_location *.  Eliminate the "column_override" parameter and
	the call to diagnostic_override_column.
	Update the "done_lexing" clause to set range 0
	on the rich_location, rather than overwriting a location_t.
	* c-common.h (c_cpp_error): Convert parameter from location_t to
	rich_location *.  Eliminate the "column_override" parameter.

gcc/c/ChangeLog:
	* c-decl.c (warn_defaults_to): Update for change in signature
	of diagnostic_set_info.
	* c-errors.c (pedwarn_c99): Likewise.
	(pedwarn_c90): Likewise.
	* c-objc-common.c (c_tree_printer): Update for new "caret_p" param
	for textinfo::set_location.

gcc/cp/ChangeLog:
	* error.c (cp_printer): Update for new "caret_p" param for
	textinfo::set_location.
	(pedwarn_cxx98): Update for change in signature of
	diagnostic_set_info.

gcc/fortran/ChangeLog:
	* cpp.c (cb_cpp_error): Convert parameter from location_t to
	rich_location *.  Eliminate the "column_override" parameter.
	* error.c (gfc_warning): Update for change in signature of
	diagnostic_set_info.
	(gfc_format_decoder): Update handling of %C/%L for changes
	to struct text_info.
	(gfc_diagnostic_starter): Use richloc when determining whether to
	print one locus or two.  When handling a location that will
	involve a call to diagnostic_show_locus, only attempt to print the
	locus for the primary location, and don't call into
	diagnostic_print_caret_line.
	(gfc_warning_now_at): Update for change in signature of
	diagnostic_set_info.
	(gfc_warning_now): Likewise.
	(gfc_error_now): Likewise.
	(gfc_fatal_error): Likewise.
	(gfc_error): Likewise.
	(gfc_internal_error): Likewise.

gcc/testsuite/ChangeLog:
	* gcc.dg/plugin/diagnostic-test-show-locus-bw.c: New file.
	* gcc.dg/plugin/diagnostic-test-show-locus-color.c: New file.
	* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c: New file.
	* gcc.dg/plugin/plugin.exp (plugin_test_list): Add the above.
	* lib/gcc-dg.exp: Load multiline.exp.

libcpp/ChangeLog:
	* errors.c (cpp_diagnostic): Update for change in signature
	of "error" callback.
	(cpp_diagnostic_with_line): Likewise, calling override_column
	on the rich_location.
	* include/cpplib.h (struct cpp_callbacks): Within "error"
	callback, convert param from source_location to rich_location *,
	and drop column_override param.
	* include/line-map.h (struct source_range): New struct.
	(struct location_range): New struct.
	(class rich_location): New class.
	(linemap_client_expand_location_to_spelling_point): New declaration.
	* line-map.c (rich_location::rich_location): New ctors.
	(rich_location::lazily_expand_location): New method.
	(rich_location::override_column): New method.
	(rich_location::add_range): New methods.
	(rich_location::set_range): New method.

From-SVN: r229884
This commit is contained in:
David Malcolm 2015-11-06 19:50:50 +00:00 committed by David Malcolm
parent 277ec793cb
commit 8a64515099
36 changed files with 2167 additions and 295 deletions

View File

@ -1,3 +1,98 @@
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* diagnostic-color.c (color_dict): Eliminate "caret"; add "range1"
and "range2".
(parse_gcc_colors): Update comment to describe default GCC_COLORS.
* diagnostic-core.h (warning_at_rich_loc): New declaration.
(error_at_rich_loc): New declaration.
(permerror_at_rich_loc): New declaration.
(inform_at_rich_loc): New declaration.
* diagnostic-show-locus.c (adjust_line): Delete.
(struct point_state): New struct.
(class colorizer): New class.
(class layout_point): New class.
(class layout_range): New class.
(struct line_bounds): New.
(class layout): New class.
(colorizer::colorizer): New ctor.
(colorizer::~colorizer): New dtor.
(layout::layout): New ctor.
(layout::print_source_line): New method.
(layout::print_annotation_line): New method.
(layout::get_state_at_point): New method.
(layout::get_x_bound_for_row): New method.
(diagnostic_show_locus): Reimplement in terms of class layout.
(diagnostic_print_caret_line): Delete.
* diagnostic.c (diagnostic_initialize): Replace
MAX_LOCATIONS_PER_MESSAGE with rich_location::MAX_RANGES.
(diagnostic_set_info_translated): Convert param from location_t
to rich_location *. Eliminate calls to set_location on the
message in favor of storing the rich_location ptr there.
(diagnostic_set_info): Convert param from location_t to
rich_location *.
(diagnostic_build_prefix): Break out array into...
(diagnostic_kind_color): New variable.
(diagnostic_get_color_for_kind): New function.
(diagnostic_report_diagnostic): Colorize the option_text
using the color for the severity.
(diagnostic_append_note): Update for change in signature of
diagnostic_set_info.
(diagnostic_append_note_at_rich_loc): New function.
(emit_diagnostic): Update for change in signature of
diagnostic_set_info.
(inform): Likewise.
(inform_at_rich_loc): New function.
(inform_n): Update for change in signature of diagnostic_set_info.
(warning): Likewise.
(warning_at): Likewise.
(warning_at_rich_loc): New function.
(warning_n): Update for change in signature of diagnostic_set_info.
(pedwarn): Likewise.
(permerror): Likewise.
(permerror_at_rich_loc): New function.
(error): Update for change in signature of diagnostic_set_info.
(error_n): Likewise.
(error_at): Likewise.
(error_at_rich_loc): New function.
(sorry): Update for change in signature of diagnostic_set_info.
(fatal_error): Likewise.
(internal_error): Likewise.
(internal_error_no_backtrace): Likewise.
(source_range::debug): New function.
* diagnostic.h (struct diagnostic_info): Eliminate field
"override_column". Add field "richloc".
(struct diagnostic_context): Add field "colorize_source_p".
(diagnostic_override_column): Delete.
(diagnostic_set_info): Convert param from location_t to
rich_location *.
(diagnostic_set_info_translated): Likewise.
(diagnostic_append_note_at_rich_loc): New function.
(diagnostic_num_locations): New function.
(diagnostic_expand_location): Get the location from the
rich_location.
(diagnostic_print_caret_line): Delete.
(diagnostic_get_color_for_kind): New declaration.
* genmatch.c (linemap_client_expand_location_to_spelling_point): New.
(error_cb): Update for change in signature of "error" callback.
(fatal_at): Likewise.
(warning_at): Likewise.
* input.c (linemap_client_expand_location_to_spelling_point): New.
* pretty-print.c (text_info::set_range): New method.
(text_info::get_location): New method.
* pretty-print.h (MAX_LOCATIONS_PER_MESSAGE): Eliminate this macro.
(struct text_info): Eliminate "locations" array in favor of
"m_richloc", a rich_location *.
(textinfo::set_location): Add a "caret_p" param, and reimplement
in terms of a call to set_range.
(textinfo::get_location): Eliminate inline implementation in favor of
an out-of-line reimplementation.
(textinfo::set_range): New method.
* rtl-error.c (diagnostic_for_asm): Update for change in signature
of diagnostic_set_info.
* tree-diagnostic.c (default_tree_printer): Update for new
"caret_p" param for textinfo::set_location.
* tree-pretty-print.c (percent_K_format): Likewise.
2015-11-06 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
Properly apply.

View File

@ -1,3 +1,13 @@
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* c-common.c (c_cpp_error): Convert parameter from location_t to
rich_location *. Eliminate the "column_override" parameter and
the call to diagnostic_override_column.
Update the "done_lexing" clause to set range 0
on the rich_location, rather than overwriting a location_t.
* c-common.h (c_cpp_error): Convert parameter from location_t to
rich_location *. Eliminate the "column_override" parameter.
2015-11-05 Cesar Philippidis <cesar@codesourcery.com>
Thomas Schwinge <thomas@codesourcery.com>
James Norris <jnorris@codesourcery.com>

View File

@ -10543,15 +10543,14 @@ c_option_controlling_cpp_error (int reason)
/* Callback from cpp_error for PFILE to print diagnostics from the
preprocessor. The diagnostic is of type LEVEL, with REASON set
to the reason code if LEVEL is represents a warning, at location
LOCATION unless this is after lexing and the compiler's location
should be used instead, with column number possibly overridden by
COLUMN_OVERRIDE if not zero; MSG is the translated message and AP
RICHLOC unless this is after lexing and the compiler's location
should be used instead; MSG is the translated message and AP
the arguments. Returns true if a diagnostic was emitted, false
otherwise. */
bool
c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
location_t location, unsigned int column_override,
rich_location *richloc,
const char *msg, va_list *ap)
{
diagnostic_info diagnostic;
@ -10592,11 +10591,11 @@ c_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
gcc_unreachable ();
}
if (done_lexing)
location = input_location;
richloc->set_range (0,
source_range::from_location (input_location),
true, true);
diagnostic_set_info_translated (&diagnostic, msg, ap,
location, dlevel);
if (column_override)
diagnostic_override_column (&diagnostic, column_override);
richloc, dlevel);
diagnostic_override_option_index (&diagnostic,
c_option_controlling_cpp_error (reason));
ret = report_diagnostic (&diagnostic);

View File

@ -995,9 +995,9 @@ extern void init_c_lex (void);
extern void c_cpp_builtins (cpp_reader *);
extern void c_cpp_builtins_optimize_pragma (cpp_reader *, tree, tree);
extern bool c_cpp_error (cpp_reader *, int, int, location_t, unsigned int,
extern bool c_cpp_error (cpp_reader *, int, int, rich_location *,
const char *, va_list *)
ATTRIBUTE_GCC_DIAG(6,0);
ATTRIBUTE_GCC_DIAG(5,0);
extern int c_common_has_attribute (cpp_reader *);
extern bool parse_optimize_options (tree, bool);

View File

@ -1,3 +1,12 @@
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* c-decl.c (warn_defaults_to): Update for change in signature
of diagnostic_set_info.
* c-errors.c (pedwarn_c99): Likewise.
(pedwarn_c90): Likewise.
* c-objc-common.c (c_tree_printer): Update for new "caret_p" param
for textinfo::set_location.
2015-11-05 Cesar Philippidis <cesar@codesourcery.com>
Thomas Schwinge <thomas@codesourcery.com>
James Norris <jnorris@codesourcery.com>

View File

@ -5285,9 +5285,10 @@ warn_defaults_to (location_t location, int opt, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
flag_isoc99 ? DK_PEDWARN : DK_WARNING);
diagnostic.option_index = opt;
report_diagnostic (&diagnostic);

View File

@ -41,13 +41,14 @@ pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
diagnostic_info diagnostic;
va_list ap;
bool warned = false;
rich_location richloc (location);
va_start (ap, gmsgid);
/* If desired, issue the C99/C11 compat warning, which is more specific
than -pedantic. */
if (warn_c99_c11_compat > 0)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc11)
? DK_PEDWARN : DK_WARNING);
diagnostic.option_index = OPT_Wc99_c11_compat;
@ -59,7 +60,7 @@ pedwarn_c99 (location_t location, int opt, const char *gmsgid, ...)
/* For -pedantic outside C11, issue a pedwarn. */
else if (pedantic && !flag_isoc11)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_PEDWARN);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
diagnostic.option_index = opt;
warned = report_diagnostic (&diagnostic);
}
@ -79,6 +80,7 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (location);
va_start (ap, gmsgid);
/* Warnings such as -Wvla are the most specific ones. */
@ -89,7 +91,7 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
goto out;
else if (opt_var > 0)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc99)
? DK_PEDWARN : DK_WARNING);
diagnostic.option_index = opt;
@ -101,7 +103,7 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
specific than -pedantic. */
if (warn_c90_c99_compat > 0)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc99)
? DK_PEDWARN : DK_WARNING);
diagnostic.option_index = OPT_Wc90_c99_compat;
@ -113,7 +115,7 @@ pedwarn_c90 (location_t location, int opt, const char *gmsgid, ...)
/* For -pedantic outside C99, issue a pedwarn. */
else if (pedantic && !flag_isoc99)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_PEDWARN);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
diagnostic.option_index = opt;
report_diagnostic (&diagnostic);
}

View File

@ -100,7 +100,7 @@ c_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
{
t = va_arg (*text->args_ptr, tree);
if (set_locus)
text->set_location (0, DECL_SOURCE_LOCATION (t));
text->set_location (0, DECL_SOURCE_LOCATION (t), true);
}
switch (*spec)

View File

@ -1,3 +1,10 @@
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* error.c (cp_printer): Update for new "caret_p" param for
textinfo::set_location.
(pedwarn_cxx98): Update for change in signature of
diagnostic_set_info.
2015-11-06 Jason Merrill <jason@redhat.com>
Support non-type constrained-type-specifiers.

View File

@ -3563,7 +3563,7 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec,
pp_string (pp, result);
if (set_locus && t != NULL)
text->set_location (0, location_of (t));
text->set_location (0, location_of (t), true);
return true;
#undef next_tree
#undef next_tcode
@ -3677,9 +3677,10 @@ pedwarn_cxx98 (location_t location, int opt, const char *gmsgid, ...)
diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);

View File

@ -164,7 +164,8 @@ static struct color_cap color_dict[] =
{ "warning", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_MAGENTA),
7, false },
{ "note", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_CYAN), 4, false },
{ "caret", SGR_SEQ (COLOR_BOLD COLOR_SEPARATOR COLOR_FG_GREEN), 5, false },
{ "range1", SGR_SEQ (COLOR_FG_GREEN), 6, false },
{ "range2", SGR_SEQ (COLOR_FG_BLUE), 6, false },
{ "locus", SGR_SEQ (COLOR_BOLD), 5, false },
{ "quote", SGR_SEQ (COLOR_BOLD), 5, false },
{ NULL, NULL, 0, false }
@ -195,7 +196,7 @@ colorize_stop (bool show_color)
}
/* Parse GCC_COLORS. The default would look like:
GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
GCC_COLORS='error=01;31:warning=01;35:note=01;36:range1=32:range2=34;locus=01:quote=01'
No character escaping is needed or supported. */
static bool
parse_gcc_colors (void)

View File

@ -63,18 +63,26 @@ extern bool warning_n (location_t, int, int, const char *, const char *, ...)
ATTRIBUTE_GCC_DIAG(4,6) ATTRIBUTE_GCC_DIAG(5,6);
extern bool warning_at (location_t, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool warning_at_rich_loc (rich_location *, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
extern void error_n (location_t, int, const char *, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,5) ATTRIBUTE_GCC_DIAG(4,5);
extern void error_at (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
extern void error_at_rich_loc (rich_location *, const char *, ...)
ATTRIBUTE_GCC_DIAG(2,3);
extern void fatal_error (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3)
ATTRIBUTE_NORETURN;
/* Pass one of the OPT_W* from options.h as the second parameter. */
extern bool pedwarn (location_t, int, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool permerror (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
extern bool permerror_at_rich_loc (rich_location *, const char *,
...) ATTRIBUTE_GCC_DIAG(2,3);
extern void sorry (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
extern void inform (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
extern void inform_at_rich_loc (rich_location *, const char *,
...) ATTRIBUTE_GCC_DIAG(2,3);
extern void inform_n (location_t, int, const char *, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,5) ATTRIBUTE_GCC_DIAG(4,5);
extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);

View File

@ -36,35 +36,650 @@ along with GCC; see the file COPYING3. If not see
# include <sys/ioctl.h>
#endif
/* If LINE is longer than MAX_WIDTH, and COLUMN is not smaller than
MAX_WIDTH by some margin, then adjust the start of the line such
that the COLUMN is smaller than MAX_WIDTH minus the margin. The
margin is either CARET_LINE_MARGIN characters or the difference
between the column and the length of the line, whatever is smaller.
The length of LINE is given by LINE_WIDTH. */
static const char *
adjust_line (const char *line, int line_width,
int max_width, int *column_p)
{
int right_margin = CARET_LINE_MARGIN;
int column = *column_p;
/* Classes for rendering source code and diagnostics, within an
anonymous namespace.
The work is done by "class layout", which embeds and uses
"class colorizer" and "class layout_range" to get things done. */
gcc_checking_assert (line_width >= column);
right_margin = MIN (line_width - column, right_margin);
right_margin = max_width - right_margin;
if (line_width >= max_width && column > right_margin)
{
line += column - right_margin;
*column_p = right_margin;
}
return line;
namespace {
/* The state at a given point of the source code, assuming that we're
in a range: which range are we in, and whether we should draw a caret at
this point. */
struct point_state
{
int range_idx;
bool draw_caret_p;
};
/* A class to inject colorization codes when printing the diagnostic locus.
It has one kind of colorization for each of:
- normal text
- range 0 (the "primary location")
- range 1
- range 2
The class caches the lookup of the color codes for the above.
The class also has responsibility for tracking which of the above is
active, filtering out unnecessary changes. This allows
layout::print_source_line and layout::print_annotation_line
to simply request a colorization code for *every* character they print,
via this class, and have the filtering be done for them here. */
class colorizer
{
public:
colorizer (diagnostic_context *context,
const diagnostic_info *diagnostic);
~colorizer ();
void set_range (int range_idx) { set_state (range_idx); }
void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
private:
void set_state (int state);
void begin_state (int state);
void finish_state (int state);
private:
static const int STATE_NORMAL_TEXT = -1;
diagnostic_context *m_context;
const diagnostic_info *m_diagnostic;
int m_current_state;
const char *m_caret_cs;
const char *m_caret_ce;
const char *m_range1_cs;
const char *m_range2_cs;
const char *m_range_ce;
};
/* A point within a layout_range; similar to an expanded_location,
but after filtering on file. */
class layout_point
{
public:
layout_point (const expanded_location &exploc)
: m_line (exploc.line),
m_column (exploc.column) {}
int m_line;
int m_column;
};
/* A class for use by "class layout" below: a filtered location_range. */
class layout_range
{
public:
layout_range (const location_range *loc_range);
bool contains_point (int row, int column) const;
layout_point m_start;
layout_point m_finish;
bool m_show_caret_p;
layout_point m_caret;
};
/* A struct for use by layout::print_source_line for telling
layout::print_annotation_line the extents of the source line that
it printed, so that underlines can be clipped appropriately. */
struct line_bounds
{
int m_first_non_ws;
int m_last_non_ws;
};
/* A class to control the overall layout when printing a diagnostic.
The layout is determined within the constructor.
It is then printed by repeatedly calling the "print_source_line"
and "print_annotation_line" methods.
We assume we have disjoint ranges. */
class layout
{
public:
layout (diagnostic_context *context,
const diagnostic_info *diagnostic);
int get_first_line () const { return m_first_line; }
int get_last_line () const { return m_last_line; }
bool print_source_line (int row, line_bounds *lbounds_out);
void print_annotation_line (int row, const line_bounds lbounds);
private:
bool
get_state_at_point (/* Inputs. */
int row, int column,
int first_non_ws, int last_non_ws,
/* Outputs. */
point_state *out_state);
int
get_x_bound_for_row (int row, int caret_column,
int last_non_ws);
private:
diagnostic_context *m_context;
pretty_printer *m_pp;
diagnostic_t m_diagnostic_kind;
expanded_location m_exploc;
colorizer m_colorizer;
bool m_colorize_source_p;
auto_vec <layout_range> m_layout_ranges;
int m_first_line;
int m_last_line;
int m_x_offset;
};
/* Implementation of "class colorizer". */
/* The constructor for "colorizer". Lookup and store color codes for the
different kinds of things we might need to print. */
colorizer::colorizer (diagnostic_context *context,
const diagnostic_info *diagnostic) :
m_context (context),
m_diagnostic (diagnostic),
m_current_state (STATE_NORMAL_TEXT)
{
m_caret_ce = colorize_stop (pp_show_color (context->printer));
m_range1_cs = colorize_start (pp_show_color (context->printer), "range1");
m_range2_cs = colorize_start (pp_show_color (context->printer), "range2");
m_range_ce = colorize_stop (pp_show_color (context->printer));
}
/* Print the physical source line corresponding to the location of
this diagnostic, and a caret indicating the precise column. This
function only prints two caret characters if the two locations
given by DIAGNOSTIC are on the same line according to
diagnostic_same_line(). */
/* The destructor for "colorize". If colorization is on, print a code to
turn it off. */
colorizer::~colorizer ()
{
finish_state (m_current_state);
}
/* Update state, printing color codes if necessary if there's a state
change. */
void
colorizer::set_state (int new_state)
{
if (m_current_state != new_state)
{
finish_state (m_current_state);
m_current_state = new_state;
begin_state (new_state);
}
}
/* Turn on any colorization for STATE. */
void
colorizer::begin_state (int state)
{
switch (state)
{
case STATE_NORMAL_TEXT:
break;
case 0:
/* Make range 0 be the same color as the "kind" text
(error vs warning vs note). */
pp_string
(m_context->printer,
colorize_start (pp_show_color (m_context->printer),
diagnostic_get_color_for_kind (m_diagnostic->kind)));
break;
case 1:
pp_string (m_context->printer, m_range1_cs);
break;
case 2:
pp_string (m_context->printer, m_range2_cs);
break;
default:
/* We don't expect more than 3 ranges per diagnostic. */
gcc_unreachable ();
break;
}
}
/* Turn off any colorization for STATE. */
void
colorizer::finish_state (int state)
{
switch (state)
{
case STATE_NORMAL_TEXT:
break;
case 0:
pp_string (m_context->printer, m_caret_ce);
break;
default:
/* Within a range. */
gcc_assert (state > 0);
pp_string (m_context->printer, m_range_ce);
break;
}
}
/* Implementation of class layout_range. */
/* The constructor for class layout_range.
Initialize various layout_point fields from expanded_location
equivalents; we've already filtered on file. */
layout_range::layout_range (const location_range *loc_range)
: m_start (loc_range->m_start),
m_finish (loc_range->m_finish),
m_show_caret_p (loc_range->m_show_caret_p),
m_caret (loc_range->m_caret)
{
}
/* Is (column, row) within the given range?
We've already filtered on the file.
Ranges are closed (both limits are within the range).
Example A: a single-line range:
start: (col=22, line=2)
finish: (col=38, line=2)
|00000011111111112222222222333333333344444444444
|34567890123456789012345678901234567890123456789
--+-----------------------------------------------
01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
02|bbbbbbbbbbbbbbbbbbbSwwwwwwwwwwwwwwwFaaaaaaaaaaa
03|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Example B: a multiline range with
start: (col=14, line=3)
finish: (col=08, line=5)
|00000011111111112222222222333333333344444444444
|34567890123456789012345678901234567890123456789
--+-----------------------------------------------
01|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
02|bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
03|bbbbbbbbbbbSwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
04|wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
05|wwwwwFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
06|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
--+-----------------------------------------------
Legend:
- 'b' indicates a point *before* the range
- 'S' indicates the start of the range
- 'w' indicates a point within the range
- 'F' indicates the finish of the range (which is
within it).
- 'a' indicates a subsequent point *after* the range. */
bool
layout_range::contains_point (int row, int column) const
{
gcc_assert (m_start.m_line <= m_finish.m_line);
/* ...but the equivalent isn't true for the columns;
consider example B in the comment above. */
if (row < m_start.m_line)
/* Points before the first line of the range are
outside it (corresponding to line 01 in example A
and lines 01 and 02 in example B above). */
return false;
if (row == m_start.m_line)
/* On same line as start of range (corresponding
to line 02 in example A and line 03 in example B). */
{
if (column < m_start.m_column)
/* Points on the starting line of the range, but
before the column in which it begins. */
return false;
if (row < m_finish.m_line)
/* This is a multiline range; the point
is within it (corresponds to line 03 in example B
from column 14 onwards) */
return true;
else
{
/* This is a single-line range. */
gcc_assert (row == m_finish.m_line);
return column <= m_finish.m_column;
}
}
/* The point is in a line beyond that containing the
start of the range: lines 03 onwards in example A,
and lines 04 onwards in example B. */
gcc_assert (row > m_start.m_line);
if (row > m_finish.m_line)
/* The point is beyond the final line of the range
(lines 03 onwards in example A, and lines 06 onwards
in example B). */
return false;
if (row < m_finish.m_line)
{
/* The point is in a line that's fully within a multiline
range (e.g. line 04 in example B). */
gcc_assert (m_start.m_line < m_finish.m_line);
return true;
}
gcc_assert (row == m_finish.m_line);
return column <= m_finish.m_column;
}
/* Given a source line LINE of length LINE_WIDTH, determine the width
without any trailing whitespace. */
static int
get_line_width_without_trailing_whitespace (const char *line, int line_width)
{
int result = line_width;
while (result > 0)
{
char ch = line[result - 1];
if (ch == ' ' || ch == '\t')
result--;
else
break;
}
gcc_assert (result >= 0);
gcc_assert (result <= line_width);
gcc_assert (result == 0 ||
(line[result - 1] != ' '
&& line[result -1] != '\t'));
return result;
}
/* Implementation of class layout. */
/* Constructor for class layout.
Filter the ranges from the rich_location to those that we can
sanely print, populating m_layout_ranges.
Determine the range of lines that we will print.
Determine m_x_offset, to ensure that the primary caret
will fit within the max_width provided by the diagnostic_context. */
layout::layout (diagnostic_context * context,
const diagnostic_info *diagnostic)
: m_context (context),
m_pp (context->printer),
m_diagnostic_kind (diagnostic->kind),
m_exploc (diagnostic->richloc->lazily_expand_location ()),
m_colorizer (context, diagnostic),
m_colorize_source_p (context->colorize_source_p),
m_layout_ranges (rich_location::MAX_RANGES),
m_first_line (m_exploc.line),
m_last_line (m_exploc.line),
m_x_offset (0)
{
rich_location *richloc = diagnostic->richloc;
for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++)
{
/* This diagnostic printer can only cope with "sufficiently sane" ranges.
Ignore any ranges that are awkward to handle. */
location_range *loc_range = richloc->get_range (idx);
/* If any part of the range isn't in the same file as the primary
location of this diagnostic, ignore the range. */
if (loc_range->m_start.file != m_exploc.file)
continue;
if (loc_range->m_finish.file != m_exploc.file)
continue;
if (loc_range->m_show_caret_p)
if (loc_range->m_caret.file != m_exploc.file)
continue;
/* Passed all the tests; add the range to m_layout_ranges so that
it will be printed. */
layout_range ri (loc_range);
m_layout_ranges.safe_push (ri);
/* Update m_first_line/m_last_line if necessary. */
if (loc_range->m_start.line < m_first_line)
m_first_line = loc_range->m_start.line;
if (loc_range->m_finish.line > m_last_line)
m_last_line = loc_range->m_finish.line;
}
/* Adjust m_x_offset.
Center the primary caret to fit in max_width; all columns
will be adjusted accordingly. */
int max_width = m_context->caret_max_width;
int line_width;
const char *line = location_get_source_line (m_exploc.file, m_exploc.line,
&line_width);
if (line && m_exploc.column <= line_width)
{
int right_margin = CARET_LINE_MARGIN;
int column = m_exploc.column;
right_margin = MIN (line_width - column, right_margin);
right_margin = max_width - right_margin;
if (line_width >= max_width && column > right_margin)
m_x_offset = column - right_margin;
gcc_assert (m_x_offset >= 0);
}
}
/* Attempt to print line ROW of source code, potentially colorized at any
ranges.
Return true if the line was printed, populating *LBOUNDS_OUT.
Return false if the source line could not be read, leaving *LBOUNDS_OUT
untouched. */
bool
layout::print_source_line (int row, line_bounds *lbounds_out)
{
int line_width;
const char *line = location_get_source_line (m_exploc.file, row,
&line_width);
if (!line)
return false;
line += m_x_offset;
m_colorizer.set_normal_text ();
/* We will stop printing the source line at any trailing
whitespace. */
line_width = get_line_width_without_trailing_whitespace (line,
line_width);
pp_space (m_pp);
int first_non_ws = INT_MAX;
int last_non_ws = 0;
int column;
for (column = 1 + m_x_offset; column <= line_width; column++)
{
/* Assuming colorization is enabled for the caret and underline
characters, we may also colorize the associated characters
within the source line.
For frontends that generate range information, we color the
associated characters in the source line the same as the
carets and underlines in the annotation line, to make it easier
for the reader to see the pertinent code.
For frontends that only generate carets, we don't colorize the
characters above them, since this would look strange (e.g.
colorizing just the first character in a token). */
if (m_colorize_source_p)
{
bool in_range_p;
point_state state;
in_range_p = get_state_at_point (row, column,
0, INT_MAX,
&state);
if (in_range_p)
m_colorizer.set_range (state.range_idx);
else
m_colorizer.set_normal_text ();
}
char c = *line == '\t' ? ' ' : *line;
if (c == '\0')
c = ' ';
if (c != ' ')
{
last_non_ws = column;
if (first_non_ws == INT_MAX)
first_non_ws = column;
}
pp_character (m_pp, c);
line++;
}
pp_newline (m_pp);
lbounds_out->m_first_non_ws = first_non_ws;
lbounds_out->m_last_non_ws = last_non_ws;
return true;
}
/* Print a line consisting of the caret/underlines for the given
source line. */
void
layout::print_annotation_line (int row, const line_bounds lbounds)
{
int x_bound = get_x_bound_for_row (row, m_exploc.column,
lbounds.m_last_non_ws);
pp_space (m_pp);
for (int column = 1 + m_x_offset; column < x_bound; column++)
{
bool in_range_p;
point_state state;
in_range_p = get_state_at_point (row, column,
lbounds.m_first_non_ws,
lbounds.m_last_non_ws,
&state);
if (in_range_p)
{
/* Within a range. Draw either the caret or an underline. */
m_colorizer.set_range (state.range_idx);
if (state.draw_caret_p)
/* Draw the caret. */
pp_character (m_pp, m_context->caret_chars[state.range_idx]);
else
pp_character (m_pp, '~');
}
else
{
/* Not in a range. */
m_colorizer.set_normal_text ();
pp_character (m_pp, ' ');
}
}
pp_newline (m_pp);
}
/* Return true if (ROW/COLUMN) is within a range of the layout.
If it returns true, OUT_STATE is written to, with the
range index, and whether we should draw the caret at
(ROW/COLUMN) (as opposed to an underline). */
bool
layout::get_state_at_point (/* Inputs. */
int row, int column,
int first_non_ws, int last_non_ws,
/* Outputs. */
point_state *out_state)
{
layout_range *range;
int i;
FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
{
if (range->contains_point (row, column))
{
out_state->range_idx = i;
/* Are we at the range's caret? is it visible? */
out_state->draw_caret_p = false;
if (row == range->m_caret.m_line
&& column == range->m_caret.m_column)
out_state->draw_caret_p = range->m_show_caret_p;
/* Within a multiline range, don't display any underline
in any leading or trailing whitespace on a line.
We do display carets, however. */
if (!out_state->draw_caret_p)
if (column < first_non_ws || column > last_non_ws)
return false;
/* We are within a range. */
return true;
}
}
return false;
}
/* Helper function for use by layout::print_line when printing the
annotation line under the source line.
Get the column beyond the rightmost one that could contain a caret or
range marker, given that we stop rendering at trailing whitespace.
ROW is the source line within the given file.
CARET_COLUMN is the column of range 0's caret.
LAST_NON_WS_COLUMN is the last column containing a non-whitespace
character of source (as determined when printing the source line). */
int
layout::get_x_bound_for_row (int row, int caret_column,
int last_non_ws_column)
{
int result = caret_column + 1;
layout_range *range;
int i;
FOR_EACH_VEC_ELT (m_layout_ranges, i, range)
{
if (row >= range->m_start.m_line)
{
if (range->m_finish.m_line == row)
{
/* On the final line within a range; ensure that
we render up to the end of the range. */
if (result <= range->m_finish.m_column)
result = range->m_finish.m_column + 1;
}
else if (row < range->m_finish.m_line)
{
/* Within a multiline range; ensure that we render up to the
last non-whitespace column. */
if (result <= last_non_ws_column)
result = last_non_ws_column + 1;
}
}
}
return result;
}
} /* End of anonymous namespace. */
/* Print the physical source code corresponding to the location of
this diagnostic, with additional annotations. */
void
diagnostic_show_locus (diagnostic_context * context,
const diagnostic_info *diagnostic)
@ -75,92 +690,32 @@ diagnostic_show_locus (diagnostic_context * context,
return;
context->last_location = diagnostic_location (diagnostic, 0);
expanded_location s0 = diagnostic_expand_location (diagnostic, 0);
expanded_location s1 = { };
/* Zero-initialized. This is checked later by diagnostic_print_caret_line. */
if (diagnostic_location (diagnostic, 1) > BUILTINS_LOCATION)
s1 = diagnostic_expand_location (diagnostic, 1);
diagnostic_print_caret_line (context, s0, s1,
context->caret_chars[0],
context->caret_chars[1]);
}
/* Print (part) of the source line given by xloc1 with caret1 pointing
at the column. If xloc2.column != 0 and it fits within the same
line as xloc1 according to diagnostic_same_line (), then caret2 is
printed at xloc2.colum. Otherwise, the caller has to set up things
to print a second caret line for xloc2. */
void
diagnostic_print_caret_line (diagnostic_context * context,
expanded_location xloc1,
expanded_location xloc2,
char caret1, char caret2)
{
if (!diagnostic_same_line (context, xloc1, xloc2))
/* This will mean ignore xloc2. */
xloc2.column = 0;
else if (xloc1.column == xloc2.column)
xloc2.column++;
int cmax = MAX (xloc1.column, xloc2.column);
int line_width;
const char *line = location_get_source_line (xloc1.file, xloc1.line,
&line_width);
if (line == NULL || cmax > line_width)
return;
/* Center the interesting part of the source line to fit in
max_width, and adjust all columns accordingly. */
int max_width = context->caret_max_width;
int offset = (int) cmax;
line = adjust_line (line, line_width, max_width, &offset);
offset -= cmax;
cmax += offset;
xloc1.column += offset;
if (xloc2.column)
xloc2.column += offset;
/* Print the source line. */
pp_newline (context->printer);
const char *saved_prefix = pp_get_prefix (context->printer);
pp_set_prefix (context->printer, NULL);
pp_space (context->printer);
while (max_width > 0 && line_width > 0)
{
char c = *line == '\t' ? ' ' : *line;
if (c == '\0')
c = ' ';
pp_character (context->printer, c);
max_width--;
line_width--;
line++;
}
pp_newline (context->printer);
/* Print the caret under the line. */
const char *caret_cs, *caret_ce;
caret_cs = colorize_start (pp_show_color (context->printer), "caret");
caret_ce = colorize_stop (pp_show_color (context->printer));
int cmin = xloc2.column
? MIN (xloc1.column, xloc2.column) : xloc1.column;
int caret_min = cmin == xloc1.column ? caret1 : caret2;
int caret_max = cmin == xloc1.column ? caret2 : caret1;
{
layout layout (context, diagnostic);
int last_line = layout.get_last_line ();
for (int row = layout.get_first_line ();
row <= last_line;
row++)
{
/* Print the source line, followed by an annotation line
consisting of any caret/underlines. If the source line can't
be read, print nothing. */
line_bounds lbounds;
if (layout.print_source_line (row, &lbounds))
layout.print_annotation_line (row, lbounds);
}
/* cmin is >= 1, but we indent with an extra space at the start like
we did above. */
int i;
for (i = 0; i < cmin; i++)
pp_space (context->printer);
pp_printf (context->printer, "%s%c%s", caret_cs, caret_min, caret_ce);
/* The closing scope here leads to the dtor for layout and thus
colorizer being called here, which affects the precise
place where colorization is turned off in the unittest
for colorized output. */
}
if (xloc2.column)
{
for (i++; i < cmax; i++)
pp_space (context->printer);
pp_printf (context->printer, "%s%c%s", caret_cs, caret_max, caret_ce);
}
pp_set_prefix (context->printer, saved_prefix);
pp_needs_newline (context->printer) = true;
}

View File

@ -144,7 +144,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
context->classify_diagnostic[i] = DK_UNSPECIFIED;
context->show_caret = false;
diagnostic_set_caret_max_width (context, pp_line_cutoff (context->printer));
for (i = 0; i < MAX_LOCATIONS_PER_MESSAGE; i++)
for (i = 0; i < rich_location::MAX_RANGES; i++)
context->caret_chars[i] = '^';
context->show_option_requested = false;
context->abort_on_error = false;
@ -234,16 +234,15 @@ diagnostic_finish (diagnostic_context *context)
translated. */
void
diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
va_list *args, location_t location,
va_list *args, rich_location *richloc,
diagnostic_t kind)
{
gcc_assert (richloc);
diagnostic->message.err_no = errno;
diagnostic->message.args_ptr = args;
diagnostic->message.format_spec = msg;
diagnostic->message.set_location (0, location);
for (int i = 1; i < MAX_LOCATIONS_PER_MESSAGE; i++)
diagnostic->message.set_location (i, UNKNOWN_LOCATION);
diagnostic->override_column = 0;
diagnostic->message.m_richloc = richloc;
diagnostic->richloc = richloc;
diagnostic->kind = kind;
diagnostic->option_index = 0;
}
@ -252,10 +251,27 @@ diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
translated. */
void
diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
va_list *args, location_t location,
va_list *args, rich_location *richloc,
diagnostic_t kind)
{
diagnostic_set_info_translated (diagnostic, _(gmsgid), args, location, kind);
gcc_assert (richloc);
diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind);
}
static const char *const diagnostic_kind_color[] = {
#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
#include "diagnostic.def"
#undef DEFINE_DIAGNOSTIC_KIND
NULL
};
/* Get a color name for diagnostics of type KIND
Result could be NULL. */
const char *
diagnostic_get_color_for_kind (diagnostic_t kind)
{
return diagnostic_kind_color[kind];
}
/* Return a malloc'd string describing a location. The caller is
@ -270,12 +286,6 @@ diagnostic_build_prefix (diagnostic_context *context,
#undef DEFINE_DIAGNOSTIC_KIND
"must-not-happen"
};
static const char *const diagnostic_kind_color[] = {
#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
#include "diagnostic.def"
#undef DEFINE_DIAGNOSTIC_KIND
NULL
};
gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND);
const char *text = _(diagnostic_kind_text[diagnostic->kind]);
@ -770,10 +780,14 @@ diagnostic_report_diagnostic (diagnostic_context *context,
if (option_text)
{
const char *cs
= colorize_start (pp_show_color (context->printer),
diagnostic_kind_color[diagnostic->kind]);
const char *ce = colorize_stop (pp_show_color (context->printer));
diagnostic->message.format_spec
= ACONCAT ((diagnostic->message.format_spec,
" ",
"[", option_text, "]",
"[", cs, option_text, ce, "]",
NULL));
free (option_text);
}
@ -853,9 +867,40 @@ diagnostic_append_note (diagnostic_context *context,
diagnostic_info diagnostic;
va_list ap;
const char *saved_prefix;
rich_location richloc (location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_NOTE);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
if (context->inhibit_notes_p)
{
va_end (ap);
return;
}
saved_prefix = pp_get_prefix (context->printer);
pp_set_prefix (context->printer,
diagnostic_build_prefix (context, &diagnostic));
pp_newline (context->printer);
pp_format (context->printer, &diagnostic.message);
pp_output_formatted_text (context->printer);
pp_destroy_prefix (context->printer);
pp_set_prefix (context->printer, saved_prefix);
diagnostic_show_locus (context, &diagnostic);
va_end (ap);
}
/* Same as diagnostic_append_note, but at RICHLOC. */
void
diagnostic_append_note_at_rich_loc (diagnostic_context *context,
rich_location *richloc,
const char * gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
const char *saved_prefix;
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, richloc, DK_NOTE);
if (context->inhibit_notes_p)
{
va_end (ap);
@ -880,16 +925,17 @@ emit_diagnostic (diagnostic_t kind, location_t location, int opt,
diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (location);
va_start (ap, gmsgid);
if (kind == DK_PERMERROR)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
permissive_error_kind (global_dc));
diagnostic.option_index = permissive_error_option (global_dc);
}
else {
diagnostic_set_info (&diagnostic, gmsgid, &ap, location, kind);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, kind);
if (kind == DK_WARNING || kind == DK_PEDWARN)
diagnostic.option_index = opt;
}
@ -906,9 +952,23 @@ inform (location_t location, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_NOTE);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
report_diagnostic (&diagnostic);
va_end (ap);
}
/* Same as "inform", but at RICHLOC. */
void
inform_at_rich_loc (rich_location *richloc, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, richloc, DK_NOTE);
report_diagnostic (&diagnostic);
va_end (ap);
}
@ -921,11 +981,12 @@ inform_n (location_t location, int n, const char *singular_gmsgid,
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (location);
va_start (ap, plural_gmsgid);
diagnostic_set_info_translated (&diagnostic,
ngettext (singular_gmsgid, plural_gmsgid, n),
&ap, location, DK_NOTE);
&ap, &richloc, DK_NOTE);
report_diagnostic (&diagnostic);
va_end (ap);
}
@ -939,9 +1000,10 @@ warning (int opt, const char *gmsgid, ...)
diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (input_location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_WARNING);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_WARNING);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);
@ -959,9 +1021,27 @@ warning_at (location_t location, int opt, const char *gmsgid, ...)
diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_WARNING);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_WARNING);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);
va_end (ap);
return ret;
}
/* Same as warning at, but using RICHLOC. */
bool
warning_at_rich_loc (rich_location *richloc, int opt, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
bool ret;
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, richloc, DK_WARNING);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);
va_end (ap);
@ -979,11 +1059,13 @@ warning_n (location_t location, int opt, int n, const char *singular_gmsgid,
diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (location);
va_start (ap, plural_gmsgid);
diagnostic_set_info_translated (&diagnostic,
ngettext (singular_gmsgid, plural_gmsgid, n),
&ap, location, DK_WARNING);
&ap, &richloc, DK_WARNING
);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);
va_end (ap);
@ -1009,9 +1091,10 @@ pedwarn (location_t location, int opt, const char *gmsgid, ...)
diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, location, DK_PEDWARN);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);
va_end (ap);
@ -1031,9 +1114,28 @@ permerror (location_t location, const char *gmsgid, ...)
diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, location,
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
permissive_error_kind (global_dc));
diagnostic.option_index = permissive_error_option (global_dc);
ret = report_diagnostic (&diagnostic);
va_end (ap);
return ret;
}
/* Same as "permerror", but at RICHLOC. */
bool
permerror_at_rich_loc (rich_location *richloc, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
bool ret;
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, richloc,
permissive_error_kind (global_dc));
diagnostic.option_index = permissive_error_option (global_dc);
ret = report_diagnostic (&diagnostic);
@ -1048,9 +1150,10 @@ error (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (input_location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ERROR);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ERROR);
report_diagnostic (&diagnostic);
va_end (ap);
}
@ -1063,11 +1166,12 @@ error_n (location_t location, int n, const char *singular_gmsgid,
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (location);
va_start (ap, plural_gmsgid);
diagnostic_set_info_translated (&diagnostic,
ngettext (singular_gmsgid, plural_gmsgid, n),
&ap, location, DK_ERROR);
&ap, &richloc, DK_ERROR);
report_diagnostic (&diagnostic);
va_end (ap);
}
@ -1078,9 +1182,25 @@ error_at (location_t loc, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (loc);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, loc, DK_ERROR);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ERROR);
report_diagnostic (&diagnostic);
va_end (ap);
}
/* Same as above, but use RICH_LOC. */
void
error_at_rich_loc (rich_location *rich_loc, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, rich_loc,
DK_ERROR);
report_diagnostic (&diagnostic);
va_end (ap);
}
@ -1093,9 +1213,10 @@ sorry (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (input_location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_SORRY);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_SORRY);
report_diagnostic (&diagnostic);
va_end (ap);
}
@ -1116,9 +1237,10 @@ fatal_error (location_t loc, const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (loc);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, loc, DK_FATAL);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_FATAL);
report_diagnostic (&diagnostic);
va_end (ap);
@ -1134,9 +1256,10 @@ internal_error (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (input_location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ICE);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ICE);
report_diagnostic (&diagnostic);
va_end (ap);
@ -1151,9 +1274,10 @@ internal_error_no_backtrace (const char *gmsgid, ...)
{
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (input_location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, input_location, DK_ICE_NOBT);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ICE_NOBT);
report_diagnostic (&diagnostic);
va_end (ap);
@ -1217,3 +1341,17 @@ real_abort (void)
{
abort ();
}
/* Display the given source_range instance, with MSG as a descriptive
comment. This issues a "note" diagnostic at the range.
This is declared within libcpp, but implemented here, since it
makes use of the diagnostic-printing machinery. */
DEBUG_FUNCTION void
source_range::debug (const char *msg) const
{
rich_location richloc (m_start);
richloc.add_range (m_start, m_finish, false);
inform_at_rich_loc (&richloc, "%s", msg);
}

View File

@ -29,10 +29,12 @@ along with GCC; see the file COPYING3. If not see
list in diagnostic.def. */
struct diagnostic_info
{
/* Text to be formatted. It also contains the location(s) for this
diagnostic. */
/* Text to be formatted. */
text_info message;
unsigned int override_column;
/* The location at which the diagnostic is to be reported. */
rich_location *richloc;
/* Auxiliary data for client. */
void *x_data;
/* The kind of diagnostic it is about. */
@ -102,8 +104,8 @@ struct diagnostic_context
/* Maximum width of the source line printed. */
int caret_max_width;
/* Characters used for caret diagnostics. */
char caret_chars[MAX_LOCATIONS_PER_MESSAGE];
/* Character used for caret diagnostics. */
char caret_chars[rich_location::MAX_RANGES];
/* True if we should print the command line option which controls
each diagnostic, if known. */
@ -181,6 +183,15 @@ struct diagnostic_context
int lock;
bool inhibit_notes_p;
/* When printing source code, should the characters at carets and ranges
be colorized? (assuming colorization is on at all).
This should be true for frontends that generate range information
(so that the ranges of code are colorized),
and false for frontends that merely specify points within the
source code (to avoid e.g. colorizing just the first character in
a token, which would look strange). */
bool colorize_source_p;
};
static inline void
@ -252,10 +263,6 @@ extern diagnostic_context *global_dc;
#define report_diagnostic(D) diagnostic_report_diagnostic (global_dc, D)
/* Override the column number to be used for reporting a
diagnostic. */
#define diagnostic_override_column(DI, COL) (DI)->override_column = (COL)
/* Override the option index to be used for reporting a
diagnostic. */
#define diagnostic_override_option_index(DI, OPTIDX) \
@ -279,13 +286,17 @@ extern bool diagnostic_report_diagnostic (diagnostic_context *,
diagnostic_info *);
#ifdef ATTRIBUTE_GCC_DIAG
extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *,
location_t, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
rich_location *, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
va_list *, location_t,
va_list *, rich_location *,
diagnostic_t)
ATTRIBUTE_GCC_DIAG(2,0);
extern void diagnostic_append_note (diagnostic_context *, location_t,
const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
extern void diagnostic_append_note_at_rich_loc (diagnostic_context *,
rich_location *,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
#endif
extern char *diagnostic_build_prefix (diagnostic_context *, const diagnostic_info *);
void default_diagnostic_starter (diagnostic_context *, diagnostic_info *);
@ -306,6 +317,14 @@ diagnostic_location (const diagnostic_info * diagnostic, int which = 0)
return diagnostic->message.get_location (which);
}
/* Return the number of locations to be printed in DIAGNOSTIC. */
static inline unsigned int
diagnostic_num_locations (const diagnostic_info * diagnostic)
{
return diagnostic->message.m_richloc->get_num_locations ();
}
/* Expand the location of this diagnostic. Use this function for
consistency. Parameter WHICH specifies which location. By default,
expand the first one. */
@ -313,12 +332,7 @@ diagnostic_location (const diagnostic_info * diagnostic, int which = 0)
static inline expanded_location
diagnostic_expand_location (const diagnostic_info * diagnostic, int which = 0)
{
expanded_location s
= expand_location_to_spelling_point (diagnostic_location (diagnostic,
which));
if (which == 0 && diagnostic->override_column)
s.column = diagnostic->override_column;
return s;
return diagnostic->richloc->get_range (which)->m_caret;
}
/* This is somehow the right-side margin of a caret line, that is, we
@ -338,11 +352,7 @@ diagnostic_same_line (const diagnostic_context *context,
&& context->caret_max_width - CARET_LINE_MARGIN > abs (s1.column - s2.column);
}
void
diagnostic_print_caret_line (diagnostic_context * context,
expanded_location xloc1,
expanded_location xloc2,
char caret1, char caret2);
extern const char *diagnostic_get_color_for_kind (diagnostic_t kind);
/* Pure text formatting support functions. */
extern char *file_name_as_prefix (diagnostic_context *, const char *);

View File

@ -1,3 +1,24 @@
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* cpp.c (cb_cpp_error): Convert parameter from location_t to
rich_location *. Eliminate the "column_override" parameter.
* error.c (gfc_warning): Update for change in signature of
diagnostic_set_info.
(gfc_format_decoder): Update handling of %C/%L for changes
to struct text_info.
(gfc_diagnostic_starter): Use richloc when determining whether to
print one locus or two. When handling a location that will
involve a call to diagnostic_show_locus, only attempt to print the
locus for the primary location, and don't call into
diagnostic_print_caret_line.
(gfc_warning_now_at): Update for change in signature of
diagnostic_set_info.
(gfc_warning_now): Likewise.
(gfc_error_now): Likewise.
(gfc_fatal_error): Likewise.
(gfc_error): Likewise.
(gfc_internal_error): Likewise.
2015-11-05 Cesar Philippidis <cesar@codesourcery.com>
* openmp.c (gfc_match_omp_clauses): Update support for the tile

View File

@ -147,9 +147,9 @@ static void cb_include (cpp_reader *, source_location, const unsigned char *,
static void cb_ident (cpp_reader *, source_location, const cpp_string *);
static void cb_used_define (cpp_reader *, source_location, cpp_hashnode *);
static void cb_used_undef (cpp_reader *, source_location, cpp_hashnode *);
static bool cb_cpp_error (cpp_reader *, int, int, location_t, unsigned int,
static bool cb_cpp_error (cpp_reader *, int, int, rich_location *,
const char *, va_list *)
ATTRIBUTE_GCC_DIAG(6,0);
ATTRIBUTE_GCC_DIAG(5,0);
void pp_dir_change (cpp_reader *, const char *);
static int dump_macro (cpp_reader *, cpp_hashnode *, void *);
@ -1024,13 +1024,12 @@ cb_used_define (cpp_reader *pfile, source_location line ATTRIBUTE_UNUSED,
/* Callback from cpp_error for PFILE to print diagnostics from the
preprocessor. The diagnostic is of type LEVEL, with REASON set
to the reason code if LEVEL is represents a warning, at location
LOCATION, with column number possibly overridden by COLUMN_OVERRIDE
if not zero; MSG is the translated message and AP the arguments.
RICHLOC; MSG is the translated message and AP the arguments.
Returns true if a diagnostic was emitted, false otherwise. */
static bool
cb_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
location_t location, unsigned int column_override,
rich_location *richloc,
const char *msg, va_list *ap)
{
diagnostic_info diagnostic;
@ -1065,9 +1064,7 @@ cb_cpp_error (cpp_reader *pfile ATTRIBUTE_UNUSED, int level, int reason,
gcc_unreachable ();
}
diagnostic_set_info_translated (&diagnostic, msg, ap,
location, dlevel);
if (column_override)
diagnostic_override_column (&diagnostic, column_override);
richloc, dlevel);
if (reason == CPP_W_WARNING_DIRECTIVE)
diagnostic_override_option_index (&diagnostic, OPT_Wcpp);
ret = report_diagnostic (&diagnostic);

View File

@ -773,6 +773,7 @@ gfc_warning (int opt, const char *gmsgid, va_list ap)
va_copy (argp, ap);
diagnostic_info diagnostic;
rich_location rich_loc (UNKNOWN_LOCATION);
bool fatal_errors = global_dc->fatal_errors;
pretty_printer *pp = global_dc->printer;
output_buffer *tmp_buffer = pp->buffer;
@ -787,7 +788,7 @@ gfc_warning (int opt, const char *gmsgid, va_list ap)
--werrorcount;
}
diagnostic_set_info (&diagnostic, gmsgid, &argp, UNKNOWN_LOCATION,
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
DK_WARNING);
diagnostic.option_index = opt;
bool ret = report_diagnostic (&diagnostic);
@ -938,10 +939,12 @@ gfc_format_decoder (pretty_printer *pp,
/* If location[0] != UNKNOWN_LOCATION means that we already
processed one of %C/%L. */
int loc_num = text->get_location (0) == UNKNOWN_LOCATION ? 0 : 1;
text->set_location (loc_num,
linemap_position_for_loc_and_offset (line_table,
loc->lb->location,
offset));
source_range range
= source_range::from_location (
linemap_position_for_loc_and_offset (line_table,
loc->lb->location,
offset));
text->set_range (loc_num, range, true);
pp_string (pp, result[loc_num]);
return true;
}
@ -1024,48 +1027,21 @@ gfc_diagnostic_build_locus_prefix (diagnostic_context *context,
}
/* This function prints the locus (file:line:column), the diagnostic kind
(Error, Warning) and (optionally) the caret line (a source line
with '1' and/or '2' below it).
(Error, Warning) and (optionally) the relevant lines of code with
annotation lines with '1' and/or '2' below them.
With -fdiagnostic-show-caret (the default) and for valid locations,
it prints for one location:
With -fdiagnostic-show-caret (the default) it prints:
[locus]:
[locus of primary range]:
some code
1
Error: Some error at (1)
for two locations that fit in the same locus line:
With -fno-diagnostic-show-caret or if the primary range is not
valid, it prints:
[locus]:
some code and some more code
1 2
Error: Some error at (1) and (2)
and for two locations that do not fit in the same locus line:
[locus]:
some code
1
[locus2]:
some other code
2
Error: Some error at (1) and (2)
With -fno-diagnostic-show-caret or if one of the locations is not
valid, it prints for one location (or for two locations that fit in
the same locus line):
[locus]: Error: Some error at (1) and (2)
and for two locations that do not fit in the same locus line:
[name]:[locus]: Error: (1)
[name]:[locus2]: Error: Some error at (1) and (2)
[locus of primary range]: Error: Some error at (1) and (2)
*/
static void
gfc_diagnostic_starter (diagnostic_context *context,
@ -1075,7 +1051,7 @@ gfc_diagnostic_starter (diagnostic_context *context,
expanded_location s1 = diagnostic_expand_location (diagnostic);
expanded_location s2;
bool one_locus = diagnostic_location (diagnostic, 1) == UNKNOWN_LOCATION;
bool one_locus = diagnostic->richloc->get_num_locations () < 2;
bool same_locus = false;
if (!one_locus)
@ -1125,35 +1101,6 @@ gfc_diagnostic_starter (diagnostic_context *context,
/* If the caret line was shown, the prefix does not contain the
locus. */
pp_set_prefix (context->printer, kind_prefix);
if (one_locus || same_locus)
return;
locus_prefix = gfc_diagnostic_build_locus_prefix (context, s2);
if (diagnostic_location (diagnostic, 1) <= BUILTINS_LOCATION)
{
/* No caret line for the second location. Override the previous
prefix with [locus2]:[prefix]. */
pp_set_prefix (context->printer,
concat (locus_prefix, " ", kind_prefix, NULL));
free (kind_prefix);
free (locus_prefix);
}
else
{
/* We print the caret for the second location. */
pp_verbatim (context->printer, locus_prefix);
free (locus_prefix);
/* Fortran uses an empty line between locus and caret line. */
pp_newline (context->printer);
s1.column = 0; /* Print only a caret line for s2. */
diagnostic_print_caret_line (context, s2, s1,
context->caret_chars[1], '\0');
pp_newline (context->printer);
/* If the caret line was shown, the prefix does not contain the
locus. */
pp_set_prefix (context->printer, kind_prefix);
}
}
}
@ -1173,10 +1120,11 @@ gfc_warning_now_at (location_t loc, int opt, const char *gmsgid, ...)
{
va_list argp;
diagnostic_info diagnostic;
rich_location rich_loc (loc);
bool ret;
va_start (argp, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &argp, loc, DK_WARNING);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);
va_end (argp);
@ -1190,10 +1138,11 @@ gfc_warning_now (int opt, const char *gmsgid, ...)
{
va_list argp;
diagnostic_info diagnostic;
rich_location rich_loc (UNKNOWN_LOCATION);
bool ret;
va_start (argp, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &argp, UNKNOWN_LOCATION,
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
DK_WARNING);
diagnostic.option_index = opt;
ret = report_diagnostic (&diagnostic);
@ -1209,11 +1158,12 @@ gfc_error_now (const char *gmsgid, ...)
{
va_list argp;
diagnostic_info diagnostic;
rich_location rich_loc (UNKNOWN_LOCATION);
error_buffer.flag = true;
va_start (argp, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &argp, UNKNOWN_LOCATION, DK_ERROR);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR);
report_diagnostic (&diagnostic);
va_end (argp);
}
@ -1226,9 +1176,10 @@ gfc_fatal_error (const char *gmsgid, ...)
{
va_list argp;
diagnostic_info diagnostic;
rich_location rich_loc (UNKNOWN_LOCATION);
va_start (argp, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &argp, UNKNOWN_LOCATION, DK_FATAL);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL);
report_diagnostic (&diagnostic);
va_end (argp);
@ -1291,6 +1242,7 @@ gfc_error (const char *gmsgid, va_list ap)
}
diagnostic_info diagnostic;
rich_location richloc (UNKNOWN_LOCATION);
bool fatal_errors = global_dc->fatal_errors;
pretty_printer *pp = global_dc->printer;
output_buffer *tmp_buffer = pp->buffer;
@ -1306,7 +1258,7 @@ gfc_error (const char *gmsgid, va_list ap)
--errorcount;
}
diagnostic_set_info (&diagnostic, gmsgid, &argp, UNKNOWN_LOCATION, DK_ERROR);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR);
report_diagnostic (&diagnostic);
if (buffered_p)
@ -1336,9 +1288,10 @@ gfc_internal_error (const char *gmsgid, ...)
{
va_list argp;
diagnostic_info diagnostic;
rich_location rich_loc (UNKNOWN_LOCATION);
va_start (argp, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &argp, UNKNOWN_LOCATION, DK_ICE);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE);
report_diagnostic (&diagnostic);
va_end (argp);

View File

@ -53,14 +53,31 @@ unsigned verbose;
static struct line_maps *line_table;
/* The rich_location class within libcpp requires a way to expand
source_location instances, and relies on the client code
providing a symbol named
linemap_client_expand_location_to_spelling_point
to do this.
This is the implementation for genmatch. */
expanded_location
linemap_client_expand_location_to_spelling_point (source_location loc)
{
const struct line_map_ordinary *map;
loc = linemap_resolve_location (line_table, loc, LRK_SPELLING_LOCATION, &map);
return linemap_expand_location (line_table, map, loc);
}
static bool
#if GCC_VERSION >= 4001
__attribute__((format (printf, 6, 0)))
__attribute__((format (printf, 5, 0)))
#endif
error_cb (cpp_reader *, int errtype, int, source_location location,
unsigned int, const char *msg, va_list *ap)
error_cb (cpp_reader *, int errtype, int, rich_location *richloc,
const char *msg, va_list *ap)
{
const line_map_ordinary *map;
source_location location = richloc->get_loc ();
linemap_resolve_location (line_table, location, LRK_SPELLING_LOCATION, &map);
expanded_location loc = linemap_expand_location (line_table, map, location);
fprintf (stderr, "%s:%d:%d %s: ", loc.file, loc.line, loc.column,
@ -102,9 +119,10 @@ __attribute__((format (printf, 2, 3)))
#endif
fatal_at (const cpp_token *tk, const char *msg, ...)
{
rich_location richloc (tk->src_loc);
va_list ap;
va_start (ap, msg);
error_cb (NULL, CPP_DL_FATAL, 0, tk->src_loc, 0, msg, &ap);
error_cb (NULL, CPP_DL_FATAL, 0, &richloc, msg, &ap);
va_end (ap);
}
@ -114,9 +132,10 @@ __attribute__((format (printf, 2, 3)))
#endif
fatal_at (source_location loc, const char *msg, ...)
{
rich_location richloc (loc);
va_list ap;
va_start (ap, msg);
error_cb (NULL, CPP_DL_FATAL, 0, loc, 0, msg, &ap);
error_cb (NULL, CPP_DL_FATAL, 0, &richloc, msg, &ap);
va_end (ap);
}
@ -126,9 +145,10 @@ __attribute__((format (printf, 2, 3)))
#endif
warning_at (const cpp_token *tk, const char *msg, ...)
{
rich_location richloc (tk->src_loc);
va_list ap;
va_start (ap, msg);
error_cb (NULL, CPP_DL_WARNING, 0, tk->src_loc, 0, msg, &ap);
error_cb (NULL, CPP_DL_WARNING, 0, &richloc, msg, &ap);
va_end (ap);
}
@ -138,9 +158,10 @@ __attribute__((format (printf, 2, 3)))
#endif
warning_at (source_location loc, const char *msg, ...)
{
rich_location richloc (loc);
va_list ap;
va_start (ap, msg);
error_cb (NULL, CPP_DL_WARNING, 0, loc, 0, msg, &ap);
error_cb (NULL, CPP_DL_WARNING, 0, &richloc, msg, &ap);
va_end (ap);
}

View File

@ -751,6 +751,22 @@ expand_location_to_spelling_point (source_location loc)
return expand_location_1 (loc, /*expansion_point_p=*/false);
}
/* The rich_location class within libcpp requires a way to expand
source_location instances, and relies on the client code
providing a symbol named
linemap_client_expand_location_to_spelling_point
to do this.
This is the implementation for libcommon.a (all host binaries),
which simply calls into expand_location_to_spelling_point. */
expanded_location
linemap_client_expand_location_to_spelling_point (source_location loc)
{
return expand_location_to_spelling_point (loc);
}
/* If LOCATION is in a system header and if it is a virtual location for
a token coming from the expansion of a macro, unwind it to the
location of the expansion point of the macro. Otherwise, just return

View File

@ -31,6 +31,27 @@ along with GCC; see the file COPYING3. If not see
#include <iconv.h>
#endif
/* Overwrite the range within this text_info's rich_location.
For use e.g. when implementing "+" in client format decoders. */
void
text_info::set_range (unsigned int idx, source_range range, bool caret_p)
{
gcc_checking_assert (m_richloc);
m_richloc->set_range (idx, range, caret_p, true);
}
location_t
text_info::get_location (unsigned int index_of_location) const
{
gcc_checking_assert (m_richloc);
if (index_of_location == 0)
return m_richloc->get_loc ();
else
return UNKNOWN_LOCATION;
}
// Default construct an output buffer.
output_buffer::output_buffer ()

View File

@ -27,11 +27,6 @@ along with GCC; see the file COPYING3. If not see
/* Maximum number of format string arguments. */
#define PP_NL_ARGMAX 30
/* Maximum number of locations associated to each message. If
location 'i' is UNKNOWN_LOCATION, then location 'i+1' is not
valid. */
#define MAX_LOCATIONS_PER_MESSAGE 2
/* The type of a text to be formatted according a format specification
along with a list of things. */
struct text_info
@ -40,21 +35,17 @@ struct text_info
va_list *args_ptr;
int err_no; /* for %m */
void **x_data;
rich_location *m_richloc;
inline void set_location (unsigned int index_of_location, location_t loc)
inline void set_location (unsigned int idx, location_t loc, bool caret_p)
{
gcc_checking_assert (index_of_location < MAX_LOCATIONS_PER_MESSAGE);
this->locations[index_of_location] = loc;
source_range src_range;
src_range.m_start = loc;
src_range.m_finish = loc;
set_range (idx, src_range, caret_p);
}
inline location_t get_location (unsigned int index_of_location) const
{
gcc_checking_assert (index_of_location < MAX_LOCATIONS_PER_MESSAGE);
return this->locations[index_of_location];
}
private:
location_t locations[MAX_LOCATIONS_PER_MESSAGE];
void set_range (unsigned int idx, source_range range, bool caret_p);
location_t get_location (unsigned int index_of_location) const;
};
/* How often diagnostics are prefixed by their locations:

View File

@ -67,9 +67,10 @@ diagnostic_for_asm (const rtx_insn *insn, const char *msg, va_list *args_ptr,
diagnostic_t kind)
{
diagnostic_info diagnostic;
rich_location richloc (location_for_asm (insn));
diagnostic_set_info (&diagnostic, msg, args_ptr,
location_for_asm (insn), kind);
&richloc, kind);
report_diagnostic (&diagnostic);
}

View File

@ -1,3 +1,11 @@
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* gcc.dg/plugin/diagnostic-test-show-locus-bw.c: New file.
* gcc.dg/plugin/diagnostic-test-show-locus-color.c: New file.
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c: New file.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add the above.
* lib/gcc-dg.exp: Load multiline.exp.
2015-11-06 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
* gcc.target/arm/combine-movs.c: Adjust for unified asm.

View File

@ -0,0 +1,149 @@
/* { dg-do compile } */
/* { dg-options "-O -fdiagnostics-show-caret" } */
/* This is a collection of unittests for diagnostic_show_locus;
see the overview in diagnostic_plugin_test_show_locus.c.
In particular, note the discussion of why we need a very long line here:
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
and that we can't use macros in this file. */
void test_simple (void)
{
#if 0
myvar = myvar.x; /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
myvar = myvar.x;
~~~~~^~
{ dg-end-multiline-output "" } */
#endif
}
void test_simple_2 (void)
{
#if 0
x = first_function () + second_function (); /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
x = first_function () + second_function ();
~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
#endif
}
void test_multiline (void)
{
#if 0
x = (first_function ()
+ second_function ()); /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
x = (first_function ()
~~~~~~~~~~~~~~~~~
+ second_function ());
^ ~~~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
#endif
}
void test_many_lines (void)
{
#if 0
x = (first_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,
consectetur, adipiscing, elit,
sed, eiusmod, tempor,
incididunt, ut, labore, et,
dolore, magna, aliqua)
+ second_function_with_a_very_long_name (lorem, ipsum, dolor, sit, /* { dg-warning "test" } */
amet, consectetur,
adipiscing, elit, sed,
eiusmod, tempor, incididunt,
ut, labore, et, dolore,
magna, aliqua));
/* { dg-begin-multiline-output "" }
x = (first_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
consectetur, adipiscing, elit,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sed, eiusmod, tempor,
~~~~~~~~~~~~~~~~~~~~~
incididunt, ut, labore, et,
~~~~~~~~~~~~~~~~~~~~~~~~~~~
dolore, magna, aliqua)
~~~~~~~~~~~~~~~~~~~~~~
+ second_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
amet, consectetur,
~~~~~~~~~~~~~~~~~~
adipiscing, elit, sed,
~~~~~~~~~~~~~~~~~~~~~~
eiusmod, tempor, incididunt,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ut, labore, et, dolore,
~~~~~~~~~~~~~~~~~~~~~~~
magna, aliqua));
~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
#endif
}
void test_richloc_from_proper_range (void)
{
#if 0
float f = 98.6f; /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
float f = 98.6f;
^~~~~
{ dg-end-multiline-output "" } */
#endif
}
void test_caret_within_proper_range (void)
{
#if 0
float f = foo * bar; /* { dg-warning "17: test" } */
/* { dg-begin-multiline-output "" }
float f = foo * bar;
~~~~^~~~~
{ dg-end-multiline-output "" } */
#endif
}
void test_very_wide_line (void)
{
#if 0
float f = foo * bar; /* { dg-warning "95: test" } */
/* { dg-begin-multiline-output "" }
float f = foo * bar;
~~~~^~~~~
{ dg-end-multiline-output "" } */
#endif
}
void test_multiple_carets (void)
{
#if 0
x = x + y /* { dg-warning "8: test" } */
/* { dg-begin-multiline-output "" }
x = x + y
A B
{ dg-end-multiline-output "" } */
#endif
}
void test_caret_on_leading_whitespace (void)
{
#if 0
ASSOCIATE (y => x)
y = 5 /* { dg-warning "6: test" } */
/* { dg-begin-multiline-output "" }
ASSOCIATE (y => x)
2
y = 5
1
{ dg-end-multiline-output "" } */
#endif
}

View File

@ -0,0 +1,158 @@
/* { dg-do compile } */
/* { dg-options "-O -fdiagnostics-show-caret -fplugin-arg-diagnostic_plugin_test_show_locus-color" } */
/* This is a collection of unittests for diagnostic_show_locus;
see the overview in diagnostic_plugin_test_show_locus.c.
In particular, note the discussion of why we need a very long line here:
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
and that we can't use macros in this file. */
void test_simple (void)
{
#if 0
myvar = myvar.x; /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
myvar = myvar.x;
~~~~~^~

{ dg-end-multiline-output "" } */
#endif
}
void test_simple_2 (void)
{
#if 0
x = first_function () + second_function (); /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
x = first_function () + second_function ();
~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~

{ dg-end-multiline-output "" } */
#endif
}
void test_multiline (void)
{
#if 0
x = (first_function ()
+ second_function ()); /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
x = (first_function ()
 ~~~~~~~~~~~~~~~~~
 + second_function ());
^ ~~~~~~~~~~~~~~~~~~

{ dg-end-multiline-output "" } */
#endif
}
void test_many_lines (void)
{
#if 0
x = (first_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,
consectetur, adipiscing, elit,
sed, eiusmod, tempor,
incididunt, ut, labore, et,
dolore, magna, aliqua)
+ second_function_with_a_very_long_name (lorem, ipsum, dolor, sit, /* { dg-warning "test" } */
amet, consectetur,
adipiscing, elit, sed,
eiusmod, tempor, incididunt,
ut, labore, et, dolore,
magna, aliqua));
/* { dg-begin-multiline-output "" }
x = (first_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  consectetur, adipiscing, elit,
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sed, eiusmod, tempor,
 ~~~~~~~~~~~~~~~~~~~~~
  incididunt, ut, labore, et,
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  dolore, magna, aliqua)
 ~~~~~~~~~~~~~~~~~~~~~~
 + second_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
 ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  amet, consectetur,
 ~~~~~~~~~~~~~~~~~~
  adipiscing, elit, sed,
 ~~~~~~~~~~~~~~~~~~~~~~
  eiusmod, tempor, incididunt,
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ut, labore, et, dolore,
 ~~~~~~~~~~~~~~~~~~~~~~~
  magna, aliqua));
~~~~~~~~~~~~~~

{ dg-end-multiline-output "" } */
#endif
}
void test_richloc_from_proper_range (void)
{
#if 0
float f = 98.6f; /* { dg-warning "test" } */
/* { dg-begin-multiline-output "" }
float f = 98.6f;
^~~~~

{ dg-end-multiline-output "" } */
#endif
}
void test_caret_within_proper_range (void)
{
#if 0
float f = foo * bar; /* { dg-warning "17: test" } */
/* { dg-begin-multiline-output "" }
float f = foo * bar;
~~~~^~~~~

{ dg-end-multiline-output "" } */
#endif
}
void test_very_wide_line (void)
{
#if 0
float f = foo * bar; /* { dg-warning "95: test" } */
/* { dg-begin-multiline-output "" }
float f = foo * bar;
~~~~^~~~~

{ dg-end-multiline-output "" } */
#endif
}
void test_multiple_carets (void)
{
#if 0
x = x + y /* { dg-warning "8: test" } */
/* { dg-begin-multiline-output "" }
x = x + y
A B

{ dg-end-multiline-output "" } */
#endif
}
void test_caret_on_leading_whitespace (void)
{
#if 0
ASSOCIATE (y => x)
y = 5 /* { dg-warning "6: test" } */
/* { dg-begin-multiline-output "" }
ASSOCIATE (y => x)
2
  y = 5
1

{ dg-end-multiline-output "" } */
#endif
}

View File

@ -0,0 +1,326 @@
/* { dg-options "-O" } */
/* This plugin exercises the diagnostics-printing code.
The goal is to unit-test the range-printing code without needing any
correct range data within the compiler's IR. We can't use any real
diagnostics for this, so we have to fake it, hence this plugin.
There are two test files used with this code:
diagnostic-test-show-locus-ascii-bw.c
..........................-ascii-color.c
to exercise uncolored vs colored output by supplying plugin arguments
to hack in the desired behavior:
-fplugin-arg-diagnostic_plugin_test_show_locus-color
The test files contain functions, but the body of each
function is disabled using the preprocessor. The plugin detects
the functions by name, and inject diagnostics within them, using
hard-coded locations relative to the top of each function.
The plugin uses a function "get_loc" below to map from line/column
numbers to source_location, and this relies on input_location being in
the same ordinary line_map as the locations in question. The plugin
runs after parsing, so input_location will be at the end of the file.
This need for all of the test code to be in a single ordinary line map
means that each test file needs to have a very long line near the top
(potentially to cover the extra byte-count of colorized data),
to ensure that further very long lines don't start a new linemap.
This also means that we can't use macros in the test files. */
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "stringpool.h"
#include "toplev.h"
#include "basic-block.h"
#include "hash-table.h"
#include "vec.h"
#include "ggc.h"
#include "basic-block.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-fold.h"
#include "tree-eh.h"
#include "gimple-expr.h"
#include "is-a.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "tree.h"
#include "tree-pass.h"
#include "intl.h"
#include "plugin-version.h"
#include "diagnostic.h"
#include "context.h"
#include "print-tree.h"
int plugin_is_GPL_compatible;
const pass_data pass_data_test_show_locus =
{
GIMPLE_PASS, /* type */
"test_show_locus", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_ssa, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
};
class pass_test_show_locus : public gimple_opt_pass
{
public:
pass_test_show_locus(gcc::context *ctxt)
: gimple_opt_pass(pass_data_test_show_locus, ctxt)
{}
/* opt_pass methods: */
bool gate (function *) { return true; }
virtual unsigned int execute (function *);
}; // class pass_test_show_locus
/* Given LINE_NUM and COL_NUM, generate a source_location in the
current file, relative to input_location. This relies on the
location being expressible in the same ordinary line_map as
input_location (which is typically at the end of the source file
when this is called). Hence the test files we compile with this
plugin must have an initial very long line (to avoid long lines
starting a new line map), and must not use macros.
COL_NUM uses the Emacs convention of 0-based column numbers. */
static source_location
get_loc (unsigned int line_num, unsigned int col_num)
{
/* Use input_location to get the relevant line_map */
const struct line_map_ordinary *line_map
= (const line_map_ordinary *)(linemap_lookup (line_table,
input_location));
/* Convert from 0-based column numbers to 1-based column numbers. */
source_location loc
= linemap_position_for_line_and_column (line_map,
line_num, col_num + 1);
return loc;
}
/* Was "color" passed in as a plugin argument? */
static bool force_show_locus_color = false;
/* We want to verify the colorized output of diagnostic_show_locus,
but turning on colorization for everything confuses "dg-warning" etc.
Hence we special-case it within this plugin by using this modified
version of default_diagnostic_finalizer, which, if "color" is
passed in as a plugin argument turns on colorization, but just
for diagnostic_show_locus. */
static void
custom_diagnostic_finalizer (diagnostic_context *context,
diagnostic_info *diagnostic)
{
bool old_show_color = pp_show_color (context->printer);
if (force_show_locus_color)
pp_show_color (context->printer) = true;
diagnostic_show_locus (context, diagnostic);
pp_show_color (context->printer) = old_show_color;
pp_destroy_prefix (context->printer);
pp_newline_and_flush (context->printer);
}
/* Exercise the diagnostic machinery to emit various warnings,
for use by diagnostic-test-show-locus-*.c.
We inject each warning relative to the start of a function,
which avoids lots of hardcoded absolute locations. */
static void
test_show_locus (function *fun)
{
tree fndecl = fun->decl;
tree identifier = DECL_NAME (fndecl);
const char *fnname = IDENTIFIER_POINTER (identifier);
location_t fnstart = fun->function_start_locus;
int fnstart_line = LOCATION_LINE (fnstart);
diagnostic_finalizer (global_dc) = custom_diagnostic_finalizer;
/* Hardcode the "terminal width", to verify the behavior of
very wide lines. */
global_dc->caret_max_width = 70;
if (0 == strcmp (fnname, "test_simple"))
{
const int line = fnstart_line + 2;
rich_location richloc (get_loc (line, 15));
richloc.add_range (get_loc (line, 10), get_loc (line, 14), false);
richloc.add_range (get_loc (line, 16), get_loc (line, 16), false);
warning_at_rich_loc (&richloc, 0, "test");
}
if (0 == strcmp (fnname, "test_simple_2"))
{
const int line = fnstart_line + 2;
rich_location richloc (get_loc (line, 24));
richloc.add_range (get_loc (line, 6),
get_loc (line, 22), false);
richloc.add_range (get_loc (line, 26),
get_loc (line, 43), false);
warning_at_rich_loc (&richloc, 0, "test");
}
if (0 == strcmp (fnname, "test_multiline"))
{
const int line = fnstart_line + 2;
rich_location richloc (get_loc (line + 1, 7));
richloc.add_range (get_loc (line, 7),
get_loc (line, 23), false);
richloc.add_range (get_loc (line + 1, 9),
get_loc (line + 1, 26), false);
warning_at_rich_loc (&richloc, 0, "test");
}
if (0 == strcmp (fnname, "test_many_lines"))
{
const int line = fnstart_line + 2;
rich_location richloc (get_loc (line + 5, 7));
richloc.add_range (get_loc (line, 7),
get_loc (line + 4, 65), false);
richloc.add_range (get_loc (line + 5, 9),
get_loc (line + 10, 61), false);
warning_at_rich_loc (&richloc, 0, "test");
}
/* Example of a rich_location constructed directly from a
source_range where the range is larger than one character. */
if (0 == strcmp (fnname, "test_richloc_from_proper_range"))
{
const int line = fnstart_line + 2;
source_range src_range;
src_range.m_start = get_loc (line, 12);
src_range.m_finish = get_loc (line, 16);
rich_location richloc (src_range);
warning_at_rich_loc (&richloc, 0, "test");
}
/* Example of a single-range location where the range starts
before the caret. */
if (0 == strcmp (fnname, "test_caret_within_proper_range"))
{
const int line = fnstart_line + 2;
location_t caret = get_loc (line, 16);
source_range src_range;
src_range.m_start = get_loc (line, 12);
src_range.m_finish = get_loc (line, 20);
rich_location richloc (caret);
richloc.set_range (0, src_range, true, false);
warning_at_rich_loc (&richloc, 0, "test");
}
/* Example of a very wide line, where the information of interest
is beyond the width of the terminal (hardcoded above). */
if (0 == strcmp (fnname, "test_very_wide_line"))
{
const int line = fnstart_line + 2;
location_t caret = get_loc (line, 94);
source_range src_range;
src_range.m_start = get_loc (line, 90);
src_range.m_finish = get_loc (line, 98);
rich_location richloc (caret);
richloc.set_range (0, src_range, true, false);
warning_at_rich_loc (&richloc, 0, "test");
}
/* Example of multiple carets. */
if (0 == strcmp (fnname, "test_multiple_carets"))
{
const int line = fnstart_line + 2;
location_t caret_a = get_loc (line, 7);
location_t caret_b = get_loc (line, 11);
rich_location richloc (caret_a);
richloc.add_range (caret_b, caret_b, true);
global_dc->caret_chars[0] = 'A';
global_dc->caret_chars[1] = 'B';
warning_at_rich_loc (&richloc, 0, "test");
global_dc->caret_chars[0] = '^';
global_dc->caret_chars[1] = '^';
}
/* Example of two carets where both carets appear to have an off-by-one
error appearing one column early.
Seen with gfortran.dg/associate_5.f03.
In an earlier version of the printer, the printing of caret 0 aka
"1" was suppressed due to it appearing within the leading whitespace
before the text in its line. Ensure that we at least faithfully
print both carets, at the given (erroneous) locations. */
if (0 == strcmp (fnname, "test_caret_on_leading_whitespace"))
{
const int line = fnstart_line + 3;
location_t caret_a = get_loc (line, 5);
location_t caret_b = get_loc (line - 1, 19);
rich_location richloc (caret_a);
richloc.add_range (caret_b, caret_b, true);
global_dc->caret_chars[0] = '1';
global_dc->caret_chars[1] = '2';
warning_at_rich_loc (&richloc, 0, "test");
global_dc->caret_chars[0] = '^';
global_dc->caret_chars[1] = '^';
}
}
unsigned int
pass_test_show_locus::execute (function *fun)
{
test_show_locus (fun);
return 0;
}
static gimple_opt_pass *
make_pass_test_show_locus (gcc::context *ctxt)
{
return new pass_test_show_locus (ctxt);
}
int
plugin_init (struct plugin_name_args *plugin_info,
struct plugin_gcc_version *version)
{
struct register_pass_info pass_info;
const char *plugin_name = plugin_info->base_name;
int argc = plugin_info->argc;
struct plugin_argument *argv = plugin_info->argv;
if (!plugin_default_version_check (version, &gcc_version))
return 1;
/* For now, tell the dc to expect ranges and thus to colorize the source
lines, not just the carets/underlines. This will be redundant
once the C frontend generates ranges. */
global_dc->colorize_source_p = true;
for (int i = 0; i < argc; i++)
{
if (0 == strcmp (argv[i].key, "color"))
force_show_locus_color = true;
}
pass_info.pass = make_pass_test_show_locus (g);
pass_info.reference_pass_name = "ssa";
pass_info.ref_pass_instance_number = 1;
pass_info.pos_op = PASS_POS_INSERT_AFTER;
register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
&pass_info);
return 0;
}

View File

@ -63,6 +63,9 @@ set plugin_test_list [list \
{ start_unit_plugin.c start_unit-test-1.c } \
{ finish_unit_plugin.c finish_unit-test-1.c } \
{ wide-int_plugin.c wide-int-test-1.c } \
{ diagnostic_plugin_test_show_locus.c \
diagnostic-test-show-locus-bw.c \
diagnostic-test-show-locus-color.c } \
]
foreach plugin_test $plugin_test_list {

View File

@ -29,6 +29,7 @@ load_lib libgloss.exp
load_lib target-libpath.exp
load_lib torture-options.exp
load_lib fortran-modules.exp
load_lib multiline.exp
# We set LC_ALL and LANG to C so that we get the same error messages as expected.
setenv LC_ALL C

View File

@ -286,7 +286,7 @@ default_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
}
if (set_locus)
text->set_location (0, DECL_SOURCE_LOCATION (t));
text->set_location (0, DECL_SOURCE_LOCATION (t), true);
if (DECL_P (t))
{

View File

@ -3770,7 +3770,7 @@ void
percent_K_format (text_info *text)
{
tree t = va_arg (*text->args_ptr, tree), block;
text->set_location (0, EXPR_LOCATION (t));
text->set_location (0, EXPR_LOCATION (t), true);
gcc_assert (pp_ti_abstract_origin (text) != NULL);
block = TREE_BLOCK (t);
*pp_ti_abstract_origin (text) = NULL;

View File

@ -1,3 +1,22 @@
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* errors.c (cpp_diagnostic): Update for change in signature
of "error" callback.
(cpp_diagnostic_with_line): Likewise, calling override_column
on the rich_location.
* include/cpplib.h (struct cpp_callbacks): Within "error"
callback, convert param from source_location to rich_location *,
and drop column_override param.
* include/line-map.h (struct source_range): New struct.
(struct location_range): New struct.
(class rich_location): New class.
(linemap_client_expand_location_to_spelling_point): New declaration.
* line-map.c (rich_location::rich_location): New ctors.
(rich_location::lazily_expand_location): New method.
(rich_location::override_column): New method.
(rich_location::add_range): New methods.
(rich_location::set_range): New method.
2015-11-06 David Malcolm <dmalcolm@redhat.com>
* include/line-map.h (struct linemap_stats): Add fields

View File

@ -57,7 +57,8 @@ cpp_diagnostic (cpp_reader * pfile, int level, int reason,
if (!pfile->cb.error)
abort ();
ret = pfile->cb.error (pfile, level, reason, src_loc, 0, _(msgid), ap);
rich_location richloc (src_loc);
ret = pfile->cb.error (pfile, level, reason, &richloc, _(msgid), ap);
return ret;
}
@ -139,7 +140,9 @@ cpp_diagnostic_with_line (cpp_reader * pfile, int level, int reason,
if (!pfile->cb.error)
abort ();
ret = pfile->cb.error (pfile, level, reason, src_loc, column, _(msgid), ap);
rich_location richloc (src_loc);
richloc.override_column (column);
ret = pfile->cb.error (pfile, level, reason, &richloc, _(msgid), ap);
return ret;
}

View File

@ -573,9 +573,9 @@ struct cpp_callbacks
/* Called to emit a diagnostic. This callback receives the
translated message. */
bool (*error) (cpp_reader *, int, int, source_location, unsigned int,
bool (*error) (cpp_reader *, int, int, rich_location *,
const char *, va_list *)
ATTRIBUTE_FPTR_PRINTF(6,0);
ATTRIBUTE_FPTR_PRINTF(5,0);
/* Callbacks for when a macro is expanded, or tested (whether
defined or not at the time) in #ifdef, #ifndef or "defined". */

View File

@ -131,6 +131,47 @@ typedef unsigned int linenum_type;
libcpp/location-example.txt. */
typedef unsigned int source_location;
/* A range of source locations.
Ranges are closed:
m_start is the first location within the range,
m_finish is the last location within the range.
We may need a more compact way to store these, but for now,
let's do it the simple way, as a pair. */
struct GTY(()) source_range
{
source_location m_start;
source_location m_finish;
/* Display this source_range instance, with MSG as a descriptive
comment. This issues a "note" diagnostic at the range, using
gcc's diagnostic machinery.
This is declared here, but is implemented within gcc/diagnostic.c,
since it makes use of gcc's diagnostic-printing machinery. This
is a slight layering violation, but this is sufficiently useful
for debugging that it's worth it.
This declaration would have a DEBUG_FUNCTION annotation, but that
is implemented in gcc/system.h and thus is not available here in
libcpp. */
void debug (const char *msg) const;
/* We avoid using constructors, since various structs that
don't yet have constructors will embed instances of
source_range. */
/* Make a source_range from a source_location. */
static source_range from_location (source_location loc)
{
source_range result;
result.m_start = loc;
result.m_finish = loc;
return result;
}
};
/* Memory allocation function typedef. Works like xrealloc. */
typedef void *(*line_map_realloc) (void *, size_t);
@ -1028,6 +1069,174 @@ typedef struct
bool sysp;
} expanded_location;
/* Both gcc and emacs number source *lines* starting at 1, but
they have differing conventions for *columns*.
GCC uses a 1-based convention for source columns,
whereas Emacs's M-x column-number-mode uses a 0-based convention.
For example, an error in the initial, left-hand
column of source line 3 is reported by GCC as:
some-file.c:3:1: error: ...etc...
On navigating to the location of that error in Emacs
(e.g. via "next-error"),
the locus is reported in the Mode Line
(assuming M-x column-number-mode) as:
some-file.c 10% (3, 0)
i.e. "3:1:" in GCC corresponds to "(3, 0)" in Emacs. */
/* Ranges are closed
m_start is the first location within the range, and
m_finish is the last location within the range. */
struct location_range
{
expanded_location m_start;
expanded_location m_finish;
/* Should a caret be drawn for this range? Typically this is
true for the 0th range, and false for subsequent ranges,
but the Fortran frontend overrides this for rendering things like:
x = x + y
1 2
Error: Shapes for operands at (1) and (2) are not conformable
where "1" and "2" are notionally carets. */
bool m_show_caret_p;
expanded_location m_caret;
};
/* A "rich" source code location, for use when printing diagnostics.
A rich_location has one or more ranges, each optionally with
a caret. Typically the zeroth range has a caret; other ranges
sometimes have carets.
The "primary" location of a rich_location is the caret of range 0,
used for determining the line/column when printing diagnostic
text, such as:
some-file.c:3:1: error: ...etc...
Additional ranges may be added to help the user identify other
pertinent clauses in a diagnostic.
rich_location instances are intended to be allocated on the stack
when generating diagnostics, and to be short-lived.
Examples of rich locations
--------------------------
Example A
*********
int i = "foo";
^
This "rich" location is simply a single range (range 0), with
caret = start = finish at the given point.
Example B
*********
a = (foo && bar)
~~~~~^~~~~~~
This rich location has a single range (range 0), with the caret
at the first "&", and the start/finish at the parentheses.
Compare with example C below.
Example C
*********
a = (foo && bar)
~~~ ^~ ~~~
This rich location has three ranges:
- Range 0 has its caret and start location at the first "&" and
end at the second "&.
- Range 1 has its start and finish at the "f" and "o" of "foo";
the caret is not flagged for display, but is perhaps at the "f"
of "foo".
- Similarly, range 2 has its start and finish at the "b" and "r" of
"bar"; the caret is not flagged for display, but is perhaps at the
"b" of "bar".
Compare with example B above.
Example D (Fortran frontend)
****************************
x = x + y
1 2
This rich location has range 0 at "1", and range 1 at "2".
Both are flagged for caret display. Both ranges have start/finish
equal to their caret point. The frontend overrides the diagnostic
context's default caret character for these ranges.
Example E
*********
printf ("arg0: %i arg1: %s arg2: %i",
^~
100, 101, 102);
~~~
This rich location has two ranges:
- range 0 is at the "%s" with start = caret = "%" and finish at
the "s".
- range 1 has start/finish covering the "101" and is not flagged for
caret printing; it is perhaps at the start of "101". */
class rich_location
{
public:
/* Constructors. */
/* Constructing from a location. */
rich_location (source_location loc);
/* Constructing from a source_range. */
rich_location (source_range src_range);
/* Accessors. */
source_location get_loc () const { return m_loc; }
source_location *get_loc_addr () { return &m_loc; }
void
add_range (source_location start, source_location finish,
bool show_caret_p);
void
add_range (source_range src_range, bool show_caret_p);
void
add_range (location_range *src_range);
void
set_range (unsigned int idx, source_range src_range,
bool show_caret_p, bool overwrite_loc_p);
unsigned int get_num_locations () const { return m_num_ranges; }
location_range *get_range (unsigned int idx)
{
linemap_assert (idx < m_num_ranges);
return &m_ranges[idx];
}
expanded_location lazily_expand_location ();
void
override_column (int column);
public:
static const int MAX_RANGES = 3;
protected:
source_location m_loc;
unsigned int m_num_ranges;
location_range m_ranges[MAX_RANGES];
bool m_have_expanded_location;
expanded_location m_expanded_location;
};
/* This is enum is used by the function linemap_resolve_location
below. The meaning of the values is explained in the comment of
that function. */
@ -1173,4 +1382,13 @@ void linemap_dump (FILE *, struct line_maps *, unsigned, bool);
specifies how many macro maps to dump. */
void line_table_dump (FILE *, struct line_maps *, unsigned int, unsigned int);
/* The rich_location class requires a way to expand source_location instances.
We would directly use expand_location_to_spelling_point, which is
implemented in gcc/input.c, but we also need to use it for rich_location
within genmatch.c.
Hence we require client code of libcpp to implement the following
symbol. */
extern expanded_location
linemap_client_expand_location_to_spelling_point (source_location );
#endif /* !LIBCPP_LINE_MAP_H */

View File

@ -1755,3 +1755,133 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
fprintf (stream, "\n");
}
}
/* class rich_location. */
/* Construct a rich_location with location LOC as its initial range. */
rich_location::rich_location (source_location loc) :
m_loc (loc),
m_num_ranges (0),
m_have_expanded_location (false)
{
/* Set up the 0th range: */
add_range (loc, loc, true);
m_ranges[0].m_caret = lazily_expand_location ();
}
/* Construct a rich_location with source_range SRC_RANGE as its
initial range. */
rich_location::rich_location (source_range src_range)
: m_loc (src_range.m_start),
m_num_ranges (0),
m_have_expanded_location (false)
{
/* Set up the 0th range: */
add_range (src_range, true);
}
/* Get an expanded_location for this rich_location's primary
location. */
expanded_location
rich_location::lazily_expand_location ()
{
if (!m_have_expanded_location)
{
m_expanded_location
= linemap_client_expand_location_to_spelling_point (m_loc);
m_have_expanded_location = true;
}
return m_expanded_location;
}
/* Set the column of the primary location. */
void
rich_location::override_column (int column)
{
lazily_expand_location ();
m_expanded_location.column = column;
}
/* Add the given range. */
void
rich_location::add_range (source_location start, source_location finish,
bool show_caret_p)
{
linemap_assert (m_num_ranges < MAX_RANGES);
location_range *range = &m_ranges[m_num_ranges++];
range->m_start = linemap_client_expand_location_to_spelling_point (start);
range->m_finish = linemap_client_expand_location_to_spelling_point (finish);
range->m_caret = range->m_start;
range->m_show_caret_p = show_caret_p;
}
/* Add the given range. */
void
rich_location::add_range (source_range src_range, bool show_caret_p)
{
linemap_assert (m_num_ranges < MAX_RANGES);
add_range (src_range.m_start, src_range.m_finish, show_caret_p);
}
void
rich_location::add_range (location_range *src_range)
{
linemap_assert (m_num_ranges < MAX_RANGES);
m_ranges[m_num_ranges++] = *src_range;
}
/* Add or overwrite the range given by IDX. It must either
overwrite an existing range, or add one *exactly* on the end of
the array.
This is primarily for use by gcc when implementing diagnostic
format decoders e.g. the "+" in the C/C++ frontends, for handling
format codes like "%q+D" (which writes the source location of a
tree back into range 0 of the rich_location).
If SHOW_CARET_P is true, then the range should be rendered with
a caret at its starting location. This
is for use by the Fortran frontend, for implementing the
"%C" and "%L" format codes. */
void
rich_location::set_range (unsigned int idx, source_range src_range,
bool show_caret_p, bool overwrite_loc_p)
{
linemap_assert (idx < MAX_RANGES);
/* We can either overwrite an existing range, or add one exactly
on the end of the array. */
linemap_assert (idx <= m_num_ranges);
location_range *locrange = &m_ranges[idx];
locrange->m_start
= linemap_client_expand_location_to_spelling_point (src_range.m_start);
locrange->m_finish
= linemap_client_expand_location_to_spelling_point (src_range.m_finish);
locrange->m_show_caret_p = show_caret_p;
if (overwrite_loc_p)
locrange->m_caret = locrange->m_start;
/* Are we adding a range onto the end? */
if (idx == m_num_ranges)
m_num_ranges = idx + 1;
if (idx == 0 && overwrite_loc_p)
{
m_loc = src_range.m_start;
/* Mark any cached value here as dirty. */
m_have_expanded_location = false;
}
}