diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1184df74999f8671c45974d18d1bcdb173dc96a1..7f5e57d0efda91ba01806bb27a0887b4a23298f8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2004-06-09  Geoffrey Keating  <geoffk@apple.com>
+
+	* Makefile.in (CPPLIB_H): Put files in order of inclusion.
+	(CPP_ID_DATA_H): New.
+	(gtype-desc.o): Update dependencies.
+	(GTFILES): Use CPP_ID_DATA_H.
+
 2004-06-09  Mark Mitchell  <mark@codesourcery.com>
 
 	Revert:
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 2fa566aeea1cd8a5450867c90157ae66405ace2f..fc87854332344e51557d230915a8436d1c9fa65a 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -712,10 +712,11 @@ C_COMMON_H = c-common.h $(SPLAY_TREE_H) $(CPPLIB_H)
 C_TREE_H = c-tree.h $(C_COMMON_H)
 SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h
 PREDICT_H = predict.h predict.def
-CPPLIB_H = $(srcdir)/../libcpp/include/cpplib.h \
-	$(srcdir)/../libcpp/include/line-map.h
+CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \
+	$(srcdir)/../libcpp/include/cpplib.h
 MKDEPS_H = $(srcdir)/../libcpp/include/mkdeps.h
 SYMTAB_H = $(srcdir)/../libcpp/include/symtab.h
+CPP_ID_DATA_H = $(CPPLIB_H) $(srcdir)/../libcpp/include/cpp-id-data.h
 TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H)
 TREE_GIMPLE_H = tree-gimple.h tree-iterator.h
 TREE_FLOW_H = tree-flow.h tree-flow-inline.h tree-ssa-operands.h \
@@ -1522,10 +1523,11 @@ dumpvers: dumpvers.c
 
 version.o: version.c version.h
 
-gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) varray.h \
-	$(HASHTAB_H) $(TREE_H) $(RTL_H) function.h insn-config.h $(EXPR_H) $(OPTABS_H) \
-	libfuncs.h debug.h $(GGC_H) bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h \
-	cselib.h insn-addr.h $(TREE_FLOW_H)
+gtype-desc.o: gtype-desc.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+	varray.h $(HASHTAB_H) $(SPLAY_TREE_H) bitmap.h $(TREE_H) $(RTL_H) \
+	function.h insn-config.h $(EXPR_H) hard-reg-set.h $(BASIC_BLOCK_H) \
+	cselib.h insn-addr.h $(OPTABS_H) libfuncs.h debug.h $(GGC_H) \
+	cgraph.h tree-alias-type.h $(TREE_FLOW_H) reload.h $(CPP_ID_DATA_H)
 
 ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \
 	$(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h
@@ -2289,7 +2291,7 @@ s-preds: genpreds$(build_exeext)
 	$(STAMP) s-preds
 
 GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
-  $(srcdir)/../libcpp/include/cpplib.h $(host_xm_file_list) \
+  $(CPP_ID_DATA_H) $(host_xm_file_list) \
   $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \
   $(srcdir)/coverage.c $(srcdir)/function.h $(srcdir)/rtl.h \
   $(srcdir)/optabs.h $(srcdir)/tree.h $(srcdir)/libfuncs.h $(SYMTAB_H) \
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 804ef70320a1900f176cdd89e025113b1c3348b3..5d7082437b02ffb4ee5d9bafa094413a32cd3485 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -875,7 +875,7 @@ note_yacc_type (options_p o, pair_p fields, pair_p typeinfo,
 }
 
 static void process_gc_options (options_p, enum gc_used_enum,
-				int *, int *, int *);
+				int *, int *, int *, type_p *);
 static void set_gc_used_type (type_p, enum gc_used_enum, type_p *);
 static void set_gc_used (pair_p);
 
@@ -883,7 +883,7 @@ static void set_gc_used (pair_p);
 
 static void
 process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
-		    int *pass_param, int *length)
+		    int *pass_param, int *length, type_p *nested_ptr)
 {
   options_p o;
   for (o = opt; o; o = o->next)
@@ -895,6 +895,8 @@ process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
       *pass_param = 1;
     else if (strcmp (o->name, "length") == 0)
       *length = 1;
+    else if (strcmp (o->name, "nested_ptr") == 0)
+      *nested_ptr = ((const struct nested_ptr_data *) o->info)->type;
 }
 
 /* Set the gc_used field of T to LEVEL, and handle the types it references.  */
@@ -914,18 +916,24 @@ set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
       {
 	pair_p f;
 	int dummy;
+	type_p dummy2;
 
-	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy);
+	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
+			    &dummy2);
 
 	for (f = t->u.s.fields; f; f = f->next)
 	  {
 	    int maybe_undef = 0;
 	    int pass_param = 0;
 	    int length = 0;
+	    type_p nested_ptr = NULL;
 	    process_gc_options (f->opt, level, &maybe_undef, &pass_param,
-				&length);
+				&length, &nested_ptr);
 
-	    if (length && f->type->kind == TYPE_POINTER)
+	    if (nested_ptr && f->type->kind == TYPE_POINTER)
+	      set_gc_used_type (nested_ptr, GC_POINTED_TO, 
+				pass_param ? param : NULL);
+	    else if (length && f->type->kind == TYPE_POINTER)
 	      set_gc_used_type (f->type->u.p, GC_USED, NULL);
 	    else if (maybe_undef && f->type->kind == TYPE_POINTER)
 	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO, NULL);
