gcc/ChangeLog: * input.c (selftest::test_making_arbitrary_locations): New function. (selftest::input_c_tests): Call it.
libcpp/ChangeLog: * include/line-map.h (linemap_position_for_file_line_and_column): New decl. * line-map.c (linemap_position_for_file_line_and_column): New function. --- gcc/input.c | 32 +++++++++++++++++++++++++++++ libcpp/include/line-map.h | 9 +++++++++ libcpp/line-map.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/gcc/input.c b/gcc/input.c index 1aad551..a3a8454 100644 --- a/gcc/input.c +++ b/gcc/input.c @@ -1795,6 +1795,37 @@ test_accessing_ordinary_linemaps (const line_table_case &case_) ASSERT_EQ (loc_d, src_range.m_finish); } +/* Verify that linemap_position_for_file_line_and_column works. */ + +static void +test_making_arbitrary_locations (const line_table_case &case_) +{ + line_table_test ltt (case_); + + /* Verify that we can make various locations in arbitrary order, + sometimes changing file, sometimes going back and making a + location "earlier" than ones we've created before. */ + + ASSERT_LOCEQ ("foo.c", 10, 5, + linemap_position_for_file_line_and_column (line_table, + "foo.c", 10, 5)); + ASSERT_LOCEQ ("foo.c", 10, 6, + linemap_position_for_file_line_and_column (line_table, + "foo.c", 10, 6)); + ASSERT_LOCEQ ("foo.c", 20, 1, + linemap_position_for_file_line_and_column (line_table, + "foo.c", 20, 1)); + ASSERT_LOCEQ ("bar.c", 100, 12, + linemap_position_for_file_line_and_column (line_table, + "bar.c", 100, 12)); + ASSERT_LOCEQ ("foo.c", 30, 1, + linemap_position_for_file_line_and_column (line_table, + "foo.c", 30, 1)); + ASSERT_LOCEQ ("foo.c", 15, 1, + linemap_position_for_file_line_and_column (line_table, + "foo.c", 15, 1)); +} + /* Verify various properties of UNKNOWN_LOCATION. */ static void @@ -3528,6 +3559,7 @@ input_c_tests () for_each_line_table_case (test_make_location_nonpure_range_endpoints); for_each_line_table_case (test_accessing_ordinary_linemaps); + for_each_line_table_case (test_making_arbitrary_locations); for_each_line_table_case (test_lexer); for_each_line_table_case (test_lexer_string_locations_simple); for_each_line_table_case (test_lexer_string_locations_ebcdic); diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h index e696041..3c74bb0 100644 --- a/libcpp/include/line-map.h +++ b/libcpp/include/line-map.h @@ -1192,6 +1192,15 @@ linemap_position_for_loc_and_offset (struct line_maps *set, source_location loc, unsigned int offset); +/* Encode and return a source location from a given file, line and column. + This is much less efficient than the above functions, and should only + be used as a last resort. */ + +source_location +linemap_position_for_file_line_and_column (struct line_maps *set, + const char *, linenum_type, + unsigned int); + /* Return the file this map is for. */ inline const char * LINEMAP_FILE (const line_map_ordinary *ord_map) diff --git a/libcpp/line-map.c b/libcpp/line-map.c index 0e5804b..32294f5 100644 --- a/libcpp/line-map.c +++ b/libcpp/line-map.c @@ -935,6 +935,57 @@ linemap_position_for_loc_and_offset (struct line_maps *set, return r; } +/* Encode and return a source location from a given file, line and column. + This is much less efficient than the above functions, and should only + be used as a last resort. */ + +source_location +linemap_position_for_file_line_and_column (struct line_maps *set, + const char *file, linenum_type line, + unsigned int column) +{ + /* First, attempt to find a pre-existing linemap that can represent + the location. */ + for (unsigned int i = 0; i < LINEMAPS_ORDINARY_USED (set); i++) + { + line_map_ordinary *ord_map = LINEMAPS_ORDINARY_MAP_AT (set, i); + if (0 == strcmp (file, ord_map->to_file)) + { + source_location loc + = linemap_position_for_line_and_column (set, ord_map, + line, column); + /* Check that it's a valid location within ord_map. */ + if (i + 1 < LINEMAPS_ORDINARY_USED (set)) + { + line_map_ordinary *next_ord_map + = LINEMAPS_ORDINARY_MAP_AT (set, i + 1); + if (loc >= next_ord_map->start_location) + continue; + } + + return loc; + } + } + + /* Failing that, we need a new linemap. */ + const line_map_ordinary *ord_map + = linemap_check_ordinary (linemap_add + (set, LC_ENTER, + /* Assume that it's not in a system header. */ + false, + xstrdup (file), line)); + unsigned int max_column_hint = MAX (80, column * 2); + linemap_line_start (set, line, max_column_hint); + + source_location loc + = linemap_position_for_line_and_column (set, ord_map, + line, column); + + linemap_add (set, LC_LEAVE, false, NULL, 0); + + return loc; +} + /* Given a virtual source location yielded by a map (either an ordinary or a macro map), returns that map. */ -- 1.8.5.3