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 */
