@@ -1281,27 +1281,6 @@ pph_in_symtab (pph_stream *stream)
}
-/* Read all the images included by STREAM. */
-
-static void
-pph_in_includes (pph_stream *stream)
-{
- unsigned i, num;
-
- pph_reading_includes++;
-
- num = pph_in_uint (stream);
- for (i = 0; i < num; i++)
- {
- const char *include_name = pph_in_string (stream);
- pph_stream *include = pph_read_file (include_name);
- pph_add_include (include, false);
- }
-
- pph_reading_includes--;
-}
-
-
/* Read a linenum_type from STREAM. */
static inline linenum_type
@@ -1320,6 +1299,20 @@ pph_in_source_location (pph_stream *stream)
}
+/* Read a line table marker from STREAM. */
+
+static inline enum pph_linetable_marker
+pph_in_linetable_marker (pph_stream *stream)
+{
+ enum pph_linetable_marker m =
+ (enum pph_linetable_marker) pph_in_uchar (stream);
+ gcc_assert (m == PPH_LINETABLE_ENTRY
+ || m == PPH_LINETABLE_REFERENCE
+ || m == PPH_LINETABLE_END);
+ return m;
+}
+
+
/* Read a line_map from STREAM into LM. */
static void
@@ -1343,47 +1336,100 @@ pph_in_line_map (pph_stream *stream, struct line_map *lm)
}
-/* Read the line_table from STREAM and merge it in LINETAB. */
+/* Read the line_table from STREAM and merge it in LINETAB. At the same time
+ load includes in the order they were originally included by loading them at
+ the point they were referenced in the line_table.
-static void
-pph_in_and_merge_line_table (pph_stream *stream, struct line_maps *linetab)
+ Returns the source_location of line 1 / col 0 for this include.
+
+ FIXME pph: The line_table is now identical to the non-pph line_table, the
+ only problem is that we load line_table entries twice for headers that are
+ re-included and are #ifdef guarded; thus shouldn't be replayed. This is
+ a known current issue, so I didn't bother working around it here for now. */
+
+static source_location
+pph_in_line_table_and_includes (pph_stream *stream, struct line_maps *linetab)
{
- unsigned int ix, pph_used, old_depth;
+ unsigned int old_depth;
+ bool first;
+ int includer_ix = -1;
+ unsigned int used_before = linetab->used;
int entries_offset = linetab->used - PPH_NUM_IGNORED_LINE_TABLE_ENTRIES;
+ enum pph_linetable_marker next_lt_marker = pph_in_linetable_marker (stream);
- pph_used = pph_in_uint (stream);
+ pph_reading_includes++;
- for (ix = 0; ix < pph_used; ix++, linetab->used++)
+ for (first = true; next_lt_marker != PPH_LINETABLE_END;
+ next_lt_marker = pph_in_linetable_marker (stream))
{
- struct line_map *lm;
+ if (next_lt_marker == PPH_LINETABLE_REFERENCE)
+ {
+ int old_loc_offset;
+ const char *include_name = pph_in_string (stream);
+ source_location prev_start_loc = pph_in_source_location (stream);
+ pph_stream *include;
+
+ gcc_assert (!first);
+
+ linetab->highest_location = (prev_start_loc - 1) + pph_loc_offset;
+
+ old_loc_offset = pph_loc_offset;
- linemap_ensure_extra_space_available (linetab);
+ include = pph_read_file (include_name);
+ pph_add_include (include, false);
- lm = &linetab->maps[linetab->used];
+ pph_loc_offset = old_loc_offset;
+ }
+ else
+ {
+ struct line_map *lm;
- pph_in_line_map (stream, lm);
+ linemap_ensure_extra_space_available (linetab);
- if (ix == 0)
- {
- pph_loc_offset = (linetab->highest_location + 1) - lm->start_location;
+ lm = &linetab->maps[linetab->used];
- /* When parsing the pph the header itself wasn't included by anything,
- now it's included by the C file we are currently compiling. */
- gcc_assert(lm->included_from == -1);
- lm->included_from = linetab->used - 1;
- }
+ pph_in_line_map (stream, lm);
- /* For the other entries in the pph's line_table which were included_from
- another entry, reflect their included_from to the new position of the
- entry which they were included from. */
- else if (lm->included_from != -1)
- lm->included_from += entries_offset;
+ if (first)
+ {
+ first = false;
+
+ pph_loc_offset = (linetab->highest_location + 1)
+ - lm->start_location;
- gcc_assert (lm->included_from < (int) linetab->used);
+ includer_ix = linetab->used - 1;
- lm->start_location += pph_loc_offset;
+ gcc_assert (lm->included_from == -1);
+ }
+
+ gcc_assert (includer_ix != -1);
+
+ /* When parsing the pph: the header itself wasn't included by
+ anything, now it's included by the file just before it in
+ the current include tree. */
+ if (lm->included_from == -1)
+ lm->included_from = includer_ix;
+ /* For the other entries in the pph's line_table which were included
+ from another entry, reflect their included_from to the new position
+ of the entry which they were included from. */
+ else
+ lm->included_from += entries_offset;
+
+ gcc_assert (lm->included_from < (int) linetab->used);
+
+ lm->start_location += pph_loc_offset;
+
+ linetab->used++;
+ }
}
+ pph_reading_includes--;
+
+ {
+ unsigned int expected_in = pph_in_uint (stream);
+ gcc_assert (linetab->used - used_before == expected_in);
+ }
+
linetab->highest_location = pph_loc_offset + pph_in_uint (stream);
linetab->highest_line = pph_loc_offset + pph_in_uint (stream);
@@ -1399,6 +1445,8 @@ pph_in_and_merge_line_table (pph_stream *stream, struct line_maps *linetab)
old_depth = linetab->depth++;
linemap_add (linetab, LC_LEAVE, 0, NULL, 0);
gcc_assert (linetab->depth == old_depth);
+
+ return linetab->maps[used_before].start_location;
}
@@ -1419,8 +1467,10 @@ pph_read_file_1 (pph_stream *stream)
if (flag_pph_debug >= 1)
fprintf (pph_logfile, "PPH: Reading %s\n", stream->name);
- /* Read all the images included by STREAM. */
- pph_in_includes (stream);
+ /* Read in STREAM's line table and merge it in the current line table.
+ At the same time, read in includes in the order they were originally
+ read. */
+ cpp_token_replay_loc = pph_in_line_table_and_includes (stream, line_table);
/* Read all the identifiers and pre-processor symbols in the global
namespace. */
@@ -1433,16 +1483,12 @@ pph_read_file_1 (pph_stream *stream)
bad_use->before_str, bad_use->after_str);
/* Re-instantiate all the pre-processor symbols defined by STREAM. Force
- their source_location to column 0 of the line the include occured on,
- this avoids shifting all of the line_table's location as we would by adding
- locations which wouldn't be there in the non-pph compile; thus working
- towards an identical line_table in pph and non-pph. */
- cpp_token_replay_loc = linemap_position_for_column (line_table, 0);
+ their source_location to line 1 / column 0 of the file they were included
+ in. This avoids shifting all of the line_table's locations as we would by
+ adding locations which wouldn't be there in the non-pph compile; thus
+ working towards an identical line_table in pph and non-pph. */
cpp_lt_replay (parse_in, &idents_used, &cpp_token_replay_loc);
- /* Read in STREAM's line table and merge it in the current line table. */
- pph_in_and_merge_line_table (stream, line_table);
-
/* Read the bindings from STREAM and merge them with the current bindings. */
pph_in_scope_chain (stream);
@@ -1142,21 +1142,6 @@ pph_out_symtab (pph_stream *stream)
}
-/* Emit the list of all the PPH files included by STREAM. */
-
-static void
-pph_out_includes (pph_stream *stream)
-{
- unsigned i;
- pph_stream *include;
-
- pph_out_uint (stream, VEC_length (pph_stream_ptr,
- stream->encoder.w.includes));
- FOR_EACH_VEC_ELT (pph_stream_ptr, stream->encoder.w.includes, i, include)
- pph_out_string (stream, include->name);
-}
-
-
/* Emit linenum_type LN to STREAM. */
static inline void
@@ -1175,6 +1160,16 @@ pph_out_source_location (pph_stream *stream, source_location sl)
}
+/* Emit line table MARKER to STREAM. */
+
+static inline void
+pph_out_linetable_marker (pph_stream *stream, enum pph_linetable_marker marker)
+{
+ gcc_assert (marker == (enum pph_linetable_marker)(unsigned char) marker);
+ pph_out_uchar (stream, marker);
+}
+
+
/* Emit all information contained in LM to STREAM. */
static void
@@ -1195,22 +1190,78 @@ pph_out_line_map (pph_stream *stream, struct line_map *lm)
}
-/* Emit the required line_map entry and some properties in LINETAB to STREAM,
- ignoring builtin and command-line entries. */
+/* Compare filenames of a header and it's potentially corresponding pph file,
+ stripping the path passed in and the extension. Returns true if HEADER_PATH
+ and PPH_PATH end with the same filename. We expect HEADER_PATH to end in .h
+ and PPH_PATH to end in .pph.
+
+ FIXME pph: We should not need to do this if we handled include paths
+ correctly, but for now the linemap holds full paths and the stream's includes
+ list only holds the include name. Also, the stream's includes hold pph
+ filenames where as the line_table as header filenames. */
+
+static bool
+pph_filename_eq_ignoring_path (const char *header_path, const char *pph_path)
+{
+ const char *header_name = lbasename (header_path);
+ const char *pph_name = lbasename (pph_path);
+
+ const char *header_ext = strchr (header_name, '.');
+ const char *pph_ext = strchr (pph_name, '.');
+
+ unsigned int name_length;
+
+ if (header_ext != NULL)
+ {
+ name_length = header_ext - header_name;
+ gcc_assert (strcmp (header_ext, ".h") == 0);
+ }
+ else
+ /* Some headers do not have a .h suffix, but will still
+ have a .pph suffix after being pph'ed. */
+ name_length = strlen (header_name);
+
+ gcc_assert (strcmp (pph_ext, ".pph") == 0);
+
+ /* Compare the filenames without their extension. */
+ return pph_ext - pph_name == name_length
+ && strncmp (header_name, pph_name, name_length) == 0;
+}
+
+
+/* Return the *NEXT_INCLUDE_IX'th pph_stream in STREAM's list of includes.
+ Returns NULL if we have read all includes. */
+
+static inline pph_stream *
+pph_get_next_include (pph_stream *stream, unsigned int *next_incl_ix)
+{
+ if (*next_incl_ix < VEC_length (pph_stream_ptr, stream->encoder.w.includes))
+ return VEC_index (pph_stream_ptr, stream->encoder.w.includes,
+ (*next_incl_ix)++);
+ else
+ return NULL;
+}
+
+
+/* Emit the required line_map entry (those directly related to this include)
+ and some properties in LINETAB to STREAM, ignoring builtin and command-line
+ entries. We will write references to our direct includes children and skip
+ their actual line_map entries (unless they are non-pph children in which case
+ we have to write out their line_map entries as well). We assume
+ stream->encoder.w.includes contains the pph headers included in the same
+ order they are seen in the line_table. */
static void
-pph_out_line_table (pph_stream *stream, struct line_maps *linetab)
+pph_out_line_table_and_includes (pph_stream *stream, struct line_maps *linetab)
{
- unsigned int ix;
+ unsigned int ix, next_incl_ix = 0;
+ pph_stream *current_include;
/* Any #include should have been fully parsed and exited at this point. */
gcc_assert (linetab->depth == 0);
- /* Only output used as the number of line_map entries we actually output. */
- pph_out_uint (stream, linetab->used - PPH_NUM_IGNORED_LINE_TABLE_ENTRIES);
+ current_include = pph_get_next_include (stream, &next_incl_ix);
- /* Output all the non-ignored line_map entries.
- Special casing the first one. */
for (ix = PPH_NUM_IGNORED_LINE_TABLE_ENTRIES; ix < linetab->used; ix++)
{
struct line_map *lm = &linetab->maps[ix];
@@ -1226,12 +1277,57 @@ pph_out_line_table (pph_stream *stream, struct line_maps *linetab)
lm->reason = LC_ENTER;
}
- pph_out_line_map (stream, lm);
-
+ /* If this is an entry from a pph header, only output reference. */
+ if (current_include != NULL
+ && pph_filename_eq_ignoring_path (lm->to_file, current_include->name))
+ {
+ int includer_level;
+
+ gcc_assert (lm->reason == LC_ENTER);
+ gcc_assert (lm->included_from != -1);
+
+ pph_out_linetable_marker (stream, PPH_LINETABLE_REFERENCE);
+ pph_out_string (stream, current_include->name);
+
+ /* We also need to output the start_location to simulate the correct
+ highest_location on the way in. */
+ pph_out_source_location (stream, lm->start_location);
+
+ /* Potentially lm could be included from a header other then the main
+ one if a textual include includes a pph header (i.e. we can't
+ simply rely on going back to included_from == -1). */
+ includer_level = INCLUDED_FROM (linetab, lm)->included_from;
+
+ /* Skip all other linemap entries up to and including the LC_LEAVE
+ from the referenced header back to the one including it. */
+ while (linetab->maps[++ix].included_from != includer_level)
+ /* We should always leave this loop before the end of the
+ current line_table entries. */
+ gcc_assert (ix < linetab->used);
+
+ current_include = pph_get_next_include (stream, &next_incl_ix);
+ }
+ else
+ {
+ pph_out_linetable_marker (stream, PPH_LINETABLE_ENTRY);
+ pph_out_line_map (stream, lm);
+ }
+
+ /* Restore changes made to first entry above if needed. */
if (ix == PPH_NUM_IGNORED_LINE_TABLE_ENTRIES)
- lm->reason = LC_RENAME;
+ lm->reason = LC_RENAME;
}
+ pph_out_linetable_marker (stream, PPH_LINETABLE_END);
+
+ /* Output the number of entries written to validate on input. */
+ pph_out_uint (stream, linetab->used - PPH_NUM_IGNORED_LINE_TABLE_ENTRIES);
+
+ /* Every pph header included should have been seen and skipped in the
+ line_table streaming above. */
+ gcc_assert (next_incl_ix == VEC_length (pph_stream_ptr,
+ stream->encoder.w.includes));
+
pph_out_source_location (stream, linetab->highest_location);
pph_out_source_location (stream, linetab->highest_line);
@@ -1248,18 +1344,14 @@ pph_write_file (pph_stream *stream)
if (flag_pph_debug >= 1)
fprintf (pph_logfile, "PPH: Writing %s\n", pph_out_file);
- /* Emit the list of PPH files included by STREAM. These files will
- be read and instantiated before any of the content in STREAM. */
- pph_out_includes (stream);
+ /* Emit the line table entries and references to our direct includes. */
+ pph_out_line_table_and_includes (stream, line_table);
/* Emit all the identifiers and pre-processor symbols in the global
namespace. */
idents_used = cpp_lt_capture (parse_in);
pph_out_identifiers (stream, &idents_used);
- /* Emit the line table entries. */
- pph_out_line_table (stream, line_table);
-
/* Emit the bindings for the global namespace. */
pph_out_scope_chain (stream);
if (flag_pph_dump_tree)
@@ -63,6 +63,21 @@ enum pph_symtab_marker {
PPH_SYMTAB_DECL
};
+/* Line table markers. We only stream line table entries from the parent header
+ file, other entries are referred to by the name of the file which is then
+ loaded as an include at the correct point in time. */
+enum pph_linetable_marker {
+
+ /* A regular line_map entry in the line_table. */
+ PPH_LINETABLE_ENTRY = 0x01,
+
+ /* A reference to another header to be loaded at this point. */
+ PPH_LINETABLE_REFERENCE,
+
+ /* Marks the end of the line_map entries. */
+ PPH_LINETABLE_END
+};
+
/* Number of sections in a PPH file. FIXME, currently only one section
is supported. To add more, it will also be necessary to handle
section names in pph_get_section_data and pph_free_section_data. */
@@ -119,6 +119,10 @@ pph_include_handler (cpp_reader *reader,
pph_file = query_pph_include_map (name);
if (pph_file != NULL && !cpp_included_before (reader, name, input_location))
{
+ /* Hack. We do this to mimic what the non-pph compiler does in
+ _cpp_stack_include as our goal is to have identical line_tables. */
+ line_table->highest_location--;
+
pph_read_file (pph_file);
read_text_file_p = false;
}
@@ -1,5 +1,4 @@
// { dg-options "-w -fpermissive" }
-// pph asm xdiff 48471
#include "p4eabi1.h"
@@ -1,5 +1,5 @@
// { dg-xfail-if "BOGUS" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "x0keyed2.h:11:1: error: redefinition of 'const char _ZTS5keyed ..'" "" { xfail *-*-* } 0 }
+// { dg-bogus "x4keyed.cc:13:1: error: redefinition of 'const char _ZTS5keyed ..'" "" { xfail *-*-* } 0 }
#include "x0keyed1.h"
#include "x0keyed2.h"
@@ -1,17 +1,17 @@
// { dg-xfail-if "BOGUS" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "x5rtti1.h:13:0: warning: .__STDC_IEC_559_COMPLEX__. redefined .enabled by default." "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti1.h:13:0: warning: .__STDC_ISO_10646__. redefined .enabled by default." "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti1.h:13:0: warning: .__STDC_IEC_559__. redefined .enabled by default." "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:15:32: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:15:54: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:16:32: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:16:54: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:17:32: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:17:54: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:18:32: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:18:54: error: no match for .operator" "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:19:1: error: redefinition of .const char _ZTS15non_polymorphic ..." "" { xfail *-*-* } 0 }
-// { dg-bogus "x5rtti2.h:19:1: error: redefinition of .const char _ZTS11polymorphic ..." "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:21:0: warning: .__STDC_IEC_559_COMPLEX__. redefined .enabled by default." "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:21:0: warning: .__STDC_ISO_10646__. redefined .enabled by default." "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:21:0: warning: .__STDC_IEC_559__. redefined .enabled by default." "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:24:32: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:24:54: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:25:32: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:25:54: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:26:32: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:26:54: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:27:32: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:27:54: error: no match for .operator" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:28:1: error: redefinition of .const char _ZTS15non_polymorphic ..." "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:28:1: error: redefinition of .const char _ZTS11polymorphic ..." "" { xfail *-*-* } 0 }
//FIXME We should make this a run test.