diff options
author | David Malcolm <dmalcolm@redhat.com> | 2018-03-14 13:58:13 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2018-03-14 13:58:13 +0000 |
commit | 082284da9d8069290a749218b6aebecab0da2868 (patch) | |
tree | aba9b3b0569617b94157dbe4f5adea052917d7e5 /libcpp | |
parent | 1422855a403391ab2896f774871c5f3748f415dc (diff) | |
download | gcc-082284da9d8069290a749218b6aebecab0da2868.zip gcc-082284da9d8069290a749218b6aebecab0da2868.tar.gz gcc-082284da9d8069290a749218b6aebecab0da2868.tar.bz2 |
Fix ICE for missing header fix-it hints with overlarge #line directives (PR c/84852)
PR c/84852 reports an ICE inside diagnostic_show_locus when printing
a diagnostic for a source file with a #line >= 2^31:
#line 7777777777
int foo (void) { return strlen(""); }
where we're attempting to print a fix-it hint at the top of the file
and underline the "strlen" (two "line spans").
The
#line 7777777777
won't fix within the 32-bit linenum_type, and is truncated from
0x1cf977871
to
0xcf977871
i.e. 3482810481 in decimal.
Such a #line is reported by -pedantic and -pedantic-errors, but we
shouldn't ICE.
The ICE is an assertion failure within layout::calculate_line_spans,
where the line spans have not been properly sorted.
The layout_ranges are stored as int, rather than linenum_type,
giving line -812156815 for the error, and line 1 for the fix-it hint.
However, line_span uses linenum_type rather than int.
line_span::comparator compares these values as int, and hence
decides that (linenum_type)3482810481 aka (int)-812156815 is less
than line 1.
This leads to this assertion failing in layout::calculate_line_spans:
1105 gcc_assert (next->m_first_line >= current->m_first_line);
since it isn't the case that 1 >= 3482810481.
The underlying problem is the mix of types for storing line numbers:
in parts of libcpp and diagnostic-show-locus.c we use linenum_type;
in other places (including libcpp's expanded_location) we use int.
I looked at using linenum_type throughout, but doing so turned into
a large patch, so this patch fixes the ICE in a less invasive way
by merely using linenum_type more consistently just within
diagnostic-show-locus.c, and fixing line_span::comparator to properly
handle line numbers (and line number differences) >= 2^31, by using
a new helper function for linenum_type differences, computing the
difference using long long, and using the sign of the difference
(as the difference might not fit in the "int" return type imposed
by qsort).
gcc/ChangeLog:
PR c/84852
* diagnostic-show-locus.c (class layout_point): Convert m_line
from int to linenum_type.
(line_span::comparator): Use linenum "compare" function when
comparing line numbers.
(test_line_span): New function.
(layout_range::contains_point): Convert param "row" from int to
linenum_type.
(layout_range::intersects_line_p): Likewise.
(layout::will_show_line_p): Likewise.
(layout::print_source_line): Likewise.
(layout::should_print_annotation_line_p): Likewise.
(layout::print_annotation_line): Likewise.
(layout::print_leading_fixits): Likewise.
(layout::annotation_line_showed_range_p): Likewise.
(struct line_corrections): Likewise for field m_row.
(line_corrections::line_corrections): Likewise for param "row".
(layout::print_trailing_fixits): Likewise.
(layout::get_state_at_point): Likewise.
(layout::get_x_bound_for_row): Likewise.
(layout::print_line): Likewise.
(diagnostic_show_locus): Likewise for locals "last_line" and
"row".
(selftest::diagnostic_show_locus_c_tests): Call test_line_span.
* input.c (selftest::test_linenum_comparisons): New function.
(selftest::input_c_tests): Call it.
* selftest.c (selftest::test_assertions): Test ASSERT_GT,
ASSERT_GT_AT, ASSERT_LT, and ASSERT_LT_AT.
* selftest.h (ASSERT_GT): New macro.
(ASSERT_GT_AT): New macro.
(ASSERT_LT): New macro.
(ASSERT_LT_AT): New macro.
gcc/testsuite/ChangeLog:
PR c/84852
* gcc.dg/fixits-pr84852-1.c: New test.
* gcc.dg/fixits-pr84852-2.c: New test.
libcpp/ChangeLog:
* include/line-map.h (compare): New function on linenum_type.
From-SVN: r258526
Diffstat (limited to 'libcpp')
-rw-r--r-- | libcpp/ChangeLog | 4 | ||||
-rw-r--r-- | libcpp/include/line-map.h | 12 |
2 files changed, 16 insertions, 0 deletions
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 791c364..a66948f 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -1,3 +1,7 @@ +2018-03-14 David Malcolm <dmalcolm@redhat.com> + + * include/line-map.h (compare): New function on linenum_type. + 2018-02-28 Jonathan Wakely <jwakely@redhat.com> PR preprocessor/84517 diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index f6242fc..d6cf816 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -49,6 +49,18 @@ along with this program; see the file COPYING3. If not see /* The type of line numbers. */ typedef unsigned int linenum_type; +/* A function for for use by qsort for comparing line numbers. */ + +inline int compare (linenum_type lhs, linenum_type rhs) +{ + /* Avoid truncation issues by using long long for the comparison, + and only consider the sign of the result. */ + long long diff = (long long)lhs - (long long)rhs; + if (diff) + return diff > 0 ? 1 : -1; + return 0; +} + /* Reason for creating a new line map with linemap_add. LC_ENTER is when including a new file, e.g. a #include directive in C. LC_LEAVE is when reaching a file's end. LC_RENAME is when a file |