diff --git a/gcc/cp/pph-streamer-in.c b/gcc/cp/pph-streamer-in.c
index 4666ace..a3a3566 100644
--- a/gcc/cp/pph-streamer-in.c
+++ b/gcc/cp/pph-streamer-in.c
@@ -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,102 @@ 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--;
+
+  {
+    /* FIXME pph: streaming this int is only needed for assertion, should be
+       wrapped in a #ifdef and only enabled if asserts are on.  */
+    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 +1447,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 +1469,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 +1485,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);
 
diff --git a/gcc/cp/pph-streamer-out.c b/gcc/cp/pph-streamer-out.c
index 1b84cc3..d744570 100644
--- a/gcc/cp/pph-streamer-out.c
+++ b/gcc/cp/pph-streamer-out.c
@@ -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,82 @@ 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 = header_path, *pph_name = pph_path;
+
+  /* Strip the path, only keeping the filenames.  */
+  for (; *header_path; header_path++)
+    if (*header_path == '/')
+      header_name = header_path + 1;
+
+  for (; *pph_path; pph_path++)
+    if (*pph_path == '/')
+      pph_name = pph_path + 1;
+
+  gcc_assert (*header_name && *pph_name);
+
+  /* Validate that filenames are equal ignoring the extension.  */
+  do {
+    if (*header_name != *pph_name)
+      return false;
+
+    header_name++;
+    pph_name++;
+  } while (*header_name != '.');
+
+  /* Validate that the remaining extensions are as we expect.  */
+  gcc_assert (strcmp (header_name, ".h") == 0);
+  gcc_assert (strcmp (pph_name, ".pph") == 0);
+
+  return true;
+}
+
+
+/* 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 +1281,58 @@ 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);
+
+  /* FIXME pph: only needed for assertion on the way in, should be wrapped in a
+     #ifdef and only enabled if asserts are on.  */
+  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 +1349,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)
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index 7842f1f..4a1f9eb 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -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.  */
diff --git a/gcc/cp/pph.c b/gcc/cp/pph.c
index 86aacbc..74f48fc 100644
--- a/gcc/cp/pph.c
+++ b/gcc/cp/pph.c
@@ -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;
     }
diff --git a/gcc/testsuite/g++.dg/pph/p4eabi1.cc b/gcc/testsuite/g++.dg/pph/p4eabi1.cc
index c7aa1b0..4bf19e6 100644
--- a/gcc/testsuite/g++.dg/pph/p4eabi1.cc
+++ b/gcc/testsuite/g++.dg/pph/p4eabi1.cc
@@ -1,5 +1,4 @@
 // { dg-options "-w -fpermissive" }
-// pph asm xdiff 48471
 
 #include "p4eabi1.h"
 
diff --git a/gcc/testsuite/g++.dg/pph/x4keyed.cc b/gcc/testsuite/g++.dg/pph/x4keyed.cc
index ef88e7c..68b30c1 100644
--- a/gcc/testsuite/g++.dg/pph/x4keyed.cc
+++ b/gcc/testsuite/g++.dg/pph/x4keyed.cc
@@ -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"
diff --git a/gcc/testsuite/g++.dg/pph/x7rtti.cc b/gcc/testsuite/g++.dg/pph/x7rtti.cc
index 8a6c981..297ebe2 100644
--- a/gcc/testsuite/g++.dg/pph/x7rtti.cc
+++ b/gcc/testsuite/g++.dg/pph/x7rtti.cc
@@ -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.
