Patchwork [pph] Merge template specializations. (issue5726044)

login
register
mail settings
Submitter Lawrence Crowl
Date March 2, 2012, 6:43 p.m.
Message ID <20120302184335.7F5BD2225E6@jade.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/144300/
State New
Headers show

Comments

Lawrence Crowl - March 2, 2012, 6:43 p.m.
This patch merges template specializations.

* Factored searching out of pph_in_merge_key_tree via a function
parameter.  Its name is now pph_in_merge_key_tree_with_searcher.  The
decl searching now resides in pph_in_search_key_decl_on_chain and
the type searching now resides in pph_in_search_key_type_in_var.
Added two convenience functions pph_in_merge_key_decl_on_chain and
pph_in_merge_key_type_in_var to enable concise replacement of calls to
pph_in_merge_key_tree..

* Split pph_out/in_global_binding to place the specialization keys
between the global keys and the global bodies.

* Changed the template state in/out functions to be non-specific to
specific tables, but specific to keys or bodies.

* Added strptrmap.h and strptrmap.c for searching for existing
specializations.

* Several routines in pph-out.c and pph-in.c needed for specialization
merging have been made extern for pt.c.


The major test changes are as follows.

* Several ICEs are now gone, most of which are replaced by other
errors.

* More instances of a bogus error on a void atomic intrinsic.

* Unimplemented trait mangling in x6dynarray5.h, which also causes all
includers to fail.

* Test abi/mangle17.C changes behavior.  It emits errors for the an
equivalent but different piece of code.  I will address this problem
later.


Test cleanups are as follows.

* Some compilation failures add a 'documentary' xfail-if.  The syntax
is exactly like "dg-xfail-if", but without the "dg-".  This change
enables searching for "xfail-if".

* Some assembly comparisons add or modify a 'xfail' comment to an
'xfail-if' comment.  This change enables searching for "xfail-if".

* The dg-pph.exp test controller now searches for xfail-if rather than
dg-xfail-if to catch expected fails with no exess errors.

* Some tests have had their xfail-if comment string clarified.

* Some tests used dg-excess-errors.  These have been removed in favor
of stating the exact failures.

* Some compilation dg-bogus patterns have been moved to the offending

* Some compilation problems have been isolated to a single line and
statement, which enables the above. line.

* One test has changed trailing include text into a comment.

Tested on x64.



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

Patch

Index: gcc/testsuite/ChangeLog.pph

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

	* lib/dg-pph.exp: Change search for dg-xfail-if to xfail-if.
	* g++.dg/pph/d0include-next.h: Put dg-warning in comment.
	* g++.dg/pph/x2incomplete4.cc: Add documentary xfail-if.
	* g++.dg/pph/x4incomplete4321.cc: Change documentary to xfail-if.
	* g++.dg/pph/x4tmplclass2.cc: Change documentary to xfail-if.
	* g++.dg/pph/x4tmplfuncinln.cc: Mark pph asm xokay.
	* g++.dg/pph/x4tmplfuncninl.cc: Mark pph asm xokay.
	* g++.dg/pph/x5dynarray7.h: Add documentary xfail-if.
	* g++.dg/pph/x6dynarray3.cc: Add documentary xfail-if.
	* g++.dg/pph/x6dynarray4.cc: Change to xfail on included pph.
	* g++.dg/pph/x6dynarray5.h: Change to xfail on included pph.
	* g++.dg/pph/x6dynarray6.h: Add documentary xfail-if.
	* g++.dg/pph/x6rtti.cc: Remove excess-errors filter.  Add bogus rtti mismatch.  Make xfail-if documentary.
	* g++.dg/pph/x7dynarray5.cc: Change to xfail on included pph.  (The bogus void intrinsic comes fail-over to reading the textual header.)
	* g++.dg/pph/x7dynarray6.cc: Change to xfail on bogus void intrinsic.
	* g++.dg/pph/x7dynarray7.cc: Remove excess-errors filter.  Add bogus void intrinsic.  Change xfail-if message.
	* g++.dg/pph/x7rtti.cc: Add documentary xfail-if.  Separate failures to separate statements.  Put dg-bogus on offending lines.
	* g++.dg/pph/z4nontrivinit.cc: Change documentary to xfail-if.
	* g++.dg/pph/z4tmplclass1.cc: Change in failing asm output.  Change documentary to xfail-if.
	* g++.dg/pph/z4tmplclass2.cc: Change in failing asm output.  Change documentary to xfail-if.
	* g++.dg/pph/z4tmplfuncinln.cc: Mark pph asm xokay.
	* g++.dg/pph/z4tmplfuncninl.cc: Mark pph asm xokay.

