diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 7f21322..70548c6 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -336,4 +336,4 @@ cp/pph.o: cp/pph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(CPPLIB_H) \
 	$(CXX_PARSER_H) $(CXX_PPH_H) $(CXX_PPH_STREAMER_H)
 cp/pph-streamer.o: cp/pph-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TREE_H) tree-pretty-print.h $(LTO_STREAMER_H) $(CXX_PPH_STREAMER_H) \
-	$(CXX_PPH_H) $(TREE_PASS_H) version.h cppbuiltin.h
+	$(CXX_PPH_H) $(TREE_PASS_H) version.h cppbuiltin.h tree-iterator.h
diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c
index af9602c..d2790fc 100644
--- a/gcc/cp/pph-streamer.c
+++ b/gcc/cp/pph-streamer.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tree.h"
 #include "langhooks.h"
+#include "tree-iterator.h"
 #include "tree-pretty-print.h"
 #include "lto-streamer.h"
 #include "pph-streamer.h"
@@ -146,6 +147,21 @@ pph_stream_write_tree (struct output_block *ob, tree expr, bool ref_p)
 {
   if (TREE_CODE (expr) == FUNCTION_DECL)
     lto_output_tree_or_ref (ob, DECL_SAVED_TREE (expr), ref_p);
+  else if (TREE_CODE (expr) == STATEMENT_LIST)
+    {
+      tree_stmt_iterator i;
+      unsigned num_stmts;
+
+      /* Compute and write the number of statements in the list.  */
+      for (num_stmts = 0, i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i))
+	num_stmts++;
+
+      lto_output_sleb128_stream (ob->main_stream, num_stmts);
+
+      /* Write the statements.  */
+      for (i = tsi_start (expr); !tsi_end_p (i); tsi_next (&i))
+	lto_output_tree_or_ref (ob, tsi_stmt (i), ref_p);
+    }
 }
 
 
@@ -160,17 +176,64 @@ pph_stream_read_tree (struct lto_input_block *ib, struct data_in *data_in,
 {
   if (TREE_CODE (expr) == FUNCTION_DECL)
     DECL_SAVED_TREE (expr) = lto_input_tree (ib, data_in);
+  else if (TREE_CODE (expr) == STATEMENT_LIST)
+    {
+      HOST_WIDE_INT i, num_trees = lto_input_sleb128 (ib);
+      for (i = 0; i < num_trees; i++)
+	{
+	  tree stmt = lto_input_tree (ib, data_in);
+	  append_to_statement_list (stmt, &expr);
+	}
+    }
+}
+
+
+/* Return true if the given tree T is streamable.  */
+
+static bool
+pph_is_streamable (tree t ATTRIBUTE_UNUSED)
+{
+  /* We accept most trees.  */
+  return TREE_CODE (t) != SSA_NAME
+	 && (TREE_CODE (t) < OMP_PARALLEL
+	     || TREE_CODE (t) > OMP_CRITICAL);
+}
+
+
+/* Callback for packing value fields in ASTs.  BP is the bitpack 
+   we are packing into.  EXPR is the tree to pack.  */
+
+static void
+pph_stream_pack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED,
+			      tree expr ATTRIBUTE_UNUSED)
+{
+  /* Do nothing for now.  */
+}
+
+
+/* Callback for unpacking value fields in ASTs.  BP is the bitpack 
+   we are unpacking from.  EXPR is the tree to unpack.  */
+
+static void
+pph_stream_unpack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED,
+				tree expr ATTRIBUTE_UNUSED)
+{
+  /* Do nothing for now.  */
 }
 
 
 /* Initialize all the streamer hooks used for streaming ASTs.  */
 
 static void
-pph_streamer_hooks_init (void)
+pph_stream_hooks_init (void)
 {
   lto_streamer_hooks *h = streamer_hooks_init ();
+  h->name = "C++ AST";
+  h->is_streamable = pph_is_streamable;
   h->write_tree = pph_stream_write_tree;
   h->read_tree = pph_stream_read_tree;
+  h->pack_value_fields = pph_stream_pack_value_fields;
+  h->unpack_value_fields = pph_stream_unpack_value_fields;
 }
 
 
@@ -187,7 +250,7 @@ pph_stream_open (const char *name, const char *mode)
   f = fopen (name, mode);
   if (f)
     {
-      pph_streamer_hooks_init ();
+      pph_stream_hooks_init ();
       stream = XCNEW (pph_stream);
       stream->file = f;
       stream->name = xstrdup (name);
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 9574d77..2347ffa 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1790,26 +1790,11 @@ unpack_value_fields (struct bitpack_d *bp, tree expr)
   if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
     unpack_ts_block_value_fields (bp, expr);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME))
-    {
-      /* We only stream the version number of SSA names.  */
-      gcc_unreachable ();
-    }
-
-  if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST))
-    {
-      /* This is only used by GENERIC.  */
-      gcc_unreachable ();
-    }
-
-  if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE))
-    {
-      /* This is only used by High GIMPLE.  */
-      gcc_unreachable ();
-    }
-
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     unpack_ts_translation_unit_decl_value_fields (bp, expr);
+
+  if (streamer_hooks ()->unpack_value_fields)
+    streamer_hooks ()->unpack_value_fields (bp, expr);
 }
 
 
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index e8390ed..f41cf0c 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -574,26 +574,11 @@ pack_value_fields (struct bitpack_d *bp, tree expr)
   if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
     pack_ts_block_value_fields (bp, expr);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME))
