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:
parent
277ec793cb
commit
8a64515099
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
202
gcc/diagnostic.c
202
gcc/diagnostic.c
@ -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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
16
gcc/input.c
16
gcc/input.c
@ -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
|
||||
|
@ -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 ()
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
149
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
Normal file
149
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
Normal 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
|
||||
}
|
158
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
Normal file
158
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
Normal 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 = [32m[Kmyvar[m[K[01;35m[K.[m[K[34m[Kx[m[K;
|
||||
[32m[K~~~~~[m[K[01;35m[K^[m[K[34m[K~
|
||||
[m[K
|
||||
{ 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 = [32m[Kfirst_function ()[m[K [01;35m[K+[m[K [34m[Ksecond_function ()[m[K;
|
||||
[32m[K~~~~~~~~~~~~~~~~~[m[K [01;35m[K^[m[K [34m[K~~~~~~~~~~~~~~~~~~
|
||||
[m[K
|
||||
{ dg-end-multiline-output "" } */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void test_multiline (void)
|
||||
{
|
||||
#if 0
|
||||
x = (first_function ()
|
||||
+ second_function ()); /* { dg-warning "test" } */
|
||||
|
||||
/* { dg-begin-multiline-output "" }
|
||||
x = ([32m[Kfirst_function ()
|
||||
[m[K [32m[K~~~~~~~~~~~~~~~~~
|
||||
[m[K [01;35m[K+[m[K [34m[Ksecond_function ()[m[K);
|
||||
[01;35m[K^[m[K [34m[K~~~~~~~~~~~~~~~~~~
|
||||
[m[K
|
||||
{ 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 = ([32m[Kfirst_function_with_a_very_long_name (lorem, ipsum, dolor, sit, amet,
|
||||
[m[K [32m[K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [32m[K consectetur, adipiscing, elit,
|
||||
[m[K [32m[K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [32m[K sed, eiusmod, tempor,
|
||||
[m[K [32m[K~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [32m[K incididunt, ut, labore, et,
|
||||
[m[K [32m[K~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [32m[K dolore, magna, aliqua)
|
||||
[m[K [32m[K~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [01;35m[K+[m[K [34m[Ksecond_function_with_a_very_long_name (lorem, ipsum, dolor, sit,
|
||||
[m[K [01;35m[K^[m[K [34m[K~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [34m[K amet, consectetur,
|
||||
[m[K [34m[K~~~~~~~~~~~~~~~~~~
|
||||
[m[K [34m[K adipiscing, elit, sed,
|
||||
[m[K [34m[K~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [34m[K eiusmod, tempor, incididunt,
|
||||
[m[K [34m[K~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [34m[K ut, labore, et, dolore,
|
||||
[m[K [34m[K~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[m[K [34m[K magna, aliqua)[m[K);
|
||||
[34m[K~~~~~~~~~~~~~~
|
||||
[m[K
|
||||
{ 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 = [01;35m[K98.6f[m[K;
|
||||
[01;35m[K^~~~~
|
||||
[m[K
|
||||
{ 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 = [01;35m[Kfoo * bar[m[K;
|
||||
[01;35m[K~~~~^~~~~
|
||||
[m[K
|
||||
{ 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 = [01;35m[Kfoo * bar[m[K;
|
||||
[01;35m[K~~~~^~~~~
|
||||
[m[K
|
||||
{ dg-end-multiline-output "" } */
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_multiple_carets (void)
|
||||
{
|
||||
#if 0
|
||||
x = x + y /* { dg-warning "8: test" } */
|
||||
/* { dg-begin-multiline-output "" }
|
||||
x = [01;35m[Kx[m[K + [32m[Ky[m[K
|
||||
[01;35m[KA[m[K [32m[KB
|
||||
[m[K
|
||||
{ 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 =>[32m[K [m[Kx)
|
||||
[32m[K2
|
||||
[m[K [01;35m[K [m[Ky = 5
|
||||
[01;35m[K1
|
||||
[m[K
|
||||
{ dg-end-multiline-output "" } */
|
||||
#endif
|
||||
}
|
326
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
Normal file
326
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
Normal 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;
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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". */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user