@@ -1015,7 +1023,7 @@ static outf_p
 create_file (const char *name, const char *oname)
 {
   static const char *const hdr[] = {
-    "   Copyright (C) 2003 Free Software Foundation, Inc.\n",
+    "   Copyright (C) 2004 Free Software Foundation, Inc.\n",
     "\n",
     "This file is part of GCC.\n",
     "\n",
@@ -1101,6 +1109,7 @@ open_base_files (void)
       "basic-block.h", "cselib.h", "insn-addr.h", "optabs.h",
       "libfuncs.h", "debug.h", "ggc.h", "cgraph.h",
       "tree-alias-type.h", "tree-flow.h", "reload.h",
+      "cpp-id-data.h",
       NULL
     };
     const char *const *ifp;
@@ -1408,7 +1417,8 @@ struct walk_type_data
   int used_length;
   type_p orig_s;
   const char *reorder_fn;
-  int needs_cast_p;
+  bool needs_cast_p;
+  bool fn_wants_lvalue;
 };
 
 /* Print a mangled name representing T to OF.  */
@@ -1511,7 +1521,7 @@ walk_type (type_p t, struct walk_type_data *d)
   options_p oo;
   const struct nested_ptr_data *nested_ptr_d = NULL;
 
-  d->needs_cast_p = 0;
+  d->needs_cast_p = false;
   for (oo = d->opt; oo; oo = oo->next)
     if (strcmp (oo->name, "length") == 0)
       length = (const char *)oo->info;
@@ -1525,7 +1535,7 @@ walk_type (type_p t, struct walk_type_data *d)
     else if (strcmp (oo->name, "desc") == 0)
       desc = (const char *)oo->info;
     else if (strcmp (oo->name, "nested_ptr") == 0)
-      nested_ptr_d = (const struct nested_ptr_data *)oo->info ;
+      nested_ptr_d = (const struct nested_ptr_data *) oo->info;
     else if (strcmp (oo->name, "dot") == 0)
       ;
     else if (strcmp (oo->name, "tag") == 0)
@@ -1643,10 +1653,12 @@ walk_type (type_p t, struct walk_type_data *d)
 		oprintf (d->of, "%*s{\n", d->indent, "");
 		d->indent += 2;
 		d->val = xasprintf ("x%d", d->counter++);
-		oprintf (d->of, "%*s%s %s * %s =\n", d->indent, "",
+		oprintf (d->of, "%*s%s %s * %s%s =\n", d->indent, "",
 			 (nested_ptr_d->type->kind == TYPE_UNION 
 			  ? "union" : "struct"), 
-			 nested_ptr_d->type->u.s.tag, d->val);
+			 nested_ptr_d->type->u.s.tag, 
+			 d->fn_wants_lvalue ? "" : "const ",
+			 d->val);
 		oprintf (d->of, "%*s", d->indent + 2, "");
 		output_escaped_param (d, nested_ptr_d->convert_from,
 				      "nested_ptr");
@@ -1654,12 +1666,15 @@ walk_type (type_p t, struct walk_type_data *d)
 
 		d->process_field (nested_ptr_d->type, d);
 
-		oprintf (d->of, "%*s%s = ", d->indent, "",
-			 d->prev_val[2]);
-		d->prev_val[2] = d->val;
-		output_escaped_param (d, nested_ptr_d->convert_to,
-				      "nested_ptr");
-		oprintf (d->of, ";\n");
+		if (d->fn_wants_lvalue)
+		  {
+		    oprintf (d->of, "%*s%s = ", d->indent, "",
+			     d->prev_val[2]);
+		    d->prev_val[2] = d->val;
+		    output_escaped_param (d, nested_ptr_d->convert_to,
+					  "nested_ptr");
+		    oprintf (d->of, ";\n");
+		  }
 
 		d->indent -= 2;
 		oprintf (d->of, "%*s}\n", d->indent, "");
@@ -1839,6 +1854,7 @@ walk_type (type_p t, struct walk_type_data *d)
 	    d->line = &f->line;
 	    d->val = newval = xasprintf ("%s%s%s", oldval, dot, f->name);
 	    d->opt = f->opt;
+	    d->used_length = false;
 
 	    if (union_p && use_param_p && d->param == NULL)
 	      oprintf (d->of, "%*sabort();\n", d->indent, "");
@@ -2231,7 +2247,7 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d)
 /* For S, a structure that's part of ORIG_S, and using parameters
    PARAM, write out a routine that:
    - Is of type gt_note_pointers
-   - If calls PROCESS_FIELD on each field of S or its substructures.
+   - Calls PROCESS_FIELD on each field of S or its substructures.
 */
 
 static void
@@ -2259,6 +2275,7 @@ write_local_func_for_structure (type_p orig_s, type_p s, type_p *param)
   d.prev_val[1] = "not valid postage";  /* Guarantee an error.  */
   d.prev_val[3] = "x";
   d.val = "(*x)";
+  d.fn_wants_lvalue = true;
 
   oprintf (d.of, "\n");
   oprintf (d.of, "void\n");
diff --git a/gcc/stringpool.c b/gcc/stringpool.c
index d17f31decdde9da68c8505ec76f16e8311312b43..0227688f6e176b723c0f863ee6db3f3e55af14ff 100644
--- a/gcc/stringpool.c
+++ b/gcc/stringpool.c
@@ -51,7 +51,12 @@ static struct obstack string_stack;
 
 static hashnode alloc_node (hash_table *);
 static int mark_ident (struct cpp_reader *, hashnode, const void *);
