summaryrefslogtreecommitdiff
path: root/gcc/diagnostic-show-locus.c
diff options
context:
space:
mode:
authordmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>2016-03-09 18:23:27 +0000
committerdmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>2016-03-09 18:23:27 +0000
commitc24757cf75cfb3aa26f5260eb36e1ea4ad82c86f (patch)
treef2d383b45fd79fc7ab53b2857eb71e9b4a498cb4 /gcc/diagnostic-show-locus.c
parent83108969e7ecc8af296a569efd678de116b1519f (diff)
downloadgcc-c24757cf75cfb3aa26f5260eb36e1ea4ad82c86f.tar.gz
PR c++/70105: prevent nonsensical underline spew for macro expansions
diagnostic_show_locus can sometimes do the wrong thing when handling expressions built up from macros. PR c++/70105 (currently marked as a P3 regression) has an example of a diagnostic where over 500 lines of irrelevant source are printed, and underlined, giving >1000 lines of useless spew to stderr. This patch adds extra sanitization to diagnostic-show-locus.c, so that we only attempt to print underlines and secondary locations if such locations are "sufficiently sane" relative to the primary location of a diagnostic. This "sufficiently sane" condition is implemented by a new helper function compatible_locations_p, which requires such locations to have the same macro expansion hierarchy as the primary location, using linemap_macro_map_loc_unwind_toward_spelling, effectively mimicing the expansion performed by LRK_SPELLING_LOCATION. This may be too strong a condition, but it effectively fixes PR c++/70105, without removing any underlines in my testing. Successfully bootstrapped&regrtested in combination with the previous patch on x86_64-pc-linux-gnu; adds 15 new PASS results to g++.sum and 4 new PASS results to gcc.sum. gcc/ChangeLog: PR c/68473 PR c++/70105 * diagnostic-show-locus.c (compatible_locations_p): New function. (layout::layout): Sanitize ranges using compatible_locations_p. gcc/testsuite/ChangeLog: PR c/68473 PR c++/70105 * g++.dg/diagnostic/pr70105.C: New test. * gcc.dg/plugin/diagnostic-test-expressions-1.c (foo): New decl. (test_multiple_ordinary_maps): New test function. libcpp/ChangeLog: PR c/68473 PR c++/70105 * line-map.c (linemap_macro_map_loc_unwind_toward_spelling): Move decl... * include/line-map.h (linemap_macro_map_loc_unwind_toward_spelling): ...here, converting from static to extern. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@234088 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/diagnostic-show-locus.c')
-rw-r--r--gcc/diagnostic-show-locus.c89
1 files changed, 87 insertions, 2 deletions
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index a940f24465e..f10ade5591c 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -463,6 +463,76 @@ get_line_width_without_trailing_whitespace (const char *line, int line_width)
return result;
}
+/* Helper function for layout's ctor, for sanitizing locations relative
+ to the primary location within a diagnostic.
+
+ Compare LOC_A and LOC_B to see if it makes sense to print underlines
+ connecting their expanded locations. Doing so is only guaranteed to
+ make sense if the locations share the same macro expansion "history"
+ i.e. they can be traced through the same macro expansions, eventually
+ reaching an ordinary map.
+
+ This may be too strong a condition, but it effectively sanitizes
+ PR c++/70105, which has an example of printing an expression where the
+ final location of the expression is in a different macro, which
+ erroneously was leading to hundreds of lines of irrelevant source
+ being printed. */
+
+static bool
+compatible_locations_p (location_t loc_a, location_t loc_b)
+{
+ if (IS_ADHOC_LOC (loc_a))
+ loc_a = get_location_from_adhoc_loc (line_table, loc_a);
+ if (IS_ADHOC_LOC (loc_b))
+ loc_b = get_location_from_adhoc_loc (line_table, loc_b);
+
+ const line_map *map_a = linemap_lookup (line_table, loc_a);
+ linemap_assert (map_a);
+
+ const line_map *map_b = linemap_lookup (line_table, loc_b);
+ linemap_assert (map_b);
+
+ /* Are they within the same map? */
+ if (map_a == map_b)
+ {
+ /* Are both within the same macro expansion? */
+ if (linemap_macro_expansion_map_p (map_a))
+ {
+ /* Expand each location towards the spelling location, and
+ recurse. */
+ const line_map_macro *macro_map = linemap_check_macro (map_a);
+ source_location loc_a_toward_spelling
+ = linemap_macro_map_loc_unwind_toward_spelling (line_table,
+ macro_map,
+ loc_a);
+ source_location loc_b_toward_spelling
+ = linemap_macro_map_loc_unwind_toward_spelling (line_table,
+ macro_map,
+ loc_b);
+ return compatible_locations_p (loc_a_toward_spelling,
+ loc_b_toward_spelling);
+ }
+
+ /* Otherwise they are within the same ordinary map. */
+ return true;
+ }
+ else
+ {
+ /* Within different maps. */
+
+ /* If either is within a macro expansion, they are incompatible. */
+ if (linemap_macro_expansion_map_p (map_a)
+ || linemap_macro_expansion_map_p (map_b))
+ return false;
+
+ /* Within two different ordinary maps; they are compatible iff they
+ are in the same file. */
+ const line_map_ordinary *ord_map_a = linemap_check_ordinary (map_a);
+ const line_map_ordinary *ord_map_b = linemap_check_ordinary (map_b);
+ return ord_map_a->to_file == ord_map_b->to_file;
+ }
+}
+
/* Implementation of class layout. */
/* Constructor for class layout.
@@ -487,6 +557,8 @@ layout::layout (diagnostic_context * context,
m_x_offset (0)
{
rich_location *richloc = diagnostic->richloc;
+ source_location primary_loc = richloc->get_range (0)->m_loc;
+
for (unsigned int idx = 0; idx < richloc->get_num_locations (); idx++)
{
/* This diagnostic printer can only cope with "sufficiently sane" ranges.
@@ -514,6 +586,14 @@ layout::layout (diagnostic_context * context,
if (caret.file != m_exploc.file)
continue;
+ /* Sanitize the caret location for non-primary ranges. */
+ if (m_layout_ranges.length () > 0)
+ if (loc_range->m_show_caret_p)
+ if (!compatible_locations_p (loc_range->m_loc, primary_loc))
+ /* Discard any non-primary ranges that can't be printed
+ sanely relative to the primary location. */
+ continue;
+
/* Everything is now known to be in the correct source file,
but it may require further sanitization. */
layout_range ri (&start, &finish, loc_range->m_show_caret_p, &caret);
@@ -521,8 +601,13 @@ layout::layout (diagnostic_context * context,
/* If we have a range that finishes before it starts (perhaps
from something built via macro expansion), printing the
range is likely to be nonsensical. Also, attempting to do so
- breaks assumptions within the printing code (PR c/68473). */
- if (start.line > finish.line)
+ breaks assumptions within the printing code (PR c/68473).
+ Similarly, don't attempt to print ranges if one or both ends
+ of the range aren't sane to print relative to the
+ primary location (PR c++/70105). */
+ if (start.line > finish.line
+ || !compatible_locations_p (src_range.m_start, primary_loc)
+ || !compatible_locations_p (src_range.m_finish, primary_loc))
{
/* Is this the primary location? */
if (m_layout_ranges.length () == 0)