https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84852

--- Comment #3 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
Author: dmalcolm
Date: Wed Mar 14 13:58:13 2018
New Revision: 258526

URL: https://gcc.gnu.org/viewcvs?rev=258526&root=gcc&view=rev
Log:
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.


Added:
    trunk/gcc/testsuite/gcc.dg/fixits-pr84852-1.c
    trunk/gcc/testsuite/gcc.dg/fixits-pr84852-2.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/diagnostic-show-locus.c
    trunk/gcc/input.c
    trunk/gcc/selftest.c
    trunk/gcc/selftest.h
    trunk/gcc/testsuite/ChangeLog
    trunk/libcpp/ChangeLog
    trunk/libcpp/include/line-map.h

Reply via email to