-static int ht_copy_and_clear (struct cpp_reader *, hashnode, const void *);
+
+static void *
+stringpool_ggc_alloc (size_t x)
+{
+  return ggc_alloc (x);
+}
 
 /* Initialize the string pool.  */
 void
@@ -60,6 +65,7 @@ init_stringpool (void)
   /* Create with 16K (2^14) entries.  */
   ident_hash = ht_create (14);
   ident_hash->alloc_node = alloc_node;
+  ident_hash->alloc_subobject = stringpool_ggc_alloc;
   gcc_obstack_init (&string_stack);
 }
 
@@ -212,39 +218,7 @@ struct string_pool_data GTY(())
 
 static GTY(()) struct string_pool_data * spd;
 
-/* Copy HP into the corresponding entry in HT2, and then clear
-   the cpplib parts of HP.  */
-
-static int
-ht_copy_and_clear (cpp_reader *r ATTRIBUTE_UNUSED, hashnode hp, const void *ht2_p)
-{
-  cpp_hashnode *h = CPP_HASHNODE (hp);
-  struct ht *ht2 = (struct ht *) ht2_p;
-
-  if (h->type != NT_VOID
-      && (h->flags & NODE_BUILTIN) == 0)
-    {
-      cpp_hashnode *h2 = CPP_HASHNODE (ht_lookup (ht2,
-						  NODE_NAME (h),
-						  NODE_LEN (h),
-						  HT_ALLOC));
-      h2->type = h->type;
-      memcpy (&h2->value, &h->value, sizeof (h->value));
-
-      h->type = NT_VOID;
-      memset (&h->value, 0, sizeof (h->value));
-    }
-  return 1;
-}
-
-/* The hash table as it was before gt_pch_save_stringpool was called.  */
-
-static struct ht *saved_ident_hash;
-
-/* Prepare the stringpool to be written (by clearing all the cpp parts
-   of each entry) and place the data to be saved in SPD.  Save the
-   current state in SAVED_IDENT_HASH so that gt_pch_fixup_stringpool
-   can restore it.  */
+/* Save the stringpool data in SPD.  */
 
 void
 gt_pch_save_stringpool (void)
@@ -255,10 +229,6 @@ gt_pch_save_stringpool (void)
   spd->entries = ggc_alloc (sizeof (spd->entries[0]) * spd->nslots);
   memcpy (spd->entries, ident_hash->entries,
 	  spd->nslots * sizeof (spd->entries[0]));
-
-  saved_ident_hash = ht_create (14);
-  saved_ident_hash->alloc_node = alloc_node;
-  ht_forall (ident_hash, ht_copy_and_clear, saved_ident_hash);
 }
 
 /* Return the stringpool to its state before gt_pch_save_stringpool
@@ -267,9 +237,6 @@ gt_pch_save_stringpool (void)
 void
 gt_pch_fixup_stringpool (void)
 {
-  ht_forall (saved_ident_hash, ht_copy_and_clear, ident_hash);
-  ht_destroy (saved_ident_hash);
-  saved_ident_hash = 0;
 }
 
 /* A PCH file has been restored, which loaded SPD; fill the real hash table
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 332e3f0628b1c6008f017c2fb51a237a3309d465..c9565dd8949c8704ae1f3a20ed807915c5055996 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2004-06-09  Geoffrey Keating  <geoffk@apple.com>
+
+	* gcc.dg/pch/macro-4.c: New.
+	* gcc.dg/pch/macro-4.hs: New.
+
 2004-06-09  Tobias Schlueter  <tobias.schlueter@physik.uni-muenchen.de>
 
 	PR fortran/13249
diff --git a/gcc/testsuite/gcc.dg/pch/macro-4.c b/gcc/testsuite/gcc.dg/pch/macro-4.c
new file mode 100644
index 0000000000000000000000000000000000000000..1c199fa6eb04a438d688d17b783fd4dd4f95e140
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pch/macro-4.c
@@ -0,0 +1,8 @@
+#define DEFN aa + bb
+
+#include "macro-4.h"
+
+int foo(int aa, int bb)
+{
+  return DEFN;
+}
diff --git a/gcc/testsuite/gcc.dg/pch/macro-4.hs b/gcc/testsuite/gcc.dg/pch/macro-4.hs
new file mode 100644
index 0000000000000000000000000000000000000000..5af162d63d1bc660d1a8687e6780e2ee438020ab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pch/macro-4.hs
@@ -0,0 +1 @@
+/* No content!  */
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index d81a049e64634445ebc6336d28d75e53162e71b3..cc2b931688754f22a1334aa56cc41c5905ba6210 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,27 @@
+2004-06-09  Geoffrey Keating  <geoffk@apple.com>
+
+	* traditional.c (push_replacement_text): Set macro->traditional.
+	(save_replacement_text): Likewise.
+	* pch.c (cpp_write_pch_state): Don't write list of defined macros.
+	(struct save_macro_item): Delete.
+	(struct save_macro_data): Use a character array not the previous
+	structured format.
+	(save_macros): Save macro as text not as internal structures.
+	(cpp_prepare_state): Update for changes to save_macro_data.
+	(cpp_read_state): Don't read macros defined in PCH.  Restore
+	-D macros as text.  
+	* macro.c (create_iso_definition): Honour alloc_subobject.
+	Clear traditional flag.
+	(_cpp_create_definition): Honour alloc_subobject.
+	* lex.c (cpp_token_val_index): New.
+	* internal.h: Include cpp-id-data.h.
+	(uchar): Move definition to cpp-id-data.h.
+	(U): Likewise.
+	(cpp_macro): Likewise.
+	* directives.c (struct answer): Move to cpp-id-data.h.
+	(do_assert): Honour alloc_subobject.
+	
+
 2004-06-09  Paolo Bonzini  <bonzini@gnu.org>
 
 	* Makefile.am (all-local): New.
