[libcpp/C] Handle lines encoded into several maps in linemap_position_for_loc_and_offset
diff mbox

Message ID CAESRpQAQaCfab7eNqzEw0tw8VgLVTbKdKYu9QEB7on9h2TGd-A@mail.gmail.com
State New
Headers show

Commit Message

Manuel López-Ibáñez Aug. 23, 2015, 4:07 p.m. UTC
linemap_position_for_loc_and_offset() tries to generate a location_t
encoding a column offset from the current location, for example, point
to a certain character inside a string. This is trivial to do when the
new location "fits within" the map of the original location. However,
it may happen that the (long) line corresponding to the original
location is encoded in several maps, thus the new location should
actually be encoded in a subsequent map from the original location.
This patch detects this case and adjusts the map correspondingly.

(This shows that the line-map representation is quite wasteful in this
case, because line-maps always start at column 0. That is, map[0]
highest location may encode up to line 8 column 80, then
map[1]->start_location starts encoding at line 8 column 0. Thus, there
are two location_t values that point to the same source location.)

No new testcase since Marek found out this when tackling PR c/66415
(https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00411.html). This
change just fixes the column number.

Bootstrapped & regtested on x86-64-linux-gnu.

OK?

libcpp/ChangeLog:

2015-08-23  Manuel López-Ibáñez  <manu@gcc.gnu.org>

    * line-map.c (linemap_position_for_loc_and_offset): Handle the
    case of long lines encoded in multiple maps.


gcc/testsuite/ChangeLog:

2015-08-23  Manuel López-Ibáñez  <manu@gcc.gnu.org>

    * gcc.dg/cpp/pr66415-1.c: Test column number.

Comments

Manuel López-Ibáñez Sept. 20, 2015, 6:23 p.m. UTC | #1
PING: https://gcc.gnu.org/ml/gcc-patches/2015-08/msg01373.html

On 23 August 2015 at 18:07, Manuel López-Ibáñez <lopezibanez@gmail.com> wrote:
> linemap_position_for_loc_and_offset() tries to generate a location_t
> encoding a column offset from the current location, for example, point
> to a certain character inside a string. This is trivial to do when the
> new location "fits within" the map of the original location. However,
> it may happen that the (long) line corresponding to the original
> location is encoded in several maps, thus the new location should
> actually be encoded in a subsequent map from the original location.
> This patch detects this case and adjusts the map correspondingly.
>
> (This shows that the line-map representation is quite wasteful in this
> case, because line-maps always start at column 0. That is, map[0]
> highest location may encode up to line 8 column 80, then
> map[1]->start_location starts encoding at line 8 column 0. Thus, there
> are two location_t values that point to the same source location.)
>
> No new testcase since Marek found out this when tackling PR c/66415
> (https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00411.html). This
> change just fixes the column number.
>
> Bootstrapped & regtested on x86-64-linux-gnu.
>
> OK?
>
> libcpp/ChangeLog:
>
> 2015-08-23  Manuel López-Ibáñez  <manu@gcc.gnu.org>
>
>     * line-map.c (linemap_position_for_loc_and_offset): Handle the
>     case of long lines encoded in multiple maps.
>
>
> gcc/testsuite/ChangeLog:
>
> 2015-08-23  Manuel López-Ibáñez  <manu@gcc.gnu.org>
>
>     * gcc.dg/cpp/pr66415-1.c: Test column number.
Marek Polacek Sept. 21, 2015, 1:01 p.m. UTC | #2
On Sun, Aug 23, 2015 at 06:07:13PM +0200, Manuel López-Ibáñez wrote:
> linemap_position_for_loc_and_offset() tries to generate a location_t
> encoding a column offset from the current location, for example, point
> to a certain character inside a string. This is trivial to do when the
> new location "fits within" the map of the original location. However,
> it may happen that the (long) line corresponding to the original
> location is encoded in several maps, thus the new location should
> actually be encoded in a subsequent map from the original location.
> This patch detects this case and adjusts the map correspondingly.
> 
> (This shows that the line-map representation is quite wasteful in this
> case, because line-maps always start at column 0. That is, map[0]
> highest location may encode up to line 8 column 80, then
> map[1]->start_location starts encoding at line 8 column 0. Thus, there
> are two location_t values that point to the same source location.)
> 
> No new testcase since Marek found out this when tackling PR c/66415
> (https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00411.html). This
> change just fixes the column number.
> 
> Bootstrapped & regtested on x86-64-linux-gnu.
> 
> OK?

Ok, thanks.

	Marek

Patch
diff mbox

Index: gcc/testsuite/gcc.dg/cpp/pr66415-1.c
===================================================================
--- gcc/testsuite/gcc.dg/cpp/pr66415-1.c	(revision 226953)
+++ gcc/testsuite/gcc.dg/cpp/pr66415-1.c	(working copy)
@@ -3,7 +3,7 @@ 
 /* { dg-options "-Wformat" } */
 
 void
 fn1 (void)
 {
-  __builtin_printf                                ("xxxxxxxxxxxxxxxxx%dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); /* { dg-warning "format" } */
+  __builtin_printf                                ("xxxxxxxxxxxxxxxxx%dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); /* { dg-warning "71:format" } */
 }
Index: libcpp/line-map.c
===================================================================
--- libcpp/line-map.c	(revision 226953)
+++ libcpp/line-map.c	(working copy)
@@ -686,32 +686,38 @@  linemap_position_for_loc_and_offset (str
     return loc;
 
   /* We find the real location and shift it.  */
   loc = linemap_resolve_location (set, loc, LRK_SPELLING_LOCATION, &map);
   /* The new location (loc + offset) should be higher than the first
-     location encoded by MAP.
-     FIXME: We used to linemap_assert_fails here and in the if below,
-     but that led to PR66415.  So give up for now.  */
-  if ((MAP_START_LOCATION (map) >= loc + offset))
+     location encoded by MAP.  This can fail if the line information
+     is messed up because of line directives (see PR66415).  */
+  if (MAP_START_LOCATION (map) >= loc + offset)
     return loc;
 
+  linenum_type line = SOURCE_LINE (map, loc);
+  unsigned int column = SOURCE_COLUMN (map, loc);
+
   /* If MAP is not the last line map of its set, then the new location
      (loc + offset) should be less than the first location encoded by
-     the next line map of the set.  */
-  if (map != LINEMAPS_LAST_ORDINARY_MAP (set))
-    if ((loc + offset >= MAP_START_LOCATION (&map[1])))
-      return loc;
+     the next line map of the set.  Otherwise, we try to encode the
+     location in the next map.  */
+  while (map != LINEMAPS_LAST_ORDINARY_MAP (set)
+	 && loc + offset >= MAP_START_LOCATION (&map[1]))
+    {
+      map = &map[1];
+      /* If the next map starts in a higher line, we cannot encode the
+	 location there.  */
+      if (line < ORDINARY_MAP_STARTING_LINE_NUMBER (map))
+	return loc;
+    }
 
-  offset += SOURCE_COLUMN (map, loc);
-  if (linemap_assert_fails
-        (offset < (1u << map->column_bits)))
+  offset += column;
+  if (linemap_assert_fails (offset < (1u << map->column_bits)))
     return loc;
 
   source_location r = 
-    linemap_position_for_line_and_column (map,
-					  SOURCE_LINE (map, loc),
-					  offset);
+    linemap_position_for_line_and_column (map, line, offset);
   if (linemap_assert_fails (r <= set->highest_location)
       || linemap_assert_fails (map == linemap_lookup (set, r)))
     return loc;
 
   return r;