Patchwork [pph] Rebuild identifier bindings. (issue5557045)

login
register
mail settings
Submitter Lawrence Crowl
Date Jan. 18, 2012, 3:19 a.m.
Message ID <20120118031956.3F960222623@jade.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/136546/
State New
Headers show

Comments

Lawrence Crowl - Jan. 18, 2012, 3:19 a.m.
Instead of emitting identifiers with binding information, emit them
without and then patch up that information later.  We switch to this
technique because the cycles in binding info were causing no end of
troubles.

This change requires handling namespaces differently from before.  In
particular, we alway emit all namespaces into the PPH file.  We may
not emit decls within them.

There is an overloading bug in this patch, but I am pushing it up
now to avoid keeping so large a change hanging.



--
This patch is available for review at http://codereview.appspot.com/5557045

Patch

Index: gcc/testsuite/ChangeLog.pph

2011-01-17   Lawrence Crowl  <crowl@google.com>

	* g++.dg/pph/x6dynarray3.cc: Add expected overload failures.
	* g++.dg/pph/x4namespace.cc: Remove expected failures.
	* g++.dg/pph/x4overset1.cc: Add expected overload asm diff failure.
	* g++.dg/pph/x4overset2.cc: Likewise.
	* g++.dg/pph/x4overset3.cc: Likewise.
	* g++.dg/pph/x4overset4.cc: Likewise.
	* g++.dg/pph/x0namespace.h: Add spacing.
	* g++.dg/pph/x0namespace2.h: Likewise.

Index: gcc/cp/ChangeLog.pph

2012-01-17   Lawrence Crowl  <crowl@google.com>

	* pph.h (pph_files_read): New.
	(chain2vec): Move from static to global.
	* pph-streamer.h (pph_dump_namespace): Add message parameter.
	* pph-core.c (pph_dump_namespace): Add message parameter.
	(pph_trace_marker): Add PPH: label to debugging output.
	(pph_cache_insert_at): Remove non-static aggregate initializer.
	(pph_loaded): Enable pph_set_global_identifier_bindings().
	* pph-out.c (chain2vec): Move from static to global.
	(pph_out_merge_key_namespace_decl): New.
	(pph_out_merge_body_namespace_decl): New.
	(pph_foreach_out_chain): New.
	(pph_out_merge_key_binding_level): Handle namespace keys separately.
	(pph_out_merge_key_tree): Likewise.
	(pph_out_merge_body_binding_level): Handle namespace bodies separately.
	(pph_out_identifier_bindings): No longer emit most binding info.
	(pph_out_merge_key_namespace_decl): Output record info.
	(pph_out_merge_body_namespace_decl): New.
	* pph-in.c (pph_in_merge_body_namespace_decl): New.
	(pph_in_merge_key_namespace_decl): New.
	(pph_in_merge_key_binding_level): Handle namespace separately.
	(pph_in_merge_key_tree): Likewise.
	(pph_in_merge_body_binding_level_1): Likewise.
	(pph_in_identifier_bindings): No longer emit most binding info.
	(pph_ensure_namespace_binding_level): New.
	(pph_in_merge_key_namespace_decl): Modify chain as needed.
	(pph_in_merge_body_namespace_decl): New.
	(bool pph_files_were_read): New.
	(pph_files_read): New.
	(pph_read_file_1): Set pph_files_were_read.
	* pt.c (pph_dump_tinst_level): Add PPH: label to debugging output.
	(pph_dump_pending_templates_list): Likewise.
	(pph_dump_spec_entry_slot): Likewise.
	(pph_dump_spec_entry_htab): Likewise.
	* parser.h (cp_debug_parser_where): New.
	* parser.c (cp_debug_parser_where): New.
	(c_parse_file): Conditionalize call to pph_loaded.
	* name-lookup.c (pph_debug_binding_action): New.
	(pph_debug_binding_inaction): New.
	(pph_foreach_on_chain_bl): New.
	(pph_set_identifier_bindings): New.
	(pph_set_chain_identifier_bindings): Use pph_set_identifier_bindings.
	(pph_set_namespace_bindings): New.
	(pph_set_chain_namespace_bindings): New.
	(pph_foreach_on_chain): New.
	(pph_set_namespace_namespace_binding): New.
	(pph_set_namespace_namespace_bindings): New.
	(pph_set_global_identifier_bindings): Add call to
	pph_set_namespace_namespace_bindings.

Index: gcc/ChangeLog.pph

2012-01-17   Lawrence Crowl  <crowl@google.com>

	* langhooks.h (get_lang_hooks): New.
	* langhooks.c (get_lang_hooks): New.


Index: gcc/testsuite/g++.dg/pph/x6dynarray3.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x6dynarray3.cc	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x6dynarray3.cc	(working copy)
@@ -1,6 +1,8 @@ 
-// pph asm xdiff 18502
-// xfail BOGUS UNKNOWN
-// Some branches seem to be missing.
+// { dg-bogus "a0dynarray-dfn1b.hi:8:13: error: no matching function for call to 'operator new" "" { xfail *-*-* } 0 }
+// { dg-bogus "a0dynarray-dfn1b.hi:22:5: error: no suitable 'operator delete" "" { xfail *-*-* } 0 }
+// { dg-bogus "a0dynarray-dfn2b.hi:8:13: error: no matching function for call to 'operator new" "" { xfail *-*-* } 0 }
+// { dg-bogus "a0dynarray-dfn2b.hi:13:9: error: no suitable 'operator delete" "" { xfail *-*-* } 0 }
+// { dg-bogus "a0dynarray-dcl3.hi:11:60: warning: no corresponding deallocation function for 'void. operator new" "" { xfail *-*-* } 0 }
 
 #include "x5dynarray3.h"
 