diff --git a/libcpp/directives.c b/libcpp/directives.c
index 5a6a342bea5b0b63e5803ffbc96d7eccb10a3447..16873dadecf3cd2dbc5b19fda9d4701c00d01d08 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -26,14 +26,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "mkdeps.h"
 #include "obstack.h"
 
-/* Chained list of answers to an assertion.  */
-struct answer
-{
-  struct answer *next;
-  unsigned int count;
-  cpp_token first[1];
-};
-
 /* Stack of conditionals currently in progress
    (including both successful and failing conditionals).  */
 struct if_stack
@@ -1727,6 +1719,8 @@ do_assert (cpp_reader *pfile)
   node = parse_assertion (pfile, &new_answer, T_ASSERT);
   if (node)
     {
+      size_t answer_size;
+
       /* Place the new answer in the answer list.  First check there
          is not a duplicate.  */
       new_answer->next = 0;
@@ -1741,11 +1735,20 @@ do_assert (cpp_reader *pfile)
 	  new_answer->next = node->value.answers;
 	}
 
+      answer_size = sizeof (struct answer) + ((new_answer->count - 1)
+					      * sizeof (cpp_token));
+      /* Commit or allocate storage for the object.  */
+      if (pfile->hash_table->alloc_subobject)
+	{
+	  struct answer *temp_answer = new_answer;
+	  new_answer = pfile->hash_table->alloc_subobject (answer_size);
+	  memcpy (new_answer, temp_answer, answer_size);
+	}
+      else
+	BUFF_FRONT (pfile->a_buff) += answer_size;
+
       node->type = NT_ASSERTION;
       node->value.answers = new_answer;
-      BUFF_FRONT (pfile->a_buff) += (sizeof (struct answer)
-				     + (new_answer->count - 1)
-				     * sizeof (cpp_token));
       check_eol (pfile);
     }
 }
diff --git a/libcpp/include/ChangeLog b/libcpp/include/ChangeLog
index a2f4bc5e3ef3c9e3f052c3d14469df8d4c5a78ad..0dbd0c33474fa348277235320d9e5a5168b934b2 100644
--- a/libcpp/include/ChangeLog
+++ b/libcpp/include/ChangeLog
@@ -1,3 +1,14 @@
+2004-06-09  Geoffrey Keating  <geoffk@apple.com>
+
+	* symtab.h (struct ht): Add field 'alloc_subobject'.
+	* cpplib.h (struct cpp_string): Add GTY marker.
+	(enum cpp_token_fld_kind): New.
+	(struct cpp_token): Add GTY markers.
+	(cpp_token_val_index): Prototype.
+	(CPP_HASHNODE_VALUE_IDX): New.
+	(struct cpp_hashnode): Don't skip fields of 'value' when marking.
+	* cpp-id-data.h: New file.
+
 2004-05-29  Geoffrey Keating  <geoffk@apple.com>
 
 	* symtab.h (struct ht): New field 'entries_owned'
diff --git a/libcpp/include/cpp-id-data.h b/libcpp/include/cpp-id-data.h
new file mode 100644
index 0000000000000000000000000000000000000000..bdeaeba5182b1568ca689d1d75fefa8ceaa2691b
--- /dev/null
+++ b/libcpp/include/cpp-id-data.h
@@ -0,0 +1,77 @@
+/* Structures that hang off cpp_identifier, for PCH.
+   Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+This program 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 2, or (at your option) any
+later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "cpplib.h"
+
+#ifndef HAVE_UCHAR
+typedef unsigned char uchar;
+#endif
+#define U (const uchar *)  /* Intended use: U"string" */
+
+/* Chained list of answers to an assertion.  */
+struct answer GTY(())
+{
+  struct answer *next;
+  unsigned int count;
+  cpp_token GTY ((length ("%h.count"))) first[1];
+};
+
+/* Each macro definition is recorded in a cpp_macro structure.
+   Variadic macros cannot occur with traditional cpp.  */
+struct cpp_macro GTY(())
+{
+  /* Parameters, if any.  */
+  cpp_hashnode ** GTY ((nested_ptr (union tree_node,
+		"%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL",
+			"%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"),
+			length ("%h.paramc")))
+    params;
+
+  /* Replacement tokens (ISO) or replacement text (traditional).  See
+     comment at top of cpptrad.c for how traditional function-like
+     macros are encoded.  */
+  union cpp_macro_u
+  {
+    cpp_token * GTY ((tag ("0"), length ("%0.count"))) tokens;
+    const uchar * GTY ((tag ("1"))) text;
+  } GTY ((desc ("%1.traditional"))) exp;
+
+  /* Definition line number.  */
+  source_location line;
+
+  /* Number of tokens in expansion, or bytes for traditional macros.  */
+  unsigned int count;
+
+  /* Number of parameters.  */
+  unsigned short paramc;
+
+  /* If a function-like macro.  */
+  unsigned int fun_like : 1;
+
+  /* If a variadic macro.  */
+  unsigned int variadic : 1;
+
+  /* If macro defined in system header.  */
+  unsigned int syshdr   : 1;
+
+  /* Nonzero if it has been expanded or had its existence tested.  */
+  unsigned int used     : 1;
+
+  /* Indicate which field of 'exp' is in use.  */
+  unsigned int traditional : 1;
+};
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index cf701b5e861661894110ada7748b977c250017e4..dab315714df68e61526417f9881c57889f259042 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -156,7 +156,7 @@ enum c_lang {CLK_GNUC89 = 0, CLK_GNUC99, CLK_STDC89, CLK_STDC94, CLK_STDC99,
 	     CLK_GNUCXX, CLK_CXX98, CLK_ASM};
 
 /* Payload of a NUMBER, STRING, CHAR or COMMENT token.  */
