aboutsummaryrefslogtreecommitdiff
path: root/libcpp
diff options
context:
space:
mode:
Diffstat (limited to 'libcpp')
-rw-r--r--libcpp/ChangeLog19
-rw-r--r--libcpp/errors.c7
-rw-r--r--libcpp/include/cpplib.h4
-rw-r--r--libcpp/include/line-map.h218
-rw-r--r--libcpp/line-map.c130
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;
+ }
+}