diff options
author | David Malcolm <dmalcolm@redhat.com> | 2015-11-06 19:50:50 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2015-11-06 19:50:50 +0000 |
commit | 8a64515099e64564542cbd09be7c9a21c2f580f3 (patch) | |
tree | de618a78e7240cd1dec5c9b663ed1464c2775915 /libcpp | |
parent | 277ec793cbb5053626a75bcfdb82af03fc735b3e (diff) | |
download | gcc-8a64515099e64564542cbd09be7c9a21c2f580f3.zip gcc-8a64515099e64564542cbd09be7c9a21c2f580f3.tar.gz gcc-8a64515099e64564542cbd09be7c9a21c2f580f3.tar.bz2 |
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
Diffstat (limited to 'libcpp')
-rw-r--r-- | libcpp/ChangeLog | 19 | ||||
-rw-r--r-- | libcpp/errors.c | 7 | ||||
-rw-r--r-- | libcpp/include/cpplib.h | 4 | ||||
-rw-r--r-- | libcpp/include/line-map.h | 218 | ||||
-rw-r--r-- | libcpp/line-map.c | 130 |
5 files changed, 374 insertions, 4 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 8abf6dd..57ac5bf 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,5 +1,24 @@ 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 "adhoc_table_size" and "adhoc_table_entries_used". * line-map.c (linemap_get_statistics): Populate above fields. diff --git a/libcpp/errors.c b/libcpp/errors.c index a33196e..c351c11 100644 --- a/libcpp/errors.c +++ b/libcpp/errors.c @@ -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; } diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 5eaea6b..a2bdfa0 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -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". */ diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index c8618a9..c9340a6 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -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 */ diff --git a/libcpp/line-map.c b/libcpp/line-map.c index 84403de..3c19f93 100644 --- a/libcpp/line-map.c +++ b/libcpp/line-map.c @@ -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; + } +} |