-struct cpp_string
+struct cpp_string GTY(())
 {
   unsigned int len;
   const unsigned char *text;
@@ -171,23 +171,48 @@ struct cpp_string
 #define NO_EXPAND	(1 << 5) /* Do not macro-expand this token.  */
 #define BOL		(1 << 6) /* Token at beginning of line.  */
 
+/* Specify which field, if any, of the cpp_token union is used.  */
+
+enum cpp_token_fld_kind {
+  CPP_TOKEN_FLD_NODE,
+  CPP_TOKEN_FLD_SOURCE,
+  CPP_TOKEN_FLD_STR,
+  CPP_TOKEN_FLD_ARG_NO,
+  CPP_TOKEN_FLD_NONE
+};
+
 /* A preprocessing token.  This has been carefully packed and should
    occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts.  */
-struct cpp_token
+struct cpp_token GTY(())
 {
   source_location src_loc;	/* Location of first char of token.  */
   ENUM_BITFIELD(cpp_ttype) type : CHAR_BIT;  /* token type */
   unsigned char flags;		/* flags - see above */
 
-  union
+  union cpp_token_u
   {
-    cpp_hashnode *node;		/* An identifier.  */
-    const cpp_token *source;	/* Inherit padding from this token.  */
-    struct cpp_string str;	/* A string, or number.  */
-    unsigned int arg_no;	/* Argument no. for a CPP_MACRO_ARG.  */
-  } val;
+    /* An identifier.  */
+    cpp_hashnode *
+      GTY ((nested_ptr (union tree_node,
+		"%h ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (%h)) : NULL",
+			"%h ? HT_IDENT_TO_GCC_IDENT (HT_NODE (%h)) : NULL"),
+	    tag ("CPP_TOKEN_FLD_NODE")))
+	 node;
+	 
+    /* Inherit padding from this token.  */
+    cpp_token * GTY ((tag ("CPP_TOKEN_FLD_SOURCE"))) source;
+
+    /* A string, or number.  */
+    struct cpp_string GTY ((tag ("CPP_TOKEN_FLD_STR"))) str;
+
+    /* Argument no. for a CPP_MACRO_ARG.  */
+    unsigned int GTY ((tag ("CPP_TOKEN_FLD_ARG_NO"))) arg_no;
+  } GTY ((desc ("cpp_token_val_index (&%1)"))) val;
 };
 
+/* Say which field is in use.  */
+extern enum cpp_token_fld_kind cpp_token_val_index (cpp_token *tok);
+
 /* A type wide enough to hold any multibyte source character.
    cpplib's character constant interpreter requires an unsigned type.
    Also, a typedef for the signed equivalent.
@@ -498,6 +523,23 @@ enum builtin_type
 #define NODE_LEN(NODE)		HT_LEN (&(NODE)->ident)
 #define NODE_NAME(NODE)		HT_STR (&(NODE)->ident)
 
+/* Specify which field, if any, of the union is used.  */
+
+enum {
+  NTV_MACRO,
+  NTV_ANSWER,
+  NTV_BUILTIN,
+  NTV_ARGUMENT,
+  NTV_NONE
+};
+
+#define CPP_HASHNODE_VALUE_IDX(HNODE)				\
+  ((HNODE.flags & NODE_MACRO_ARG) ? NTV_ARGUMENT		\
+   : HNODE.type == NT_MACRO ? ((HNODE.flags & NODE_BUILTIN) 	\
+			       ? NTV_BUILTIN : NTV_MACRO)	\
+   : HNODE.type == NT_ASSERTION ? NTV_ANSWER			\
+   : NTV_NONE)
+
 /* The common part of an identifier node shared amongst all 3 C front
    ends.  Also used to store CPP identifiers, which are a superset of
    identifiers in the grammatical sense.  */
@@ -515,14 +557,14 @@ struct cpp_hashnode GTY(())
   union _cpp_hashnode_value
   {
     /* If a macro.  */
-    cpp_macro * GTY((skip)) macro;
+    cpp_macro * GTY((tag ("NTV_MACRO"))) macro;
     /* Answers to an assertion.  */
-    struct answer * GTY ((skip)) answers;
+    struct answer * GTY ((tag ("NTV_ANSWER"))) answers;
     /* Code for a builtin macro.  */
-    enum builtin_type GTY ((tag ("1"))) builtin;
+    enum builtin_type GTY ((tag ("NTV_BUILTIN"))) builtin;
     /* Macro argument index.  */
-    unsigned short GTY ((tag ("0"))) arg_index;
-  } GTY ((desc ("0"))) value;
+    unsigned short GTY ((tag ("NTV_ARGUMENT"))) arg_index;
+  } GTY ((desc ("CPP_HASHNODE_VALUE_IDX (%1)"))) value;
 };
 
 /* Call this first to get a handle to pass to other functions.
diff --git a/libcpp/include/symtab.h b/libcpp/include/symtab.h
index d11e4efe6dcf971f5f38399c723cc1315614cfb3..0b2a848739e13ee6526f274d0ee740d75a0161a0 100644
--- a/libcpp/include/symtab.h
+++ b/libcpp/include/symtab.h
@@ -46,8 +46,11 @@ struct ht
   struct obstack stack;
 
   hashnode *entries;
-  /* Call back.  */
+  /* Call back, allocate a node.  */
   hashnode (*alloc_node) (hash_table *);
