Handle lines encoded into several maps in linemap_position_for_loc_and_offset
authorManuel López-Ibáñez <manu@gcc.gnu.org>
Mon, 21 Sep 2015 14:52:09 +0000 (14:52 +0000)
committerManuel López-Ibáñez <manu@gcc.gnu.org>
Mon, 21 Sep 2015 14:52:09 +0000 (14:52 +0000)
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.)

libcpp/ChangeLog:

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

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

gcc/testsuite/ChangeLog:

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

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

From-SVN: r227975

gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cpp/pr66415-1.c
libcpp/ChangeLog
libcpp/line-map.c

index 5eacecad6c8d7d4fd68d815f9bd0a2ef228cb1f9..61c3b962782a79561c263e5a6c97fc4b13ddb928 100644 (file)
@@ -1,3 +1,8 @@
+2015-09-21  Manuel López-Ibáñez  <manu@gcc.gnu.org>
+
+       PR c/66415
+       * gcc.dg/cpp/pr66415-1.c: Test column number.
+
 2015-09-21  Richard Biener  <rguenther@suse.de>
 
        * g++.dg/ext/attr-alias-3.C: Add -g.
index 922e3268251aa7c0789c11b1f7d28052eb554e04..349ec4883fa21bfdfa9bdfd036404003143517cc 100644 (file)
@@ -5,5 +5,5 @@
 void
 fn1 (void)
 {
-  __builtin_printf                                ("xxxxxxxxxxxxxxxxx%dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); /* { dg-warning "format" } */
+  __builtin_printf                                ("xxxxxxxxxxxxxxxxx%dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); /* { dg-warning "71:format" } */
 }
index 3173bf558d1c95b192c1d4a70a926ff3810821c7..5cb23d032676240bfc50469d1611e14a16082d49 100644 (file)
@@ -1,3 +1,9 @@
+2015-09-21  Manuel López-Ibáñez  <manu@gcc.gnu.org>
+
+       PR c/66415
+       * line-map.c (linemap_position_for_loc_and_offset): Handle the
+       case of long lines encoded in multiple maps.
+
 2015-09-07  Marek Polacek  <polacek@redhat.com>
 
        * system.h (INTTYPE_MINIMUM): Rewrite to avoid shift warning.
index d58cad23fdbf440273ed346bd5ef7d56d70d52ef..3d82e9bfca94e9b8ca3deac99d5e41588074d452 100644 (file)
@@ -688,28 +688,34 @@ linemap_position_for_loc_and_offset (struct line_maps *set,
   /* 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;