PR c/99323 describes an ICE due to a failed assertion deep inside the fix-it printing machinery, where the fix-it hints on one line have not been properly sorted in layout's constructor.
The underlying issue occurs when multiple fix-it hints affect a line wider that LINE_MAP_MAX_COLUMN_NUMBER, where the location_t values for characters after that threshold fall back to having column zero. It's not meaningful to try to handle fix-it hints without column information, so this patch rejects them as they are added to the rich_location, falling back to the "no fix-it hints on this diagnostic" case, fixing the crash. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r11-7461-g41fbacdd10305654b1d10f887fa3f4677f9b8f34. gcc/ChangeLog: PR c/99323 * diagnostic-show-locus.c (selftest::test_one_liner_many_fixits_2): Fix accidental usage of column 0. gcc/testsuite/ChangeLog: PR c/99323 * gcc.dg/pr99323-1.c: New test. * gcc.dg/pr99323-2.c: New test. libcpp/ChangeLog: PR c/99323 * line-map.c (rich_location::maybe_add_fixit): Reject fix-it hints at column 0. --- gcc/diagnostic-show-locus.c | 4 ++-- gcc/testsuite/gcc.dg/pr99323-1.c | 17 +++++++++++++++++ gcc/testsuite/gcc.dg/pr99323-2.c | 11 +++++++++++ libcpp/line-map.c | 8 ++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr99323-1.c create mode 100644 gcc/testsuite/gcc.dg/pr99323-2.c diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c index 458830aa2a9..4111cd66544 100644 --- a/gcc/diagnostic-show-locus.c +++ b/gcc/diagnostic-show-locus.c @@ -3288,14 +3288,14 @@ test_one_liner_many_fixits_2 () rich_location richloc (line_table, equals); for (int i = 0; i < 19; i++) { - location_t loc = linemap_position_for_column (line_table, i * 2); + location_t loc = linemap_position_for_column (line_table, (i * 2) + 1); richloc.add_fixit_insert_before (loc, "a"); } ASSERT_EQ (19, richloc.get_num_fixit_hints ()); diagnostic_show_locus (&dc, &richloc, DK_ERROR); ASSERT_STREQ (" foo = bar.field;\n" " ^\n" - "a a a a a a a a a a a a a a a a a a a\n", + " a a a a a a a a a a a a a a a a a a a\n", pp_formatted_text (dc.printer)); } diff --git a/gcc/testsuite/gcc.dg/pr99323-1.c b/gcc/testsuite/gcc.dg/pr99323-1.c new file mode 100644 index 00000000000..6fe14002e59 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr99323-1.c @@ -0,0 +1,17 @@ +/* Verify that fix-it printing doesn't ICE when there are multiple + fix-it hints on a very long line after LINE_MAP_MAX_COLUMN_NUMBER. */ + +/* { dg-options "-Wall -no-integrated-cpp -fdiagnostics-show-caret" } */ +/* { dg-allow-blank-lines-in-output 1 } */ +/* { dg-prune-output ".*" } */ + +typedef struct { +} REFERENCE; +#define LIM2() LIM1() +#define LIM3() LIM2() LIM2() LIM2() LIM2() LIM2() LIM2() +#define LIM4() \ + LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() +#define LIM5() \ + LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() +#define LIM1() DEF(), +REFERENCE references[] = {LIM5()}; diff --git a/gcc/testsuite/gcc.dg/pr99323-2.c b/gcc/testsuite/gcc.dg/pr99323-2.c new file mode 100644 index 00000000000..d4075b61525 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr99323-2.c @@ -0,0 +1,11 @@ +/* Verify that fix-it printing doesn't ICE when there are multiple + fix-it hints on a very long line after LINE_MAP_MAX_COLUMN_NUMBER. */ + +/* { dg-options "-Wall -fdiagnostics-show-caret" } */ +/* { dg-allow-blank-lines-in-output 1 } */ +/* { dg-prune-output ".*" } */ + +typedef struct { +} REFERENCE; + +REFERENCE references[] = {DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(),} diff --git a/libcpp/line-map.c b/libcpp/line-map.c index ccabd51c62f..a003af8533c 100644 --- a/libcpp/line-map.c +++ b/libcpp/line-map.c @@ -2431,6 +2431,14 @@ rich_location::maybe_add_fixit (location_t start, stop_supporting_fixits (); return; } + /* If we have very long lines, tokens will eventually fall back to + having column == 0. + We can't handle fix-it hints that use such locations. */ + if (exploc_start.column == 0 || exploc_next_loc.column == 0) + { + stop_supporting_fixits (); + return; + } const char *newline = strchr (new_content, '\n'); if (newline) -- 2.26.2