+  /* Call back, allocate something that hangs off a node like a cpp_macro.  
+     NULL means use the usual allocator.  */
+  void * (*alloc_subobject) (size_t);
 
   unsigned int nslots;		/* Total slots in the entries array.  */
   unsigned int nelements;	/* Number of live elements.  */
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 3608201d560ecebea8e514a4e93701c2c9863e81..fd3facf6136d38b3a75406d56bab5e133c36ac4f 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -24,6 +24,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #define LIBCPP_INTERNAL_H
 
 #include "symtab.h"
+#include "cpp-id-data.h"
 
 #if defined HAVE_ICONV_H && defined HAVE_ICONV
 #include <iconv.h>
@@ -45,11 +46,6 @@ struct cset_converter
   iconv_t cd;
 };
 
-#ifndef HAVE_UCHAR
-typedef unsigned char uchar;
-#endif
-#define U (const uchar *)  /* Intended use: U"string" */
-
 #define BITS_PER_CPPCHAR_T (CHAR_BIT * sizeof (cppchar_t))
 
 /* Test if a sign is valid within a preprocessing number.  */
@@ -90,44 +86,6 @@ struct dummy
 #define CPP_ALIGN2(size, align) (((size) + ((align) - 1)) & ~((align) - 1))
 #define CPP_ALIGN(size) CPP_ALIGN2 (size, DEFAULT_ALIGNMENT)
 
-/* Each macro definition is recorded in a cpp_macro structure.
-   Variadic macros cannot occur with traditional cpp.  */
-struct cpp_macro
-{
-  /* Parameters, if any.  */
-  cpp_hashnode **params;
-
-  /* Replacement tokens (ISO) or replacement text (traditional).  See
-     comment at top of cpptrad.c for how traditional function-like
-     macros are encoded.  */
-  union
-  {
-    cpp_token *tokens;
-    const uchar *text;
-  } exp;
-
-  /* Definition line number.  */
-  fileline line;
-
-  /* Number of tokens in expansion, or bytes for traditional macros.  */
-  unsigned int count;
-
-  /* Number of parameters.  */
-  unsigned short paramc;
-
-  /* If a function-like macro.  */
-  unsigned int fun_like : 1;
-
-  /* If a variadic macro.  */
-  unsigned int variadic : 1;
-
-  /* If macro defined in system header.  */
-  unsigned int syshdr   : 1;
-
-  /* Nonzero if it has been expanded or had its existence tested.  */
-  unsigned int used     : 1;
-};
-
 #define _cpp_mark_macro_used(NODE) do {					\
   if ((NODE)->type == NT_MACRO && !((NODE)->flags & NODE_BUILTIN))	\
     (NODE)->value.macro->used = 1; } while (0)
diff --git a/libcpp/lex.c b/libcpp/lex.c
index 37df6efc0b718eed4b391b96e6cbcd407e3c354b..7eafb13d3b432982d92e83bc4f7e447552ea3382 100644
--- a/libcpp/lex.c
+++ b/libcpp/lex.c
@@ -1556,3 +1556,25 @@ _cpp_aligned_alloc (cpp_reader *pfile, size_t len)
   buff->cur = result + len;
   return result;
 }
+
+/* Say which field of TOK is in use.  */
+
+enum cpp_token_fld_kind
+cpp_token_val_index (cpp_token *tok)
+{
+  switch (TOKEN_SPELL (tok))
+    {
+    case SPELL_IDENT:
+      return CPP_TOKEN_FLD_NODE;
+    case SPELL_LITERAL:
+      return CPP_TOKEN_FLD_STR;
+    case SPELL_NONE:
+      if (tok->type == CPP_MACRO_ARG)
+	return CPP_TOKEN_FLD_ARG_NO;
+      else if (tok->type == CPP_PADDING)
+	return CPP_TOKEN_FLD_SOURCE;
+      /* else fall through */
+    default:
+      return CPP_TOKEN_FLD_NONE;
+    }
+}
diff --git a/libcpp/macro.c b/libcpp/macro.c
index cfc42b4050fcd52cd627b6156a45bb6bdd4014ff..dc58b3180f12e2861232dbed3d91e6dc1d913e63 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -1408,8 +1408,16 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
       if (!ok)
 	return false;
 
-      /* Success.  Commit the parameter array.  */
-      BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
+      /* Success.  Commit or allocate the parameter array.  */
+      if (pfile->hash_table->alloc_subobject)
+	{
+	  cpp_token *tokns = pfile->hash_table->alloc_subobject
+	    (sizeof (cpp_token) * macro->paramc);
+	  memcpy (tokns, macro->params, sizeof (cpp_token) * macro->paramc);
+	  macro->params = tokns;
+	}
+      else
+	BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->params[macro->paramc];
       macro->fun_like = 1;
     }
   else if (ctoken->type != CPP_EOF && !(ctoken->flags & PREV_WHITE))
@@ -1472,6 +1480,7 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
     }
 
   macro->exp.tokens = (cpp_token *) BUFF_FRONT (pfile->a_buff);
