Add selftests for the new capabilities in input.cc related to source code locations that are stored in memory rather than ordinary files.
gcc/ChangeLog: * input.cc (temp_source_file::do_linemap_add): New function. (line_table_case::line_table_case): Add GENERATED_DATA argument. (line_table_test::line_table_test): Implement new M_GENERATED_DATA argument. (for_each_line_table_case): Optionally include generated data locations in the set of cases. (test_accessing_ordinary_linemaps): Test generated data locations. (test_make_location_nonpure_range_endpoints): Likewise. (test_line_offset_overflow): Likewise. (input_cc_tests): Likewise. * selftest.cc (named_temp_file::named_temp_file): Interpret a null SUFFIX argument as a request to use in-memory data. (named_temp_file::~named_temp_file): Support in-memory data. (temp_source_file::temp_source_file): Likewise. (temp_source_file::~temp_source_file): Likewise. * selftest.h (struct line_map_ordinary): Foward declare. (class named_temp_file): Add missing explicit to the constructor. (class temp_source_file): Add new members to support in-memory data. (class line_table_test): Likewise. (for_each_line_table_case): Adjust prototype. --- gcc/input.cc | 81 +++++++++++++++++++++++++++++++++---------------- gcc/selftest.cc | 53 +++++++++++++++++++++++++------- gcc/selftest.h | 19 ++++++++++-- 3 files changed, 113 insertions(+), 40 deletions(-) diff --git a/gcc/input.cc b/gcc/input.cc index 790279d4273..8c4e40aaf23 100644 --- a/gcc/input.cc +++ b/gcc/input.cc @@ -2066,6 +2066,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. */ @@ -2144,13 +2158,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 @@ -2167,6 +2184,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 @@ -2188,6 +2206,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. */ @@ -2207,7 +2226,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); @@ -2257,21 +2279,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); @@ -2318,10 +2342,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); @@ -3978,7 +4003,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 @@ -3997,16 +4023,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 @@ -4017,7 +4046,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); @@ -4257,9 +4286,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); diff --git a/gcc/selftest.cc b/gcc/selftest.cc index 20c10bbd055..7126b9901dd 100644 --- a/gcc/selftest.cc +++ b/gcc/selftest.cc @@ -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 diff --git a/gcc/selftest.h b/gcc/selftest.h index 20d522afda4..ede3b008145 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -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,7 +98,7 @@ 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; } @@ -113,7 +115,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 +179,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 +195,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.