-    {
-      /* We only stream the version number of SSA names.  */
-      gcc_unreachable ();
-    }
-
-  if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST))
-    {
-      /* This is only used by GENERIC.  */
-      gcc_unreachable ();
-    }
-
-  if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE))
-    {
-      /* This is only used by High GIMPLE.  */
-      gcc_unreachable ();
-    }
-
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     pack_ts_translation_unit_decl_value_fields (bp, expr);
+
+  if (streamer_hooks ()->pack_value_fields)
+    streamer_hooks ()->pack_value_fields (bp, expr);
 }
 
 
@@ -1229,12 +1214,14 @@ lto_output_tree_header (struct output_block *ob, tree expr, int ix)
 {
   enum LTO_tags tag;
   enum tree_code code;
+  lto_streamer_hooks *h = streamer_hooks ();
+
 
   /* We should not see any non-GIMPLE tree nodes here.  */
   code = TREE_CODE (expr);
-  if (!lto_is_streamable (expr))
-    internal_error ("tree code %qs is not supported in gimple streams",
-		    tree_code_name[code]);
+  if (h->is_streamable && !h->is_streamable (expr))
+    internal_error ("tree code %qs is not supported in %s streams",
+		    h->name, tree_code_name[code]);
 
   /* The header of a tree node consists of its tag, the size of
      the node, and any other information needed to instantiate
diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
index f9b5285..7b51763 100644
--- a/gcc/lto-streamer.c
+++ b/gcc/lto-streamer.c
@@ -804,14 +804,41 @@ lto_check_version (int major, int minor)
 }
 
 
+/* Return true if EXPR is a tree node that can be written to disk.  */
+
+static inline bool
+lto_is_streamable (tree expr)
+{
+  enum tree_code code = TREE_CODE (expr);
+
+  /* Notice that we reject SSA_NAMEs as well.  We only emit the SSA
+     name version in lto_output_tree_ref (see output_ssa_names).  */
+  return !is_lang_specific (expr)
+	 && code != SSA_NAME
+	 && code != CALL_EXPR
+	 && code != LANG_TYPE
+	 && code != MODIFY_EXPR
+	 && code != INIT_EXPR
+	 && code != TARGET_EXPR
+	 && code != BIND_EXPR
+	 && code != WITH_CLEANUP_EXPR
+	 && code != STATEMENT_LIST
+	 && (code == CASE_LABEL_EXPR
+	     || code == DECL_EXPR
+	     || TREE_CODE_CLASS (code) != tcc_statement);
+}
+
+
 /* Initialize all the streamer hooks used for streaming GIMPLE.  */
 
 void
 gimple_streamer_hooks_init (void)
 {
   lto_streamer_hooks *h = streamer_hooks_init ();
+  h->name = "gimple";
   h->reader_init = gimple_streamer_reader_init;
   h->writer_init = NULL;
+  h->is_streamable = lto_is_streamable;
   h->write_tree = gimple_streamer_write_tree;
   h->read_tree = gimple_streamer_read_tree;
 }
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index b58bb62..1502b0c 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 struct output_block;
 struct lto_input_block;
 struct data_in;
+struct bitpack_d;
 
 /* Define when debugging the LTO streamer.  This causes the writer
    to output the numeric value for the memory address of the tree node
@@ -51,12 +52,18 @@ struct data_in;
    replace the default behavior and those that supplement it.  Any
    or all of these hooks can be NULL.  */
 typedef struct lto_streamer_hooks {
+  /* A string identifying this streamer.  */
+  const char *name;
+
   /* Called by lto_reader_init after it does basic initialization.  */
   void (*reader_init) (void);
 
   /* Called by lto_writer_init after it does basic initalization.  */
   void (*writer_init) (void);
 
+  /* Return true if the given tree is supported by this streamer.  */
+  bool (*is_streamable) (tree);
+
   /* Called by lto_write_tree after writing all the common parts of
      a tree.  If defined, the callback is in charge of writing all
      the fields that lto_write_tree did not write out.  Arguments
@@ -78,6 +85,14 @@ typedef struct lto_streamer_hooks {
      the fields that lto_read_tree did not read in.  Arguments
      are as in lto_read_tree.  */
   void (*read_tree) (struct lto_input_block *, struct data_in *, tree);
+
+  /* Called by pack_value_fields to store any non-pointer fields
+     in the tree structure.  The arguments are as in pack_value_fields.  */
+  void (*pack_value_fields) (struct bitpack_d *, tree);
+
+  /* Called by unpack_value_fields to retrieve any non-pointer fields
+     in the tree structure.  The arguments are as in unpack_value_fields.  */
+  void (*unpack_value_fields) (struct bitpack_d *, tree);
 } lto_streamer_hooks;
 
 
@@ -1113,29 +1128,6 @@ lto_stream_as_builtin_p (tree expr)
 	      || DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD));
 }
 
-/* Return true if EXPR is a tree node that can be written to disk.  */
-static inline bool
-lto_is_streamable (tree expr)
-{
-  enum tree_code code = TREE_CODE (expr);
-
-  /* Notice that we reject SSA_NAMEs as well.  We only emit the SSA
-     name version in lto_output_tree_ref (see output_ssa_names).  */
-  return !is_lang_specific (expr)
-	 && code != SSA_NAME
-	 && code != CALL_EXPR
-	 && code != LANG_TYPE
-	 && code != MODIFY_EXPR
-	 && code != INIT_EXPR
-	 && code != TARGET_EXPR
-	 && code != BIND_EXPR
-	 && code != WITH_CLEANUP_EXPR
-	 && code != STATEMENT_LIST
-	 && (code == CASE_LABEL_EXPR
-	     || code == DECL_EXPR
-	     || TREE_CODE_CLASS (code) != tcc_statement);
-}
-
 DEFINE_DECL_STREAM_FUNCS (TYPE, type)
 DEFINE_DECL_STREAM_FUNCS (FIELD_DECL, field_decl)
 DEFINE_DECL_STREAM_FUNCS (FN_DECL, fn_decl)
