diff options
author | dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-03-09 18:23:27 +0000 |
---|---|---|
committer | dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-03-09 18:23:27 +0000 |
commit | c24757cf75cfb3aa26f5260eb36e1ea4ad82c86f (patch) | |
tree | f2d383b45fd79fc7ab53b2857eb71e9b4a498cb4 /gcc/diagnostic-show-locus.c | |
parent | 83108969e7ecc8af296a569efd678de116b1519f (diff) | |
download | gcc-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®rtested 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.c | 89 |
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) |