diff options
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; + } +} |