@@ -9206,11 +9206,15 @@ try_to_locate_new_include_insertion_point (const char *file, location_t loc)
const line_map_ordinary *ord_map
= LINEMAPS_ORDINARY_MAP_AT (line_table, i);
+ if (ORDINARY_MAP_GENERATED_DATA_P (ord_map))
+ continue;
+
if (const line_map_ordinary *from
= linemap_included_from_linemap (line_table, ord_map))
/* We cannot use pointer equality, because with preprocessed
input all filename strings are unique. */
- if (0 == strcmp (from->to_file, file))
+ if (!ORDINARY_MAP_GENERATED_DATA_P (from)
+ && 0 == strcmp (ORDINARY_MAP_FILE_NAME (from), file))
{
last_include_ord_map = from;
last_ord_map_after_include = NULL;
@@ -9218,7 +9222,8 @@ try_to_locate_new_include_insertion_point (const char *file, location_t loc)
/* Likewise, use strcmp, and reject any line-zero introductory
map. */
- if (ord_map->to_line && 0 == strcmp (ord_map->to_file, file))
+ if (ord_map->to_line
+ && 0 == strcmp (ORDINARY_MAP_FILE_NAME (ord_map), file))
{
if (!first_ord_map_in_file)
first_ord_map_in_file = ord_map;
@@ -4537,7 +4537,7 @@ get_corrected_substring (const substring_loc &fmt_loc,
if (caret.column > finish.column)
return NULL;
- char_span line = location_get_source_line (start.file, start.line);
+ char_span line = location_get_source_line (start);
if (!line)
return NULL;
@@ -50,7 +50,7 @@ get_visual_column (expanded_location exploc,
unsigned int *first_nws,
unsigned int tab_width)
{
- char_span line = location_get_source_line (exploc.file, exploc.line);
+ char_span line = location_get_source_line (exploc);
if (!line)
return false;
if ((size_t)exploc.column > line.length ())
@@ -87,13 +87,13 @@ get_visual_column (expanded_location exploc,
Otherwise, return false, leaving *FIRST_NWS untouched. */
static bool
-get_first_nws_vis_column (const char *file, int line_num,
+get_first_nws_vis_column (expanded_location exploc,
unsigned int *first_nws,
unsigned int tab_width)
{
gcc_assert (first_nws);
- char_span line = location_get_source_line (file, line_num);
+ char_span line = location_get_source_line (exploc);
if (!line)
return false;
unsigned int vis_column = 0;
@@ -158,19 +158,18 @@ get_first_nws_vis_column (const char *file, int line_num,
Return true if such an unindent/outdent is detected. */
static bool
-detect_intervening_unindent (const char *file,
- int body_line,
+detect_intervening_unindent (expanded_location exploc,
int next_stmt_line,
unsigned int vis_column,
unsigned int tab_width)
{
- gcc_assert (file);
- gcc_assert (next_stmt_line > body_line);
+ gcc_assert (exploc.file);
+ gcc_assert (next_stmt_line > exploc.line);
- for (int line = body_line + 1; line < next_stmt_line; line++)
+ while (++exploc.line < next_stmt_line)
{
unsigned int line_vis_column;
- if (get_first_nws_vis_column (file, line, &line_vis_column, tab_width))
+ if (get_first_nws_vis_column (exploc, &line_vis_column, tab_width))
if (line_vis_column < vis_column)
return true;
}
@@ -528,8 +527,7 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
/* Don't warn if there is an unindent between the two statements. */
int vis_column = MIN (next_stmt_vis_column, body_vis_column);
- if (detect_intervening_unindent (body_exploc.file, body_exploc.line,
- next_stmt_exploc.line,
+ if (detect_intervening_unindent (body_exploc, next_stmt_exploc.line,
vis_column, tab_width))
return false;
@@ -691,12 +689,10 @@ assert_get_visual_column_succeeds (const location &loc,
unsigned int expected_visual_column,
unsigned int expected_first_nws)
{
- expanded_location exploc;
+ expanded_location exploc = {};
exploc.file = file;
exploc.line = line;
exploc.column = column;
- exploc.data = NULL;
- exploc.sysp = false;
unsigned int actual_visual_column;
unsigned int actual_first_nws;
bool result = get_visual_column (exploc,
@@ -729,12 +725,10 @@ assert_get_visual_column_fails (const location &loc,
const char *file, int line, int column,
const unsigned int tab_width)
{
- expanded_location exploc;
+ expanded_location exploc = {};
exploc.file = file;
exploc.line = line;
exploc.column = column;
- exploc.data = NULL;
- exploc.sysp = false;
unsigned int actual_visual_column;
unsigned int actual_first_nws;
bool result = get_visual_column (exploc,
@@ -16250,6 +16250,8 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info,
iter != end; ++iter)
if (iter->src != current)
{
+ if (ORDINARY_MAP_GENERATED_DATA_P (iter->src))
+ continue;
current = iter->src;
const char *fname = ORDINARY_MAP_FILE_NAME (iter->src);
@@ -16267,7 +16269,7 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info,
preprocessed input we could have multiple instances
of the same name, and we'd rather not percolate
that. */
- const_cast<line_map_ordinary *> (iter->src)->to_file = name;
+ const_cast<line_map_ordinary *> (iter->src)->data = name;
fname = NULL;
break;
}
@@ -16295,6 +16297,8 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info,
for (auto iter = ord_loc_remap->begin (), end = ord_loc_remap->end ();
iter != end; ++iter)
{
+ if (ORDINARY_MAP_GENERATED_DATA_P (iter->src))
+ continue;
dump (dumper::LOCATION)
&& dump ("Span:%u ordinary [%u+%u,+%u)->[%u,+%u)",
iter - ord_loc_remap->begin (),
@@ -16456,7 +16460,8 @@ module_state::read_ordinary_maps (unsigned num_ord_locs, unsigned range_bits)
map->m_range_bits = sec.u ();
map->m_column_and_range_bits = sec.u () + map->m_range_bits;
unsigned fnum = sec.u ();
- map->to_file = (fnum < filenames.length () ? filenames[fnum] : "");
+ map->data = (fnum < filenames.length () ? filenames[fnum] : "");
+ map->data_len = 1 + strlen (map->data);
map->to_line = sec.u ();
base = map;
}
@@ -709,9 +709,9 @@ static layout_range
make_range (int start_line, int start_col, int end_line, int end_col)
{
const expanded_location start_exploc
- = {"", start_line, start_col, NULL, false};
+ = {"", start_line, start_col, NULL, false, 0, NULL};
const expanded_location finish_exploc
- = {"", end_line, end_col, NULL, false};
+ = {"", end_line, end_col, NULL, false, 0, NULL};
return layout_range (exploc_with_display_col (start_exploc, def_policy (),
LOCATION_ASPECT_START),
exploc_with_display_col (finish_exploc, def_policy (),
@@ -998,7 +998,7 @@ compatible_locations_p (location_t loc_a, location_t loc_b)
are in the same file. */
const line_map_ordinary *ord_map_a = linemap_check_ordinary (map_a);
const line_map_ordinary *ord_map_b = linemap_check_ordinary (map_b);
- return ord_map_a->to_file == ord_map_b->to_file;
+ return ORDINARY_MAPS_SAME_FILE_P (ord_map_a, ord_map_b);
}
}
@@ -1614,8 +1614,7 @@ layout::calculate_x_offset_display ()
return;
}
- const char_span line = location_get_source_line (m_exploc.file,
- m_exploc.line);
+ const char_span line = location_get_source_line (m_exploc);
if (!line)
{
/* Nothing to do, we couldn't find the source line. */
@@ -2403,17 +2402,18 @@ class line_corrections
{
public:
line_corrections (const char_display_policy &policy,
- const char *filename,
- linenum_type row)
- : m_policy (policy), m_filename (filename), m_row (row)
- {}
+ expanded_location exploc, linenum_type row = 0)
+ : m_policy (policy), m_exploc (exploc)
+ {
+ if (row)
+ m_exploc.line = row;
+ }
~line_corrections ();
void add_hint (const fixit_hint *hint);
const char_display_policy &m_policy;
- const char *m_filename;
- linenum_type m_row;
+ expanded_location m_exploc;
auto_vec <correction *> m_corrections;
};
@@ -2433,7 +2433,7 @@ line_corrections::~line_corrections ()
class source_line
{
public:
- source_line (const char *filename, int line);
+ explicit source_line (expanded_location xloc);
char_span as_span () { return char_span (chars, width); }
@@ -2443,9 +2443,9 @@ public:
/* source_line's ctor. */
-source_line::source_line (const char *filename, int line)
+source_line::source_line (expanded_location exploc)
{
- char_span span = location_get_source_line (filename, line);
+ char_span span = location_get_source_line (exploc);
chars = span.get_buffer ();
width = span.length ();
}
@@ -2489,7 +2489,7 @@ line_corrections::add_hint (const fixit_hint *hint)
affected_bytes.start - 1);
/* Try to read the source. */
- source_line line (m_filename, m_row);
+ source_line line (m_exploc);
if (line.chars && between.finish < line.width)
{
/* Consolidate into the last correction:
@@ -2545,7 +2545,7 @@ layout::print_trailing_fixits (linenum_type row)
{
/* Build a list of correction instances for the line,
potentially consolidating hints (for the sake of readability). */
- line_corrections corrections (m_policy, m_exploc.file, row);
+ line_corrections corrections (m_policy, m_exploc, row);
for (unsigned int i = 0; i < m_fixit_hints.length (); i++)
{
const fixit_hint *hint = m_fixit_hints[i];
@@ -2783,7 +2783,7 @@ layout::show_ruler (int max_column) const
void
layout::print_line (linenum_type row)
{
- char_span line = location_get_source_line (m_exploc.file, row);
+ char_span line = location_get_source_line (m_exploc, row);
if (!line)
return;
@@ -2992,10 +2992,10 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
no multibyte characters earlier on the line. */
const int emoji_col = 102;
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
line_table_test ltt (case_);
-
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, 1 + line_bytes,
+ ltt.m_generated_data);
+ tmp.do_linemap_add (1);
location_t line_end = linemap_position_for_column (line_table, line_bytes);
@@ -3003,17 +3003,23 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
- ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
+ if (ltt.m_generated_data)
+ {
+ ASSERT_EQ (nullptr, tmp.get_filename ());
+ ASSERT_STREQ (special_fname_generated (), LOCATION_FILE (line_end));
+ }
+ else
+ ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
ASSERT_EQ (1, LOCATION_LINE (line_end));
ASSERT_EQ (line_bytes, LOCATION_COLUMN (line_end));
- char_span lspan = location_get_source_line (tmp.get_filename (), 1);
+ const expanded_location xloc = expand_location (line_end);
+ char_span lspan = location_get_source_line (xloc);
ASSERT_EQ (line_display_cols,
cpp_display_width (lspan.get_buffer (), lspan.length (),
def_policy ()));
ASSERT_EQ (line_display_cols,
- location_compute_display_column (expand_location (line_end),
- def_policy ()));
+ location_compute_display_column (xloc, def_policy ()));
ASSERT_EQ (0, memcmp (lspan.get_buffer () + (emoji_col - 1),
"\xf0\x9f\x98\x82\xf0\x9f\x98\x82", 8));
@@ -3145,10 +3151,10 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
a space would have taken up. */
ASSERT_EQ (7, extra_width[10]);
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
line_table_test ltt (case_);
-
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, line_bytes + 1,
+ ltt.m_generated_data);
+ tmp.do_linemap_add (1);
location_t line_end = linemap_position_for_column (line_table, line_bytes);
@@ -3157,7 +3163,8 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
return;
/* Check that cpp_display_width handles the tabs as expected. */
- char_span lspan = location_get_source_line (tmp.get_filename (), 1);
+ const expanded_location xloc = expand_location (line_end);
+ char_span lspan = location_get_source_line (xloc);
ASSERT_EQ ('\t', *(lspan.get_buffer () + (tab_col - 1)));
for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
{
@@ -3166,8 +3173,7 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
cpp_display_width (lspan.get_buffer (), lspan.length (),
policy));
ASSERT_EQ (line_bytes + extra_width[tabstop],
- location_compute_display_column (expand_location (line_end),
- policy));
+ location_compute_display_column (xloc, policy));
}
/* Check that the tab is expanded to the expected number of spaces. */
@@ -3791,10 +3797,10 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
....................0000000001111111.
....................1234567890123456. */
const char *content = "foo = bar.field;\n";
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
line_table_test ltt (case_);
-
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, strlen (content),
+ ltt.m_generated_data);
+ tmp.do_linemap_add (1);
location_t line_end = linemap_position_for_column (line_table, 16);
@@ -3802,7 +3808,14 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
- ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
+ if (ltt.m_generated_data)
+ {
+ ASSERT_EQ (nullptr, tmp.get_filename ());
+ ASSERT_STREQ (special_fname_generated (), LOCATION_FILE (line_end));
+ }
+ else
+ ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
+
ASSERT_EQ (1, LOCATION_LINE (line_end));
ASSERT_EQ (16, LOCATION_COLUMN (line_end));
@@ -4373,10 +4386,10 @@ test_diagnostic_show_locus_one_liner_utf8 (const line_table_case &case_)
/* 0000000000000000000001111111111111111111222222222222222222222233333
1111222233334444567890122223333456789999000011112222345678999900001
Byte columns. */
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
line_table_test ltt (case_);
-
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, strlen (content),
+ ltt.m_generated_data);
+ tmp.do_linemap_add (1);
location_t line_end = linemap_position_for_column (line_table, 31);
@@ -4384,11 +4397,18 @@ test_diagnostic_show_locus_one_liner_utf8 (const line_table_case &case_)
if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
- ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
+ if (ltt.m_generated_data)
+ {
+ ASSERT_EQ (nullptr, tmp.get_filename ());
+ ASSERT_STREQ (special_fname_generated (), LOCATION_FILE (line_end));
+ }
+ else
+ ASSERT_STREQ (tmp.get_filename (), LOCATION_FILE (line_end));
+
ASSERT_EQ (1, LOCATION_LINE (line_end));
ASSERT_EQ (31, LOCATION_COLUMN (line_end));
- char_span lspan = location_get_source_line (tmp.get_filename (), 1);
+ char_span lspan = location_get_source_line (expand_location (line_end));
ASSERT_EQ (25, cpp_display_width (lspan.get_buffer (), lspan.length (),
def_policy ()));
ASSERT_EQ (25, location_compute_display_column (expand_location (line_end),
@@ -4425,12 +4445,10 @@ test_add_location_if_nearby (const line_table_case &case_)
" double x;\n" /* line 4. */
" double y;\n" /* line 5. */
";\n"); /* line 6. */
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
line_table_test ltt (case_);
-
- const line_map_ordinary *ord_map
- = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
- tmp.get_filename (), 0));
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, strlen (content),
+ ltt.m_generated_data);
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
@@ -4489,12 +4507,10 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
"\n" /* line 4. */
"\n" /* line 5. */
" : 0.0};\n"); /* line 6. */
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
line_table_test ltt (case_);
-
- const line_map_ordinary *ord_map
- = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
- tmp.get_filename (), 0));
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, strlen (content),
+ ltt.m_generated_data);
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
@@ -4585,8 +4601,10 @@ static void
test_fixit_consolidation (const line_table_case &case_)
{
line_table_test ltt (case_);
-
- linemap_add (line_table, LC_ENTER, false, "test.c", 1);
+ if (ltt.m_generated_data)
+ linemap_add (line_table, LC_GEN, false, "some content", 1, 13);
+ else
+ linemap_add (line_table, LC_ENTER, false, "test.c", 1);
const location_t c10 = linemap_position_for_column (line_table, 10);
const location_t c15 = linemap_position_for_column (line_table, 15);
@@ -4732,13 +4750,11 @@ test_overlapped_fixit_printing (const line_table_case &case_)
...123456789012345678901234567890123456789. */
const char *content
= (" foo *f = (foo *)ptr->field;\n");
- temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
line_table_test ltt (case_);
+ temp_source_file tmp (SELFTEST_LOCATION, ".C", content, strlen (content),
+ ltt.m_generated_data);
- const line_map_ordinary *ord_map
- = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
- tmp.get_filename (), 0));
-
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
const location_t final_line_end
@@ -4759,6 +4775,8 @@ test_overlapped_fixit_printing (const line_table_case &case_)
= linemap_position_for_line_and_column (line_table, ord_map, 1, 28);
const location_t expr = make_location (expr_start, expr_start, expr_finish);
+ const expanded_location xloc = expand_location (expr);
+
/* Various examples of fix-it hints that aren't themselves consolidated,
but for which the *printing* may need consolidation. */
@@ -4802,7 +4820,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
/* Add each hint in turn to a line_corrections instance,
and verify that they are consolidated into one correction instance
as expected. */
- line_corrections lc (policy, tmp.get_filename (), 1);
+ line_corrections lc (policy, xloc);
/* The first replace hint by itself. */
lc.add_hint (hint_0);
@@ -4943,13 +4961,10 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
12344445555666677778901234566667777888899990123456789012333344445
Byte columns. */
- temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
line_table_test ltt (case_);
-
- const line_map_ordinary *ord_map
- = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
- tmp.get_filename (), 0));
-
+ temp_source_file tmp (SELFTEST_LOCATION, ".C", content, strlen (content),
+ ltt.m_generated_data);
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
const location_t final_line_end
@@ -4970,6 +4985,8 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
= linemap_position_for_line_and_column (line_table, ord_map, 1, 34);
const location_t expr = make_location (expr_start, expr_start, expr_finish);
+ const expanded_location xloc = expand_location (expr);
+
/* Various examples of fix-it hints that aren't themselves consolidated,
but for which the *printing* may need consolidation. */
@@ -5018,7 +5035,7 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
/* Add each hint in turn to a line_corrections instance,
and verify that they are consolidated into one correction instance
as expected. */
- line_corrections lc (policy, tmp.get_filename (), 1);
+ line_corrections lc (policy, xloc);
/* The first replace hint by itself. */
lc.add_hint (hint_0);
@@ -5176,13 +5193,11 @@ test_overlapped_fixit_printing_2 (const line_table_case &case_)
...123456789012345678901234567890123456789. */
const char *content
= ("int a5[][0][0] = { 1, 2 };\n");
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
- line_table_test ltt (case_);
-
- const line_map_ordinary *ord_map
- = linemap_check_ordinary (linemap_add (line_table, LC_ENTER, false,
- tmp.get_filename (), 0));
+ line_table_test ltt (case_);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, strlen (content),
+ ltt.m_generated_data);
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
const location_t final_line_end
@@ -5267,10 +5282,10 @@ test_fixit_insert_containing_newline (const line_table_case &case_)
" x = a;\n" /* line 2. */
" case 'b':\n" /* line 3. */
" x = b;\n");/* line 4. */
-
- temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
line_table_test ltt (case_);
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 3);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content,
+ strlen (old_content), false);
+ tmp.do_linemap_add (3);
location_t case_start = linemap_position_for_column (line_table, 5);
location_t case_finish = linemap_position_for_column (line_table, 13);
@@ -5338,12 +5353,11 @@ test_fixit_insert_containing_newline_2 (const line_table_case &case_)
"{\n" /* line 2. */
" putchar (ch);\n" /* line 3. */
"}\n"); /* line 4. */
-
- temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
line_table_test ltt (case_);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content,
+ strlen (old_content), ltt.m_generated_data);
- const line_map_ordinary *ord_map = linemap_check_ordinary
- (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
/* The primary range is the "putchar" token. */
@@ -5402,9 +5416,10 @@ test_fixit_replace_containing_newline (const line_table_case &case_)
.........................1234567890123. */
const char *old_content = "foo = bar ();\n";
- temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
line_table_test ltt (case_);
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content,
+ strlen (old_content), ltt.m_generated_data);
+ tmp.do_linemap_add (1);
/* Replace the " = " with "\n = ", as if we were reformatting an
overly long line. */
@@ -5442,10 +5457,10 @@ test_fixit_deletion_affecting_newline (const line_table_case &case_)
const char *old_content = ("foo = bar (\n"
" );\n");
- temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content);
line_table_test ltt (case_);
- const line_map_ordinary *ord_map = linemap_check_ordinary
- (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", old_content,
+ strlen (old_content), ltt.m_generated_data);
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
/* Attempt to delete the " (\n...)". */
@@ -5494,9 +5509,10 @@ test_tab_expansion (const line_table_case &case_)
const int last_byte_col = 25;
ASSERT_EQ (35, cpp_display_width (content, last_byte_col, policy));
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
line_table_test ltt (case_);
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, strlen (content),
+ ltt.m_generated_data);
+ tmp.do_linemap_add (1);
/* Don't attempt to run the tests if column data might be unavailable. */
location_t line_end = linemap_position_for_column (line_table, last_byte_col);
@@ -5543,15 +5559,14 @@ test_escaping_bytes_1 (const line_table_case &case_)
{
const char content[] = "before\0\1\2\3\v\x80\xff""after\n";
const size_t sz = sizeof (content);
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content, sz);
line_table_test ltt (case_);
- const line_map_ordinary *ord_map = linemap_check_ordinary
- (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, sz,
+ ltt.m_generated_data);
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
location_t finish
- = linemap_position_for_line_and_column (line_table, ord_map, 1,
- strlen (content));
+ = linemap_position_for_line_and_column (line_table, ord_map, 1, sz);
if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
@@ -5599,15 +5614,14 @@ test_escaping_bytes_2 (const line_table_case &case_)
{
const char content[] = "\0after\n";
const size_t sz = sizeof (content);
- temp_source_file tmp (SELFTEST_LOCATION, ".c", content, sz);
line_table_test ltt (case_);
- const line_map_ordinary *ord_map = linemap_check_ordinary
- (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
+ temp_source_file tmp (SELFTEST_LOCATION, ".c", content, sz,
+ ltt.m_generated_data);
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
location_t finish
- = linemap_position_for_line_and_column (line_table, ord_map, 1,
- strlen (content));
+ = linemap_position_for_line_and_column (line_table, ord_map, 1, sz);
if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
@@ -5659,8 +5673,7 @@ test_line_numbers_multiline_range ()
temp_source_file tmp (SELFTEST_LOCATION, ".txt", pp_formatted_text (&pp));
line_table_test ltt;
- const line_map_ordinary *ord_map = linemap_check_ordinary
- (linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 0));
+ const line_map_ordinary *ord_map = tmp.do_linemap_add (0);
linemap_line_start (line_table, 1, 100);
/* Create a multi-line location, starting at the "line" of line 9, with
@@ -5701,28 +5714,28 @@ diagnostic_show_locus_cc_tests ()
test_display_widths ();
- for_each_line_table_case (test_layout_x_offset_display_utf8);
- for_each_line_table_case (test_layout_x_offset_display_tab);
+ for_each_line_table_case (test_layout_x_offset_display_utf8, true);
+ for_each_line_table_case (test_layout_x_offset_display_tab, true);
test_get_line_bytes_without_trailing_whitespace ();
test_diagnostic_show_locus_unknown_location ();
- for_each_line_table_case (test_diagnostic_show_locus_one_liner);
- for_each_line_table_case (test_diagnostic_show_locus_one_liner_utf8);
- for_each_line_table_case (test_add_location_if_nearby);
- for_each_line_table_case (test_diagnostic_show_locus_fixit_lines);
- for_each_line_table_case (test_fixit_consolidation);
- for_each_line_table_case (test_overlapped_fixit_printing);
- for_each_line_table_case (test_overlapped_fixit_printing_utf8);
- for_each_line_table_case (test_overlapped_fixit_printing_2);
- for_each_line_table_case (test_fixit_insert_containing_newline);
- for_each_line_table_case (test_fixit_insert_containing_newline_2);
- for_each_line_table_case (test_fixit_replace_containing_newline);
- for_each_line_table_case (test_fixit_deletion_affecting_newline);
- for_each_line_table_case (test_tab_expansion);
- for_each_line_table_case (test_escaping_bytes_1);
- for_each_line_table_case (test_escaping_bytes_2);
+ for_each_line_table_case (test_diagnostic_show_locus_one_liner, true);
+ for_each_line_table_case (test_diagnostic_show_locus_one_liner_utf8, true);
+ for_each_line_table_case (test_add_location_if_nearby, true);
+ for_each_line_table_case (test_diagnostic_show_locus_fixit_lines, true);
+ for_each_line_table_case (test_fixit_consolidation, true);
+ for_each_line_table_case (test_overlapped_fixit_printing, true);
+ for_each_line_table_case (test_overlapped_fixit_printing_utf8, true);
+ for_each_line_table_case (test_overlapped_fixit_printing_2, true);
+ for_each_line_table_case (test_fixit_insert_containing_newline, true);
+ for_each_line_table_case (test_fixit_insert_containing_newline_2, true);
+ for_each_line_table_case (test_fixit_replace_containing_newline, true);
+ for_each_line_table_case (test_fixit_deletion_affecting_newline, true);
+ for_each_line_table_case (test_tab_expansion, true);
+ for_each_line_table_case (test_escaping_bytes_1, true);
+ for_each_line_table_case (test_escaping_bytes_2, true);
test_line_numbers_multiline_range ();
}
@@ -798,13 +798,15 @@ diagnostic_report_current_module (diagnostic_context *context, location_t where)
if (!includes_seen (context, map))
{
bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
+ const bool was_gen = ORDINARY_MAP_GENERATED_DATA_P (map);
expanded_location s = {};
do
{
where = linemap_included_from (map);
map = linemap_included_from_linemap (line_table, map);
bool is_module = MAP_MODULE_P (map);
- s.file = LINEMAP_FILE (map);
+ s.file = (ORDINARY_MAP_GENERATED_DATA_P (map)
+ ? special_fname_generated () : LINEMAP_FILE (map));
s.line = SOURCE_LINE (map, where);
int col = -1;
if (first && context->show_column)
@@ -823,10 +825,13 @@ diagnostic_report_current_module (diagnostic_context *context, location_t where)
N_("of module"),
N_("In module imported at"), /* 6 */
N_("imported at"),
+ N_("In buffer generated from"), /* 8 */
};
- unsigned index = (was_module ? 6 : is_module ? 4
- : need_inc ? 2 : 0) + !first;
+ const unsigned index
+ = was_gen ? 8
+ : ((was_module ? 6 : is_module ? 4 : need_inc ? 2 : 0)
+ + !first);
pp_verbatim (context->printer, "%s%s %r%s%s%R",
first ? "" : was_module ? ", " : ",\n",
@@ -2690,12 +2695,10 @@ assert_location_text (const char *expected_loc_text,
dc.column_unit = column_unit;
dc.column_origin = origin;
- expanded_location xloc;
+ expanded_location xloc = {};
xloc.file = filename;
xloc.line = line;
xloc.column = column;
- xloc.data = NULL;
- xloc.sysp = false;
char *actual_loc_text = diagnostic_get_location_text (&dc, xloc);
ASSERT_STREQ (expected_loc_text, actual_loc_text);
@@ -78,7 +78,7 @@ static bool
blank_line_before_p (location_t loc)
{
expanded_location exploc = expand_location (loc);
- char_span line = location_get_source_line (exploc.file, exploc.line);
+ char_span line = location_get_source_line (exploc);
if (!line)
return false;
if (line.length () < (size_t)exploc.column)
@@ -84,7 +84,8 @@ Gcc_linemap::to_string(Location location)
resolved_location =
linemap_resolve_location (line_table, location.gcc_location(),
LRK_SPELLING_LOCATION, &lmo);
- if (lmo == NULL || resolved_location < RESERVED_LOCATION_COUNT)
+ if (lmo == NULL || resolved_location < RESERVED_LOCATION_COUNT
+ || ORDINARY_MAP_GENERATED_DATA_P (lmo))
return "";
const char *path = LINEMAP_FILE (lmo);
if (!path)
@@ -35,6 +35,12 @@ special_fname_builtin ()
return _("<built-in>");
}
+const char *
+special_fname_generated ()
+{
+ return _("<generated>");
+}
+
/* Input charset configuration. */
static const char *default_charset_callback (const char *)
{
@@ -49,34 +55,88 @@ file_cache::initialize_input_context (diagnostic_input_charset_callback ccb,
in_context.should_skip_bom = should_skip_bom;
}
-/* This is a cache used by get_next_line to store the content of a
- file to be searched for file lines. */
-class file_cache_slot
-{
-public:
- file_cache_slot ();
- ~file_cache_slot ();
+/* This is an abstract interface for a class that provides data which we want to
+ look up by line number. Concrete implementations will follow, which handle
+ the cases of reading the data from the input source files, or of reading it
+ from in-memory generated data buffers. The design is driven with reading
+ from files in mind, in particular it is desirable to read only as much of a
+ file from disk as necessary. It works like a simplified std::istream, i.e.
+ virtual function calls are only needed when we need to retrieve more data
+ from the underlying source. */
- bool read_line_num (size_t line_num,
- char ** line, ssize_t *line_len);
+class cache_data_source
+{
- /* Accessors. */
- const char *get_file_path () const { return m_file_path; }
+public:
+ bool read_line_num (size_t line_num, const char **line, ssize_t *line_len);
unsigned get_use_count () const { return m_use_count; }
+ void inc_use_count () { m_use_count++; }
+ bool get_next_line (const char **line, ssize_t *line_len);
+ bool goto_next_line ();
bool missing_trailing_newline_p () const
{
return m_missing_trailing_newline;
}
char_span get_full_file_content ();
+ bool unused () const { return !m_data_begin; }
+ virtual void reset ();
+
+protected:
+ cache_data_source ();
+ virtual ~cache_data_source ();
+
+ /* These pointers delimit the data that we are processing. They are
+ maintained by the derived classes, we only ask for more by calling
+ get_more_data(). That function should return TRUE if more data was
+ obtained. Calling get_more_data () may invalidate these pointers
+ (i.e. reallocating them to a larger buffer). */
+ const char *m_data_begin;
+ const char *m_data_end;
+ virtual bool get_more_data () = 0;
+
+ /* This is to be called by the derived classes when this object is
+ being activated. */
+ void on_create (unsigned int use_count, size_t total_lines)
+ {
+ m_use_count = use_count;
+ m_total_lines = total_lines;
+ }
- void inc_use_count () { m_use_count++; }
+private:
+ /* Non-copyable. */
+ cache_data_source (const cache_data_source &) = delete;
+ cache_data_source& operator= (const cache_data_source &) = delete;
- bool create (const file_cache::input_context &in_context,
- const char *file_path, FILE *fp, unsigned highest_use_count);
- void evict ();
+ /* The number of times this data has been accessed. This is used to designate
+ which entry to evict from the cache array when needed. */
+ unsigned m_use_count;
- private:
- /* These are information used to store a line boundary. */
+ /* Could this file be missing a trailing newline on its final line?
+ Initially true (to cope with empty files), set to true/false
+ as each line is read. */
+ bool m_missing_trailing_newline;
+
+ /* This is the total number of lines in the current data. At the
+ moment, we try to get this information from the line map
+ subsystem. Note that this is just a hint. When using the C++
+ front-end, this hint is correct because the input file is then
+ completely tokenized before parsing starts; so the line map knows
+ the number of lines before compilation really starts. For e.g,
+ the C front-end, it can happen that we start emitting diagnostics
+ before the line map has seen the end of the file. */
+ size_t m_total_lines;
+
+ /* The number of the previous lines read. This starts at 1. Zero
+ means we've read no line so far. */
+ size_t m_line_num;
+
+ /* The index of the beginning of the current line. */
+ size_t m_line_start_idx;
+
+ /* These are information used to store a line boundary. Here and below, we
+ store always byte offsets, not pointers, since the underlying buffer may be
+ reallocated by the derived implementation unbeknownst to us after calling
+ get_more_data(). */
class line_info
{
public:
@@ -84,13 +144,12 @@ public:
size_t line_num;
/* The position (byte count) of the beginning of the line,
- relative to the file data pointer. This starts at zero. */
+ relative to M_DATA_BEGIN. This starts at zero. */
size_t start_pos;
- /* The position (byte count) of the last byte of the line. This
- normally points to the '\n' character, or to one byte after the
- last byte of the file, if the file doesn't contain a '\n'
- character. */
+ /* The position (byte count) of the last byte of the line. This normally
+ points to the '\n' character, or to M_DATA_END, if the data doesn't end
+ with a '\n' character. */
size_t end_pos;
line_info (size_t l, size_t s, size_t e)
@@ -98,91 +157,76 @@ public:
{}
line_info ()
- :line_num (0), start_pos (0), end_pos (0)
+ : line_num (0), start_pos (0), end_pos (0)
{}
};
- bool needs_read_p () const;
- bool needs_grow_p () const;
- void maybe_grow ();
- bool read_data ();
- bool maybe_read_data ();
- bool get_next_line (char **line, ssize_t *line_len);
- bool read_next_line (char ** line, ssize_t *line_len);
- bool goto_next_line ();
-
- static const size_t buffer_size = 4 * 1024;
+ /* This is a record of the beginning and end of the lines we've seen
+ while reading the file. This is useful to avoid walking the data
+ from the beginning when we are asked to read a line that is
+ before M_LINE_START_IDX. Note that the maximum size of this
+ record is line_record_size, so that the memory consumption
+ doesn't explode. We thus scale total_lines down to
+ line_record_size. */
+ vec<line_info, va_heap> m_line_record;
static const size_t line_record_size = 100;
+};
- /* The number of time this file has been accessed. This is used
- to designate which file cache to evict from the cache
- array. */
- unsigned m_use_count;
-
- /* The file_path is the key for identifying a particular file in
- the cache.
- For libcpp-using code, the underlying buffer for this field is
- owned by the corresponding _cpp_file within the cpp_reader. */
- const char *m_file_path;
-
- FILE *m_fp;
-
- /* This points to the content of the file that we've read so
- far. */
- char *m_data;
-
- /* The allocated buffer to be freed may start a little earlier than DATA,
- e.g. if a UTF8 BOM was skipped at the beginning. */
- int m_alloc_offset;
+/* This is the implementation of cache_data_source for ordinary
+ source files. */
+class file_cache_slot final : public cache_data_source
+{
- /* The size of the DATA array above.*/
- size_t m_size;
+public:
+ file_cache_slot ();
+ ~file_cache_slot ();
- /* The number of bytes read from the underlying file so far. This
- must be less (or equal) than SIZE above. */
- size_t m_nb_read;
+ const char *get_file_path () const { return m_file_path; }
+ bool create (const file_cache::input_context &in_context,
+ const char *file_path, FILE *fp, unsigned highest_use_count);
+ void reset () override;
- /* The index of the beginning of the current line. */
- size_t m_line_start_idx;
+protected:
+ bool get_more_data () override;
- /* The number of the previous line read. This starts at 1. Zero
- means we've read no line so far. */
- size_t m_line_num;
-
- /* This is the total number of lines of the current file. At the
- moment, we try to get this information from the line map
- subsystem. Note that this is just a hint. When using the C++
- front-end, this hint is correct because the input file is then
- completely tokenized before parsing starts; so the line map knows
- the number of lines before compilation really starts. For e.g,
- the C front-end, it can happen that we start emitting diagnostics
- before the line map has seen the end of the file. */
- size_t m_total_lines;
+private:
+ /* The file_path is the key for identifying a particular file in the cache.
+ For libcpp-using code, the underlying buffer for this field is owned by the
+ corresponding _cpp_file within the cpp_reader. */
+ const char *m_file_path;
- /* Could this file be missing a trailing newline on its final line?
- Initially true (to cope with empty files), set to true/false
- as each line is read. */
- bool m_missing_trailing_newline;
+ FILE *m_fp;
- /* This is a record of the beginning and end of the lines we've seen
- while reading the file. This is useful to avoid walking the data
- from the beginning when we are asked to read a line that is
- before LINE_START_IDX above. Note that the maximum size of this
- record is line_record_size, so that the memory consumption
- doesn't explode. We thus scale total_lines down to
- line_record_size. */
- vec<line_info, va_heap> m_line_record;
+ /* The base class M_DATA_BEGIN and M_DATA_END delimit the bytes that are ready
+ to process. These two pointers here track a growable memory buffer, owned
+ by this object, where we store data as we read it from the file; we arrange
+ for the base class pointers to point to the right place within this
+ buffer. */
+ char *m_buf_begin;
+ char *m_buf_end;
+ void maybe_grow ();
+};
- void offset_buffer (int offset)
+/* This is the implementation of cache_data_source for generated
+ data that is already in memory. */
+class data_cache_slot final : public cache_data_source
+{
+public:
+ void create (const char *data, unsigned int data_len,
+ unsigned int highest_use_count);
+ bool represents_data (const char *data, unsigned int) const
{
- gcc_assert (offset < 0 ? m_alloc_offset + offset >= 0
- : (size_t) offset <= m_size);
- gcc_assert (m_data);
- m_alloc_offset += offset;
- m_data += offset;
- m_size -= offset;
+ /* We can just use pointer equality here since the generated data lives in
+ memory in one persistent place. It isn't anticipated there would be
+ several generated data buffers with the same content, so we don't mind
+ that in such a case we will store it twice. */
+ return m_data_begin == data;
}
+protected:
+ /* In contrast to file_cache_slot, we do not own a buffer. The buffer
+ passed to create() needs to outlive this object. */
+ bool get_more_data () override { return false; }
};
/* Current position in real source file. */
@@ -283,6 +327,8 @@ expand_location_1 (location_t loc,
xloc.data = block;
if (loc <= BUILTINS_LOCATION)
xloc.file = loc == UNKNOWN_LOCATION ? NULL : special_fname_builtin ();
+ else if (xloc.generated_data_len)
+ xloc.file = special_fname_generated ();
return xloc;
}
@@ -317,11 +363,12 @@ diagnostic_file_cache_fini (void)
equals the actual number of lines of the file. */
static size_t
-total_lines_num (const char *file_path)
+total_lines_num (const char *fname_or_data, bool is_data)
{
size_t r = 0;
location_t l = 0;
- if (linemap_get_file_highest_location (line_table, file_path, &l))
+ if (linemap_get_file_highest_location (line_table, fname_or_data,
+ is_data, &l))
{
gcc_assert (l >= RESERVED_LOCATION_COUNT);
expanded_location xloc = expand_location (l);
@@ -357,6 +404,21 @@ file_cache::lookup_file (const char *file_path)
return r;
}
+data_cache_slot *
+file_cache::lookup_data (const char *data, unsigned int data_len)
+{
+ for (unsigned int i = 0; i != num_file_slots; ++i)
+ {
+ const auto slot = m_data_slots + i;
+ if (slot->represents_data (data, data_len))
+ {
+ slot->inc_use_count ();
+ return slot;
+ }
+ }
+ return nullptr;
+}
+
/* Purge any mention of FILENAME from the cache of files used for
printing source code. For use in selftests when working
with tempfiles. */
@@ -372,6 +434,15 @@ diagnostics_file_cache_forcibly_evict_file (const char *file_path)
global_dc->m_file_cache->forcibly_evict_file (file_path);
}
+void
+diagnostics_file_cache_forcibly_evict_data (const char *data,
+ unsigned int data_len)
+{
+ if (!global_dc->m_file_cache)
+ return;
+ global_dc->m_file_cache->forcibly_evict_data (data, data_len);
+}
+
void
file_cache::forcibly_evict_file (const char *file_path)
{
@@ -382,55 +453,39 @@ file_cache::forcibly_evict_file (const char *file_path)
/* Not found. */
return;
- r->evict ();
+ r->reset ();
}
void
-file_cache_slot::evict ()
+file_cache::forcibly_evict_data (const char *data, unsigned int data_len)
{
- m_file_path = NULL;
- if (m_fp)
- fclose (m_fp);
- m_fp = NULL;
- m_nb_read = 0;
- m_line_start_idx = 0;
- m_line_num = 0;
- m_line_record.truncate (0);
- m_use_count = 0;
- m_total_lines = 0;
- m_missing_trailing_newline = true;
+ if (auto r = lookup_data (data, data_len))
+ r->reset ();
}
-/* Return the file cache that has been less used, recently, or the
+/* Return the cache that has been less used, recently, or the
first empty one. If HIGHEST_USE_COUNT is non-null,
*HIGHEST_USE_COUNT is set to the highest use count of the entries
in the cache table. */
-file_cache_slot*
-file_cache::evicted_cache_tab_entry (unsigned *highest_use_count)
+template <class Slot>
+Slot *
+file_cache::evicted_cache_tab_entry (Slot *slots,
+ unsigned int *highest_use_count)
{
- diagnostic_file_cache_init ();
-
- file_cache_slot *to_evict = &m_file_slots[0];
+ auto to_evict = &slots[0];
unsigned huc = to_evict->get_use_count ();
for (unsigned i = 1; i < num_file_slots; ++i)
{
- file_cache_slot *c = &m_file_slots[i];
- bool c_is_empty = (c->get_file_path () == NULL);
-
+ auto c = &slots[i];
if (c->get_use_count () < to_evict->get_use_count ()
- || (to_evict->get_file_path () && c_is_empty))
+ || (!to_evict->unused () && c->unused ()))
/* We evict C because it's either an entry with a lower use
count or one that is empty. */
to_evict = c;
if (huc < c->get_use_count ())
huc = c->get_use_count ();
-
- if (c_is_empty)
- /* We've reached the end of the cache; subsequent elements are
- all empty. */
- break;
}
if (highest_use_count)
@@ -454,24 +509,21 @@ file_cache::add_file (const char *file_path)
return NULL;
unsigned highest_use_count = 0;
- file_cache_slot *r = evicted_cache_tab_entry (&highest_use_count);
+ file_cache_slot *r = evicted_cache_tab_entry (m_file_slots,
+ &highest_use_count);
if (!r->create (in_context, file_path, fp, highest_use_count))
return NULL;
return r;
}
-/* Get a borrowed char_span to the full content of this file
- as decoded according to the input charset, encoded as UTF-8. */
-
-char_span
-file_cache_slot::get_full_file_content ()
+data_cache_slot *
+file_cache::add_data (const char *data, unsigned int data_len)
{
- char *line;
- ssize_t line_len;
- while (get_next_line (&line, &line_len))
- {
- }
- return char_span (m_data, m_nb_read);
+ unsigned int highest_use_count = 0;
+ data_cache_slot *r = evicted_cache_tab_entry (m_data_slots,
+ &highest_use_count);
+ r->create (data, data_len, highest_use_count);
+ return r;
}
/* Populate this slot for use on FILE_PATH and FP, dropping any
@@ -482,22 +534,12 @@ file_cache_slot::create (const file_cache::input_context &in_context,
const char *file_path, FILE *fp,
unsigned highest_use_count)
{
+ reset ();
+ on_create (highest_use_count + 1, total_lines_num (file_path, false));
+ m_data_begin = m_buf_begin;
+ m_data_end = m_buf_begin;
m_file_path = file_path;
- if (m_fp)
- fclose (m_fp);
m_fp = fp;
- if (m_alloc_offset)
- offset_buffer (-m_alloc_offset);
- m_nb_read = 0;
- m_line_start_idx = 0;
- m_line_num = 0;
- m_line_record.truncate (0);
- /* Ensure that this cache entry doesn't get evicted next time
- add_file_to_cache_tab is called. */
- m_use_count = ++highest_use_count;
- m_total_lines = total_lines_num (file_path);
- m_missing_trailing_newline = true;
-
/* Check the input configuration to determine if we need to do any
transformations, such as charset conversion or BOM skipping. */
@@ -510,29 +552,37 @@ file_cache_slot::create (const file_cache::input_context &in_context,
= cpp_get_converted_source (file_path, input_charset);
if (!cs.data)
return false;
- if (m_data)
- XDELETEVEC (m_data);
- m_data = cs.data;
- m_nb_read = m_size = cs.len;
- m_alloc_offset = cs.data - cs.to_free;
+ XDELETEVEC (m_buf_begin);
+ m_buf_begin = cs.to_free;
+ m_buf_end = cs.data + cs.len;
+ m_data_begin = cs.data;
+ m_data_end = m_buf_end;
}
- else if (in_context.should_skip_bom)
+ else if (in_context.should_skip_bom && get_more_data ())
{
- if (read_data ())
- {
- const int offset = cpp_check_utf8_bom (m_data, m_nb_read);
- offset_buffer (offset);
- m_nb_read -= offset;
- }
+ const int offset = cpp_check_utf8_bom (m_data_begin,
+ m_data_end - m_data_begin);
+ m_data_begin += offset;
}
return true;
}
+void
+data_cache_slot::create (const char *data, unsigned int data_len,
+ unsigned int highest_use_count)
+{
+ reset ();
+ on_create (highest_use_count + 1, total_lines_num (data, true));
+ m_data_begin = data;
+ m_data_end = data + data_len;
+}
+
/* file_cache's ctor. */
file_cache::file_cache ()
-: m_file_slots (new file_cache_slot[num_file_slots])
+ : m_file_slots (new file_cache_slot[num_file_slots]),
+ m_data_slots (new data_cache_slot[num_file_slots])
{
initialize_input_context (nullptr, false);
}
@@ -541,6 +591,7 @@ file_cache::file_cache ()
file_cache::~file_cache ()
{
+ delete[] m_data_slots;
delete[] m_file_slots;
}
@@ -558,55 +609,69 @@ file_cache::lookup_or_add_file (const char *file_path)
return r;
}
-/* Default constructor for a cache of file used by caret
- diagnostic. */
+data_cache_slot *
+file_cache::lookup_or_add_data (const char *data, unsigned int data_len)
+{
+ data_cache_slot *r = lookup_data (data, data_len);
+ if (!r)
+ r = add_data (data, data_len);
+ return r;
+}
-file_cache_slot::file_cache_slot ()
-: m_use_count (0), m_file_path (NULL), m_fp (NULL), m_data (0),
- m_alloc_offset (0), m_size (0), m_nb_read (0), m_line_start_idx (0),
- m_line_num (0), m_total_lines (0), m_missing_trailing_newline (true)
+cache_data_source::cache_data_source ()
+: m_data_begin (nullptr), m_data_end (nullptr),
+ m_use_count (0),
+ m_missing_trailing_newline (true),
+ m_total_lines (0),
+ m_line_num (0),
+ m_line_start_idx (0)
{
m_line_record.create (0);
}
-/* Destructor for a cache of file used by caret diagnostic. */
-
-file_cache_slot::~file_cache_slot ()
+cache_data_source::~cache_data_source ()
{
- if (m_fp)
- {
- fclose (m_fp);
- m_fp = NULL;
- }
- if (m_data)
- {
- offset_buffer (-m_alloc_offset);
- XDELETEVEC (m_data);
- m_data = 0;
- }
m_line_record.release ();
}
-/* Returns TRUE iff the cache would need to be filled with data coming
- from the file. That is, either the cache is empty or full or the
- current line is empty. Note that if the cache is full, it would
- need to be extended and filled again. */
-
-bool
-file_cache_slot::needs_read_p () const
+void
+cache_data_source::reset ()
{
- return m_fp && (m_nb_read == 0
- || m_nb_read == m_size
- || (m_line_start_idx >= m_nb_read - 1));
+ m_data_begin = nullptr;
+ m_data_end = nullptr;
+ m_use_count = 0;
+ m_missing_trailing_newline = true;
+ m_total_lines = 0;
+ m_line_num = 0;
+ m_line_start_idx = 0;
+ m_line_record.truncate (0);
}
-/* Return TRUE iff the cache is full and thus needs to be
- extended. */
+file_cache_slot::file_cache_slot ()
+: m_file_path (nullptr), m_fp (nullptr),
+ m_buf_begin (nullptr), m_buf_end (nullptr)
+{}
-bool
-file_cache_slot::needs_grow_p () const
+file_cache_slot::~file_cache_slot ()
{
- return m_nb_read == m_size;
+ if (m_fp)
+ fclose (m_fp);
+ XDELETEVEC (m_buf_begin);
+}
+
+void
+file_cache_slot::reset ()
+{
+ cache_data_source::reset ();
+ m_file_path = NULL;
+ if (m_fp)
+ {
+ fclose (m_fp);
+ m_fp = NULL;
+ }
+
+ /* Do not free the buffer here, we intend to reuse it the next time this
+ slot is activated. */
}
/* Grow the cache if it needs to be extended. */
@@ -614,22 +679,23 @@ file_cache_slot::needs_grow_p () const
void
file_cache_slot::maybe_grow ()
{
- if (!needs_grow_p ())
- return;
-
- if (!m_data)
+ if (!m_buf_begin)
{
- gcc_assert (m_size == 0 && m_alloc_offset == 0);
- m_size = buffer_size;
- m_data = XNEWVEC (char, m_size);
+ const size_t buffer_size = 4 * 1024;
+ m_buf_begin = XNEWVEC (char, buffer_size);
+ m_buf_end = m_buf_begin + buffer_size;
+ m_data_begin = m_buf_begin;
+ m_data_end = m_data_begin;
}
- else
+ else if (m_data_end == m_buf_end)
{
- const int offset = m_alloc_offset;
- offset_buffer (-offset);
- m_size *= 2;
- m_data = XRESIZEVEC (char, m_data, m_size);
- offset_buffer (offset);
+ const auto new_size = 2 * (m_buf_end - m_buf_begin);
+ const auto data_offset = m_data_begin - m_buf_begin;
+ const auto data_size = m_data_end - m_data_begin;
+ m_buf_begin = XRESIZEVEC (char, m_buf_begin, new_size);
+ m_buf_end = m_buf_begin + new_size;
+ m_data_begin = m_buf_begin + data_offset;
+ m_data_end = m_data_begin + data_size;
}
}
@@ -637,45 +703,28 @@ file_cache_slot::maybe_grow ()
Returns TRUE iff new data could be read. */
bool
-file_cache_slot::read_data ()
+file_cache_slot::get_more_data ()
{
- if (feof (m_fp) || ferror (m_fp))
+ if (!m_fp || feof (m_fp) || ferror (m_fp))
return false;
-
maybe_grow ();
-
- char * from = m_data + m_nb_read;
- size_t to_read = m_size - m_nb_read;
- size_t nb_read = fread (from, 1, to_read, m_fp);
-
- if (ferror (m_fp))
+ char *const dest = m_buf_begin + (m_data_end - m_buf_begin);
+ const auto nb_read = fread (dest, 1, m_buf_end - dest, m_fp);
+ if (ferror (m_fp) || !nb_read)
return false;
-
- m_nb_read += nb_read;
- return !!nb_read;
-}
-
-/* Read new data iff the cache needs to be filled with more data
- coming from the file FP. Return TRUE iff the cache was filled with
- mode data. */
-
-bool
-file_cache_slot::maybe_read_data ()
-{
- if (!needs_read_p ())
- return false;
- return read_data ();
+ m_data_end += nb_read;
+ return true;
}
-/* Helper function for file_cache_slot::get_next_line (), to find the end of
+/* Helper function for cache_data_source::get_next_line (), to find the end of
the next line. Returns with the memchr convention, i.e. nullptr if a line
terminator was not found. We need to determine line endings in the same
manner that libcpp does: any of \n, \r\n, or \r is a line ending. */
-static char *
-find_end_of_line (char *s, size_t len)
+static const char *
+find_end_of_line (const char *s, const char *end)
{
- for (const auto end = s + len; s != end; ++s)
+ for (; s != end; ++s)
{
if (*s == '\n')
return s;
@@ -698,41 +747,38 @@ find_end_of_line (char *s, size_t len)
return nullptr;
}
-/* Read a new line from file FP, using C as a cache for the data
- coming from the file. Upon successful completion, *LINE is set to
- the beginning of the line found. *LINE points directly in the
- line cache and is only valid until the next call of get_next_line.
- *LINE_LEN is set to the length of the line. Note that the line
- does not contain any terminal delimiter. This function returns
- true if some data was read or process from the cache, false
- otherwise. Note that subsequent calls to get_next_line might
- make the content of *LINE invalid. */
+/* Read a new line from the data source. Upon successful completion, *LINE is
+ set to the beginning of the line found. *LINE points directly in the line
+ cache and is only valid until the next call of get_next_line. *LINE_LEN is
+ set to the length of the line. Note that the line does not contain any
+ terminal delimiter. This function returns true if some data was read or
+ processed from the cache, false otherwise. Note that subsequent calls to
+ get_next_line might make the content of *LINE invalid. */
bool
-file_cache_slot::get_next_line (char **line, ssize_t *line_len)
+cache_data_source::get_next_line (const char **line, ssize_t *line_len)
{
- /* Fill the cache with data to process. */
- maybe_read_data ();
+ const char *line_start = m_data_begin + m_line_start_idx;
- size_t remaining_size = m_nb_read - m_line_start_idx;
- if (remaining_size == 0)
- /* There is no more data to process. */
- return false;
-
- char *line_start = m_data + m_line_start_idx;
+ /* Check if we are all done reading the file. */
+ if (line_start == m_data_end)
+ {
+ if (!get_more_data ())
+ return false;
+ line_start = m_data_begin + m_line_start_idx;
+ }
- char *next_line_start = NULL;
- size_t len = 0;
- char *line_end = find_end_of_line (line_start, remaining_size);
+ /* Find the end of the current line. */
+ const char *next_line_start = NULL;
+ const char *line_end = find_end_of_line (line_start, m_data_end);
if (line_end == NULL)
{
/* We haven't found an end-of-line delimiter in the cache.
Fill the cache with more data from the file and look again. */
- while (maybe_read_data ())
+ while (get_more_data ())
{
- line_start = m_data + m_line_start_idx;
- remaining_size = m_nb_read - m_line_start_idx;
- line_end = find_end_of_line (line_start, remaining_size);
+ line_start = m_data_begin + m_line_start_idx;
+ line_end = find_end_of_line (line_start, m_data_end);
if (line_end != NULL)
{
next_line_start = line_end + 1;
@@ -749,8 +795,8 @@ file_cache_slot::get_next_line (char **line, ssize_t *line_len)
If the file ends in a \r, we didn't identify it as a line
terminator above, so do that now instead. */
- line_end = m_data + m_nb_read;
- if (m_nb_read && line_end[-1] == '\r')
+ line_end = m_data_end;
+ if (line_end != m_data_begin && line_end[-1] == '\r')
{
--line_end;
m_missing_trailing_newline = false;
@@ -767,18 +813,11 @@ file_cache_slot::get_next_line (char **line, ssize_t *line_len)
m_missing_trailing_newline = false;
}
- if (m_fp && ferror (m_fp))
- return false;
-
/* At this point, we've found the end of the of line. It either points to
the line terminator or to one byte after the last byte of the file. */
- gcc_assert (line_end != NULL);
-
- len = line_end - line_start;
-
- if (m_line_start_idx < m_nb_read)
- *line = line_start;
-
+ const auto len = line_end - line_start;
+ *line = line_start;
+ *line_len = len;
++m_line_num;
/* Before we update our line record, make sure the hint about the
@@ -800,7 +839,7 @@ file_cache_slot::get_next_line (char **line, ssize_t *line_len)
m_line_record.safe_push
(file_cache_slot::line_info (m_line_num,
m_line_start_idx,
- line_end - m_data));
+ line_end - m_data_begin));
else if (m_total_lines > line_record_size)
{
/* ... otherwise, we just scale total_lines down to
@@ -811,23 +850,14 @@ file_cache_slot::get_next_line (char **line, ssize_t *line_len)
m_line_record.safe_push
(file_cache_slot::line_info (m_line_num,
m_line_start_idx,
- line_end - m_data));
+ line_end - m_data_begin));
}
}
/* Update m_line_start_idx so that it points to the next line to be
read. */
- if (next_line_start)
- m_line_start_idx = next_line_start - m_data;
- else
- /* We didn't find any terminal '\n'. Let's consider that the end
- of line is the end of the data in the cache. The next
- invocation of get_next_line will either read more data from the
- underlying file or return false early because we've reached the
- end of the file. */
- m_line_start_idx = m_nb_read;
-
- *line_len = len;
+ m_line_start_idx
+ = (next_line_start ? next_line_start : m_data_end) - m_data_begin;
return true;
}
@@ -839,15 +869,15 @@ file_cache_slot::get_next_line (char **line, ssize_t *line_len)
completion. */
bool
-file_cache_slot::goto_next_line ()
+cache_data_source::goto_next_line ()
{
- char *l;
+ const char *l;
ssize_t len;
return get_next_line (&l, &len);
}
-/* Read an arbitrary line number LINE_NUM from the file cached in C.
+/* Read an arbitrary line number LINE_NUM from the data cache.
If the line was read successfully, *LINE points to the beginning
of the line in the file cache and *LINE_LEN is the length of the
line. *LINE is not nul-terminated, but may contain zero bytes.
@@ -855,8 +885,8 @@ file_cache_slot::goto_next_line ()
This function returns bool if a line was read. */
bool
-file_cache_slot::read_line_num (size_t line_num,
- char ** line, ssize_t *line_len)
+cache_data_source::read_line_num (size_t line_num,
+ const char ** line, ssize_t *line_len)
{
gcc_assert (line_num > 0);
@@ -864,7 +894,7 @@ file_cache_slot::read_line_num (size_t line_num,
{
/* We've been asked to read lines that are before m_line_num.
So lets use our line record (if it's not empty) to try to
- avoid re-reading the file from the beginning again. */
+ avoid re-scanning the data from the beginning again. */
if (m_line_record.is_empty ())
{
@@ -873,7 +903,7 @@ file_cache_slot::read_line_num (size_t line_num,
}
else
{
- file_cache_slot::line_info *i = NULL;
+ line_info *i = NULL;
if (m_total_lines <= line_record_size)
{
/* In languages where the input file is not totally
@@ -909,7 +939,7 @@ file_cache_slot::read_line_num (size_t line_num,
if (i && i->line_num == line_num)
{
/* We have the start/end of the line. */
- *line = m_data + i->start_pos;
+ *line = m_data_begin + i->start_pos;
*line_len = i->end_pos - i->start_pos;
return true;
}
@@ -938,6 +968,20 @@ file_cache_slot::read_line_num (size_t line_num,
return get_next_line (line, line_len);
}
+/* Get a borrowed char_span to the full content of this file
+ as decoded according to the input charset, encoded as UTF-8. */
+
+char_span
+cache_data_source::get_full_file_content ()
+{
+ const char *line;
+ ssize_t line_len;
+ while (get_next_line (&line, &line_len))
+ {
+ }
+ return char_span (m_data_begin, m_data_end - m_data_begin);
+}
+
/* Return the physical source line that corresponds to FILE_PATH/LINE.
The line is not nul-terminated. The returned pointer is only
valid until the next call of location_get_source_line.
@@ -946,30 +990,56 @@ file_cache_slot::read_line_num (size_t line_num,
If the function fails, a NULL char_span is returned. */
char_span
-location_get_source_line (const char *file_path, int line)
+location_get_source_line (expanded_location xloc, int line)
{
- char *buffer = NULL;
- ssize_t len;
-
+ const char_span fail (nullptr, 0);
if (line == 0)
- return char_span (NULL, 0);
-
- if (file_path == NULL)
- return char_span (NULL, 0);
+ return fail;
diagnostic_file_cache_init ();
- file_cache_slot *c = global_dc->m_file_cache->lookup_or_add_file (file_path);
- if (c == NULL)
- return char_span (NULL, 0);
+ cache_data_source *c;
+ if (xloc.generated_data_len)
+ {
+ if (!xloc.generated_data)
+ return fail;
+ c = global_dc->m_file_cache->lookup_or_add_data (xloc.generated_data,
+ xloc.generated_data_len);
+ }
+ else
+ {
+ if (!xloc.file)
+ return fail;
+ c = global_dc->m_file_cache->lookup_or_add_file (xloc.file);
+ }
+ if (!c)
+ return fail;
+
+ const char *buffer = NULL;
+ ssize_t len;
bool read = c->read_line_num (line, &buffer, &len);
if (!read)
- return char_span (NULL, 0);
+ return fail;
return char_span (buffer, len);
}
+char_span
+location_get_source_line (expanded_location xloc)
+{
+ return location_get_source_line (xloc, xloc.line);
+}
+
+char_span
+location_get_source_line (const char *file_path, int line)
+{
+ expanded_location xloc = {};
+ xloc.file = file_path;
+ xloc.line = line;
+ return location_get_source_line (xloc);
+}
+
/* Return a NUL-terminated copy of the source text between two locations, or
NULL if the arguments are invalid. The caller is responsible for freeing
the return value. */
@@ -986,8 +1056,18 @@ get_source_text_between (location_t start, location_t end)
start, give up and return nothing. */
if (!expstart.file || !expend.file)
return NULL;
- if (strcmp (expstart.file, expend.file) != 0)
+ if (expstart.generated_data_len != expend.generated_data_len)
return NULL;
+ if (expstart.generated_data_len)
+ {
+ if (expstart.generated_data != expend.generated_data)
+ return NULL;
+ }
+ else
+ {
+ if (strcmp (expstart.file, expend.file) != 0)
+ return NULL;
+ }
if (expstart.line > expend.line)
return NULL;
if (expstart.line == expend.line
@@ -1229,9 +1309,10 @@ int
location_compute_display_column (expanded_location exploc,
const cpp_char_column_policy &policy)
{
- if (!(exploc.file && *exploc.file && exploc.line && exploc.column))
+ if (!(exploc.file && (exploc.generated_data_len || *exploc.file)
+ && exploc.line && exploc.column))
return exploc.column;
- char_span line = location_get_source_line (exploc.file, exploc.line);
+ char_span line = location_get_source_line (exploc);
/* If line is NULL, this function returns exploc.column which is the
desired fallback. */
return cpp_byte_column_to_display_column (line.get_buffer (), line.length (),
@@ -1391,7 +1472,19 @@ dump_location_info (FILE *stream)
fprintf (stream, "ORDINARY MAP: %i\n", idx);
dump_location_range (stream,
MAP_START_LOCATION (map), end_location);
- fprintf (stream, " file: %s\n", ORDINARY_MAP_FILE_NAME (map));
+
+ if (ORDINARY_MAP_GENERATED_DATA_P (map))
+ {
+ fprintf (stream, " file: %s%s\n",
+ ORDINARY_MAP_CONTAINING_FILE_NAME (line_table, map),
+ special_fname_generated ());
+ fprintf (stream, " data: %.*s\n",
+ (int) ORDINARY_MAP_GENERATED_DATA_LEN (map),
+ ORDINARY_MAP_GENERATED_DATA (map));
+ }
+ else
+ fprintf (stream, " file: %s\n", LINEMAP_FILE (map));
+
fprintf (stream, " starting at line: %i\n",
ORDINARY_MAP_STARTING_LINE_NUMBER (map));
fprintf (stream, " column and range bits: %i\n",
@@ -1417,6 +1510,9 @@ dump_location_info (FILE *stream)
case LC_ENTER_MACRO:
reason = "LC_RENAME_MACRO";
break;
+ case LC_GEN:
+ reason = "LC_GEN";
+ break;
default:
reason = "Unknown";
}
@@ -1446,13 +1542,14 @@ dump_location_info (FILE *stream)
{
/* Beginning of a new source line: draw the line. */
- char_span line_text = location_get_source_line (exploc.file,
- exploc.line);
+ char_span line_text = location_get_source_line (exploc);
if (!line_text)
break;
fprintf (stream,
- "%s:%3i|loc:%5i|%.*s\n",
- exploc.file, exploc.line,
+ "%s%s:%3i|loc:%5i|%.*s\n",
+ exploc.file,
+ exploc.generated_data ? special_fname_generated () : "",
+ exploc.line,
loc,
(int)line_text.length (), line_text.get_buffer ());
@@ -1767,14 +1864,17 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
expanded_location finish
= expand_location_to_spelling_point (src_range.m_finish,
LOCATION_ASPECT_FINISH);
- if (start.file != finish.file)
+ if (start.generated_data_len != finish.generated_data_len
+ || (start.generated_data_len
+ ? start.generated_data != finish.generated_data
+ : start.file != finish.file))
return "range endpoints are in different files";
if (start.line != finish.line)
return "range endpoints are on different lines";
if (start.column > finish.column)
return "range endpoints are reversed";
- char_span line = location_get_source_line (start.file, start.line);
+ char_span line = location_get_source_line (start);
if (!line)
return "unable to read source line";
@@ -1814,11 +1914,13 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
/* Bulletproofing. We ought to only have different ordinary maps
for start vs finish due to line-length jumps. */
if (start_ord_map != final_ord_map
- && start_ord_map->to_file != final_ord_map->to_file)
+ && !ORDINARY_MAPS_SAME_FILE_P (start_ord_map, final_ord_map))
return "start and finish are spelled in different ordinary maps";
/* The file from linemap_resolve_location ought to match that from
expand_location_to_spelling_point. */
- if (start_ord_map->to_file != start.file)
+ if (ORDINARY_MAP_GENERATED_DATA_P (start_ord_map)
+ ? ORDINARY_MAP_GENERATED_DATA (start_ord_map) != start.generated_data
+ : ORDINARY_MAP_FILE_NAME (start_ord_map) != start.file)
return "mismatching file after resolving linemap";
location_t start_loc
@@ -1990,6 +2092,20 @@ get_num_source_ranges_for_substring (cpp_reader *pfile,
/* Selftests of location handling. */
+/* Wrapper around linemap_add to handle transparently adding either a tmp file,
+ or in-memory generated content. */
+const line_map_ordinary *
+temp_source_file::do_linemap_add (int line)
+{
+ const line_map *map;
+ if (content_buf)
+ map = linemap_add (line_table, LC_GEN, false, content_buf,
+ line, content_len);
+ else
+ map = linemap_add (line_table, LC_ENTER, false, get_filename (), line);
+ return linemap_check_ordinary (map);
+}
+
/* Verify that compare() on linenum_type handles comparisons over the full
range of the type. */
@@ -2068,13 +2184,16 @@ assert_loceq (const char *exp_filename, int exp_linenum, int exp_colnum,
class line_table_case
{
public:
- line_table_case (int default_range_bits, int base_location)
+ line_table_case (int default_range_bits, int base_location,
+ bool generated_data)
: m_default_range_bits (default_range_bits),
- m_base_location (base_location)
+ m_base_location (base_location),
+ m_generated_data (generated_data)
{}
int m_default_range_bits;
int m_base_location;
+ bool m_generated_data;
};
/* Constructor. Store the old value of line_table, and create a new
@@ -2091,6 +2210,7 @@ line_table_test::line_table_test ()
gcc_assert (saved_line_table->round_alloc_size);
line_table->round_alloc_size = saved_line_table->round_alloc_size;
line_table->default_range_bits = 0;
+ m_generated_data = false;
}
/* Constructor. Store the old value of line_table, and create a new
@@ -2112,6 +2232,7 @@ line_table_test::line_table_test (const line_table_case &case_)
line_table->highest_location = case_.m_base_location;
line_table->highest_line = case_.m_base_location;
}
+ m_generated_data = case_.m_generated_data;
}
/* Destructor. Restore the old value of line_table. */
@@ -2131,7 +2252,10 @@ test_accessing_ordinary_linemaps (const line_table_case &case_)
line_table_test ltt (case_);
/* Build a simple linemap describing some locations. */
- linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
+ if (ltt.m_generated_data)
+ linemap_add (line_table, LC_GEN, false, "some data", 0, 10);
+ else
+ linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
linemap_line_start (line_table, 1, 100);
location_t loc_a = linemap_position_for_column (line_table, 1);
@@ -2181,21 +2305,23 @@ test_accessing_ordinary_linemaps (const line_table_case &case_)
linemap_add (line_table, LC_LEAVE, false, NULL, 0);
/* Verify that we can recover the location info. */
- assert_loceq ("foo.c", 1, 1, loc_a);
- assert_loceq ("foo.c", 1, 23, loc_b);
- assert_loceq ("foo.c", 2, 1, loc_c);
- assert_loceq ("foo.c", 2, 17, loc_d);
- assert_loceq ("foo.c", 3, 700, loc_e);
- assert_loceq ("foo.c", 4, 100, loc_back_to_short);
+ const auto fname
+ = (ltt.m_generated_data ? special_fname_generated () : "foo.c");
+ assert_loceq (fname, 1, 1, loc_a);
+ assert_loceq (fname, 1, 23, loc_b);
+ assert_loceq (fname, 2, 1, loc_c);
+ assert_loceq (fname, 2, 17, loc_d);
+ assert_loceq (fname, 3, 700, loc_e);
+ assert_loceq (fname, 4, 100, loc_back_to_short);
/* In the very wide line, the initial location should be fully tracked. */
- assert_loceq ("foo.c", 5, 2000, loc_start_of_very_long_line);
+ assert_loceq (fname, 5, 2000, loc_start_of_very_long_line);
/* ...but once we exceed LINE_MAP_MAX_COLUMN_NUMBER column-tracking should
be disabled. */
- assert_loceq ("foo.c", 5, 0, loc_too_wide);
- assert_loceq ("foo.c", 5, 0, loc_too_wide_2);
+ assert_loceq (fname, 5, 0, loc_too_wide);
+ assert_loceq (fname, 5, 0, loc_too_wide_2);
/*...and column-tracking should be re-enabled for subsequent lines. */
- assert_loceq ("foo.c", 6, 10, loc_sane_again);
+ assert_loceq (fname, 6, 10, loc_sane_again);
assert_loceq ("bar.c", 1, 150, loc_f);
@@ -2242,10 +2368,11 @@ test_make_location_nonpure_range_endpoints (const line_table_case &case_)
with C++ frontend.
....................0000000001111111111222.
....................1234567890123456789012. */
- const char *content = " r += !aaa == bbb;\n";
- temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
line_table_test ltt (case_);
- linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
+ const char *content = " r += !aaa == bbb;\n";
+ temp_source_file tmp (SELFTEST_LOCATION, ".C", content, strlen (content),
+ ltt.m_generated_data);
+ tmp.do_linemap_add (1);
const location_t c11 = linemap_position_for_column (line_table, 11);
const location_t c12 = linemap_position_for_column (line_table, 12);
@@ -3902,7 +4029,8 @@ static const location_t boundary_locations[] = {
/* Run TESTCASE multiple times, once for each case in our test matrix. */
void
-for_each_line_table_case (void (*testcase) (const line_table_case &))
+for_each_line_table_case (void (*testcase) (const line_table_case &),
+ bool test_generated_data)
{
/* As noted above in the description of struct line_table_case,
we want to explore a test matrix of interesting line_table
@@ -3921,16 +4049,19 @@ for_each_line_table_case (void (*testcase) (const line_table_case &))
const int num_boundary_locations = ARRAY_SIZE (boundary_locations);
for (int loc_idx = 0; loc_idx < num_boundary_locations; loc_idx++)
{
- line_table_case c (default_range_bits, boundary_locations[loc_idx]);
-
- testcase (c);
-
- num_cases_tested++;
+ /* ...and try both normal files, and internally generated data. */
+ for (int gen = 0; gen != 1+test_generated_data; ++gen)
+ {
+ line_table_case c (default_range_bits,
+ boundary_locations[loc_idx], gen);
+ testcase (c);
+ num_cases_tested++;
+ }
}
}
/* Verify that we fully covered the test matrix. */
- ASSERT_EQ (num_cases_tested, 2 * 12);
+ ASSERT_EQ (num_cases_tested, 2 * 12 * (1+test_generated_data));
}
/* Verify that when presented with a consecutive pair of locations with
@@ -3941,7 +4072,7 @@ for_each_line_table_case (void (*testcase) (const line_table_case &))
static void
test_line_offset_overflow ()
{
- line_table_test ltt (line_table_case (5, 0));
+ line_table_test ltt (line_table_case (5, 0, false));
linemap_add (line_table, LC_ENTER, false, "foo.c", 0);
linemap_line_start (line_table, 1, 100);
@@ -4181,9 +4312,9 @@ input_cc_tests ()
test_should_have_column_data_p ();
test_unknown_location ();
test_builtins ();
- for_each_line_table_case (test_make_location_nonpure_range_endpoints);
+ for_each_line_table_case (test_make_location_nonpure_range_endpoints, true);
- for_each_line_table_case (test_accessing_ordinary_linemaps);
+ for_each_line_table_case (test_accessing_ordinary_linemaps, true);
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);
@@ -34,6 +34,7 @@ extern GTY(()) class line_maps *saved_line_table;
/* Returns the translated string referring to the special location. */
const char *special_fname_builtin ();
+const char *special_fname_generated ();
/* line-map.cc reserves RESERVED_LOCATION_COUNT to the user. Ensure
both UNKNOWN_LOCATION and BUILTINS_LOCATION fit into that. */
@@ -114,14 +115,21 @@ class char_span
};
extern char_span location_get_source_line (const char *file_path, int line);
+
+/* The version taking an exploc handles generated source too, and should be used
+ whenever possible. */
+extern char_span location_get_source_line (expanded_location exploc);
+extern char_span location_get_source_line (expanded_location exploc, int line);
+
extern char *get_source_text_between (location_t, location_t);
extern char_span get_source_file_content (const char *file_path);
extern bool location_missing_trailing_newline (const char *file_path);
-/* Forward decl of slot within file_cache, so that the definition doesn't
+/* Forward decl of slots within file_cache, so that the definition doesn't
need to be in this header. */
class file_cache_slot;
+class data_cache_slot;
/* A cache of source files for use when emitting diagnostics
(and in a few places in the C/C++ frontends).
@@ -139,7 +147,9 @@ class file_cache
~file_cache ();
file_cache_slot *lookup_or_add_file (const char *file_path);
+ data_cache_slot *lookup_or_add_data (const char *data, unsigned int data_len);
void forcibly_evict_file (const char *file_path);
+ void forcibly_evict_data (const char *data, unsigned int data_len);
/* See comments in diagnostic.h about the input conversion context. */
struct input_context
@@ -151,13 +161,17 @@ class file_cache
bool should_skip_bom);
private:
- file_cache_slot *evicted_cache_tab_entry (unsigned *highest_use_count);
+ template <class Slot>
+ Slot *evicted_cache_tab_entry (Slot *slots, unsigned int *highest_use_count);
+
file_cache_slot *add_file (const char *file_path);
+ data_cache_slot *add_data (const char *data, unsigned int data_len);
file_cache_slot *lookup_file (const char *file_path);
+ data_cache_slot *lookup_data (const char *data, unsigned int data_len);
- private:
static const size_t num_file_slots = 16;
file_cache_slot *m_file_slots;
+ data_cache_slot *m_data_slots;
input_context in_context;
};
@@ -254,6 +268,8 @@ void dump_location_info (FILE *stream);
void diagnostics_file_cache_fini (void);
void diagnostics_file_cache_forcibly_evict_file (const char *file_path);
+void diagnostics_file_cache_forcibly_evict_data (const char *data,
+ unsigned int data_len);
class GTY(()) string_concat
{
@@ -163,14 +163,21 @@ assert_str_startswith (const location &loc,
named_temp_file::named_temp_file (const char *suffix)
{
- m_filename = make_temp_file (suffix);
- ASSERT_NE (m_filename, NULL);
+ if (suffix)
+ {
+ m_filename = make_temp_file (suffix);
+ ASSERT_NE (m_filename, NULL);
+ }
+ else
+ m_filename = nullptr;
}
/* Destructor. Delete the tempfile. */
named_temp_file::~named_temp_file ()
{
+ if (!m_filename)
+ return;
unlink (m_filename);
diagnostics_file_cache_forcibly_evict_file (m_filename);
free (m_filename);
@@ -183,7 +190,9 @@ named_temp_file::~named_temp_file ()
temp_source_file::temp_source_file (const location &loc,
const char *suffix,
const char *content)
-: named_temp_file (suffix)
+: named_temp_file (suffix),
+ content_buf (nullptr),
+ content_len (0)
{
FILE *out = fopen (get_filename (), "w");
if (!out)
@@ -192,19 +201,41 @@ temp_source_file::temp_source_file (const location &loc,
fclose (out);
}
-/* As above, but with a size, to allow for NUL bytes in CONTENT. */
+/* As above, but with a size, to allow for NUL bytes in CONTENT. When
+ IS_GENERATED==true, the data is kept in memory instead, for testing LC_GEN
+ maps. */
temp_source_file::temp_source_file (const location &loc,
const char *suffix,
const char *content,
- size_t sz)
-: named_temp_file (suffix)
+ size_t sz,
+ bool is_generated)
+: named_temp_file (is_generated ? nullptr : suffix),
+ content_buf (is_generated ? XNEWVEC (char, sz) : nullptr),
+ content_len (is_generated ? sz : 0)
{
- FILE *out = fopen (get_filename (), "w");
- if (!out)
- fail_formatted (loc, "unable to open tempfile: %s", get_filename ());
- fwrite (content, sz, 1, out);
- fclose (out);
+ if (is_generated)
+ {
+ gcc_assert (sz); /* Empty generated content is not supported. */
+ memcpy (content_buf, content, sz);
+ }
+ else
+ {
+ FILE *out = fopen (get_filename (), "w");
+ if (!out)
+ fail_formatted (loc, "unable to open tempfile: %s", get_filename ());
+ fwrite (content, sz, 1, out);
+ fclose (out);
+ }
+}
+
+temp_source_file::~temp_source_file ()
+{
+ if (content_buf)
+ {
+ diagnostics_file_cache_forcibly_evict_data (content_buf, content_len);
+ XDELETEVEC (content_buf);
+ }
}
/* Avoid introducing locale-specific differences in the results
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see
#if CHECKING_P
+struct line_map_ordinary;
+
namespace selftest {
/* A struct describing the source-location of a selftest, to make it
@@ -96,10 +98,9 @@ extern void assert_str_startswith (const location &loc,
class named_temp_file
{
public:
- named_temp_file (const char *suffix);
+ explicit named_temp_file (const char *suffix);
~named_temp_file ();
const char *get_filename () const { return m_filename; }
-
private:
char *m_filename;
};
@@ -113,7 +114,13 @@ class temp_source_file : public named_temp_file
temp_source_file (const location &loc, const char *suffix,
const char *content);
temp_source_file (const location &loc, const char *suffix,
- const char *content, size_t sz);
+ const char *content, size_t sz,
+ bool is_generated = false);
+ ~temp_source_file ();
+
+ char *const content_buf;
+ const size_t content_len;
+ const line_map_ordinary *do_linemap_add (int line); /* In input.cc */
};
/* RAII-style class for avoiding introducing locale-specific differences
@@ -171,6 +178,10 @@ class line_table_test
/* Destructor. Restore the saved line_table. */
~line_table_test ();
+
+ /* When this is enabled in the line_table_case, test storing all the data
+ in memory rather than a file. */
+ bool m_generated_data;
};
/* Helper function for selftests that need a function decl. */
@@ -183,7 +194,8 @@ extern tree make_fndecl (tree return_type,
/* Run TESTCASE multiple times, once for each case in our test matrix. */
extern void
-for_each_line_table_case (void (*testcase) (const line_table_case &));
+for_each_line_table_case (void (*testcase) (const line_table_case &),
+ bool test_generated_data = false);
/* Read the contents of PATH into memory, returning a 0-terminated buffer
that must be freed by the caller.
@@ -430,7 +430,7 @@ test_show_locus (function *fun)
to upper case. Give all of the ranges labels (sharing one label). */
if (0 == strcmp (fnname, "test_many_nested_locations"))
{
- const char *file = LOCATION_FILE (fnstart);
+ const expanded_location xloc = expand_location (fnstart);
const int start_line = fnstart_line + 2;
const int finish_line = start_line + 7;
location_t loc = get_loc (start_line - 1, 2);
@@ -438,7 +438,7 @@ test_show_locus (function *fun)
rich_location richloc (line_table, loc);
for (int line = start_line; line <= finish_line; line++)
{
- char_span content = location_get_source_line (file, line);
+ char_span content = location_get_source_line (xloc, line);
gcc_assert (content);
/* Split line up into words. */
for (int idx = 0; idx < content.length (); idx++)
@@ -1165,7 +1165,7 @@ _cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
const char *to_file, linenum_type to_line,
unsigned int sysp)
{
- linemap_assert (reason != LC_ENTER_MACRO);
+ linemap_assert (reason != LC_ENTER_MACRO && reason != LC_GEN);
const line_map_ordinary *ord_map = NULL;
if (!to_line && reason == LC_RENAME_VERBATIM)
@@ -1176,6 +1176,7 @@ _cpp_do_file_change (cpp_reader *pfile, enum lc_reason reason,
preprocessed source. */
line_map_ordinary *last = LINEMAPS_LAST_ORDINARY_MAP (pfile->line_table);
if (!ORDINARY_MAP_STARTING_LINE_NUMBER (last)
+ && !ORDINARY_MAP_GENERATED_DATA_P (last)
&& 0 == filename_cmp (to_file, ORDINARY_MAP_FILE_NAME (last))
&& SOURCE_LINE (last, pfile->line_table->highest_line) == 2)
{
@@ -75,6 +75,8 @@ enum lc_reason
LC_RENAME_VERBATIM, /* Likewise, but "" != stdin. */
LC_ENTER_MACRO, /* Begin macro expansion. */
LC_MODULE, /* A (C++) Module. */
+ LC_GEN, /* Internally generated source. */
+
/* FIXME: add support for stringize and paste. */
LC_HWM /* High Water Mark. */
};
@@ -437,7 +439,13 @@ struct GTY((tag ("1"))) line_map_ordinary : public line_map {
/* Pointer alignment boundary on both 32 and 64-bit systems. */
- const char *to_file;
+ /* For an LC_GEN map, DATA points to the actual content. Otherwise it is
+ a file name. In the former case, the data could contain embedded nulls
+ and it need not be null terminated, so we use the GTY markup appropriate
+ for that case. */
+ const char * GTY((string_length ("%h.data_len"))) data;
+ unsigned int data_len;
+
linenum_type to_line;
/* Location from whence this line map was included. For regular
@@ -662,6 +670,12 @@ ORDINARY_MAP_IN_SYSTEM_HEADER_P (const line_map_ordinary *ord_map)
return ord_map->sysp;
}
+/* TRUE if this line map contains generated data. */
+inline bool ORDINARY_MAP_GENERATED_DATA_P (const line_map_ordinary *ord_map)
+{
+ return ord_map->reason == LC_GEN;
+}
+
/* TRUE if this line map is for a module (not a source file). */
inline bool
@@ -671,14 +685,42 @@ MAP_MODULE_P (const line_map *map)
&& linemap_check_ordinary (map)->reason == LC_MODULE);
}
-/* Get the filename of ordinary map MAP. */
+/* Get the data contents of ordinary map MAP. */
inline const char *
ORDINARY_MAP_FILE_NAME (const line_map_ordinary *ord_map)
{
- return ord_map->to_file;
+ linemap_assert (ord_map->reason != LC_GEN);
+ return ord_map->data;
}
+inline const char *
+ORDINARY_MAP_GENERATED_DATA (const line_map_ordinary *ord_map)
+{
+ linemap_assert (ord_map->reason == LC_GEN);
+ return ord_map->data;
+}
+
+inline unsigned int
+ORDINARY_MAP_GENERATED_DATA_LEN (const line_map_ordinary *ord_map)
+{
+ linemap_assert (ord_map->reason == LC_GEN);
+ return ord_map->data_len;
+}
+
+/* Sometimes we don't need to care which kind it is. */
+inline const char *
+ORDINARY_MAP_FILE_NAME_OR_DATA (const line_map_ordinary *ord_map)
+{
+ return ord_map->data;
+}
+
+/* If we just want to know whether two maps point to the same
+ file/buffer or not. */
+bool
+ORDINARY_MAPS_SAME_FILE_P (const line_map_ordinary *map1,
+ const line_map_ordinary *map2);
+
/* Get the cpp macro whose expansion gave birth to macro map MAP. */
inline cpp_hashnode *
@@ -1097,17 +1139,19 @@ extern line_map *line_map_new_raw (line_maps *, bool, unsigned);
map that records locations of tokens that are not part of macro
replacement-lists present at a macro expansion point.
- The text pointed to by TO_FILE must have a lifetime
- at least as long as the lifetime of SET. An empty
- TO_FILE means standard input. If reason is LC_LEAVE, and
- TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their
- natural values considering the file we are returning to.
+ The text pointed to by DATA must have a lifetime at least as long as the
+ lifetime of SET. If reason is LC_LEAVE, and DATA is NULL, then DATA, TO_LINE
+ and SYSP are given their natural values considering the file we are returning
+ to. If reason is LC_GEN, then DATA is the actual content, and DATA_LEN>0 is
+ the length of it. Otherwise DATA is a file name and DATA_LEN need not be
+ specified. If DATA_LEN is specified for a file name, it should be the length
+ of the file name, including the terminating null.
- A call to this function can relocate the previous set of
- maps, so any stored line_map pointers should not be used. */
+ A call to this function can relocate the previous set of maps, so any stored
+ line_map pointers should not be used. */
extern const line_map *linemap_add
(class line_maps *, enum lc_reason, unsigned int sysp,
- const char *to_file, linenum_type to_line);
+ const char *data, linenum_type to_line, unsigned int data_len = 0);
/* Create a macro map. A macro map encodes source locations of tokens
that are part of a macro replacement-list, at a macro expansion
@@ -1257,7 +1301,7 @@ linemap_position_for_loc_and_offset (class line_maps *set,
inline const char *
LINEMAP_FILE (const line_map_ordinary *ord_map)
{
- return ord_map->to_file;
+ return ORDINARY_MAP_FILE_NAME (ord_map);
}
/* Return the line number this map started encoding location from. */
@@ -1277,6 +1321,13 @@ LINEMAP_SYSP (const line_map_ordinary *ord_map)
return ord_map->sysp;
}
+/* For a normal ordinary map, this is the same as ORDINARY_MAP_FILE_NAME;
+ but for an LC_GEN map, it returns the file name from which the data
+ originated, instead of asserting. */
+const char *
+ORDINARY_MAP_CONTAINING_FILE_NAME (line_maps *set,
+ const line_map_ordinary *ord_map);
+
const struct line_map *first_map_in_common (line_maps *set,
location_t loc0,
location_t loc1,
@@ -1316,6 +1367,11 @@ typedef struct
/* In a system header?. */
bool sysp;
+
+ /* If generated data, the data and its length. The data may contain embedded
+ nulls and need not be null-terminated. */
+ unsigned int generated_data_len;
+ const char *generated_data;
} expanded_location;
class range_label;
@@ -2104,12 +2160,14 @@ struct linemap_stats
long adhoc_table_entries_used;
};
-/* Return the highest location emitted for a given file for which
- there is a line map in SET. FILE_NAME is the file name to
- consider. If the function returns TRUE, *LOC is set to the highest
- location emitted for that file. */
+/* Return the highest location emitted for a given file or generated data buffer
+ for which there is a line map in SET. If the function returns TRUE, *LOC is
+ set to the highest location emitted for that file. The const char* arg is
+ either a file name or a generated data buffer, as indicated by
+ IS_DATA. */
bool linemap_get_file_highest_location (class line_maps * set,
- const char *file_name,
+ const char *fname_or_data,
+ bool is_data,
location_t *loc);
/* Compute and return statistics about the memory consumption of some
@@ -48,6 +48,35 @@ static location_t linemap_macro_loc_to_exp_point (line_maps *,
extern unsigned num_expanded_macros_counter;
extern unsigned num_macro_tokens_counter;
+/* For a normal ordinary map, this is the same as ORDINARY_MAP_FILE_NAME;
+ but for an LC_GEN map, it returns the file name from which the data
+ originated, instead of asserting. */
+const char *
+ORDINARY_MAP_CONTAINING_FILE_NAME (line_maps *set,
+ const line_map_ordinary *ord_map)
+{
+ while (ORDINARY_MAP_GENERATED_DATA_P (ord_map))
+ {
+ ord_map = linemap_included_from_linemap (set, ord_map);
+ if (!ord_map)
+ return "-";
+ }
+ return ORDINARY_MAP_FILE_NAME (ord_map);
+}
+
+/* If we just want to know whether two maps point to the same
+ file/buffer or not. */
+bool
+ORDINARY_MAPS_SAME_FILE_P (const line_map_ordinary *map1,
+ const line_map_ordinary *map2)
+{
+ const bool is_data = ORDINARY_MAP_GENERATED_DATA_P (map1);
+ return is_data == ORDINARY_MAP_GENERATED_DATA_P (map2)
+ && (is_data
+ ? map1->data == map2->data
+ : !filename_cmp (map1->data, map2->data));
+}
+
/* Destructor for class line_maps.
Ensure non-GC-managed memory is released. */
@@ -411,8 +440,9 @@ linemap_check_files_exited (line_maps *set)
for (const line_map_ordinary *map = LINEMAPS_LAST_ORDINARY_MAP (set);
! MAIN_FILE_P (map);
map = linemap_included_from_linemap (set, map))
- fprintf (stderr, "line-map.cc: file \"%s\" entered but not left\n",
- ORDINARY_MAP_FILE_NAME (map));
+ fprintf (stderr, "line-map.cc: file \"%s%s\" entered but not left\n",
+ ORDINARY_MAP_CONTAINING_FILE_NAME (set, map),
+ ORDINARY_MAP_GENERATED_DATA_P (map) ? "<generated>" : "");
}
/* Create NUM zero-initialized maps of type MACRO_P. */
@@ -505,21 +535,25 @@ LAST_SOURCE_LINE_LOCATION (const line_map_ordinary *map)
}
/* Add a mapping of logical source line to physical source file and
- line number.
+ line number. This function creates an "ordinary map", which is a
+ map that records locations of tokens that are not part of macro
+ replacement-lists present at a macro expansion point.
- The text pointed to by TO_FILE must have a lifetime
- at least as long as the final call to lookup_line (). An empty
- TO_FILE means standard input. If reason is LC_LEAVE, and
- TO_FILE is NULL, then TO_FILE, TO_LINE and SYSP are given their
- natural values considering the file we are returning to.
+ The text pointed to by DATA must have a lifetime at least as long as the
+ lifetime of SET. If reason is LC_LEAVE, and DATA is NULL, then DATA, TO_LINE
+ and SYSP are given their natural values considering the file we are returning
+ to. If reason is LC_GEN, then DATA is the actual content, and DATA_LEN>0 is
+ the length of it. Otherwise DATA is a file name and DATA_LEN need not be
+ specified. If DATA_LEN is specified for a file name, it should be the length
+ of the file name, including the terminating null.
- FROM_LINE should be monotonic increasing across calls to this
- function. A call to this function can relocate the previous set of
- maps, so any stored line_map pointers should not be used. */
+ A call to this function can relocate the previous set of maps, so any stored
+ line_map pointers should not be used. */
const struct line_map *
linemap_add (line_maps *set, enum lc_reason reason,
- unsigned int sysp, const char *to_file, linenum_type to_line)
+ unsigned int sysp, const char *data, linenum_type to_line,
+ unsigned int data_len)
{
/* Generate a start_location above the current highest_location.
If possible, make the low range bits be zero. */
@@ -535,13 +569,25 @@ linemap_add (line_maps *set, enum lc_reason reason,
>= MAP_START_LOCATION (LINEMAPS_LAST_ORDINARY_MAP (set))));
/* When we enter the file for the first time reason cannot be
- LC_RENAME. */
- linemap_assert (!(set->depth == 0 && reason == LC_RENAME));
+ LC_RENAME. To keep things simple, don't track LC_RENAME for
+ LC_GEN maps, but just keep their reason as always LC_GEN. */
+ if (reason == LC_RENAME)
+ {
+ linemap_assert (set->depth != 0);
+ const auto prev = LINEMAPS_LAST_ORDINARY_MAP (set);
+ linemap_assert (prev);
+ if (prev->reason == LC_GEN)
+ {
+ reason = LC_GEN;
+ data = prev->data;
+ data_len = prev->data_len;
+ }
+ }
/* If we are leaving the main file, return a NULL map. */
if (reason == LC_LEAVE
&& MAIN_FILE_P (LINEMAPS_LAST_ORDINARY_MAP (set))
- && to_file == NULL)
+ && data == NULL)
{
set->depth--;
return NULL;
@@ -557,8 +603,9 @@ linemap_add (line_maps *set, enum lc_reason reason,
= linemap_check_ordinary (new_linemap (set, start_location));
map->reason = reason;
- if (to_file && *to_file == '\0' && reason != LC_RENAME_VERBATIM)
- to_file = "<stdin>";
+ if (data && *data == '\0' && reason != LC_RENAME_VERBATIM
+ && reason != LC_GEN)
+ data = "<stdin>";
if (reason == LC_RENAME_VERBATIM)
reason = LC_RENAME;
@@ -577,20 +624,31 @@ linemap_add (line_maps *set, enum lc_reason reason,
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)
+ /* A DATA of NULL is special - we use the natural values. */
+ if (data == NULL)
{
- to_file = ORDINARY_MAP_FILE_NAME (from);
+ data = ORDINARY_MAP_FILE_NAME_OR_DATA (from);
to_line = SOURCE_LINE (from, from[1].start_location);
sysp = ORDINARY_MAP_IN_SYSTEM_HEADER_P (from);
}
else
- linemap_assert (filename_cmp (ORDINARY_MAP_FILE_NAME (from),
- to_file) == 0);
+ linemap_assert (ORDINARY_MAP_GENERATED_DATA_P (from)
+ ? (ORDINARY_MAP_GENERATED_DATA (from) == data)
+ : (filename_cmp (ORDINARY_MAP_FILE_NAME (from), data)
+ == 0));
}
map->sysp = sysp;
- map->to_file = to_file;
+ map->data = data;
+
+ if (reason == LC_GEN)
+ {
+ gcc_assert (data_len);
+ map->data_len = data_len;
+ }
+ else
+ map->data_len = (data_len > 0 ? data_len : strlen (data) + 1);
+
map->to_line = to_line;
LINEMAPS_ORDINARY_CACHE (set) = LINEMAPS_ORDINARY_USED (set) - 1;
/* Do not store range_bits here. That's readjusted in
@@ -606,7 +664,7 @@ linemap_add (line_maps *set, enum lc_reason reason,
pure_location_p. */
linemap_assert (pure_location_p (set, start_location));
- if (reason == LC_ENTER)
+ if (reason == LC_ENTER || reason == LC_GEN)
{
if (set->depth == 0)
map->included_from = 0;
@@ -617,7 +675,7 @@ linemap_add (line_maps *set, enum lc_reason reason,
& ~((1 << map[-1].m_column_and_range_bits) - 1))
+ map[-1].start_location);
set->depth++;
- if (set->trace_includes)
+ if (set->trace_includes && reason == LC_ENTER)
trace_include (set, map);
}
else if (reason == LC_RENAME)
@@ -863,8 +921,9 @@ linemap_line_start (line_maps *set, linenum_type to_line,
(const_cast <line_map *>
(linemap_add (set, LC_RENAME,
ORDINARY_MAP_IN_SYSTEM_HEADER_P (map),
- ORDINARY_MAP_FILE_NAME (map),
- to_line)));
+ ORDINARY_MAP_FILE_NAME_OR_DATA (map),
+ to_line,
+ map->data_len)));
map->m_column_and_range_bits = column_bits;
map->m_range_bits = range_bits;
r = (MAP_START_LOCATION (map)
@@ -1025,7 +1084,7 @@ linemap_position_for_loc_and_offset (line_maps *set,
cannot encode the location there. */
if ((map + 1)->reason != LC_RENAME
|| line < ORDINARY_MAP_STARTING_LINE_NUMBER (map + 1)
- || 0 != strcmp (LINEMAP_FILE (map + 1), LINEMAP_FILE (map)))
+ || !ORDINARY_MAPS_SAME_FILE_P (map, map + 1))
return loc;
column += column_offset;
@@ -1283,7 +1342,7 @@ linemap_get_expansion_filename (line_maps *set,
linemap_macro_loc_to_exp_point (set, location, &map);
- return LINEMAP_FILE (map);
+ return ORDINARY_MAP_CONTAINING_FILE_NAME (set, map);
}
/* Return the name of the macro associated to MACRO_MAP. */
@@ -1853,8 +1912,12 @@ linemap_expand_location (line_maps *set,
abort ();
const line_map_ordinary *ord_map = linemap_check_ordinary (map);
-
- xloc.file = LINEMAP_FILE (ord_map);
+ xloc.file = ORDINARY_MAP_CONTAINING_FILE_NAME (set, ord_map);
+ if (ORDINARY_MAP_GENERATED_DATA_P (ord_map))
+ {
+ xloc.generated_data = ORDINARY_MAP_GENERATED_DATA (ord_map);
+ xloc.generated_data_len = ORDINARY_MAP_GENERATED_DATA_LEN (ord_map);
+ }
xloc.line = SOURCE_LINE (ord_map, loc);
xloc.column = SOURCE_COLUMN (ord_map, loc);
xloc.sysp = LINEMAP_SYSP (ord_map) != 0;
@@ -1873,7 +1936,7 @@ linemap_dump (FILE *stream, class line_maps *set, unsigned ix, bool is_macro)
{
const char *const lc_reasons_v[LC_HWM]
= { "LC_ENTER", "LC_LEAVE", "LC_RENAME", "LC_RENAME_VERBATIM",
- "LC_ENTER_MACRO", "LC_MODULE" };
+ "LC_ENTER_MACRO", "LC_MODULE", "LC_GEN" };
const line_map *map;
unsigned reason;
@@ -1903,11 +1966,15 @@ linemap_dump (FILE *stream, class line_maps *set, unsigned ix, bool is_macro)
const line_map_ordinary *includer_map
= linemap_included_from_linemap (set, ord_map);
- fprintf (stream, "File: %s:%d\n", ORDINARY_MAP_FILE_NAME (ord_map),
+ fprintf (stream, "File: %s:%d\n",
+ ORDINARY_MAP_GENERATED_DATA_P (ord_map) ? "<generated>"
+ : ORDINARY_MAP_FILE_NAME (ord_map),
ORDINARY_MAP_STARTING_LINE_NUMBER (ord_map));
fprintf (stream, "Included from: [%d] %s\n",
includer_map ? int (includer_map - set->info_ordinary.maps) : -1,
- includer_map ? ORDINARY_MAP_FILE_NAME (includer_map) : "None");
+ includer_map ? ORDINARY_MAP_CONTAINING_FILE_NAME (set,
+ includer_map)
+ : "None");
}
else
{
@@ -1931,7 +1998,7 @@ linemap_dump_location (line_maps *set,
{
const line_map_ordinary *map;
location_t location;
- const char *path = "", *from = "";
+ const char *path = "", *path_suffix = "", *from = "";
int l = -1, c = -1, s = -1, e = -1;
if (IS_ADHOC_LOC (loc))
@@ -1948,7 +2015,9 @@ linemap_dump_location (line_maps *set,
linemap_assert (location < RESERVED_LOCATION_COUNT);
else
{
- path = LINEMAP_FILE (map);
+ path = ORDINARY_MAP_CONTAINING_FILE_NAME (set, map);
+ if (ORDINARY_MAP_GENERATED_DATA_P (map))
+ path_suffix = "<generated>";
l = SOURCE_LINE (map, location);
c = SOURCE_COLUMN (map, location);
s = LINEMAP_SYSP (map) != 0;
@@ -1959,24 +2028,27 @@ linemap_dump_location (line_maps *set,
{
const line_map_ordinary *from_map
= linemap_included_from_linemap (set, map);
- from = from_map ? LINEMAP_FILE (from_map) : "<NULL>";
+ from = from_map ? ORDINARY_MAP_CONTAINING_FILE_NAME (set, from_map)
+ : "<NULL>";
}
}
/* P: path, L: line, C: column, S: in-system-header, M: map address,
E: macro expansion?, LOC: original location, R: resolved location */
- fprintf (stream, "{P:%s;F:%s;L:%d;C:%d;S:%d;M:%p;E:%d,LOC:%d,R:%d}",
- path, from, l, c, s, (void*)map, e, loc, location);
+ fprintf (stream, "{P:%s%s;F:%s;L:%d;C:%d;S:%d;M:%p;E:%d,LOC:%d,R:%d}",
+ path, path_suffix, from, l, c, s, (void*)map, e, loc, location);
}
-/* Return the highest location emitted for a given file for which
- there is a line map in SET. FILE_NAME is the file name to
- consider. If the function returns TRUE, *LOC is set to the highest
- location emitted for that file. */
+/* Return the highest location emitted for a given file or generated data buffer
+ for which there is a line map in SET. If the function returns TRUE, *LOC is
+ set to the highest location emitted for that file. The const char* arg is
+ either a file name or a generated data buffer, as indicated by
+ IS_DATA. */
bool
linemap_get_file_highest_location (line_maps *set,
- const char *file_name,
+ const char *fname_or_data,
+ bool is_data,
location_t *loc)
{
/* If the set is empty or no ordinary map has been created then
@@ -1984,13 +2056,23 @@ linemap_get_file_highest_location (line_maps *set,
if (set == NULL || set->info_ordinary.used == 0)
return false;
- /* Now look for the last ordinary map created for FILE_NAME. */
+ /* Now look for the last ordinary map created for this file. */
int i;
for (i = set->info_ordinary.used - 1; i >= 0; --i)
{
- const char *fname = set->info_ordinary.maps[i].to_file;
- if (fname && !filename_cmp (fname, file_name))
- break;
+ const auto map = set->info_ordinary.maps + i;
+ if (is_data)
+ {
+ if (ORDINARY_MAP_GENERATED_DATA_P (map)
+ && ORDINARY_MAP_GENERATED_DATA (map) == fname_or_data)
+ break;
+ }
+ else if (!ORDINARY_MAP_GENERATED_DATA_P (map))
+ {
+ const auto this_fname = ORDINARY_MAP_FILE_NAME (map);
+ if (this_fname && !filename_cmp (this_fname, fname_or_data))
+ break;
+ }
}
if (i < 0)