Index: gcc/cp/ChangeLog.pph

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

	* pph-core.c (pph_include_handler): Make warning message a single line.
	* Make-lang.in (cp/pt.o): Depend on strptrmap.h.
	* pph.h (pph_out_merge_key_tree): Made extern.
	(pph_in_string): Made extern.
	(typedef pph_merge_searcher): New.
	(pph_in_merge_key_tree_with_searcher): Made extern.
	(pph_out_pending_templates_list): Removed.
	(pph_out_spec_entry_tables): Removed.
	(pph_in_pending_templates_list): Removed.
	(pph_in_spec_entry_tables): Removed.
	(pph_out_merge_key_template_state): New.
	(pph_out_merge_body_template_state): New.
	(pph_in_merge_key_template_state): New.
	(pph_in_merge_body_template_state): New.
	* pt.c (#include "strptrmap.h"): New.
	(pph_out_pending_templates_list): Move dump to higher level.
	(pph_in_pending_templates_list): Make static.
	(pph_out_key_spec_entry_slot): New.
	(pph_out_spec_entry_slot): Renamed to pph_out_body_spec_entry_slot.
	(pph_out_spec_entry_htab): Make slot function a parameter.
	(pph_in_search_key_spec): New.
	(pph_in_keys_spec_entry_htab): New.
	(pph_in_spec_entry_htab): Rename to pph_in_bodies_spec_entry_htab.
	(pph_out_merge_key_template_state): New.
	(pph_out_spec_entry_tables): Rename to
	pph_out_merge_body_template_state.  Pass search functions.  Add call
	to pph_out_pending_templates_list.  Move dumping here.
	(static strptrmap_t *decl_spec_tbl): New.
	(static strptrmap_t *type_spec_tbl): New.
	(pph_in_merge_key_template_state): New.
	(pph_in_spec_entry_tables): Rename to pph_in_merge_body_template_state.
	Add call to pph_in_pending_templates_list.  Move dumping here.
	* pph-out.c (pph_out_merge_key_tree): Made extern.  Added bool
	parameter to force merge name emission, which is used for template
	type specialization merging.
	(pph_out_global_binding): Split into pph_out_global_binding_keys and
	pph_out_global_binding_bodies.
	(pph_write_file): Change calls for emitting global bindings and
	template state.
	* pph-in.c (pph_in_string): Make extern.
	(pph_in_merge_key_tree): Factor out searching into function parameter.
	Rename to pph_in_merge_key_tree_with_searcher.  Always merge trees
	when a match is found.  Make extern.
	(pph_in_search_key_decl_on_chain): New.
	(pph_in_merge_key_decl_on_chain): New.
	(pph_in_search_key_type_in_field): New.
	(pph_in_merge_key_type_in_field): New.
	(pph_in_global_binding): Split into pph_in_global_binding_keys and
	pph_in_global_binding_bodies.
	(pph_read_file_1): Change calls for emitting global bindings and
        template state.

Index: gcc/ChangeLog.pph

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

	* strptrmap.h: New.
	* strptrmap.c: New.
	* Makefile.in: Added entries for strptrmap.h and strptrmap.c.


Index: gcc/testsuite/lib/dg-pph.exp
===================================================================
--- gcc/testsuite/lib/dg-pph.exp	(revision 184772)
+++ gcc/testsuite/lib/dg-pph.exp	(working copy)
@@ -145,7 +145,7 @@  proc dg-pph-pos { subdir test options ma
     if { ![file_on_host exists "$bname.s"] } {
 	# Expect assembly to be missing when the compile is an
 	# expected fail.
-	if { ![llength [grep $test "dg-xfail-if.*-fpph-map"]]
+	if { ![llength [grep $test "xfail-if.*-fpph-map"]]
 	     && ![llength [grep $test "dg-bogus.*error:"]] } {
 	    fail "$nshort $options (pph assembly missing)"
 	}
Index: gcc/testsuite/g++.dg/pph/x4tmplfuncninl.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4tmplfuncninl.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x4tmplfuncninl.cc	(working copy)
@@ -1,5 +1,5 @@ 
-// { dg-xfail-if "ICE instantiate_decl - bad merge" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "internal compiler error: in instantiate_decl, at cp/pt.c" "" { xfail *-*-* } 0 }
+// pph asm xokay 51578
+
 #include "x0tmplfuncninl1.h"
 #include "x0tmplfuncninl2.h"
 #include "a0tmplfuncninl_u.h"
Index: gcc/testsuite/g++.dg/pph/z4tmplfuncninl.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/z4tmplfuncninl.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/z4tmplfuncninl.cc	(working copy)
@@ -1,5 +1,5 @@ 
-// { dg-xfail-if "ICE instantiate_decl - bad merge" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "internal compiler error: in instantiate_decl, at cp/pt.c" "" { xfail *-*-* } 0 }
+// pph asm xokay 14419
+
 #include "x0tmplfuncninl3.h"
 #include "x0tmplfuncninl4.h"
 #include "a0tmplfuncninl_u.h"
Index: gcc/testsuite/g++.dg/pph/x6dynarray3.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x6dynarray3.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x6dynarray3.cc	(working copy)
@@ -1,3 +1,4 @@ 
+// {    xfail-if "BOGUS NEW OVERLOAD" { "*-*-*" } { "-fpph-map=pph.map" } }
 // { dg-bogus "a0dynarray-dcl3.hi:11:60: error: call of overloaded 'operator new" "" { xfail *-*-* } 0 }
 
 #include "x5dynarray3.h"
Index: gcc/testsuite/g++.dg/pph/x2incomplete4.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x2incomplete4.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x2incomplete4.cc	(working copy)
@@ -1,4 +1,5 @@ 
 // pph asm xdiff 21766
+// xfail-if BOGUS XTRAFUN
 // copies::copies() is wrongly generated
 
 #include "x1incomplete3.h"
Index: gcc/testsuite/g++.dg/pph/x7dynarray5.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x7dynarray5.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x7dynarray5.cc	(working copy)
@@ -1,9 +1,8 @@ 
-// { dg-xfail-if "BOGUS POSSIBLY DROPPING SYMBOLS " { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "internal compiler error: canonical types differ for identical types" "" { xfail *-*-* } 0 }
-// { dg-excess-errors "type mismatch errors due to TYPE_CANONICAL problems." }
+// {    xfail-if "DEPENDENT" { "*-*-*" } { "-fpph-map=pph.map" } }
+// { dg-bogus "ext/atomicity.h:48:61: error: void value not ignored as it ought to be" "" { xfail *-*-* } 0 }
 
 #include "x0dynarray4.h"
-#include "x6dynarray5.h"
+#include "x6dynarray5.h" // { dg-bogus "warning: cannot open PPH file x6dynarray5.pph" "" { xfail *-*-* } }
 
 #include <algorithm>
 #include <iostream>
Index: gcc/testsuite/g++.dg/pph/x6dynarray4.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x6dynarray4.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x6dynarray4.cc	(working copy)
@@ -1,7 +1,6 @@ 
-// { dg-xfail-if "BOGUS MERGING" { "*-*-*" } { "-fpph-map=pph.map" } }
-// Too many failures to diagnose.
+// {    xfail-if "DEPENDENT" { "*-*-*" } { "-fpph-map=pph.map" } }
 
-#include "x6dynarray5.h"
+#include "x6dynarray5.h" // { dg-bogus "cannot open PPH file x6dynarray5.pph" "" { xfail *-*-* } }
 
 #include <algorithm>
 
Index: gcc/testsuite/g++.dg/pph/x6dynarray5.h
===================================================================
--- gcc/testsuite/g++.dg/pph/x6dynarray5.h	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x6dynarray5.h	(working copy)
@@ -1,3 +1,10 @@ 
+// { dg-xfail-if "UNIMPL TRAIT MANGLING" { "*-*-*" } { "-fpph-map=pph.map" } }
+// { dg-bogus "bits/stl_uninitialized.h:178:12: sorry, unimplemented: mangling trait_expr" "" { xfail *-*-* } 0 }
+// { dg-bogus "bits/allocator.h:153:12: sorry, unimplemented: mangling trait_expr" "" { xfail *-*-* } 0 }
+// { dg-bogus "bits/stl_construct.h:98:12: sorry, unimplemented: mangling trait_expr" "" { xfail *-*-* } 0 }
+// { dg-bogus "bits/stl_tempbuf.h:183:12: sorry, unimplemented: mangling trait_expr" "" { xfail *-*-* } 0 }
+// { dg-bogus "bits/cpp_type_traits.h:87:12: internal compiler error: in write_template_arg_literal, at cp/mangle.c:2919" "" { xfail *-*-* } 0 }
+
 #ifndef X6DYNARRAY5_H
 #define X6DYNARRAY5_H
 
Index: gcc/testsuite/g++.dg/pph/x7dynarray6.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x7dynarray6.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x7dynarray6.cc	(working copy)
@@ -1,5 +1,6 @@ 
-// { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-excess-errors "Embedded text merging problems" }
+// { dg-xfail-if "BOGUS INTRINSIC RETURN" { "*-*-*" } { "-fpph-map=pph.map" } }
+// { dg-bogus "ext/atomicity.h:48:61: error: void value not ignored as it ought to be" "" { xfail *-*-* } 0 }
+
 #include <algorithm>
 #include <iostream>
 
Index: gcc/testsuite/g++.dg/pph/x7rtti.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x7rtti.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x7rtti.cc	(working copy)
@@ -1,21 +1,21 @@ 
-// { dg-xfail-if "rtti problems" { *-*-* } { "-fpph-map=pph.map" } }
-// { dg-excess-errors "macro redefinition and operator match problems" }
-
+// {    xfail-if "UNKNOWN MACRO AND BOGUS RTTI" { "*-*-*" } { "-fpph-map=pph.map" } }
+// { dg-bogus "x7rtti.cc:9:0: warning: .__STDC_IEC_559_COMPLEX__. redefined" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:9:0: warning: .__STDC_ISO_10646__. redefined" "" { xfail *-*-* } 0 }
+// { dg-bogus "x7rtti.cc:9:0: warning: .__STDC_IEC_559__. redefined" "" { xfail *-*-* } 0 }
 // FIXME pph: This should be a { dg=do run } (with '=' replaced by '-')
+
 #include "x5rtti1.h"
 #include "x5rtti2.h"
 
 int main()
 {
-    if (poly1() == poly2()
-	&& nonp1() == nonp2()
-        && hpol1() == hpol2()
-	&& hnpl1() == hnpl2()
-        && poly1() != nonp1()
-	&& hpol1() == hnpl1()
-        && poly2() != nonp2()
-	&& hpol2() == hnpl2())
-      return 0;
-    else
-      return 1;
+    bool a = poly1() == poly2(); // { dg-bogus "no match for 'operator=='" "" { xfail *-*-* } }
+    bool b = nonp1() == nonp2(); // { dg-bogus "no match for 'operator=='" "" { xfail *-*-* } }
+    bool c = hpol1() == hpol2(); // { dg-bogus "no match for 'operator=='" "" { xfail *-*-* } }
+    bool d = hnpl1() == hnpl2(); // { dg-bogus "no match for 'operator=='" "" { xfail *-*-* } }
+    bool e = poly1() != nonp1(); // { dg-bogus "no match for 'operator!='" "" { xfail *-*-* } }
+    bool f = hpol1() == hnpl1(); // { dg-bogus "no match for 'operator=='" "" { xfail *-*-* } }
+    bool g = poly2() != nonp2(); // { dg-bogus "no match for 'operator!='" "" { xfail *-*-* } }
+    bool h = hpol2() == hnpl2(); // { dg-bogus "no match for 'operator=='" "" { xfail *-*-* } }
+    return !(a && b && c && d && e && f && g && h);
 }
Index: gcc/testsuite/g++.dg/pph/z4tmplclass1.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/z4tmplclass1.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/z4tmplclass1.cc	(working copy)
@@ -1,5 +1,5 @@ 
-// pph asm xdiff 43522
-// xfail DUPVAR DUPFUNC
+// pph asm xdiff 54665
+// xfail-if BOGUS DUPFUNC
 
 #include "x0tmplclass13.h"
 #include "x0tmplclass14.h"
Index: gcc/testsuite/g++.dg/pph/d0include-next.h
===================================================================
--- gcc/testsuite/g++.dg/pph/d0include-next.h	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/d0include-next.h	(working copy)
@@ -2,5 +2,5 @@ 
 /* We do not support #include_next in PPH images.  */
 #ifndef D0INCLUDE_NEXT_H
 #define D0INCLUDE_NEXT_H
-#include_next "d0include-next.h" { dg-warning ".*PPH generation disabled" }
+#include_next "d0include-next.h" // { dg-warning ".*PPH generation disabled" }
 #endif
Index: gcc/testsuite/g++.dg/pph/x6dynarray6.h
===================================================================
--- gcc/testsuite/g++.dg/pph/x6dynarray6.h	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x6dynarray6.h	(working copy)
@@ -1,3 +1,4 @@ 
+// {    xfail-if "INTRINSIC RETURN" { "*-*-*" } { "-fpph-map=pph.map" } }
 // { dg-bogus "atomicity.h:48:61: error: void value not ignored as it ought to be" "" { xfail *-*-* } 0 }
 
 #ifndef X6DYNARRAY6_H
Index: gcc/testsuite/g++.dg/pph/x7dynarray7.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x7dynarray7.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x7dynarray7.cc	(working copy)
@@ -1,5 +1,6 @@ 
-// { dg-xfail-if "ICE" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-excess-errors "Embedded text merging problems" }
+// { dg-xfail-if "BOGUS INTRINSIC RETURN" { "*-*-*" } { "-fpph-map=pph.map" } }
+// { dg-bogus "ext/atomicity.h:48:61: error: void value not ignored as it ought to be" "" { xfail *-*-* } 0 }
+
 #include <algorithm>
 #include <iostream>
 
Index: gcc/testsuite/g++.dg/pph/x4tmplfuncinln.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4tmplfuncinln.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x4tmplfuncinln.cc	(working copy)
@@ -1,5 +1,5 @@ 
-// { dg-xfail-if "ICE instantiate_decl - bad merge" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "internal compiler error: in instantiate_decl, at cp/pt.c" "" { xfail *-*-* } 0 }
+// pph asm xokay 14419
+
 #include "x0tmplfuncinln1.h"
 #include "x0tmplfuncinln2.h"
 #include "a0tmplfuncinln_u.h"
Index: gcc/testsuite/g++.dg/pph/z4tmplfuncinln.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/z4tmplfuncinln.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/z4tmplfuncinln.cc	(working copy)
@@ -1,5 +1,5 @@ 
-// { dg-xfail-if "ICE instantiate_decl - bad merge" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "internal compiler error: in instantiate_decl, at cp/pt.c" "" { xfail *-*-* } 0 }
+// pph asm xokay 14419
+
 #include "x0tmplfuncinln3.h"
 #include "x0tmplfuncinln4.h"
 #include "a0tmplfuncinln_u.h"
Index: gcc/testsuite/g++.dg/pph/z4tmplclass2.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/z4tmplclass2.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/z4tmplclass2.cc	(working copy)
@@ -1,5 +1,5 @@ 
-// pph asm xdiff 26423
-// xfail DUPVAR DUPFUNC
+// pph asm xdiff 44158
+// xfail-if BOGUS DUPVAR DUPFUNC
 
 #include "x0tmplclass23.h"
 #include "x0tmplclass24.h"
Index: gcc/testsuite/g++.dg/pph/z4nontrivinit.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/z4nontrivinit.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/z4nontrivinit.cc	(working copy)
@@ -1,5 +1,5 @@ 
 // pph asm xdiff 46966
-// xfail BOGUS DOUBLE DYNINIT
+// xfail-if BOGUS DOUBLE DYNINIT
 
 #include "x0nontrivinit1.h"
 #include "x0nontrivinit2.h"
Index: gcc/testsuite/g++.dg/pph/x4incomplete4321.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4incomplete4321.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x4incomplete4321.cc	(working copy)
@@ -1,5 +1,6 @@ 
 // pph asm xdiff 64351
-// XFAIL missing constructors
+// xfail-if BOGUS MISSFUN
+// missing constructors
 
 #include "x0incomplete3.h"
 #include "x0incomplete2.h"
Index: gcc/testsuite/g++.dg/pph/x4tmplclass2.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x4tmplclass2.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x4tmplclass2.cc	(working copy)
@@ -1,5 +1,5 @@ 
 // pph asm xdiff 51443
-// xfail DUPFUNC
+// xfail-if BOGUS DUPFUNC
 
 #include "x0tmplclass21.h"
 #include "x0tmplclass22.h"
Index: gcc/testsuite/g++.dg/pph/x5dynarray7.h
===================================================================
--- gcc/testsuite/g++.dg/pph/x5dynarray7.h	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x5dynarray7.h	(working copy)
@@ -1,3 +1,4 @@ 
+// {    xfail-if "INTRINSIC RETURN" { "*-*-*" } { "-fpph-map=pph.map" } }
 // { dg-bogus "atomicity.h:48:61: error: void value not ignored as it ought to be" "" { xfail *-*-* } 0 }
 
 #ifndef X5DYNARRAY7_H
Index: gcc/testsuite/g++.dg/pph/x6rtti.cc
===================================================================
--- gcc/testsuite/g++.dg/pph/x6rtti.cc	(revision 184772)
+++ gcc/testsuite/g++.dg/pph/x6rtti.cc	(working copy)
@@ -1,10 +1,11 @@ 
-// { dg-xfail-if "rtti problems" { *-*-* } { "-fpph-map=pph.map" } }
-// { dg-excess-errors "operator match problems due to type merging." }
+// {    xfail-if "BOGUS RTTI" { "*-*-*" } { "-fpph-map=pph.map" } }
 // FIXME pph - We should make this a run test.
 
 #include "x5rtti1.h"
 
 int main()
 {
-    return poly1() != nonp1() && hpol1() == hnpl1();
+    bool a = poly1() != nonp1(); // { dg-bogus "no match for 'operator!='" "" { xfail *-*-* } }
+    bool b = hpol1() == hnpl1(); // { dg-bogus "no match for 'operator=='" "" { xfail *-*-* } }
+    return !(a && b);
 }
Index: gcc/cp/pph-core.c
===================================================================
--- gcc/cp/pph-core.c	(revision 184772)
+++ gcc/cp/pph-core.c	(working copy)
@@ -839,7 +839,7 @@  pph_include_handler (cpp_reader *reader,
 	read_text_file_p = false;
       else
 	warning_at (loc, OPT_Wmissing_pph,
-		    "cannot open PPH file %s for reading: %m\n"
+		    "cannot open PPH file %s for reading: %m; "
 		    "using original header %s", pph_file, name);
     }
 
Index: gcc/cp/Make-lang.in
===================================================================
--- gcc/cp/Make-lang.in	(revision 184772)
+++ gcc/cp/Make-lang.in	(working copy)
@@ -323,7 +323,7 @@  cp/except.o: cp/except.c $(CXX_TREE_H) $
 cp/expr.o: cp/expr.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) $(TM_P_H)
 cp/pt.o: cp/pt.c $(CXX_TREE_H) $(TM_H) cp/decl.h cp/cp-objcp-common.h \
   toplev.h $(TREE_INLINE_H) pointer-set.h gt-cp-pt.h vecprim.h intl.h \
-  c-family/c-objc.h $(CXX_PPH_H)
+  c-family/c-objc.h $(CXX_PPH_H) strptrmap.h
 cp/error.o: cp/error.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_H) \
   $(FLAGS_H) $(REAL_H) $(LANGHOOKS_DEF_H) $(CXX_PRETTY_PRINT_H) \
   tree-diagnostic.h tree-pretty-print.h pointer-set.h c-family/c-objc.h
Index: gcc/cp/pph.h
===================================================================
--- gcc/cp/pph.h	(revision 184772)
+++ gcc/cp/pph.h	(working copy)
@@ -153,6 +153,7 @@  extern void pph_out_uint (pph_stream *st
 extern void pph_out_location (pph_stream *stream, location_t loc);
 extern void pph_out_tree (pph_stream *stream, tree t);
 extern void pph_out_tree_vec (pph_stream *stream, VEC(tree,gc) *v);
+extern void pph_out_merge_key_tree (pph_stream *, tree, bool);
 extern void pph_out_record_marker (pph_stream *stream,
 			enum pph_record_marker marker, enum pph_tag tag);
 void pph_add_decl_to_symtab (tree, enum pph_symtab_action, bool, bool);
@@ -160,7 +161,12 @@  void pph_add_decl_to_symtab (tree, enum 
 /* In pph-in.c.  */
 extern unsigned int pph_in_uint (pph_stream *stream);
 extern location_t pph_in_location (pph_stream *stream);
+extern const char *pph_in_string (pph_stream *stream);
 extern tree pph_in_tree (pph_stream *stream);
+typedef tree (*pph_merge_searcher)(pph_stream *stream, tree read_expr,
+				   const char **name, void *holder);
+extern tree pph_in_merge_key_tree_with_searcher (pph_stream *stream,
+	void *holder, pph_merge_searcher searcher);
 extern VEC(tree,gc) *pph_in_tree_vec (pph_stream *stream);
 extern void pph_union_into_tree_vec (VEC(tree,gc) **into, VEC(tree,gc) *from);
 extern enum pph_record_marker pph_in_record_marker (pph_stream *stream,
@@ -179,10 +185,10 @@  extern struct binding_table_s *pph_in_bi
 extern void pph_set_global_identifier_bindings (void);
 
 /* In pt.c.  */
-extern void pph_out_pending_templates_list (pph_stream *);
-extern void pph_out_spec_entry_tables (pph_stream *);
-extern void pph_in_pending_templates_list (pph_stream *);
-extern void pph_in_spec_entry_tables (pph_stream *);
+extern void pph_out_merge_key_template_state (pph_stream *);
+extern void pph_out_merge_body_template_state (pph_stream *);
+extern void pph_in_merge_key_template_state (pph_stream *);
+extern void pph_in_merge_body_template_state (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.  */
Index: gcc/cp/pph-out.c
===================================================================
--- gcc/cp/pph-out.c	(revision 184772)
+++ gcc/cp/pph-out.c	(working copy)
@@ -37,13 +37,6 @@  along with GCC; see the file COPYING3.  
 #include "parser.h"
 
 
-/****************************************************** forward declarations */
-
-
-/* Forward declarations to avoid circular references.  */
-static void pph_out_merge_key_tree (pph_stream *, tree);
-
-
 /***************************************************** stream initialization */
 
 
@@ -1012,7 +1005,7 @@  pph_out_merge_key_vec (pph_stream *strea
   tree t;
   pph_out_hwi (stream, VEC_length (tree, v));
   FOR_EACH_VEC_ELT_REVERSE (tree, v, i, t)
-    pph_out_merge_key_tree (stream, t);
+    pph_out_merge_key_tree (stream, t, false);
 }
 
 
@@ -2274,8 +2267,8 @@  pph_out_merge_body_namespace_decl (pph_s
 
 /* Write the merge key for tree EXPR to STREAM.  */
 
-static void
-pph_out_merge_key_tree (pph_stream *stream, tree expr)
+void
+pph_out_merge_key_tree (pph_stream *stream, tree expr, bool name_type)
 {
   if (pph_out_start_merge_key_tree_record (stream, expr))
     return;
@@ -2299,11 +2292,13 @@  pph_out_merge_key_tree (pph_stream *stre
 	  tree type = TREE_TYPE (expr);
 	  pph_out_bool (stream, is_implicit);
 	  if (is_implicit)
-	    pph_out_merge_key_tree (stream, type);
+	    pph_out_merge_key_tree (stream, type, false);
 	}
     }
   else
     {
+      if (name_type)
+	pph_out_merge_name (stream, expr);
       gcc_assert (TYPE_P (expr));
     }
 
@@ -2580,10 +2575,10 @@  pph_out_identifiers (pph_stream *stream,
 }
 
 
-/* Write the global bindings in scope_chain to STREAM.  */
+/* Write the keys for global bindings in scope_chain to STREAM.  */
 
 static void
-pph_out_global_binding (pph_stream *stream)
+pph_out_global_binding_keys (pph_stream *stream)
 {
   cp_binding_level *bl;
 
@@ -2618,6 +2613,15 @@  pph_out_global_binding (pph_stream *stre
   /* Emit all the merge keys for objects that need to be merged when
      reading multiple PPH images.  */
   pph_out_merge_key_binding_level (stream, bl);
+}
+
+
+/* Write the bodies for global bindings in scope_chain to STREAM.  */
+
+static void
+pph_out_global_binding_bodies (pph_stream *stream)
+{
+  cp_binding_level *bl = scope_chain->bindings;
 
   /* Now emit all the bodies.  */
   pph_out_merge_body_binding_level (stream, bl);
@@ -2642,19 +2646,17 @@  pph_write_file (pph_stream *stream)
   idents_used = cpp_lt_capture (parse_in);
   pph_out_identifiers (stream, &idents_used);
 
-  /* Emit the bindings for the global namespace.  */
-  pph_out_global_binding (stream);
+  /* Emit the bindings for namespace scopes and template state.  */
+  pph_out_global_binding_keys (stream);
+  pph_out_merge_key_template_state (stream);
+  pph_out_global_binding_bodies (stream);
+  pph_out_merge_body_template_state (stream);
 
   /* Emit other global state kept by the parser.  FIXME pph, these
      globals should be fields in struct cp_parser.  */
   pph_out_tree (stream, keyed_classes);
   pph_out_tree_vec (stream, unemitted_tinfo_decls);
-
-  pph_out_pending_templates_list (stream);
-  pph_out_spec_entry_tables (stream);
-
   pph_out_tree (stream, static_aggregates);
-
   pph_out_decl2_hidden_state (stream);
 
   /* Emit the symbol table.  */
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 184772)
+++ gcc/cp/pt.c	(working copy)
@@ -46,6 +46,7 @@  along with GCC; see the file COPYING3.  
 #include "timevar.h"
 #include "tree-iterator.h"
 #include "vecprim.h"
+#include "strptrmap.h"
 
 /* The type of functions taking a tree, and some additional data, and
    returning an int.  */
@@ -20681,9 +20682,6 @@  pph_out_pending_templates_list (pph_stre
   int count = 0;
   struct pending_template *cur;
 
-  if (flag_pph_dump_tree)
-    pph_dump_pending_templates_list (stderr);
-
   /* Count the number of items.  */
   for (cur = pending_templates; cur != NULL;  cur = cur->next )
     ++count;
@@ -20696,7 +20694,7 @@  pph_out_pending_templates_list (pph_stre
 
 /* Load and merge the pending_templates list from STREAM.  */
 
-void
+static void
 pph_in_pending_templates_list (pph_stream *stream)
 { 
   unsigned count = pph_in_uint (stream);
@@ -20715,17 +20713,27 @@  pph_in_pending_templates_list (pph_strea
         pending_templates = pt;
       last_pending_template = pt;
     }
+}
 
-  if (flag_pph_dump_tree)
-    pph_dump_pending_templates_list (stderr);
+
+/* A callback of htab_traverse.  Writes out the PPH the merge keys for SLOT
+   using the AUXillary information. */
+
+static int
+pph_out_key_spec_entry_slot (void **slot, void *aux)
+{
+  pph_stream *stream = (pph_stream *)aux;
+  struct spec_entry *entry = (struct spec_entry *) *slot;
+  pph_out_merge_key_tree (stream, entry->spec, true);
+  return 1;
 }
 
 
-/* A callback of htab_traverse. Just extracts a (type) tree from SLOT
-   and writes it out for PPH using the AUXillary information. */
+/* A callback of htab_traverse.  Writes out the PPH the merge bodies for SLOT
+   using the AUXillary information. */
 
 static int
-pph_out_spec_entry_slot (void **slot, void *aux)
+pph_out_body_spec_entry_slot (void **slot, void *aux)
 {
   pph_stream *stream = (pph_stream *)aux;
   struct spec_entry *entry = (struct spec_entry *) *slot;
@@ -20735,16 +20743,18 @@  pph_out_spec_entry_slot (void **slot, vo
   return 1;
 }
 
-/* Emit a spec_entry TABLE to STREAM.  */
+
+/* Write a spec_entry TABLE to STREAM using FUNC.  */
 
 static void
-pph_out_spec_entry_htab (pph_stream *stream, htab_t *table)
+pph_out_spec_entry_htab (pph_stream *stream, htab_t *table,
+			 int (*func)(void **slot, void *aux))
 {
   if (*table)
     {
       /*FIXME pph: This write may be unstable.  */
       pph_out_uint (stream, htab_elements (*table));
-      htab_traverse_noresize (*table, pph_out_spec_entry_slot, stream);
+      htab_traverse_noresize (*table, func, stream);
     }
   else
     pph_out_uint (stream, 0);
@@ -20766,7 +20776,8 @@  pph_dump_spec_entry_slot (void **slot, v
   return 1;
 }
 
-/* Dump a spec_entry TABLE to STREAM.  */
+
+/* Dump keys in spec_entry TABLE to STREAM.  */
 
 static void
 pph_dump_spec_entry_htab (FILE *stream, const char *name, htab_t *table)
@@ -20781,14 +20792,50 @@  pph_dump_spec_entry_htab (FILE *stream, 
     fprintf (stream, "PPH: NULL %s spec_entry elements\n", name);
 }
 
-/* Load and merge a spec_entry TABLE from STREAM.  */
+
+/* Search for a decl or type key READ_EXPR within the specialization name
+   table HOLDER.  Read the name necessary for that search from STREAM and
+   update *NAME_P with the string found.  */
+
+static tree
+pph_in_search_key_spec (pph_stream *stream, tree read_expr,
+			const char **name_p, void *holder)
+{
+  tree expr;
+  strptrmap_t *spec_tbl = (strptrmap_t*)holder;
+  *name_p = pph_in_string (stream);
+  expr = (tree)strptrmap_insert (spec_tbl, *name_p, read_expr);
+  if (expr)
+    return expr;
+  else
+    return read_expr;
+}
+
+
+/* Load merge keys for a spec_entry TABLE from STREAM.  */
 
 static void
-pph_in_spec_entry_htab (pph_stream *stream, htab_t *table)
+pph_in_keys_spec_entry_htab (pph_stream *stream, pph_merge_searcher searcher,
+			     strptrmap_t *spec_tbl)
 {
   unsigned count = pph_in_uint (stream);
   if (flag_pph_debug >= 2)
-    fprintf (pph_logfile, "PPH: loading %d spec_entries\n", count );
+    fprintf (pph_logfile, "PPH: loading keys for %d spec_entries\n", count );
+  for (; count > 0; --count)
+    {
+      pph_in_merge_key_tree_with_searcher (stream, (void*)spec_tbl, searcher);
+    }
+}
+
+
+/* Load merge bodies for a spec_entry TABLE from STREAM.  */
+
+static void
+pph_in_bodies_spec_entry_htab (pph_stream *stream, htab_t *table)
+{
+  unsigned count = pph_in_uint (stream);
+  if (flag_pph_debug >= 2)
+    fprintf (pph_logfile, "PPH: loading bodies %d spec_entries\n", count );
   for (; count > 0; --count)
     {
       hashval_t hash;
@@ -20804,30 +20851,69 @@  pph_in_spec_entry_htab (pph_stream *stre
 }
 
 
-/* Emit all spec_entry tables to STREAM. */
+/* Write merge keys for template state to STREAM. */
 
 void
-pph_out_spec_entry_tables (pph_stream *stream)
+pph_out_merge_key_template_state (pph_stream *stream ATTRIBUTE_UNUSED)
 {
-  pph_out_spec_entry_htab (stream, &decl_specializations);
-  if (flag_pph_dump_tree)
-    pph_dump_spec_entry_htab (pph_logfile, "decl", &decl_specializations);
-  pph_out_spec_entry_htab (stream, &type_specializations);
-  if (flag_pph_dump_tree)
-    pph_dump_spec_entry_htab (pph_logfile, "type", &type_specializations);
+  pph_out_spec_entry_htab (stream, &decl_specializations,
+			   pph_out_key_spec_entry_slot);
+  pph_out_spec_entry_htab (stream, &type_specializations,
+			   pph_out_key_spec_entry_slot);
 }
 
-/* Load and merge all spec_entry tables from STREAM.  */
+
+/* Write merge bodies for template state to STREAM. */
 
 void
-pph_in_spec_entry_tables (pph_stream *stream)
+pph_out_merge_body_template_state (pph_stream *stream)
 {
-  pph_in_spec_entry_htab (stream, &decl_specializations);
+  pph_out_spec_entry_htab (stream, &decl_specializations,
+			   pph_out_body_spec_entry_slot);
+  pph_out_spec_entry_htab (stream, &type_specializations,
+			   pph_out_body_spec_entry_slot);
+  pph_out_pending_templates_list (stream);
   if (flag_pph_dump_tree)
-    pph_dump_spec_entry_htab (pph_logfile, "decl", &decl_specializations);
-  pph_in_spec_entry_htab (stream, &type_specializations);
+    {
+      pph_dump_spec_entry_htab (pph_logfile, "decl", &decl_specializations);
+      pph_dump_spec_entry_htab (pph_logfile, "type", &type_specializations);
+      pph_dump_pending_templates_list (stderr);
+    }
+}
+
+
+/* Tables for merging decl and type specializations.  */
+
+static strptrmap_t *decl_spec_tbl = strptrmap_create ();
+static strptrmap_t *type_spec_tbl = strptrmap_create ();
+
+
+/* Read merge keys for template state from STREAM.  */
+
+void
+pph_in_merge_key_template_state (pph_stream *stream ATTRIBUTE_UNUSED)
+{
+  pph_in_keys_spec_entry_htab (stream, pph_in_search_key_spec,
+			       decl_spec_tbl);
+  pph_in_keys_spec_entry_htab (stream, pph_in_search_key_spec,
+			       type_spec_tbl);
+}
+
+
+/* Read merge keys for template state from STREAM.  */
+
+void
+pph_in_merge_body_template_state (pph_stream *stream)
+{
+  pph_in_bodies_spec_entry_htab (stream, &decl_specializations);
+  pph_in_bodies_spec_entry_htab (stream, &type_specializations);
+  pph_in_pending_templates_list (stream);
   if (flag_pph_dump_tree)
-    pph_dump_spec_entry_htab (pph_logfile, "type", &type_specializations);
+    {
+      pph_dump_spec_entry_htab (pph_logfile, "type", &type_specializations);
+      pph_dump_spec_entry_htab (pph_logfile, "decl", &decl_specializations);
+      pph_dump_pending_templates_list (stderr);
+    }
 }
 
 
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 184772)
+++ gcc/cp/mangle.c	(working copy)
@@ -2914,7 +2914,11 @@  write_template_arg_literal (const tree v
     switch (TREE_CODE (value))
       {
       case CONST_DECL:
-	write_integer_cst (DECL_INITIAL (value));
+	{
+	  tree initial = DECL_INITIAL (value);
+	  gcc_assert (TREE_CODE (initial) == INTEGER_CST);
+	  write_integer_cst (value);
+	}
 	break;
 
       case INTEGER_CST:
Index: gcc/cp/pph-in.c
===================================================================
--- gcc/cp/pph-in.c	(revision 184772)
+++ gcc/cp/pph-in.c	(working copy)
@@ -50,7 +50,8 @@  DEF_VEC_ALLOC_P(char_p,heap);
 
 
 /* Forward declarations to avoid circularity.  */
-static tree pph_in_merge_key_tree (pph_stream *, tree *);
+static tree pph_in_merge_key_decl_on_chain (pph_stream *, tree *);
+static tree pph_in_merge_key_type_in_var (pph_stream *, tree *);
 
 
 /***************************************************** stream initialization */
@@ -193,7 +194,7 @@  pph_in_bytes (pph_stream *stream, void *
 
 /* Read and return a string from STREAM.  */
 
-static const char *
+const char *
 pph_in_string (pph_stream *stream)
 {
   const char *s = streamer_read_string (stream->encoder.r.data_in,
@@ -859,7 +860,7 @@  pph_in_merge_key_chain (pph_stream *stre
 
   count = pph_in_hwi (stream);
   for (i = 0; i < count; i++)
-    pph_in_merge_key_tree (stream, chain);
+    pph_in_merge_key_decl_on_chain (stream, chain);
 }
 
 
@@ -884,7 +885,7 @@  pph_in_merge_body_chain (pph_stream *str
    address.
 
    This TOC is indexed by two values: the merge key read by
-   pph_in_merge_key_tree and the context in which we are doing this
+   pph_in_merge_key_decl_on_chain and the context in which we are doing this
    merge.  */
 static htab_t merge_toc = NULL;
 
@@ -2535,13 +2536,14 @@  pph_merge_tree_attributes (tree expr, tr
 }
 
 
-/* Read a merge key from STREAM.  If CHAIN is not NULL and the merge
-   key read from STREAM is not found in *CHAIN, the newly allocated
-   tree is added to it.  If no CHAIN is given, then the tree is just
-   allocated and added to the pickle cache.  */
+/* Read a merge key from STREAM,
+   using the SEARCHER to find a matching existing tree within HOLDER.
+   If the search succeeds, merge into the existing tree and use that.
+   In any event, the resulting tree is added to the pickle cache.  */
 
-static tree
-pph_in_merge_key_tree (pph_stream *stream, tree *chain)
+tree
+pph_in_merge_key_tree_with_searcher (pph_stream *stream, void *holder,
+				     pph_merge_searcher searcher)
 {
   enum pph_record_marker marker;
   unsigned image_ix, ix;
@@ -2560,28 +2562,14 @@  pph_in_merge_key_tree (pph_stream *strea
      language-independent bitfields for the new tree.  */
   read_expr = pph_in_tree_header (stream, &fully_read_p);
   gcc_assert (!fully_read_p);
-  gcc_assert (chain);
+  gcc_assert (holder);
 
-  if (DECL_P (read_expr))
-    {
-      name = pph_in_string (stream);
-      /* If we are merging into an existing CHAIN.  Look for a match in
-         CHAIN to READ_EXPR's header.  If we found a match, EXPR will be
-         the existing tree that matches READ_EXPR. Otherwise, EXPR is the
-         newly allocated READ_EXPR.  */
-      expr = pph_merge_into_chain (read_expr, name, chain);
-      if (expr != read_expr)
-	pph_merge_tree_attributes (expr, read_expr);
-    }
-  else
-    {
-      gcc_assert (TYPE_P (read_expr));
-      if (*chain)
-	expr = *chain;
-      else
-	expr = read_expr;
-    }
+  expr = searcher (stream, read_expr, &name, holder);
   gcc_assert (expr != NULL);
+
+  if (expr != read_expr)
+    pph_merge_tree_attributes (expr, read_expr);
+
   pph_cache_insert_at (&stream->cache, expr, ix,
 		       pph_tree_code_to_tag (expr));
 
@@ -2596,7 +2584,7 @@  pph_in_merge_key_tree (pph_stream *strea
 	{
 	  bool is_implicit = pph_in_bool (stream);
 	  if (is_implicit)
-	    pph_in_merge_key_tree (stream, &(TREE_TYPE (expr)));
+	    pph_in_merge_key_type_in_var (stream, &(TREE_TYPE (expr)));
 	}
     }
   else
@@ -2612,6 +2600,60 @@  pph_in_merge_key_tree (pph_stream *strea
 }
 
 
+/* Search in HOLDER for an existing decl that matches READ_EXPR.
+   Read the match string from STREAM and assign to *NAME_P.  */
+
+static tree
+pph_in_search_key_decl_on_chain (pph_stream *stream, tree read_expr,
+				const char **name_p, void *holder)
+{
+  gcc_assert (DECL_P (read_expr));
+  *name_p = pph_in_string (stream);
+  /* If we are merging into an existing CHAIN.  Look for a match in
+     CHAIN to READ_EXPR's header.  If we found a match, EXPR will be
+     the existing tree that matches READ_EXPR. Otherwise, EXPR is the
+     newly allocated READ_EXPR.  */
+  return pph_merge_into_chain (read_expr, *name_p, (tree*)holder);
+}
+
+
+/* Read a decl merge key from STREAM and search for matches on the CHAIN.  */
+
+static tree
+pph_in_merge_key_decl_on_chain (pph_stream *stream, tree *chain)
+{
+  return pph_in_merge_key_tree_with_searcher (stream, (void*) chain,
+					      pph_in_search_key_decl_on_chain);
+}
+
+
+/* Search in HOLDER for an existing type that matches READ_EXPR.
+   The HOLDER is its decl's type field.  */
+
+static tree
+pph_in_search_key_type_in_field (pph_stream *stream ATTRIBUTE_UNUSED,
+	tree read_expr, const char **name_p ATTRIBUTE_UNUSED, void *holder)
+{
+  tree *field = (tree*)holder;
+  gcc_assert (TYPE_P (read_expr));
+  if (*field)
+    return *field;
+  else
+    return read_expr;
+}
+
+
+/* Read a type merge key from STREAM and search for matches in its decl's
+   type field.  */
+
+static tree
+pph_in_merge_key_type_in_var (pph_stream *stream, tree *field)
+{
+  return pph_in_merge_key_tree_with_searcher (stream, (void*) field,
+					      pph_in_search_key_type_in_field);
+}
+
+
 /* Read and return a tree from STREAM.  */
 
 tree
@@ -3017,12 +3059,12 @@  pph_in_identifiers (pph_stream *stream, 
 }
 
 
-/* Read global bindings from STREAM and merge them into
+/* Read keys global bindings from STREAM and merge them into
    scope_chain->bindings.  Bindings are merged at every level starting
    at the global bindings from STREAM.  */
 
 static void
-pph_in_global_binding (pph_stream *stream)
+pph_in_global_binding_keys (pph_stream *stream)
 {
   cp_binding_level *bl, *other_bl;
   bool existed_p;
@@ -3041,6 +3083,17 @@  pph_in_global_binding (pph_stream *strea
      same slot IX that the writer used, the trees read now will be
      bound to scope_chain->bindings.  */
   pph_in_merge_key_binding_level (stream, &bl);
+}
+
+
+/* Read global bindings from STREAM and merge them into
+   scope_chain->bindings.  Bindings are merged at every level starting
+   at the global bindings from STREAM.  */
+
+static void
+pph_in_global_binding_bodies (pph_stream *stream)
+{
+  cp_binding_level *bl = scope_chain->bindings;
 
   /* Once all the symbols and types at every binding level have been
      merged to the corresponding binding levels in the current
@@ -3119,20 +3172,18 @@  pph_read_file_1 (pph_stream *stream)
      working towards an identical line_table in pph and non-pph.  */
   cpp_lt_replay (parse_in, &idents_used, &cpp_token_replay_loc);
 
-  /* Read the bindings from STREAM.  */
-  pph_in_global_binding (stream);
+  /* Read the namespace scope bindings and template state from STREAM.  */
+  pph_in_global_binding_keys (stream);
+  pph_in_merge_key_template_state (stream);
+  pph_in_global_binding_bodies (stream);
+  pph_in_merge_body_template_state (stream);
 
   /* Read and merge the other global state collected during parsing of
      the original header.  */
   pph_union_into_chain (&keyed_classes, pph_in_tree (stream));
   pph_union_into_tree_vec (&unemitted_tinfo_decls, pph_in_tree_vec (stream));
-
-  pph_in_pending_templates_list (stream);
-  pph_in_spec_entry_tables (stream);
-
   file_static_aggregates = pph_in_tree (stream);
   static_aggregates = chainon (file_static_aggregates, static_aggregates);
-
   pph_in_decl2_hidden_state (stream);
 
   /* Read and process the symbol table.  */
Index: gcc/strptrmap.c
===================================================================
--- gcc/strptrmap.c	(revision 0)
+++ gcc/strptrmap.c	(revision 0)
@@ -0,0 +1,175 @@ 
+/* A string to string mapping.
+
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Lawrence Crowl <crowl@google.com>.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "libiberty.h"
+#include "hashtab.h"
+
+#include "strptrmap.h"
+
+/* The hash table slot type.  */
+
+typedef struct strptrhashslot_d
+{
+  const char *key;
+  void *val;
+} strptrhashslot_t;
+
+/* Returns a hash code for the slot v.
+   Function type is typedef hashval_t (*htab_hash) (const void *);  */
+
+static hashval_t
+strptrhashslot_hash (const void *v)
+{
+  const strptrhashslot_t *s = (const strptrhashslot_t *) v;
+  return htab_hash_string (s->key);
+}
+
+/* Compares two slots, V1 and V2, for equality.
+   Function type is typedef int (*htab_eq) (const void *, const void *);  */
+
+static int
+strptrhashslot_eq (const void *v1, const void *v2)
+{
+  const strptrhashslot_t *s1 = (const strptrhashslot_t *) v1;
+  const strptrhashslot_t *s2 = (const strptrhashslot_t *) v2;
+  return strcmp (s1->key, s2->key) == 0;
+}
+
+/* Free the slot V.  */
+
+static void
+strptrhashslot_free (void *v)
+{
+  strptrhashslot_t *s = (strptrhashslot_t *) v;
+  free (CONST_CAST (void *, (const void *) s->key));
+  free (v);
+}
+
+/* The type for the hash table itself.  */
+
+struct strptrmap_d
+{
+  htab_t tab;
+};
+
+/* Create a hash table.  */
+
+strptrmap_t*
+strptrmap_create (void)
+{
+  strptrmap_t *tbl;
+  htab_t tab;
+  tbl = XCNEW (strptrmap_t);
+  gcc_assert (tbl != NULL);
+  tab = htab_create (37, strptrhashslot_hash,
+                     strptrhashslot_eq, strptrhashslot_free);
+  gcc_assert (tab != NULL);
+  tbl->tab = tab;
+  return tbl;
+}
+
+/* Destroy the hash table TBL.  */
+
+void
+strptrmap_destroy (strptrmap_t *tbl)
+{
+  htab_delete (tbl->tab);
+  free (tbl);
+}
+
+/* Insert a mapping from KEY to VAL into hash table TBL.
+   All parameters must not be NULL.
+   If the KEY is new, the insert returns NULL.
+   If the KEY is not new, the insert returns the old VAL,
+   which has NOT been replaced.  */
+
+void *
+strptrmap_insert (strptrmap_t *tbl, const char *key, void *val)
+{
+  strptrhashslot_t query;
+  strptrhashslot_t **spot;
+  void* result;
+
+  gcc_assert (tbl != NULL);
+  gcc_assert (key != NULL);
+
+  query.key = key;
+  query.val = val;
+  spot = (strptrhashslot_t **) htab_find_slot (tbl->tab, &query, INSERT);
+
+  if (*spot == NULL)
+    {
+      /* We found no instance of key in the table.  */
+      strptrhashslot_t *entry
+          = (strptrhashslot_t *) xmalloc (sizeof (strptrhashslot_t));
+      entry->key = xstrdup (key);
+      entry->val = val;
+      *spot = entry;
+      result = NULL;
+    }
+  else
+    {
+      /* We found an instance of key already in the table.  */
+      strptrhashslot_t *entry = (strptrhashslot_t *)*spot;
+      result = entry->val;
+    }
+
+  return result;
+}
+
+/* Lookup a mapping for KEY in hash table TBL.
+   All parameters must not be NULL.
+   If the KEY is new, the insert returns NULL.
+   If the KEY is not new, the insert returns the old VAL,
+   which has been replaced.  */
+
+void*
+strptrmap_lookup (strptrmap_t* tbl, const char* key)
+{
+  strptrhashslot_t query;
+  strptrhashslot_t **spot;
+  void* result;
+
+  gcc_assert (tbl != NULL);
+  gcc_assert (key != NULL);
+
+  query.key = key;
+  spot = (strptrhashslot_t **) htab_find_slot (tbl->tab, &query, NO_INSERT);
+
+  if (spot == NULL)
+    {
+      /* We found no instance of key in the table.  */
+      result = NULL;
+    }
+  else
+    {
+      /* We found an instance of key in the table.  */
+      strptrhashslot_t *entry = (strptrhashslot_t *)*spot;
+      gcc_assert (entry != NULL);
+      result = entry->val;
+    }
+
+  return result;
+}
Index: gcc/strptrmap.h
===================================================================
--- gcc/strptrmap.h	(revision 0)
+++ gcc/strptrmap.h	(revision 0)
@@ -0,0 +1,27 @@ 
+/* A string to string mapping. 
+
+   Copyright (C) 2012 Free Software Foundation, Inc.
+   Contributed by Lawrence Crowl <crowl@google.com>.
+   
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+typedef struct strptrmap_d strptrmap_t;
+
+extern strptrmap_t* strptrmap_create (void);
+extern void strptrmap_destroy (strptrmap_t *tbl);
+extern void* strptrmap_insert (strptrmap_t *tbl, const char *key, void *val);
+extern void* strptrmap_lookup (strptrmap_t *tbl, const char *key);
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 184772)
+++ gcc/Makefile.in	(working copy)
@@ -1350,6 +1350,7 @@  OBJS = \
 	store-motion.o \
 	streamer-hooks.o \
 	stringpool.o \
+	strptrmap.o \
 	strstrmap.o \
 	target-globals.o \
 	targhooks.o \
@@ -2748,6 +2749,10 @@  s-bversion: BASE-VER
 	echo "#define BUILDING_GCC_VERSION (BUILDING_GCC_MAJOR * 1000 + BUILDING_GCC_MINOR)" >> bversion.h
 	$(STAMP) s-bversion
 
+strptrmap.o: strptrmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   $(srcdir)/../include/libiberty.h $(srcdir)/../include/hashtab.h \
+   strptrmap.h
+
 strstrmap.o: strstrmap.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(srcdir)/../include/libiberty.h $(srcdir)/../include/hashtab.h \
    strstrmap.h