Index: gcc/testsuite/g++.dg/pph/x4overset1.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4overset1.cc	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x4overset1.cc	(working copy)
@@ -1,3 +1,5 @@ 
+// pph asm xdiff 56596
+
 #include "x1overset1.h"
 #include "x1overset2.h"
 
Index: gcc/testsuite/g++.dg/pph/x4overset2.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4overset2.cc	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x4overset2.cc	(working copy)
@@ -1,4 +1,5 @@ 
-// pph asm xwant 57625
+// pph asm xdiff 01525
+// wanted 57625
 // This test produces overload differences because the declaration and
 // call orders are different between pph and textual parsing.
 
Index: gcc/testsuite/g++.dg/pph/x4namespace.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4namespace.cc	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x4namespace.cc	(working copy)
@@ -1,10 +1,8 @@ 
-// { dg-bogus "x4namespace.cc:11:1: error: 'C' does not name a type" "" { xfail *-*-* } 0 }
-// { dg-bogus "x4namespace.cc:27:5: error: 'z' is not a member of 'A'" "" { xfail *-*-* } 0 }
-
 #include "x0namespace.h"
 #include "x0namespace2.h"
 
 namespace A {
+
 int x = 3;
 int x2 = 5;
 
Index: gcc/testsuite/g++.dg/pph/x4overset3.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4overset3.cc	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x4overset3.cc	(working copy)
@@ -1,3 +1,5 @@ 
+// pph asm xdiff 56596
+
 #include "x1overset1.h"
 #include "x1overset2.h"
 #include "x1overset1.h"
Index: gcc/testsuite/g++.dg/pph/x0namespace2.h
===================================================================
--- gcc/testsuite/g++.dg/pph/x0namespace2.h	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x0namespace2.h	(working copy)
@@ -1,8 +1,11 @@ 
 #ifndef X0NAMESPACE2_H
 #define X0NAMESPACE2_H
+
 namespace A {
+
 extern int x2;
 struct B2;
+
 template< typename T >
 struct C2 {
     T* b;
@@ -10,13 +13,17 @@  struct C2 {
     int another()
     { return *b; }
 };
+
 template< typename T >
 int C2< T >::method()
 { return x2; }
+
 } // namespace A
+
 struct D2 : A::C2< int > {
     int method();
     int another()
     { return *b; }
 };
+
 #endif
Index: gcc/testsuite/g++.dg/pph/x4overset4.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4overset4.cc	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x4overset4.cc	(working copy)
@@ -1,4 +1,5 @@ 
-// pph asm xwant 57625
+// pph asm xdiff 01525
+// wanted 57625
 // This test produces overload differences because the declaration and
 // call orders are different between pph and textual parsing.
 
Index: gcc/testsuite/g++.dg/pph/x0namespace.h
===================================================================
--- gcc/testsuite/g++.dg/pph/x0namespace.h	(revision 183260)
+++ gcc/testsuite/g++.dg/pph/x0namespace.h	(working copy)
@@ -1,8 +1,11 @@ 
 #ifndef X0NAMESPACE_H
 #define X0NAMESPACE_H
+
 namespace A {
+
 extern int x;
 struct B;
+
 template< typename T >
 struct C {
     T* b;
@@ -10,13 +13,17 @@  struct C {
     int another()
     { return *b; }
 };
+
 template< typename T >
 int C< T >::method()
 { return x; }
+
 } // namespace A
+
 struct D : A::C< int > {
     int method();
     int another()
     { return *b; }
 };
+
 #endif
Index: gcc/cp/pph-core.c
===================================================================
--- gcc/cp/pph-core.c	(revision 183260)
+++ gcc/cp/pph-core.c	(working copy)
@@ -147,8 +147,10 @@  pph_dump_binding (FILE *file, cp_binding
 /* Dump namespace NS for PPH.  */
 
 void
-pph_dump_namespace (FILE *file, tree ns)
+pph_dump_namespace (FILE *file, tree ns, const char *msg)
 {
+  if (msg)
+    fprintf (file, "\nPPH: %s\n", msg);
   fprintf (file, "namespace ");
   pph_dump_tree_name (file, ns, 0);
   fprintf (file, "{\n");
@@ -183,7 +185,7 @@  pph_dump_binding (FILE *file, cp_binding
     {
       next = DECL_CHAIN (t);
       if (!DECL_IS_BUILTIN (t))
-        pph_dump_namespace (file, t);
+        pph_dump_namespace (file, t, (const char *)NULL);
     }
 }
 
@@ -227,7 +229,7 @@  static const char *tag_strings[] =
 void
 pph_trace_marker (enum pph_record_marker marker, enum pph_tag tag)
 {
-  fprintf (pph_logfile, "marker ");
+  fprintf (pph_logfile, "PPH: marker ");
   if (PPH_RECORD_START <= marker && marker <= PPH_RECORD_PREF)
     fprintf (pph_logfile, "%s", marker_strings[marker - PPH_RECORD_START]);
   else
@@ -401,7 +403,13 @@  pph_cache_insert_at (pph_cache *cache, v
                      enum pph_tag tag)
 {
   void **map_slot;
-  pph_cache_entry e = { data, tag, false, 0, 0 };
+  pph_cache_entry e;
+
+  e.data = data;
+  e.tag = tag;
+  e.needs_merge_body = false;
+  e.crc = 0;
+  e.crc_nbytes = 0;
 
   map_slot = pointer_map_insert (cache->m, data);
 
@@ -843,12 +851,9 @@  pph_add_include (pph_stream *stream, pph
 void
 pph_loaded (void)
 {
-/* FIXME pph: Reconstructing the global binding does not yet work.  */
-#if 0
   pph_set_global_identifier_bindings();
-#endif
   if (flag_pph_dump_tree)
-    pph_dump_namespace (pph_logfile, global_namespace);
+    pph_dump_namespace (pph_logfile, global_namespace, "after all pph read");
 }
 
 
Index: gcc/cp/pph.h
===================================================================
--- gcc/cp/pph.h	(revision 183260)
+++ gcc/cp/pph.h	(working copy)
@@ -159,6 +159,7 @@  extern location_t pph_in_location (pph_s
 extern tree pph_in_tree (pph_stream *stream);
 extern enum pph_record_marker pph_in_record_marker (pph_stream *stream,
 			enum pph_tag *tag_p);
+extern bool pph_files_read (void);
 
 /* In name-lookup.c.  */
 struct binding_table_s;
@@ -172,6 +173,9 @@  extern void pph_out_spec_entry_tables (p
 extern void pph_in_pending_templates_list (pph_stream *);
 extern void pph_in_spec_entry_tables (pph_stream *);
 
+/* FIXME pph: These functions should be moved to tree.c on merge.  */
+extern VEC(tree,heap) *chain2vec (tree chain);  /* In pph-out.c.  */
+
 
 /* Inline functions.  */
 
Index: gcc/cp/pph-out.c
===================================================================
--- gcc/cp/pph-out.c	(revision 183260)
+++ gcc/cp/pph-out.c	(working copy)
@@ -1087,7 +1087,7 @@  chain2vec_filter (pph_stream *stream, tr
 
 /* Convert a CHAIN to a VEC by copying the nodes.  */
 
-static VEC(tree,heap) *
+VEC(tree,heap) *
 chain2vec (tree chain)
 {
   tree t;
@@ -1160,6 +1160,8 @@  pph_out_merge_body_chain (pph_stream *st
 
 /* Forward declaration to break cyclic dependencies.  */
 static void pph_out_binding_level (pph_stream *, cp_binding_level *, unsigned);
+static void pph_out_merge_key_namespace_decl (pph_stream *stream, tree ns);
+static void pph_out_merge_body_namespace_decl (pph_stream *stream, tree ns);
 
 
 /* Helper for pph_out_cxx_binding.  STREAM and CB are as in
@@ -1307,31 +1309,54 @@  pph_out_binding_level (pph_stream *strea
 }
 
 
-/* Write an index of mergeable objects from cp_binding_level BL to STREAM.  */
+/* Iterate over a chain FIRST, apply FILTER, and call output FUNCTION.  */
+
+static void
+pph_foreach_out_chain (pph_stream *stream, tree first, unsigned filter,
+		       void (*function)(pph_stream *, tree))
+{
+  unsigned i;
+  tree ns;
+  VEC(tree,heap) *v;
+  v = chain2vec_filter (stream, first, filter);
+  pph_out_hwi (stream, VEC_length (tree, v));
+  FOR_EACH_VEC_ELT_REVERSE (tree, v, i, ns)
+    (*function) (stream, ns);
+  VEC_free (tree, heap, v);
+}
+
+
+/* Write an index of mergeable namespaces from cp_binding_level BL to
+   STREAM. */
 
 static void
 pph_out_merge_key_binding_level (pph_stream *stream, cp_binding_level *bl)
 {
-  unsigned filter = PPHF_NO_XREFS | PPHF_NO_PREFS | PPHF_NO_BUILTINS;
-  pph_out_merge_key_chain (stream, bl->names, filter);
-  pph_out_merge_key_chain (stream, bl->namespaces, filter);
-  pph_out_merge_key_chain (stream, bl->usings, filter);
-  pph_out_merge_key_chain (stream, bl->using_directives, filter);
+  unsigned filter1 = PPHF_NO_PREFS | PPHF_NO_BUILTINS;
+  unsigned filter2 = PPHF_NO_XREFS | PPHF_NO_PREFS | PPHF_NO_BUILTINS;
+  pph_foreach_out_chain (stream, bl->namespaces, filter1,
+			 pph_out_merge_key_namespace_decl);
+  pph_out_merge_key_chain (stream, bl->names, filter2);
+  pph_out_merge_key_chain (stream, bl->usings, filter2);
+  pph_out_merge_key_chain (stream, bl->using_directives, filter2);
 }
 
 
-/* Write bodies of mergeable objects from cp_binding_level BL to STREAM.  */
+/* Write bodies of mergeable namespaces from from cp_binding_level BL
+   to STREAM. */
 
 static void
 pph_out_merge_body_binding_level (pph_stream *stream, cp_binding_level *bl)
 {
-  unsigned filter = PPHF_NO_XREFS | PPHF_NO_PREFS | PPHF_NO_BUILTINS;
-  pph_out_merge_body_chain (stream, bl->names, filter);
-  pph_out_merge_body_chain (stream, bl->namespaces, filter);
-  pph_out_merge_body_chain (stream, bl->usings, filter);
-  pph_out_merge_body_chain (stream, bl->using_directives, filter);
-  pph_out_tree_vec_filtered (stream, bl->static_decls, filter);
-  pph_out_binding_level_1 (stream, bl, filter);
+  unsigned filter1 = PPHF_NO_PREFS | PPHF_NO_BUILTINS;
+  unsigned filter2 = PPHF_NO_XREFS | PPHF_NO_PREFS | PPHF_NO_BUILTINS;
+  pph_foreach_out_chain (stream, bl->namespaces, filter1,
+			 pph_out_merge_body_namespace_decl);
+  pph_out_merge_body_chain (stream, bl->names, filter2);
+  pph_out_merge_body_chain (stream, bl->usings, filter2);
+  pph_out_merge_body_chain (stream, bl->using_directives, filter2);
+  pph_out_tree_vec_filtered (stream, bl->static_decls, filter2);
+  pph_out_binding_level_1 (stream, bl, filter2);
 }
 
 
@@ -1872,18 +1897,9 @@  pph_out_tcc_declaration (pph_stream *str
 
 /* Emit the bindings for an identifier expr. */
 
-void
+static void
 pph_out_identifier_bindings (pph_stream *stream, tree expr)
 {
-/* FIXME pph: Writing bindings is causing trouble,
-   but not writing them is not yet working.  */
-#if 0
-#else
-  pph_out_cxx_binding (stream, IDENTIFIER_NAMESPACE_BINDINGS (expr));
-  pph_out_cxx_binding (stream, IDENTIFIER_BINDING (expr));
-  pph_out_tree (stream, IDENTIFIER_TEMPLATE (expr));
-  pph_out_tree (stream, IDENTIFIER_LABEL_VALUE (expr));
-#endif
   pph_out_tree (stream, REAL_IDENTIFIER_TYPE_VALUE (expr));
 }
 
@@ -2196,7 +2212,7 @@  pph_out_merge_name (pph_stream *stream, 
 }
 
 
-/* Write merge information for a namespace DECL to STREAM.  */
+/* Write merge key information for a namespace DECL to STREAM.  */
 
 static void
 pph_out_merge_key_namespace_decl (pph_stream *stream, tree decl)
@@ -2205,12 +2221,52 @@  pph_out_merge_key_namespace_decl (pph_st
 
   gcc_assert (TREE_CODE (decl) == NAMESPACE_DECL);
 
+  pph_out_start_merge_key_tree_record (stream, decl);
+
+  pph_out_tree_header (stream, decl);
+  pph_out_merge_name (stream, decl);
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_front, pph_trace_key_out);
+
+  pph_out_tree (stream, DECL_NAME (decl));
+
   /* If EXPR is a namespace alias, it will not have an associated
      binding.  In that case, tell the reader not to bother with it.  */
   is_namespace_alias = (DECL_NAMESPACE_ALIAS (decl) != NULL_TREE);
   pph_out_bool (stream, is_namespace_alias);
   if (!is_namespace_alias)
     pph_out_merge_key_binding_level (stream, NAMESPACE_LEVEL (decl));
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_back, pph_trace_key_out);
+}
+
+
+/* Write merge body information for a namespace DECL to STREAM.  */
+
+static void
+pph_out_merge_body_namespace_decl (pph_stream *stream, tree decl)
+{
+  bool is_namespace_alias;
+
+  gcc_assert (TREE_CODE (decl) == NAMESPACE_DECL);
+
+  pph_out_start_tree_record (stream, decl);
+  pph_out_tree_header (stream, decl);
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_front, pph_trace_merge_body);
+
+  /* If EXPR is a namespace alias, it will not have an associated
+     binding.  In that case, tell the reader not to bother with it.  */
+  is_namespace_alias = (DECL_NAMESPACE_ALIAS (decl) != NULL_TREE);
+  pph_out_bool (stream, is_namespace_alias);
+  if (!is_namespace_alias)
+    pph_out_merge_body_binding_level (stream, NAMESPACE_LEVEL (decl));
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_back, pph_trace_merge_body);
 }
 
 
@@ -2234,8 +2290,6 @@  pph_out_merge_key_tree (pph_stream *stre
   pph_out_merge_name (stream, expr);
   if (DECL_P (expr))
     {
-      if (TREE_CODE (expr) == NAMESPACE_DECL)
-	pph_out_merge_key_namespace_decl (stream, expr);
 #if 0
 /* FIXME pph: Distable tree merging for the moment.  */
       else if (TREE_CODE (expr) == TYPE_DECL)
@@ -2589,7 +2643,7 @@  pph_write_file (pph_stream *stream)
   cpp_idents_used idents_used;
 
   if (flag_pph_tracer >= 1)
-    fprintf (pph_logfile, "PPH: Writing %s\n", pph_out_file);
+    fprintf (pph_logfile, "\nPPH: Writing %s\n", pph_out_file);
 
   /* Emit the line table entries and references to our direct includes.   */
   pph_out_line_table_and_includes (stream);
@@ -2616,7 +2670,7 @@  pph_write_file (pph_stream *stream)
   pph_out_symtab (stream);
 
   if (flag_pph_dump_tree)
-    pph_dump_namespace (pph_logfile, global_namespace);
+    pph_dump_namespace (pph_logfile, global_namespace, "after pph write");
 }
 
 
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 183260)
+++ gcc/cp/pt.c	(working copy)
@@ -20597,11 +20597,13 @@  pph_dump_tinst_level (FILE *stream, stru
     ++count;
 
   /* Now dump them.  */
-  fprintf (stream, "%d tinst_levels\n", count);
+  fprintf (stream, "PPH: %d tinst_levels\n", count);
   for (cur = tinst; cur != NULL;  cur = cur->next)
     {
+      fprintf (stream, "PPH: ");
       pph_dump_location (stream, cur->locus);
       fprintf (stream, "\n");
+      fprintf (stream, "PPH: ");
       pph_dump_tree_name (stream, cur->decl, 0);
       fprintf (stream, "%d errors, ", cur->errors);
       fprintf (stream, "%d in system header\n", cur->in_system_header_p);
@@ -20647,7 +20649,7 @@  pph_dump_pending_templates_list (FILE *s
     ++count;
 
   /* Now dump them.  */
-  fprintf (stream, "%d pending templates\n", count );
+  fprintf (stream, "PPH: %d pending templates\n", count );
   for (cur = pending_templates; cur != NULL;  cur = cur->next )
     pph_dump_tinst_level (stream, cur->tinst);
 }
@@ -20738,9 +20740,9 @@  pph_dump_spec_entry_slot (void **slot, v
 {
   FILE *stream = (FILE *)aux;
   struct spec_entry *entry = (struct spec_entry *) *slot;
-  fprintf (stream, "spec_entry.tmpl: " );
+  fprintf (stream, "PPH: spec_entry.tmpl: " );
   pph_dump_tree_name (stream, entry->tmpl, 0);
-  fprintf (stream, "spec_entry.spec: " );
+  fprintf (stream, "PPH: spec_entry.spec: " );
   pph_dump_tree_name (stream, entry->spec, 0);
   return 1;
 }
@@ -20752,12 +20754,12 @@  pph_dump_spec_entry_htab (FILE *stream, 
 {
   if (*table)
     {
-      fprintf (stream, "%d %s spec_entry elements\n",
+      fprintf (stream, "PPH: %d %s spec_entry elements\n",
                (int) htab_elements (*table), name);
       htab_traverse_noresize (*table, pph_dump_spec_entry_slot, stream);
     }
   else
-    fprintf (stream, "NULL %s spec_entry elements\n", name);
+    fprintf (stream, "PPH: NULL %s spec_entry elements\n", name);
 }
 
 /* Load and merge a spec_entry TABLE from STREAM.  */
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 183260)
+++ gcc/cp/parser.c	(working copy)
@@ -463,6 +463,24 @@  cp_debug_parser_tokens (FILE *file, cp_p
 }
 
 
+/* Concisely dump the tokens around where the PARSER's current token
+   in a concise manner.  If FILE is NULL, the output is printed on
+   stderr. */
+
+void
+cp_debug_parser_where (FILE *file, cp_parser *parser)
+{
+  const size_t window_size = 20;
+  cp_token *token = parser->lexer->next_token;
+  expanded_location eloc = expand_location (token->location);
+
+  if (file == NULL)
+    file = stderr;
+
+  fprintf (file, "%s:%d:%d ", eloc.file, eloc.line, eloc.column);
+  cp_debug_parser_tokens (file, parser, window_size);
+}
+
 /* Dump debugging information for the given PARSER.  If FILE is NULL,
    the output is printed on stderr.  */
 
@@ -27440,7 +27458,8 @@  c_parse_file (void)
 
   the_parser = cp_parser_new ();
 
-  pph_loaded();
+  if (pph_enabled_p () && pph_files_read ())
+    pph_loaded ();
 
   push_deferring_access_checks (flag_access_control
 				? dk_no_deferred : dk_no_check);
Index: gcc/cp/parser.h
===================================================================
--- gcc/cp/parser.h	(revision 183260)
+++ gcc/cp/parser.h	(working copy)
@@ -359,5 +359,6 @@  typedef struct GTY(()) cp_parser {
 extern void cp_lexer_debug_tokens (VEC(cp_token,gc) *);
 extern cp_token_cache *cp_token_cache_new (cp_token *, cp_token *);
 extern void cp_debug_parser (FILE *, cp_parser *);
+extern void cp_debug_parser_where (FILE *, cp_parser *);
 
 #endif  /* GCC_CP_PARSER_H  */
Index: gcc/cp/pph-streamer.h
===================================================================
--- gcc/cp/pph-streamer.h	(revision 183260)
+++ gcc/cp/pph-streamer.h	(working copy)
@@ -249,7 +249,7 @@  enum pph_trace_end
 
 /* In pph-core.c.  */
 const char *pph_tree_code_text (enum tree_code code);
-void pph_dump_namespace (FILE *, tree ns);
+void pph_dump_namespace (FILE *, tree ns, const char *msg);
 pph_stream *pph_stream_registry_lookup (const char *);
 void pph_stream_set_header_name (pph_stream *, const char *);
 pph_stream *pph_stream_open (const char *, const char *);
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 183260)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -6085,29 +6085,163 @@  pph_in_binding_table (pph_stream *stream
 }
 
 
+/*  Dump a taken binding action.  */
+
+static void
+pph_debug_binding_action (const char *action, tree decl)
+{
+  if (flag_pph_debug >= 5 || (flag_pph_debug >= 2 && !DECL_IS_BUILTIN (decl)))
+    {
+      fprintf (pph_logfile, "%s ", action);
+      pph_dump_tree_name (pph_logfile, decl, 0);
+    }
+}
+
+/*  Dump a not-taken binding action.  */
+
+static void
+pph_debug_binding_inaction (const char *action, tree decl)
+{
+  if (flag_pph_debug >= 5 || (flag_pph_debug >= 3 && !DECL_IS_BUILTIN (decl)))
+    {
+      fprintf (pph_logfile, "not %s ", action);
+      pph_dump_tree_name (pph_logfile, decl, 0);
+    }
+}
+
+
+/* Iterate over chain starting at FIRST and calling FUNCTION for each decl
+   with argument BL.  */
+
+static void
+pph_foreach_on_chain_bl (tree first, cp_binding_level *bl,
+			 void (*function)(tree, cp_binding_level *))
+{
+  unsigned i;
+  tree decl;
+  VEC(tree,heap) *w = chain2vec (first);
+  FOR_EACH_VEC_ELT_REVERSE (tree, w, i, decl)
+    (*function) (decl, bl);
+  VEC_free (tree, heap, w);
+}
+
+
+/* Set a identifier binding.  */
+
+static void
+pph_set_identifier_bindings (tree decl, cp_binding_level *bl)
+{
+  /* Set the identifier binding for a single decl.  */
+  tree id = DECL_NAME (decl);
+  if (id)
+    {
+      pph_debug_binding_action ("i-bind", decl);
+      push_binding (id, decl, bl);
+    }
+}
+
+
 /*  Set the identifier bindings for an individual chain.  */
 
 static void
 pph_set_chain_identifier_bindings (tree first, cp_binding_level *bl)
 {
-  tree decl;
-  for (decl = first; decl; decl = TREE_CHAIN (decl))
+  pph_foreach_on_chain_bl (first, bl, pph_set_identifier_bindings);
+}
+
+
+/*  Set a namespace identifier binding.  */
+
+static void
+pph_set_namespace_bindings (tree decl, cp_binding_level *bl)
+{
+  /* Set the namespace identifier binding for a single decl.  */
+  tree id = DECL_NAME (decl);
+  if (id)
     {
-      /* Set the identifier binding for a single decl.  */
-      tree id = DECL_NAME (decl);
-      if (id)
+      /* This code plagarizes from set_namespace_binding.
+	 It has trouble with supplement_binding, methinks.  */
+      /* FIXME pph: we should do more merging here.  */
+      cxx_binding *b = binding_for_name (bl, id);
+      if (!b->value)
 	{
-	  if (flag_pph_debug >=2)
-	    {
-	     fprintf (pph_logfile, "binding ");
-	     pph_dump_tree_name (pph_logfile, id, 0);
-	   }
-	  push_binding (id, decl, bl);
+	  b->value = decl;
+	  pph_debug_binding_action ("v-bind", decl);
+	}
+      else if (TREE_CODE (b->value) == TYPE_DECL &&
+    	   TREE_CODE (decl) != TYPE_DECL)
+	{
+	  b->type = b->value;
+	  b->value = decl;
+	  pph_debug_binding_action ("p-bind", decl);
+	}
+      else if (TREE_CODE (b->value) != TYPE_DECL &&
+    	   TREE_CODE (decl) == TYPE_DECL)
+	{
+	  b->type = decl;
+	  pph_debug_binding_action ("t-bind", decl);
 	}
+      else
+	pph_debug_binding_inaction ("n-bind", decl);
+    }
+}
+
+
+/*  Set the namespace identifier bindings.  */
+
+static void
+pph_set_chain_namespace_bindings (tree first, cp_binding_level *bl)
+{
+  pph_foreach_on_chain_bl (first, bl, pph_set_namespace_bindings);
+}
+
+
+static void
+pph_foreach_on_chain (tree first, void (*function)(tree))
+{
+  unsigned i;
+  tree decl;
+  VEC(tree,heap) *w = chain2vec (first);
+  FOR_EACH_VEC_ELT_REVERSE (tree, w, i, decl)
+    (*function) (decl);
+  VEC_free (tree, heap, w);
+}
+
+
+/* Forward declaration.  */
+
+static void
+pph_set_namespace_namespace_bindings (cp_binding_level *bl);
+
+
+/* Set a namespace namespace binding.  */
+
+static void
+pph_set_namespace_namespace_binding (tree decl)
+{
+  /* Set the namespace identifier binding for a single decl.  */
+  tree id = DECL_NAME (decl);
+  if (id)
+    {
+      pph_debug_binding_action ("bind recurse", decl);
+      pph_set_namespace_namespace_bindings (NAMESPACE_LEVEL (decl));
     }
 }
 
 
+/*  Set the namespace identifier bindings for a namespace.  */
+
+static void
+pph_set_namespace_namespace_bindings (cp_binding_level *bl)
+{
+  pph_set_chain_namespace_bindings (bl->names, bl);
+  pph_set_chain_namespace_bindings (bl->namespaces, bl);
+  pph_set_chain_namespace_bindings (bl->usings, bl);
+  /* FIXME pph: pph_set_chain_namespace_bindings (bl->using_directives, bl);  */
+  pph_foreach_on_chain (bl->namespaces, pph_set_namespace_namespace_binding);
+}
+
+
 /* Set the identifier bindings for the global namespace
    after having read all the PPH files.  */
 
@@ -6119,6 +6253,7 @@  pph_set_global_identifier_bindings (void
   pph_set_chain_identifier_bindings (bl->namespaces, bl);
   pph_set_chain_identifier_bindings (bl->usings, bl);
   pph_set_chain_identifier_bindings (bl->using_directives, bl);
+  pph_set_namespace_namespace_bindings (bl);
 }
 
 
Index: gcc/cp/pph-in.c
===================================================================
--- gcc/cp/pph-in.c	(revision 183260)
+++ gcc/cp/pph-in.c	(working copy)
@@ -987,6 +987,8 @@  pph_merge_into_chain (tree expr, const c
 
 /* Forward declaration to break cyclic dependencies.  */
 static cp_binding_level *pph_in_binding_level (pph_stream *);
+static void pph_in_merge_body_namespace_decl (pph_stream *stream);
+static void pph_in_merge_key_namespace_decl (pph_stream *stream, tree *chain);
 
 /* Helper for pph_in_cxx_binding.  Read and return a cxx_binding
    instance from STREAM.  */
@@ -1203,9 +1205,12 @@  pph_in_binding_level (pph_stream *stream
 static void
 pph_in_merge_key_binding_level (pph_stream *stream, cp_binding_level *bl)
 {
-  /* Read all the merge keys and merge into the bindings.  */
+  unsigned count, num;
+  num = pph_in_hwi (stream);
+  for (count = 0; count < num; ++count)
+    pph_in_merge_key_namespace_decl (stream, &bl->namespaces);
+  /* FIXME pph:  The null check should be unnecessary. */
   pph_in_merge_key_chain (stream, (bl) ? &bl->names : NULL);
-  pph_in_merge_key_chain (stream, (bl) ? &bl->namespaces : NULL);
   pph_in_merge_key_chain (stream, (bl) ? &bl->usings : NULL);
   pph_in_merge_key_chain (stream, (bl) ? &bl->using_directives : NULL);
 }
@@ -1216,7 +1221,10 @@  pph_in_merge_key_binding_level (pph_stre
 static void
 pph_in_merge_body_binding_level_1 (pph_stream *stream, cp_binding_level *bl)
 {
-  pph_in_merge_body_chain (stream);
+  unsigned count, num;
+  num = pph_in_hwi (stream);
+  for (count = 0; count < num; ++count)
+    pph_in_merge_body_namespace_decl (stream);
   pph_in_merge_body_chain (stream);
   pph_in_merge_body_chain (stream);
   pph_in_merge_body_chain (stream);
@@ -1225,7 +1233,6 @@  pph_in_merge_body_binding_level_1 (pph_s
   pph_in_binding_level_1 (stream, bl);
 }
 
-
 /* Read all the merge bodies from STREAM into the cp_binding_level BL.  */
 
 static void
@@ -1964,16 +1971,9 @@  static void
 pph_in_identifier_bindings (pph_stream *stream, tree expr)
 {
   if (flag_pph_debug >= 3)
-    fprintf (pph_logfile, "in identifier %s\n", IDENTIFIER_POINTER (expr));
+    fprintf (pph_logfile, "PPH: in identifier %s\n", IDENTIFIER_POINTER (expr));
 /* FIXME pph: Writing bindings is causing trouble,
    but not writing them is not yet working.  */
-#if 0
-#else
-  IDENTIFIER_NAMESPACE_BINDINGS (expr) = pph_in_cxx_binding (stream);
-  IDENTIFIER_BINDING (expr) = pph_in_cxx_binding (stream);
-  IDENTIFIER_TEMPLATE (expr) = pph_in_tree (stream);
-  IDENTIFIER_LABEL_VALUE (expr) = pph_in_tree (stream);
-#endif
   REAL_IDENTIFIER_TYPE_VALUE (expr) = pph_in_tree (stream);
 }
 
@@ -2260,13 +2260,74 @@  pph_in_tree_header (pph_stream *stream, 
 }
 
 
+/* Ensure that a binding level exists for a namespace DECL. */
+
+static void
+pph_ensure_namespace_binding_level (tree decl)
+{
+  if (!DECL_LANG_SPECIFIC (decl))
+    {
+      retrofit_lang_decl (decl);
+      NAMESPACE_LEVEL (decl) = ggc_alloc_cleared_cp_binding_level ();
+    }
+}
+
+
 /* Read all the merge keys for the names under namespace DECL from
    STREAM.  */
 
 static void
-pph_in_merge_key_namespace_decl (pph_stream *stream, tree decl)
+pph_in_merge_key_namespace_decl (pph_stream *stream, tree *chain)
 {
+  struct lto_input_block *ib = stream->encoder.r.ib;
   bool is_namespace_alias;
+  unsigned image_ix, ix;
+  enum pph_record_marker marker;
+  tree read_decl = NULL, decl = NULL;
+  enum LTO_tags tag;
+  const char *name;
+  tree name_id;
+
+  marker = pph_in_start_record (stream, &image_ix, &ix, PPH_any_tree);
+  gcc_assert (marker != PPH_RECORD_END);
+  if (pph_is_reference_marker (marker))
+    decl = (tree) pph_cache_find (stream, marker, image_ix, ix, PPH_any_tree);
+  else
+    gcc_assert (marker == PPH_RECORD_START_MERGE_KEY);
+
+  tag = streamer_read_record_start (ib);
+
+  read_decl = pph_in_tree_header (stream, tag);
+  gcc_assert (pph_tree_is_mergeable (read_decl));
+  name = pph_in_string (stream);
+
+  gcc_assert (TREE_CODE (read_decl) == NAMESPACE_DECL);
+
+  if (!decl)
+    {
+      /* The record is new, so we need to link it in.  */
+
+      /* If we are merging into an existing CHAIN.  Look for a match in
+         CHAIN to READ_DECL's header.  If we found a match, DECL will be
+         the existing tree that matches READ_DECL. Otherwise, DECL is the
+         newly allocated READ_DECL.  */
+      decl = (chain) ? pph_merge_into_chain (read_decl, name, chain)
+		     : read_decl;
+      gcc_assert (decl != NULL);
+
+      pph_cache_insert_at (&stream->cache, decl, ix,
+			   pph_tree_code_to_tag (decl));
+    }
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_front, pph_trace_unmerged_key);
+
+  name_id = pph_in_tree (stream);
+  if (decl == read_decl)
+    {
+      DECL_NAME (decl) = name_id;
+      TREE_TYPE (decl) = void_type_node;
+    }
 
   /* If EXPR is a namespace alias, we do not need to merge
      its binding level (namespaces aliases do not have a
@@ -2275,6 +2336,7 @@  pph_in_merge_key_namespace_decl (pph_str
   is_namespace_alias = pph_in_bool (stream);
   if (!is_namespace_alias)
     {
+      /* FIXME pph this comment is broken.  */
       /* If this is the first time we see DECL, it will not have
 	 a decl_lang nor a binding level associated with it.  This
 	 means that we do not actually need to do any merging, so
@@ -2284,11 +2346,89 @@  pph_in_merge_key_namespace_decl (pph_str
 	 under DECL, but it will not try to attempt any merging.
 	 This is fine.  The namespace will be populated once we read
 	 DECL's body.  */
-      cp_binding_level *bl = DECL_LANG_SPECIFIC (decl)
-			     ? NAMESPACE_LEVEL (decl)
-			     : NULL;
-      pph_in_merge_key_binding_level (stream, bl);
+      pph_ensure_namespace_binding_level (decl);
+      pph_in_merge_key_binding_level (stream, NAMESPACE_LEVEL (decl));
+    }
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_back, pph_trace_unmerged_key);
+}
+
+
+/* Read all the merge bodies for the names under namespace DECL from
+   STREAM.  */
+
+static void
+pph_in_merge_body_namespace_decl (pph_stream *stream)
+{
+  bool is_namespace_alias;
+  unsigned image_ix, ix;
+  /* FIXME pph: remove internal cache duplication of external
+  unsigned local_ix;
+  */
+  enum pph_record_marker marker;
+  tree read_decl = NULL, decl = NULL;
+  enum LTO_tags tag;
+  struct lto_input_block *ib = stream->encoder.r.ib;
+
+  marker = pph_in_start_record (stream, &image_ix, &ix, PPH_any_tree);
+  gcc_assert (marker != PPH_RECORD_END);
+  if (pph_is_reference_marker (marker))
+    decl = (tree) pph_cache_find (stream, marker, image_ix, ix, PPH_any_tree);
+  else if (marker == PPH_RECORD_START_MUTATED)
+    /* FIXME pph: remove internal cache duplication of external
+    local_ix = pph_in_uint (stream);
+    */
+    ;
+  else
+    gcc_assert (marker == PPH_RECORD_START_MERGE_BODY);
+
+  tag = streamer_read_record_start (ib);
+  read_decl = pph_in_tree_header (stream, tag);
+  gcc_assert (TREE_CODE (read_decl) == NAMESPACE_DECL);
+  if (!decl)
+    {
+      if (marker == PPH_RECORD_START_MUTATED)
+        {
+          /* When reading a mutated tree, we only need to re-read its
+             body, the tree itself is already in the cache for another
+             PPH image.  */
+          decl = (tree) pph_cache_find (stream, PPH_RECORD_XREF, image_ix, ix,
+                                        PPH_any_tree);
+      
+          /* Read the internal cache slot where EXPR should be stored at.  */
+	  /* FIXME pph: remove internal cache duplication of external
+          ix = local_ix;
+	  */
+        }
+      else if (marker == PPH_RECORD_START_MERGE_BODY)
+        {
+          /* When reading a merge body, the tree has already been allocated
+             and added to STREAM's cache.  All we have to do now is read
+             its body.  */
+          decl = (tree) pph_cache_get (&stream->cache, ix);
+        }
     }
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_front, pph_trace_merge_body);
+
+  gcc_assert (DECL_NAME (decl));
+
+  /* If EXPR is a namespace alias, we do not need to merge
+     its binding level (namespaces aliases do not have a
+     binding level, they use the one from the namespace they
+     alias).  */
+  is_namespace_alias = pph_in_bool (stream);
+  if (!is_namespace_alias)
+    {
+      gcc_assert (DECL_LANG_SPECIFIC (decl));
+      gcc_assert (NAMESPACE_LEVEL (decl));
+      pph_in_merge_body_binding_level_1 (stream, NAMESPACE_LEVEL (decl));
+    }
+
+  if (flag_pph_tracer)
+    pph_trace_tree (decl, pph_trace_back, pph_trace_merge_body);
 }
 
 
@@ -2338,8 +2478,6 @@  pph_in_merge_key_tree (pph_stream *strea
 
   if (DECL_P (expr))
     {
-      if (TREE_CODE (expr) == NAMESPACE_DECL)
-	pph_in_merge_key_namespace_decl (stream, expr);
 #if 0
 /* FIXME pph: Disable type merging for the moment.  */
       else if (TREE_CODE (expr) == TYPE_DECL)
@@ -2823,6 +2961,20 @@  pph_in_global_binding (pph_stream *strea
 }
 
 
+/* Keep track of whether or not we actually read any PPH files.  */
+
+static bool pph_files_were_read = false;
+
+
+/* Report whether or not we actually read any PPH files.  */
+
+bool
+pph_files_read (void)
+{
+  return pph_files_were_read;
+}
+
+
 /* Helper for pph_read_file.  Read contents of PPH file in STREAM.  */
 
 static void
@@ -2848,14 +3000,20 @@  pph_read_file_1 (pph_stream *stream)
      (common in system headers).  */
   stream->in_memory_p = true;
 
+  pph_files_were_read = true;
+
   if (flag_pph_tracer >= 1)
-    fprintf (pph_logfile, "PPH: Reading %s\n", stream->name);
+    fprintf (pph_logfile, "\nPPH: Reading Lines and Includes for %s\n",
+			  stream->name);
 
   /* 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);
 
+  if (flag_pph_tracer >= 1)
+    fprintf (pph_logfile, "\nPPH: Reading Contents for %s\n", stream->name);
+
   /* Read all the identifiers and pre-processor symbols in the global
      namespace.  */
   pph_in_identifiers (stream, &idents_used);
@@ -2895,7 +3053,7 @@  pph_read_file_1 (pph_stream *stream)
   pph_in_symtab (stream);
 
   if (flag_pph_dump_tree)
-    pph_dump_namespace (pph_logfile, global_namespace);
+    pph_dump_namespace (pph_logfile, global_namespace, "after pph read");
 }
 
 
Index: gcc/langhooks.c
===================================================================
--- gcc/langhooks.c	(revision 183260)
+++ gcc/langhooks.c	(working copy)
@@ -657,3 +657,10 @@  lhd_end_section (void)
       saved_section = NULL;
     }
 }
+
+/* FIXME pph: This is a gdb workaround.  Maybe it stays, maybe it does not.  */
+struct lang_hooks *
+get_lang_hooks()
+{
+  return &lang_hooks;
+}
Index: gcc/langhooks.h
===================================================================
--- gcc/langhooks.h	(revision 183260)
+++ gcc/langhooks.h	(working copy)
@@ -490,4 +490,7 @@  extern tree add_builtin_function_ext_sco
 					    const char *library_name,
 					    tree attrs);
 
+/* FIXME pph: This is a gdb workaround.  Maybe it stays, maybe it does not.  */
+extern struct lang_hooks *get_lang_hooks (void);
+
 #endif /* GCC_LANG_HOOKS_H */