+  macro->traditional = 0;
 
   /* Don't count the CPP_EOF.  */
   macro->count--;
@@ -1480,8 +1489,16 @@ create_iso_definition (cpp_reader *pfile, cpp_macro *macro)
   if (macro->count)
     macro->exp.tokens[0].flags &= ~PREV_WHITE;
 
-  /* Commit the memory.  */
-  BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->exp.tokens[macro->count];
+  /* Commit or allocate the memory.  */
+  if (pfile->hash_table->alloc_subobject)
+    {
+      cpp_token *tokns = pfile->hash_table->alloc_subobject (sizeof (cpp_token)
+							     * macro->count);
+      memcpy (tokns, macro->exp.tokens, sizeof (cpp_token) * macro->count);
+      macro->exp.tokens = tokns;
+    }
+  else
+    BUFF_FRONT (pfile->a_buff) = (uchar *) &macro->exp.tokens[macro->count];
 
   return true;
 }
@@ -1494,7 +1511,10 @@ _cpp_create_definition (cpp_reader *pfile, cpp_hashnode *node)
   unsigned int i;
   bool ok;
 
-  macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
+  if (pfile->hash_table->alloc_subobject)
+    macro = pfile->hash_table->alloc_subobject (sizeof (cpp_macro));
+  else
+    macro = (cpp_macro *) _cpp_aligned_alloc (pfile, sizeof (cpp_macro));
   macro->line = pfile->directive_line;
   macro->params = 0;
   macro->paramc = 0;
diff --git a/libcpp/pch.c b/libcpp/pch.c
index 51175a9a67b0ff594e3be911d27e03020390d09d..a9d139a30b76121e0ed457b791c20853c6b95567 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -347,15 +347,6 @@ cpp_write_pch_state (cpp_reader *r, FILE *f)
 {
   struct macrodef_struct z;
 
-  /* Write out the list of defined identifiers.  */
-  cpp_forall_identifiers (r, write_macdef, f);
-  memset (&z, 0, sizeof (z));
-  if (fwrite (&z, sizeof (z), 1, f) != 1)
-    {
-      cpp_errno (r, CPP_DL_ERROR, "while writing precompiled header");
-      return -1;
-    }
-
   if (!r->deps)
     r->deps = deps_init ();
 
@@ -544,46 +535,64 @@ cpp_valid_state (cpp_reader *r, const char *name, int fd)
   return 1;
 }
 
-/* Save all the existing macros and assertions.  
-   This code assumes that there might be hundreds, but not thousands of
-   existing definitions.  */
-
-struct save_macro_item {
-  struct save_macro_item *next;
-  struct cpp_hashnode macs[64];
-};
+/* Save all the existing macros.  */
 
 struct save_macro_data 
 {
-  struct save_macro_item *macros;
+  uchar **defns;
   size_t count;
+  size_t array_size;
   char **saved_pragmas;
 };
 
-/* Save the definition of a single macro, so that it will persist across
-   a PCH restore.  */
+/* Save the definition of a single macro, so that it will persist
+   across a PCH restore.  Because macro data is in GCed memory, which
+   will be blown away by PCH, it must be temporarily copied to
+   malloced memory.  (The macros will refer to identifier nodes which
+   are also GCed and so on, so the copying is done by turning them
+   into self-contained strings.)  The assumption is that most macro
+   definitions will come from the PCH file, not from the compilation
+   before the PCH file is loaded, so it doesn't matter that this is
+   a little expensive.
+
+   It would reduce the cost even further if macros defined in the PCH
+   file were not saved in this way, but this is not done (yet), except
+   for builtins, and for #assert by default.  */
 
 static int 
-save_macros (cpp_reader *r ATTRIBUTE_UNUSED, cpp_hashnode *h, void *data_p)
+save_macros (cpp_reader *r, cpp_hashnode *h, void *data_p)
 {
   struct save_macro_data *data = (struct save_macro_data *)data_p;
   if (h->type != NT_VOID
       && (h->flags & NODE_BUILTIN) == 0)
     {
-      cpp_hashnode *save;
-      if (data->count == ARRAY_SIZE (data->macros->macs))
+      if (data->count == data->array_size)
+	{
+	  data->array_size *= 2;
+	  data->defns = xrealloc (data->defns, (data->array_size 
+						* sizeof (uchar *)));
+	}
+      
+      switch (h->type)
 	{
-	  struct save_macro_item *d = data->macros;
-	  data->macros = xmalloc (sizeof (struct save_macro_item));
-	  data->macros->next = d;
-	  data->count = 0;
+	case NT_ASSERTION:
+	  /* Not currently implemented.  */
+	  return 1;
+
+	case NT_MACRO:
+	  {
+	    const uchar * defn = cpp_macro_definition (r, h);
+	    size_t defnlen = ustrlen (defn);
+
+	    data->defns[data->count] = xmemdup (defn, defnlen, defnlen + 2);
+	    data->defns[data->count][defnlen] = '\n';
+	  }
+	  break;
+	  
+	default:
+	  abort ();
 	}
-      save = data->macros->macs + data->count;
       data->count++;
-      memcpy (save, h, sizeof (struct cpp_hashnode));
-      HT_STR (&save->ident) = xmemdup (HT_STR (HT_NODE (save)),
-				       HT_LEN (HT_NODE (save)),
-				       HT_LEN (HT_NODE (save)) + 1);
     }
   return 1;
 }
