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

--- Comment #13 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
So, my understanding of what's going on on the #c11 vs. #c12 vs.
--- gcc/testsuite/gcc.dg/cpp/pr120067-2.c.jj    2024-09-17 09:04:10.523093614
+0200
+++ gcc/testsuite/gcc.dg/cpp/pr120067-2.c       2025-05-05 16:54:01.715460583
+0200
@@ -0,0 +1,4 @@
+/* PR preprocessor/120067 */
+/* { dg-do compile } */
+/* { dg-options "-nostdinc -std=c23" } */
+#include "pr120067-3.h"
--- gcc/testsuite/gcc.dg/cpp/pr120067-3.h.jj    2024-09-17 09:04:10.523093614
+0200
+++ gcc/testsuite/gcc.dg/cpp/pr120067-3.h       2025-05-05 18:50:33.155590765
+0200
@@ -0,0 +1,3 @@
+int i;
+#include "pr120067-2.h"
+static_assert (__LINE__ == 3, "");
testcases is below.
The #c11 and #c12 testcases are indeed problematic, because
do_include_common -> parse_include -> check_eol -> check_eol_1 ->
cpp_get_token_1 -> _cpp_lex_token -> _cpp_lex_direct -> linemap_line_start
triggers there
      /* Allocate the new line_map.  However, if the current map only has a
         single line we can sometimes just increase its column_bits instead. */
      if (line_delta < 0
          || last_line != ORDINARY_MAP_STARTING_LINE_NUMBER (map)
          || SOURCE_COLUMN (map, highest) >= (1U << (column_bits - range_bits))
          || ( /* We can't reuse the map if the line offset is sufficiently
                  large to cause overflow when computing location_t values.  */
              (to_line - ORDINARY_MAP_STARTING_LINE_NUMBER (map))
              >= (((uint64_t) 1)
                  << (CHAR_BIT * sizeof (linenum_type) - column_bits)))
          || range_bits < map->m_range_bits)
        map = linemap_check_ordinary
                (const_cast <line_map *>
                  (linemap_add (set, LC_RENAME,
                                ORDINARY_MAP_IN_SYSTEM_HEADER_P (map),
                                ORDINARY_MAP_FILE_NAME (map),
                                to_line)));
and so creates a new ordinary map on the line right after the (problematic)
#include line.
Now, in the spot that r14-11679-g8a884140c2bcb7 patched,
pfile->line_table->highest_location in all 3 tests
is before the decrement is the start of the line after the #include line and so
the decrement is really desirable in that case to put highest_location
somewhere on the line where the #include actually is.
But at the same time it is also undesirable, because if we do decrement it,
then linemap_add LC_ENTER
called from _cpp_do_file_change will then
  /* Generate a start_location above the current highest_location.
     If possible, make the low range bits be zero.  */
  location_t start_location = set->highest_location + 1;
  unsigned range_bits = 0;
  if (start_location < LINE_MAP_MAX_LOCATION_WITH_COLS)
    range_bits = set->default_range_bits;
  start_location += (1 << range_bits) - 1;
  start_location &=  ~((1 << range_bits) - 1);

  linemap_assert (!LINEMAPS_ORDINARY_USED (set)
                  || (start_location
                      >= MAP_START_LOCATION (LINEMAPS_LAST_ORDINARY_MAP
(set))));
and we can end up with the new LC_ENTER ordinary map having the same
start_location as the preceding LC_RENAME one.
Next thing that happens is computation of included_from:
  if (reason == LC_ENTER)
    {
      if (set->depth == 0)
        map->included_from = 0;
      else
        /* The location of the end of the just-closed map.  */
        map->included_from
          = (((map[0].start_location - 1 - map[-1].start_location)
              & ~((1 << map[-1].m_column_and_range_bits) - 1))
             + map[-1].start_location);
The normal case (e.g. with the testcase included at the start of this comment)
is that map[-1] starts somewhere earlier and so map->included_from computation
above nicely computes location_t which expands to the start of the #include
line.
With r14-11679 reverted, for #c11 as well as #c12 map[0].start_location ==
map[-1].start_location above, and
so it is ((location_t) -1 & ~((1 << map[-1].m_column_and_range_bits) - 1))) +
map[-1].start_location, which happens to be start of the #include line.  For
#c11 map[0].start_location is 0x500003a0 and map[-1] has
m_column_and_range_bits 7 and map[-2] has m_column_and_range_bits 12 and
ma[0].included_from is set to 0x50000320.
For #c12 map[0].start_location is 0x606c0402 and map[-2].start_location is
0x606c0400 and m_column_and_range_bits is 0 for all 3 maps. 
map[0].included_from is set to 0x606c0401.
The last important part is again in linemap_add when doing LC_LEAVE:
      /* (MAP - 1) points to the map we are leaving. The
         map from which (MAP - 1) got included should be the map
         that comes right before MAP in the same file.  */
      from = linemap_included_from_linemap (set, map - 1);

      /* A TO_FILE of NULL is special - we use the natural values.  */
      if (to_file == NULL)
        {
          to_file = ORDINARY_MAP_FILE_NAME (from);
          to_line = SOURCE_LINE (from, from[1].start_location);
          sysp = ORDINARY_MAP_IN_SYSTEM_HEADER_P (from);
        }
Here it wants to compute the right to_line which ought to be the line after the
#include directive.
On the #c11 testcase that doesn't work correctly though, because
map[-1].included_from is 0x50000320, from[0]
for that is LC_ENTER with start_location 0x4080 and m_column_and_range_bits 12
but note that we've earlier
computed map[-1].start_location + (-1 & 0xffffff80) and so only decreased by 7
bits, so to_line is still on
the line with #include and not after it.  In the #c12 that doesn't happen, all
the ordinary maps involved there had 0 m_column_and_range_bits and so this
computes correct line.

Now, one question is if linemap_ordinary_map_lookup which performs a binary
search can deal properly with the map[n].start_location == map[n +
1].start_location case (that the linemap_assert clearly allows).

Reply via email to