@@ -596,8 +605,9 @@ cpp_prepare_state (cpp_reader *r, struct save_macro_data **data)
 {
   struct save_macro_data *d = xmalloc (sizeof (struct save_macro_data));
   
-  d->macros = NULL;
-  d->count = ARRAY_SIZE (d->macros->macs);
+  d->array_size = 512;
+  d->defns = xmalloc (d->array_size * sizeof (d->defns[0]));
+  d->count = 0;
   cpp_forall_identifiers (r, save_macros, d);
   d->saved_pragmas = _cpp_save_pragma_names (r);
   *data = d;
@@ -612,11 +622,9 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
 		struct save_macro_data *data)
 {
   struct macrodef_struct m;
-  size_t defnlen = 256;
-  unsigned char *defn = xmalloc (defnlen);
-  struct lexer_state old_state;
   struct save_macro_item *d;
   size_t i, mac_count;
+  struct lexer_state old_state;
 
   /* Restore spec_nodes, which will be full of references to the old 
      hashtable entries and so will now be invalid.  */
@@ -628,70 +636,28 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
     s->n__VA_ARGS__     = cpp_lookup (r, DSC("__VA_ARGS__"));
   }
 
-  /* Run through the carefully-saved macros, insert them.  */
-  d = data->macros;
-  mac_count = data->count;
-  while (d)
-    {
-      struct save_macro_item *nextd;
-      for (i = 0; i < mac_count; i++)
-	{
-	  cpp_hashnode *h;
-	  
-	  h = cpp_lookup (r, HT_STR (HT_NODE (&d->macs[i])), 
-			  HT_LEN (HT_NODE (&d->macs[i])));
-	  h->type = d->macs[i].type;
-	  h->flags = d->macs[i].flags;
-	  h->value = d->macs[i].value;
-	  free ((void *)HT_STR (HT_NODE (&d->macs[i])));
-	}
-      nextd = d->next;
-      free (d);
-      d = nextd;
-      mac_count = ARRAY_SIZE (d->macs);
-    }
-
-  _cpp_restore_pragma_names (r, data->saved_pragmas);
-
-  free (data);
-
   old_state = r->state;
-
   r->state.in_directive = 1;
   r->state.prevent_expansion = 1;
   r->state.angled_headers = 0;
 
-  /* Read in the identifiers that must be defined.  */
-  for (;;)
+  /* Run through the carefully-saved macros, insert them.  */
+  for (i = 0; i < data->count; i++)
     {
       cpp_hashnode *h;
-      
-      if (fread (&m, sizeof (m), 1, f) != 1)
-	goto error;
-      
-      if (m.name_length == 0)
-	break;
-
-      if (defnlen < m.definition_length + 1)
-	{
-	  defnlen = m.definition_length + 256;
-	  defn = xrealloc (defn, defnlen);
-	}
+      size_t namelen;
+      uchar *defn;
 
-      if (fread (defn, 1, m.definition_length, f) != m.definition_length)
-	goto error;
-      defn[m.definition_length] = '\n';
-      
-      h = cpp_lookup (r, defn, m.name_length);
+      namelen = strcspn (data->defns[i], "( \n");
+      h = cpp_lookup (r, data->defns[i], namelen);
+      defn = data->defns[i] + namelen;
 
-      if (h->type == NT_MACRO)
-	_cpp_free_definition (h);
-      if (m.flags & NODE_POISONED)
-	h->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
-      else if (m.name_length != m.definition_length)
+      /* The PCH file is valid, so we know that if there is a definition
+	 from the PCH file it must be the same as the one we had
+	 originally, and so do not need to restore it.  */
+      if (h->type == NT_VOID)
 	{
-	  if (cpp_push_buffer (r, defn + m.name_length, 
-			       m.definition_length - m.name_length, true)
+	  if (cpp_push_buffer (r, defn, ustrchr (defn, '\n') - defn, true)
 	      != NULL)
 	    {
 	      _cpp_clean_line (r);
@@ -702,11 +668,14 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
 	  else
 	    abort ();
 	}
-    }
 
+      free (data->defns[i]);
+    }
   r->state = old_state;
-  free (defn);
-  defn = NULL;
+
+  _cpp_restore_pragma_names (r, data->saved_pragmas);
+
+  free (data);
 
   if (deps_restore (r->deps, f, CPP_OPTION (r, restore_pch_deps) ? name : NULL)
       != 0)
diff --git a/libcpp/traditional.c b/libcpp/traditional.c
index f4ce9f66e4772567d478df1be8e98ba111ec93c2..38e301c43ff767fac0773b5c305b21ace9257cf9 100644
--- a/libcpp/traditional.c
+++ b/libcpp/traditional.c
@@ -701,6 +701,7 @@ push_replacement_text (cpp_reader *pfile, cpp_hashnode *node)
       cpp_macro *macro = node->value.macro;
       macro->used = 1;
       text = macro->exp.text;
+      macro->traditional = 1;
       len = macro->count;
     }
 
@@ -934,6 +935,7 @@ save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
       memcpy (exp, pfile->out.base, len);
       exp[len] = '\n';
       macro->exp.text = exp;
+      macro->traditional = 1;
       macro->count = len;
     }
   else
@@ -949,6 +951,7 @@ save_replacement_text (cpp_reader *pfile, cpp_macro *macro,
       exp = BUFF_FRONT (pfile->a_buff);
       block = (struct block *) (exp + macro->count);
       macro->exp.text = exp;
+      macro->traditional = 1;
 
       /* Write out the block information.  */
       block->text_len = len;