This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: identifier GC


This patch changes identifier nodes to be truly garbage collected.  I
need this for the incremental compiler, so that memory use in the
server does not grow without bound.

However, it is also fairly independent from the other changes and
seems worthwhile.  With this it is pretty common to see the GC collect
200-300k after parsing is complete.

The basic idea is to use the struct hack for storing the contents of
the identifier, like we do for STRING_CST.  After parsing is complete,
we turn the string pool hash from a root into a weak set, allowing
collection.

There are a few oddities though.  I worry that these will be
off-putting.

* Identifier nodes have different sizes in different front ends.  So,
  I added a new field to the langhook structure so that the generic
  code knows how to compute the offset of the string pointer.  There's
  a new requirement on front ends that the last field of
  lang_identifier be a struct ht_identifier.

  I considered doing something simpler here -- just ggc_alloc the
  string data and let the GC do its thing, but that wastes a half word
  per identifier on average (since currently strings are allocated on
  an obstack with no padding, AIUI).  I'm happy to change this if the
  rest of this is too gross for you...

* IDENTIFIER_POINTER now has to add in this offset from the langhook.
  I.e., the offset to the string data varies by front end.

  Anywhere you use IDENTIFIER_POINTER you must include langhooks.h.

  Also, debugging is a little weird now... what I do is cast the tree
  to a 'struct lang_identifier *', then grovel around for the string
  data.

* There was some code assuming that the result of ggc_alloc_string (or
  ggc_strdup) was uncollectable.  This is a bad practice to begin
  with, so in a sense this change is ferreting out bugs :-)
  Anyway, in the new regime, these things must be treated exactly like
  any other GC-allocated memory.  I don't consider this a huge
  problem, since we're all used to following those rules for other
  objects already.

* The g++ get_identifier_nocopy had to go.  And btw, in the future,
  please don't hide hacks like this away from the rest of the
  functions associated with a data structure -- this, plus a rogue use
  of ggc_strdup in g++, took me 3 painful days of debugging to find.

* I didn't make the cpp hash table support deletion.  So, there's a
  bit of churn at each GC where we re-allocate the backing array and
  re-hash.  Few collections actually collect no identifiers (a mildly
  surprising fact), though, so I left it as is.  This is simple to
  change.

* This may mildly affect PCH.  I am not sure if a 'char*' read from a
  PCH file will still point to the middle of its corresponding
  identifier node (i.e., if the 'char*' was taken via
  IDENTIFIER_POINTER and stashed somewhere).  This should only affect
  code that is using == on such pointers, and I would hope we don't
  have anything like that.  In any case nothing showed up during
  testing.

This patch updates all front ends.  I bootstrapped and regtested it on
the compile farm.  Also I've been using it pretty regularly for months
on the incremental compiler branch.

One omission here is that I have not done any performance testing.
Maybe someone could say what the norm is here.  Do we have a standard
compile-time benchmark?  Bootstrap?

Tom

gcc/ChangeLog:
2008-03-21  Tom Tromey  <tromey@redhat.com>

	* ggc-page.c: Include langhooks.h
	(gt_ggc_m_S): New function.
	* ggc-common.c (ggc_mark_roots): Call ggc_mark_stringpool twice.
	(ggc_protect_identifiers): New global.
	* ggc.h (ggc_protect_identifiers): Declare.
	(ggc_mark_stringpool): Update.
	(gt_ggc_m_S): Change argument type.
	* toplev.c (compile_file): Set and reset ggc_protect_identifiers.
	* stringpool.c (check_ident): New function.
	(ggc_mark_stringpool): Add 'marking' argument.  Remove elements
	from identifier table if requested.
	Include langhooks.h.
	(string_stack): Remove.
	(init_stringpool): Update.
	(alloc_node): Add length argument.  Use build_identifier.
	(ggc_alloc_string): Use ggc_alloc.
	(gt_ggc_m_S): Remove.
	* langhooks-def.h (LANG_HOOKS_IDENTIFIER_OFFSET): New define.
	(LANG_HOOKS_INITIALIZER): Use it.
	* c-common.h (C_RID_CODE): Rewrote.
	(struct c_common_identifier) <node>: Remove field.
	* var-tracking.c: Include langhooks.h.
	* tree-outof-ssa.c: Include langhooks.h.
	* c-pragma.c: Include langhooks.h.
	* print-rtl.c: Include langhooks.h.
	* langhooks.h (struct lang_hooks) <identifier_offset>: New field.
	* c-pretty-print.c: Include langhooks.h.
	* c-decl.c (struct lang_identifier) <node>: New field.
	(C_IDENTIFIER_OFFSET_isnt_accurate): New declaration.
	(struct lang_identifier): Add comment for 'node' field.
	* c-aux-info.c: Include langhooks.h.
	* c-tree.h (C_SIZEOF_STRUCT_LANG_IDENTIFIER): Redefine.
	(C_IDENTIFIER_OFFSET): New define.
	* c-objc-common.h (LANG_HOOKS_IDENTIFIER_OFFSET): New define.
	* tree.h (IDENTIFIER_LENGTH): Redefine.
	(IDENTIFIER_POINTER): Likewise.
	(IDENTIFIER_HASH_VALUE): Likewise.
	(HT_IDENT_TO_GCC_IDENT): Likewise.
	(GCC_IDENT_TO_HT_IDENT): Likewise.
	(struct tree_identifier) <id>: Remove.
	(build_identifier): Declare.
	* tree.c (make_node_stat): Don't allow IDENTIFIER_NODEs.
	(build_identifier): New function.
	* c-lex.c: Include langhooks.h.
	* gengtype.c (write_types_process_field): Arrange to mark
	strings.
	(open_base_files): Include langhooks.h.
	* tree-complex.c: Include langhooks.h.

gcc/java/ChangeLog:
2008-03-21  Tom Tromey  <tromey@redhat.com>

	* java-tree.h (struct lang_identifier) <id>: New field.
	* expr.c: Include langhooks.h.
	* mangle.c: Include langhooks.h.
	* verify-glue.c: Include langhooks.h.
	* except.c: Include langhooks.h.
	* resource.c: Include langhooks.h.
	* constants.c: Include langhooks.h.
	* jcf-parse.c: Include langhooks.h.
	* class.c: Include langhooks.h.
	* typeck.c: Include langhooks.h.

gcc/cp/ChangeLog:
2008-03-21  Tom Tromey  <tromey@redhat.com>

	* parser.c: Include langhooks.h.
	* decl2.c: Include langhooks.h.
	* name-lookup.c: Include langhooks.h.
	* semantics.c: Include langhooks.h.
	* pt.c: Include langhooks.h.
	* cp-lang.c (LANG_HOOKS_IDENTIFIER_OFFSET): New define.
	* cxx-pretty-print.c: Include langhooks.h.
	* cp-tree.h (struct lang_identifier) <node>: New field.
	* tree.c: Include langhooks.h.
	* error.c: Include langhooks.h.
	* except.c: Include langhooks.h.
	* method.c: Include langhooks.h.
	* repo.c: Include langhooks.h.
	* class.c: Include langhooks.h.
	* typeck.c: Include langhooks.h.
	* mangle.c: Include langhooks.h.
	(save_partially_mangled_name): Remove.
	(restore_partially_mangled_name): Likewise.
	(write_encoding): Update.
	(write_unqualified_name): Likewise.
	(start_mangling): Always use name_obstack.  Remove 'ident_p'
	argument.
	(get_identifier_nocopy): Remove.
	(finish_mangling_internal): Rename from finish_mangling.
	(finish_mangling): New function.
	(finish_mangling_get_identifier): Likewise.
	(partially_mangled_name, partially_mangled_name_len): Remove.
	(mangle_decl_string): Change return type.  Update.
	(mangle_decl, mangle_type_string, mangle_special_for_type,
	mangle_ctor_vtbl_for_type, mangle_thunk, mangle_guard_variable,
	mangle_ref_init_variable): Update.
	* lex.c: Include langhooks.h.
	(handle_pragma_interface): Don't copy the filename.
	(handle_pragma_implementation): Copy filename using xstrdup.

gcc/ada/ChangeLog:
2008-03-21  Tom Tromey  <tromey@redhat.com>

	* utils2.c: Include langhooks.h.
	* decl.c: Include langhooks.h.
	* misc.c (LANG_HOOKS_IDENTIFIER_SIZE): Remove.
	* utils.c: Include langhooks.h.
	* ada-tree.h (struct lang_identifier): New struct.
	(union lang_tree_node) <identifier>: New field.
	* trans.c: Include langhooks.h.

gcc/fortran/ChangeLog:
2008-03-21  Tom Tromey  <tromey@redhat.com>

	* trans-decl.c: Include langhooks.h.
	* iresolve.c: Include langhooks.h.
	* f95-lang.c (struct lang_identifier) <id>: New field.

libcpp/ChangeLog:
2008-03-21  Tom Tromey  <tromey@redhat.com>

	* include/symtab.h (enum ht_lookup_option) <HT_ALLOCED>: Remove.
	(ht_identifier): Put 'str' at the end.  Change type for struct
	hack.
	(struct ht) <alloc_node>: Add size_t argument.
	(ht_rehash_fn): Declare.
	(ht_remove_identifiers): Declare.
	* symtab.c (ht_rehash): Rename from ht_expand.  Add arguments.
	(ht_lookup_with_hash): Update.  Remove HT_ALLOCED code.  Copy
	directly into HT_STR.
	(ht_remove_identifiers): New function.
	* lex.c (lex_identifier): Use CPP_HASHNODE.
	* traditional.c (lex_identifier): Use CPP_HASHNODE.
	* identifiers.c (alloc_node): Use HT_NODE.  Fix types.  Update for
	change to struct ht.
	(_cpp_init_hashtable): Remove cast.
	(struct callback_info): New struct.
	(cpp_ht_proxy): New function.
	(cpp_forall_identifiers): Use cpp_ht_proxy.
	* include/cpplib.h (CPP_HASHNODE): Redefine.
	(HT_NODE): Likewise.
	(cpp_hashnode): Put 'ident' at the end.

Index: gcc/tree-complex.c
===================================================================
--- gcc/tree-complex.c	(revision 133392)
+++ gcc/tree-complex.c	(working copy)
@@ -31,6 +31,7 @@
 #include "tree-pass.h"
 #include "tree-ssa-propagate.h"
 #include "diagnostic.h"
+#include "langhooks.h"
 
 
 /* For each complex ssa name, a lattice value.  We're interested in finding
Index: gcc/gengtype.c
===================================================================
--- gcc/gengtype.c	(revision 133392)
+++ gcc/gengtype.c	(working copy)
@@ -1530,7 +1530,7 @@
       "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h",
       "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h",
       "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h",
-      "cfglayout.h", "except.h", "output.h", "cfgloop.h", NULL
+      "cfglayout.h", "except.h", "output.h", "cfgloop.h", "langhooks.h", NULL
     };
     const char *const *ifp;
     outf_p gtype_desc_c;
@@ -2355,9 +2355,6 @@
       break;
 
     case TYPE_STRING:
-      if (wtd->param_prefix == NULL)
-	break;
-
     case TYPE_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
@@ -3101,7 +3098,7 @@
 	oprintf (f, "    &%s,\n", name);
 	oprintf (f, "    1, \n");
 	oprintf (f, "    sizeof (%s),\n", v->name);
-	oprintf (f, "    &gt_ggc_m_S,\n");
+	oprintf (f, "    (gt_pointer_walker) &gt_ggc_m_S,\n");
 	oprintf (f, "    (gt_pointer_walker) &gt_pch_n_S\n");
 	oprintf (f, "  },\n");
       }
Index: gcc/java/typeck.c
===================================================================
--- gcc/java/typeck.c	(revision 133392)
+++ gcc/java/typeck.c	(working copy)
@@ -37,6 +37,7 @@
 #include "convert.h"
 #include "toplev.h"
 #include "ggc.h"
+#include "langhooks.h"
 
 static tree convert_ieee_real_to_integer (tree, tree);
 static tree parse_signature_type (const unsigned char **,
Index: gcc/java/class.c
===================================================================
--- gcc/java/class.c	(revision 133392)
+++ gcc/java/class.c	(working copy)
@@ -46,6 +46,7 @@
 #include "tree-iterator.h"
 #include "cgraph.h"
 #include "vecprim.h"
+#include "langhooks.h"
 
 /* DOS brain-damage */
 #ifndef O_BINARY
Index: gcc/java/jcf-parse.c
===================================================================
--- gcc/java/jcf-parse.c	(revision 133392)
+++ gcc/java/jcf-parse.c	(working copy)
@@ -44,6 +44,7 @@
 #include "tm_p.h"
 #include "cgraph.h"
 #include "vecprim.h"
+#include "langhooks.h"
 
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
Index: gcc/java/constants.c
===================================================================
--- gcc/java/constants.c	(revision 133392)
+++ gcc/java/constants.c	(working copy)
@@ -30,6 +30,7 @@
 #include "java-tree.h"
 #include "toplev.h"
 #include "ggc.h"
+#include "langhooks.h"
 
 static void set_constant_entry (CPool *, int, int, jword);
 static int find_tree_constant (CPool *, int, tree);
Index: gcc/java/resource.c
===================================================================
--- gcc/java/resource.c	(revision 133392)
+++ gcc/java/resource.c	(working copy)
@@ -42,6 +42,7 @@
 #include "expr.h"
 #include "tree-iterator.h"
 #include "cgraph.h"
+#include "langhooks.h"
 
 /* DOS brain-damage */
 #ifndef O_BINARY
Index: gcc/java/except.c
===================================================================
--- gcc/java/except.c	(revision 133392)
+++ gcc/java/except.c	(working copy)
@@ -37,6 +37,7 @@
 #include "except.h"
 #include "java-except.h"
 #include "toplev.h"
+#include "langhooks.h"
 
 static void expand_start_java_handler (struct eh_range *);
 static struct eh_range *find_handler_in_range (int, struct eh_range *,
Index: gcc/java/verify-glue.c
===================================================================
--- gcc/java/verify-glue.c	(revision 133392)
+++ gcc/java/verify-glue.c	(working copy)
@@ -35,6 +35,7 @@
 #include "java-tree.h"
 #include "java-except.h"
 #include "toplev.h"
+#include "langhooks.h"
 
 void *
 vfy_alloc (size_t bytes)
Index: gcc/java/mangle.c
===================================================================
--- gcc/java/mangle.c	(revision 133392)
+++ gcc/java/mangle.c	(working copy)
@@ -36,6 +36,7 @@
 #include "toplev.h"
 #include "ggc.h"
 #include "langhooks-def.h"
+#include "langhooks.h"
 
 static void mangle_class_field (tree);
 static void mangle_vtable (tree);
Index: gcc/java/expr.c
===================================================================
--- gcc/java/expr.c	(revision 133392)
+++ gcc/java/expr.c	(working copy)
@@ -44,6 +44,7 @@
 #include "ggc.h"
 #include "tree-gimple.h"
 #include "target.h"
+#include "langhooks.h"
 
 static void flush_quick_stack (void);
 static void push_value (tree);
Index: gcc/java/java-tree.h
===================================================================
--- gcc/java/java-tree.h	(revision 133392)
+++ gcc/java/java-tree.h	(working copy)
@@ -653,6 +653,9 @@
   /* If non-NULL:  An ADDR_REF to a VAR_DECL that contains
    * the Utf8Const representation of the identifier.  */
   tree utf8_ref;
+
+  /* The identifier allocation code requires this field to be last.  */
+  struct ht_identifier id;
 };
 
 /* The resulting tree type.  */
Index: gcc/c-lex.c
===================================================================
--- gcc/c-lex.c	(revision 133392)
+++ gcc/c-lex.c	(working copy)
@@ -41,6 +41,7 @@
 #include "splay-tree.h"
 #include "debug.h"
 #include "target.h"
+#include "langhooks.h"
 
 /* We may keep statistics about how long which files took to compile.  */
 static int header_time, body_time;
Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 133392)
+++ gcc/tree.c	(working copy)
@@ -341,7 +341,8 @@
 
 /* Compute the number of bytes occupied by a tree with code CODE.
    This function cannot be used for nodes that have variable sizes,
-   including TREE_VEC, PHI_NODE, STRING_CST, and CALL_EXPR.  */
+   including TREE_VEC, PHI_NODE, STRING_CST, IDENTIFIER_NODE, and
+   CALL_EXPR.  */
 size_t
 tree_code_size (enum tree_code code)
 {
@@ -411,12 +412,12 @@
     case tcc_exceptional:  /* something random, like an identifier.  */
       switch (code)
 	{
-	case IDENTIFIER_NODE:	return lang_hooks.identifier_size;
 	case TREE_LIST:		return sizeof (struct tree_list);
 
 	case ERROR_MARK:
 	case PLACEHOLDER_EXPR:	return sizeof (struct tree_common);
 
+	case IDENTIFIER_NODE:
 	case TREE_VEC:
 	case OMP_CLAUSE:
 	case PHI_NODE:		gcc_unreachable ();
@@ -457,6 +458,9 @@
       return (sizeof (struct tree_vec)
 	      + (TREE_VEC_LENGTH (node) - 1) * sizeof (tree));
 
+    case IDENTIFIER_NODE:
+      gcc_unreachable ();
+
     case STRING_CST:
       return TREE_STRING_LENGTH (node) + offsetof (struct tree_string, str) + 1;
 
@@ -488,6 +492,7 @@
   tree t;
   enum tree_code_class type = TREE_CODE_CLASS (code);
   size_t length = tree_code_size (code);
+  gcc_assert (code != IDENTIFIER_NODE);
 #ifdef GATHER_STATISTICS
   tree_node_kind kind;
 
@@ -673,7 +678,7 @@
   enum tree_code code = TREE_CODE (node);
   size_t length;
 
-  gcc_assert (code != STATEMENT_LIST);
+  gcc_assert (code != STATEMENT_LIST && code != IDENTIFIER_NODE);
 
   length = tree_size (node);
   t = ggc_alloc_zone_pass_stat (length, &tree_zone);
@@ -1200,6 +1205,27 @@
   return s;
 }
 
+/* Return a new identifier node of the given size.  The caller will
+   fill in the characters.  */
+
+tree
+build_identifier (size_t size)
+{
+  tree s;
+
+#ifdef GATHER_STATISTICS
+  tree_node_counts[(int) id_kind]++;
+  tree_node_sizes[(int) id_kind] += size;
+#endif  
+
+  s = ggc_alloc_tree (size);
+
+  memset (s, 0, size);
+  TREE_SET_CODE (s, IDENTIFIER_NODE);
+
+  return s;
+}
+
 /* Return a newly constructed COMPLEX_CST node whose value is
    specified by the real and imaginary parts REAL and IMAG.
    Both REAL and IMAG should be constant nodes.  TYPE, if specified,
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 133392)
+++ gcc/tree.h	(working copy)
@@ -1480,23 +1480,25 @@
 /* Define fields and accessors for some special-purpose tree nodes.  */
 
 #define IDENTIFIER_LENGTH(NODE) \
-  (IDENTIFIER_NODE_CHECK (NODE)->identifier.id.len)
+  (GCC_IDENT_TO_HT_IDENT (&(IDENTIFIER_NODE_CHECK (NODE)->identifier))->len)
 #define IDENTIFIER_POINTER(NODE) \
-  ((const char *) IDENTIFIER_NODE_CHECK (NODE)->identifier.id.str)
+  ((const char *) (GCC_IDENT_TO_HT_IDENT (&(IDENTIFIER_NODE_CHECK (NODE)->identifier))->str))
 #define IDENTIFIER_HASH_VALUE(NODE) \
-  (IDENTIFIER_NODE_CHECK (NODE)->identifier.id.hash_value)
+  (GCC_IDENT_TO_HT_IDENT (&(IDENTIFIER_NODE_CHECK (NODE)->identifier))->hash_value)
 
 /* Translate a hash table identifier pointer to a tree_identifier
    pointer, and vice versa.  */
 
 #define HT_IDENT_TO_GCC_IDENT(NODE) \
-  ((tree) ((char *) (NODE) - sizeof (struct tree_common)))
-#define GCC_IDENT_TO_HT_IDENT(NODE) (&((struct tree_identifier *) (NODE))->id)
+  ((tree) ((char *) (NODE) - lang_hooks.identifier_offset))
+#define GCC_IDENT_TO_HT_IDENT(NODE) \
+  ((struct ht_identifier *) ((char *) (NODE) + lang_hooks.identifier_offset))
 
 struct tree_identifier GTY(())
 {
   struct tree_common common;
-  struct ht_identifier id;
+  /* Note that every front end's tree_identifier must include an
+     ht_identifier structure at the end.  */
 };
 
 /* In a TREE_LIST node.  */
@@ -3989,6 +3991,7 @@
 extern tree build_complex (tree, tree, tree);
 extern tree build_one_cst (tree);
 extern tree build_string (int, const char *);
+extern tree build_identifier (size_t);
 extern tree build_tree_list_stat (tree, tree MEM_STAT_DECL);
 #define build_tree_list(t,q) build_tree_list_stat(t,q MEM_STAT_INFO)
 extern tree build_decl_stat (enum tree_code, tree, tree MEM_STAT_DECL);
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 133392)
+++ gcc/toplev.c	(working copy)
@@ -948,6 +948,8 @@
 {
   /* Initialize yet another pass.  */
 
+  ggc_protect_identifiers = true;
+
   init_cgraph ();
   init_final (main_input_filename);
   coverage_init (aux_base_name);
@@ -967,6 +969,8 @@
 
   lang_hooks.decls.final_write_globals ();
 
+/*   ggc_protect_identifiers = false; */
+
   if (errorcount || sorrycount)
     return;
 
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 133392)
+++ gcc/cp/typeck.c	(working copy)
@@ -44,6 +44,7 @@
 #include "convert.h"
 #include "c-common.h"
 #include "params.h"
+#include "langhooks.h"
 
 static tree pfn_from_ptrmemfunc (tree);
 static tree delta_from_ptrmemfunc (tree);
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 133392)
+++ gcc/cp/class.c	(working copy)
@@ -37,6 +37,7 @@
 #include "convert.h"
 #include "cgraph.h"
 #include "tree-dump.h"
+#include "langhooks.h"
 
 /* The number of nested classes being processed.  If we are not in the
    scope of any class, this is zero.  */
Index: gcc/cp/repo.c
===================================================================
--- gcc/cp/repo.c	(revision 133392)
+++ gcc/cp/repo.c	(working copy)
@@ -36,6 +36,7 @@
 #include "toplev.h"
 #include "diagnostic.h"
 #include "flags.h"
+#include "langhooks.h"
 
 static char *extract_string (char **);
 static const char *get_base_filename (const char *);
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 133392)
+++ gcc/cp/decl.c	(working copy)
@@ -53,6 +53,7 @@
 #include "timevar.h"
 #include "tree-flow.h"
 #include "pointer-set.h"
+#include "langhooks.h"
 
 static tree grokparms (cp_parameter_declarator *, tree *);
 static const char *redeclaration_error_message (tree, tree);
Index: gcc/cp/method.c
===================================================================
--- gcc/cp/method.c	(revision 133392)
+++ gcc/cp/method.c	(working copy)
@@ -38,6 +38,7 @@
 #include "target.h"
 #include "tree-pass.h"
 #include "diagnostic.h"
+#include "langhooks.h"
 
 /* Various flags to control the mangling process.  */
 
Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c	(revision 133392)
+++ gcc/cp/except.c	(working copy)
@@ -38,6 +38,7 @@
 #include "tree-inline.h"
 #include "tree-iterator.h"
 #include "target.h"
+#include "langhooks.h"
 
 static void push_eh_cleanup (tree);
 static tree prepare_eh_type (tree);
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c	(revision 133392)
+++ gcc/cp/error.c	(working copy)
@@ -30,6 +30,7 @@
 #include "diagnostic.h"
 #include "langhooks-def.h"
 #include "cxx-pretty-print.h"
+#include "langhooks.h"
 
 #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
 
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c	(revision 133392)
+++ gcc/cp/tree.c	(working copy)
@@ -37,6 +37,7 @@
 #include "target.h"
 #include "convert.h"
 #include "tree-flow.h"
+#include "langhooks.h"
 
 static tree bot_manip (tree *, int *, void *);
 static tree bot_replace (tree *, int *, void *);
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 133392)
+++ gcc/cp/mangle.c	(working copy)
@@ -1,5 +1,5 @@
 /* Name mangling for the 3.0 C++ ABI.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
    Free Software Foundation, Inc.
    Written by Alex Samuel <samuel@codesourcery.com>
 
@@ -58,6 +58,7 @@
 #include "varray.h"
 #include "flags.h"
 #include "target.h"
+#include "langhooks.h"
 
 /* Debugging support.  */
 
@@ -117,13 +118,6 @@
    allocated on the name_obstack.  */
 static void *name_base;
 
-/* An incomplete mangled name.  There will be no NUL terminator.  If
-   there is no incomplete mangled name, this variable is NULL.  */
-static char *partially_mangled_name;
-
-/* The number of characters in the PARTIALLY_MANGLED_NAME.  */
-static size_t partially_mangled_name_len;
-
 /* Indices into subst_identifiers.  These are identifiers used in
    special substitution rules.  */
 typedef enum
@@ -217,11 +211,11 @@
 static void write_discriminator (const int);
 static void write_local_name (const tree, const tree, const tree);
 static void dump_substitution_candidates (void);
-static const char *mangle_decl_string (const tree);
+static tree mangle_decl_string (const tree);
 
 /* Control functions.  */
 
-static inline void start_mangling (const tree, bool);
+static inline void start_mangling (const tree);
 static inline const char *finish_mangling (const bool);
 static tree mangle_special_for_type (const tree, const char *);
 
@@ -259,42 +253,6 @@
 #define write_unsigned_number(NUMBER)					\
   write_number ((NUMBER), /*unsigned_p=*/1, 10)
 
-/* Save the current (incomplete) mangled name and release the obstack
-   storage holding it.  This function should be used during mangling
-   when making a call that could result in a call to get_identifier,
-   as such a call will clobber the same obstack being used for
-   mangling.  This function may not be called twice without an
-   intervening call to restore_partially_mangled_name.  */
-
-static void
-save_partially_mangled_name (void)
-{
-  if (mangle_obstack == &ident_hash->stack)
-    {
-      gcc_assert (!partially_mangled_name);
-      partially_mangled_name_len = obstack_object_size (mangle_obstack);
-      partially_mangled_name = XNEWVEC (char, partially_mangled_name_len);
-      memcpy (partially_mangled_name, obstack_base (mangle_obstack),
-	      partially_mangled_name_len);
-      obstack_free (mangle_obstack, obstack_finish (mangle_obstack));
-    }
-}
-
-/* Restore the incomplete mangled name saved with
-   save_partially_mangled_name.  */
-
-static void
-restore_partially_mangled_name (void)
-{
-  if (partially_mangled_name)
-    {
-      obstack_grow (mangle_obstack, partially_mangled_name,
-		    partially_mangled_name_len);
-      free (partially_mangled_name);
-      partially_mangled_name = NULL;
-    }
-}
-
 /* If DECL is a template instance, return nonzero and, if
    TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info.
    Otherwise return zero.  */
@@ -743,9 +701,7 @@
 
       if (decl_is_template_id (decl, NULL))
 	{
-	  save_partially_mangled_name ();
 	  fn_type = get_mostly_instantiated_function_type (decl);
-	  restore_partially_mangled_name ();
 	  /* FN_TYPE will not have parameter types for in-charge or
 	     VTT parameters.  Therefore, we pass NULL_TREE to
 	     write_bare_function_type -- otherwise, it will get
@@ -1110,9 +1066,7 @@
       if (decl_is_template_id (decl, NULL))
 	{
 	  tree fn_type;
-	  save_partially_mangled_name ();
 	  fn_type = get_mostly_instantiated_function_type (decl);
-	  restore_partially_mangled_name ();
 	  type = TREE_TYPE (fn_type);
 	}
       else
@@ -2562,26 +2516,21 @@
 /* Start mangling ENTITY.  */
 
 static inline void
-start_mangling (const tree entity, const bool ident_p)
+start_mangling (const tree entity)
 {
   G.entity = entity;
   G.need_abi_warning = false;
-  if (!ident_p)
-    {
-      obstack_free (&name_obstack, name_base);
-      mangle_obstack = &name_obstack;
-      name_base = obstack_alloc (&name_obstack, 0);
-    }
-  else
-    mangle_obstack = &ident_hash->stack;
+  obstack_free (&name_obstack, name_base);
+  mangle_obstack = &name_obstack;
+  name_base = obstack_alloc (&name_obstack, 0);
 }
 
-/* Done with mangling.  Return the generated mangled name.  If WARN is
-   true, and the name of G.entity will be mangled differently in a
-   future version of the ABI, issue a warning.  */
+/* Done with mangling. If WARN is true, and the name of G.entity will
+   be mangled differently in a future version of the ABI, issue a
+   warning.  */
 
-static inline const char *
-finish_mangling (const bool warn)
+static void
+finish_mangling_internal (const bool warn)
 {
   if (warn_abi && warn && G.need_abi_warning)
     warning (OPT_Wabi, "the mangled name of %qD will change in a future "
@@ -2593,10 +2542,29 @@
 
   /* Null-terminate the string.  */
   write_char ('\0');
+}
 
+
+/* Like finish_mangling_internal, but return the mangled string.  */
+
+static inline const char *
+finish_mangling (const bool warn)
+{
+  finish_mangling_internal (warn);
   return (const char *) obstack_finish (mangle_obstack);
 }
 
+/* Like finish_mangling_internal, but return an identifier.  */
+
+static tree
+finish_mangling_get_identifier (const bool warn)
+{
+  finish_mangling_internal (warn);
+  /* Don't obstack_finish here, and the next start_mangling will
+     remove the identifier.  */
+  return get_identifier ((const char *) name_base);
+}
+
 /* Initialize data structures for mangling.  */
 
 void
@@ -2618,41 +2586,31 @@
 
 /* Generate the mangled name of DECL.  */
 
-static const char *
+static tree
 mangle_decl_string (const tree decl)
 {
-  const char *result;
+  tree result;
 
-  start_mangling (decl, /*ident_p=*/true);
+  start_mangling (decl);
 
   if (TREE_CODE (decl) == TYPE_DECL)
     write_type (TREE_TYPE (decl));
   else
     write_mangled_name (decl, true);
 
-  result = finish_mangling (/*warn=*/true);
+  result = finish_mangling_get_identifier (/*warn=*/true);
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_decl_string = '%s'\n\n", result);
+    fprintf (stderr, "mangle_decl_string = '%s'\n\n",
+	     IDENTIFIER_POINTER (result));
   return result;
 }
 
-/* Like get_identifier, except that NAME is assumed to have been
-   allocated on the obstack used by the identifier hash table.  */
-
-static inline tree
-get_identifier_nocopy (const char *name)
-{
-  hashnode ht_node = ht_lookup (ident_hash, (const unsigned char *) name,
-				strlen (name), HT_ALLOCED);
-  return HT_IDENT_TO_GCC_IDENT (ht_node);
-}
-
 /* Create an identifier for the external mangled name of DECL.  */
 
 void
 mangle_decl (const tree decl)
 {
-  tree id = get_identifier_nocopy (mangle_decl_string (decl));
+  tree id = mangle_decl_string (decl);
   id = targetm.mangle_decl_assembler_name (decl, id);
   SET_DECL_ASSEMBLER_NAME (decl, id);
 }
@@ -2664,7 +2622,7 @@
 {
   const char *result;
 
-  start_mangling (type, /*ident_p=*/false);
+  start_mangling (type);
   write_type (type);
   result = finish_mangling (/*warn=*/false);
   if (DEBUG_MANGLE)
@@ -2679,11 +2637,11 @@
 static tree
 mangle_special_for_type (const tree type, const char *code)
 {
-  const char *result;
+  tree result;
 
   /* We don't have an actual decl here for the special component, so
      we can't just process the <encoded-name>.  Instead, fake it.  */
-  start_mangling (type, /*ident_p=*/true);
+  start_mangling (type);
 
   /* Start the mangling.  */
   write_string ("_Z");
@@ -2691,12 +2649,13 @@
 
   /* Add the type.  */
   write_type (type);
-  result = finish_mangling (/*warn=*/false);
+  result = finish_mangling_get_identifier (/*warn=*/false);
 
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_special_for_type = %s\n\n", result);
+    fprintf (stderr, "mangle_special_for_type = %s\n\n",
+	     IDENTIFIER_POINTER (result));
 
-  return get_identifier_nocopy (result);
+  return result;
 }
 
 /* Create an identifier for the mangled representation of the typeinfo
@@ -2750,9 +2709,9 @@
 tree
 mangle_ctor_vtbl_for_type (const tree type, const tree binfo)
 {
-  const char *result;
+  tree result;
 
-  start_mangling (type, /*ident_p=*/true);
+  start_mangling (type);
 
   write_string ("_Z");
   write_string ("TC");
@@ -2761,10 +2720,11 @@
   write_char ('_');
   write_type (BINFO_TYPE (binfo));
 
-  result = finish_mangling (/*warn=*/false);
+  result = finish_mangling_get_identifier (/*warn=*/false);
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n", result);
-  return get_identifier_nocopy (result);
+    fprintf (stderr, "mangle_ctor_vtbl_for_type = %s\n\n",
+	     IDENTIFIER_POINTER (result));
+  return result;
 }
 
 /* Mangle a this pointer or result pointer adjustment.
@@ -2806,9 +2766,9 @@
 mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
 	      tree virtual_offset)
 {
-  const char *result;
+  tree result;
 
-  start_mangling (fn_decl, /*ident_p=*/true);
+  start_mangling (fn_decl);
 
   write_string ("_Z");
   write_char ('T');
@@ -2839,10 +2799,10 @@
   /* Scoped name.  */
   write_encoding (fn_decl);
 
-  result = finish_mangling (/*warn=*/false);
+  result = finish_mangling_get_identifier (/*warn=*/false);
   if (DEBUG_MANGLE)
-    fprintf (stderr, "mangle_thunk = %s\n\n", result);
-  return get_identifier_nocopy (result);
+    fprintf (stderr, "mangle_thunk = %s\n\n", IDENTIFIER_POINTER (result));
+  return result;
 }
 
 /* This hash table maps TYPEs to the IDENTIFIER for a conversion
@@ -2914,7 +2874,7 @@
 tree
 mangle_guard_variable (const tree variable)
 {
-  start_mangling (variable, /*ident_p=*/true);
+  start_mangling (variable);
   write_string ("_ZGV");
   if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
     /* The name of a guard variable for a reference temporary should refer
@@ -2922,7 +2882,7 @@
     write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
   else
     write_name (variable, /*ignore_local_scope=*/0);
-  return get_identifier_nocopy (finish_mangling (/*warn=*/false));
+  return finish_mangling_get_identifier (/*warn=*/false);
 }
 
 /* Return an identifier for the name of a temporary variable used to
@@ -2932,10 +2892,10 @@
 tree
 mangle_ref_init_variable (const tree variable)
 {
-  start_mangling (variable, /*ident_p=*/true);
+  start_mangling (variable);
   write_string ("_ZGR");
   write_name (variable, /*ignore_local_scope=*/0);
-  return get_identifier_nocopy (finish_mangling (/*warn=*/false));
+  return finish_mangling_get_identifier (/*warn=*/false);
 }
 
 
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 133392)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -209,6 +209,9 @@
   cxx_binding *bindings;
   tree class_template_info;
   tree label_value;
+  /* This must be last, as we use the struct hack to store the
+     identifier characters at the end of the object.  */
+  struct cpp_hashnode node;
 };
 
 /* In an IDENTIFIER_NODE, nonzero if this identifier is actually a
Index: gcc/cp/cxx-pretty-print.c
===================================================================
--- gcc/cp/cxx-pretty-print.c	(revision 133392)
+++ gcc/cp/cxx-pretty-print.c	(working copy)
@@ -26,6 +26,7 @@
 #include "cxx-pretty-print.h"
 #include "cp-tree.h"
 #include "toplev.h"
+#include "langhooks.h"
 
 static void pp_cxx_unqualified_id (cxx_pretty_printer *, tree);
 static void pp_cxx_nested_name_specifier (cxx_pretty_printer *, tree);
Index: gcc/cp/cp-lang.c
===================================================================
--- gcc/cp/cp-lang.c	(revision 133392)
+++ gcc/cp/cp-lang.c	(working copy)
@@ -58,6 +58,10 @@
 #undef LANG_HOOKS_INIT_TS
 #define LANG_HOOKS_INIT_TS cp_init_ts
 
+#undef LANG_HOOKS_IDENTIFIER_OFFSET
+#define LANG_HOOKS_IDENTIFIER_OFFSET \
+  offsetof (struct lang_identifier, node.ident)
+
 /* Each front end provides its own lang hook initializer.  */
 const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 133392)
+++ gcc/cp/pt.c	(working copy)
@@ -45,6 +45,7 @@
 #include "timevar.h"
 #include "tree-iterator.h"
 #include "vecprim.h"
+#include "langhooks.h"
 
 /* The type of functions taking a tree, and some additional data, and
    returning an int.  */
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 133392)
+++ gcc/cp/semantics.c	(working copy)
@@ -46,6 +46,7 @@
 #include "tree-iterator.h"
 #include "vec.h"
 #include "target.h"
+#include "langhooks.h"
 
 /* There routines provide a modular interface to perform many parsing
    operations.  They may therefore be used during actual parsing, or
Index: gcc/cp/name-lookup.c
===================================================================
--- gcc/cp/name-lookup.c	(revision 133392)
+++ gcc/cp/name-lookup.c	(working copy)
@@ -32,6 +32,7 @@
 #include "diagnostic.h"
 #include "debug.h"
 #include "c-pragma.h"
+#include "langhooks.h"
 
 /* The bindings for a particular name in a particular scope.  */
 
Index: gcc/cp/lex.c
===================================================================
--- gcc/cp/lex.c	(revision 133392)
+++ gcc/cp/lex.c	(working copy)
@@ -37,6 +37,7 @@
 #include "output.h"
 #include "tm_p.h"
 #include "timevar.h"
+#include "langhooks.h"
 
 static int interface_strcmp (const char *);
 static void init_cp_pragma (void);
@@ -518,7 +519,7 @@
   else if (fname == 0)
     filename = lbasename (input_filename);
   else
-    filename = ggc_strdup (TREE_STRING_POINTER (fname));
+    filename = TREE_STRING_POINTER (fname);
 
   finfo = get_fileinfo (input_filename);
 
@@ -566,7 +567,7 @@
     }
   else
     {
-      filename = ggc_strdup (TREE_STRING_POINTER (fname));
+      filename = TREE_STRING_POINTER (fname);
       if (cpp_included_before (parse_in, filename, input_location))
 	warning (0, "#pragma implementation for %qs appears after "
 		 "file is included", filename);
@@ -580,7 +581,7 @@
   if (ifiles == 0)
     {
       ifiles = XNEW (struct impl_files);
-      ifiles->filename = filename;
+      ifiles->filename = xstrdup (filename);
       ifiles->next = impl_file_chain;
       impl_file_chain = ifiles;
     }
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	(revision 133392)
+++ gcc/cp/decl2.c	(working copy)
@@ -50,6 +50,7 @@
 #include "c-pragma.h"
 #include "tree-dump.h"
 #include "intl.h"
+#include "langhooks.h"
 
 extern cpp_reader *parse_in;
 
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 133392)
+++ gcc/cp/parser.c	(working copy)
@@ -37,6 +37,7 @@
 #include "target.h"
 #include "cgraph.h"
 #include "c-common.h"
+#include "langhooks.h"
 
 
 /* The lexer.  */
Index: gcc/c-objc-common.h
===================================================================
--- gcc/c-objc-common.h	(revision 133392)
+++ gcc/c-objc-common.h	(working copy)
@@ -29,6 +29,8 @@
 
 #undef LANG_HOOKS_IDENTIFIER_SIZE
 #define LANG_HOOKS_IDENTIFIER_SIZE C_SIZEOF_STRUCT_LANG_IDENTIFIER
+#undef LANG_HOOKS_IDENTIFIER_OFFSET
+#define LANG_HOOKS_IDENTIFIER_OFFSET C_IDENTIFIER_OFFSET
 #undef LANG_HOOKS_FINISH
 #define LANG_HOOKS_FINISH c_common_finish
 #undef LANG_HOOKS_INIT_OPTIONS
Index: gcc/c-tree.h
===================================================================
--- gcc/c-tree.h	(revision 133392)
+++ gcc/c-tree.h	(working copy)
@@ -1,6 +1,6 @@
 /* Definitions for C parsing and type checking.
    Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -28,8 +28,13 @@
 /* struct lang_identifier is private to c-decl.c, but langhooks.c needs to
    know how big it is.  This is sanity-checked in c-decl.c.  */
 #define C_SIZEOF_STRUCT_LANG_IDENTIFIER \
-  (sizeof (struct c_common_identifier) + 3 * sizeof (void *))
+  (sizeof (struct c_common_identifier) + 3 * sizeof (void *) \
+   + sizeof (struct cpp_hashnode))
 
+#define C_IDENTIFIER_OFFSET \
+  (sizeof (struct c_common_identifier) + 3 * sizeof (void *) \
+   + offsetof (struct cpp_hashnode, ident))
+
 /* Language-specific declaration information.  */
 
 struct lang_decl GTY(())
Index: gcc/ada/trans.c
===================================================================
--- gcc/ada/trans.c	(revision 133392)
+++ gcc/ada/trans.c	(working copy)
@@ -56,6 +56,7 @@
 #include "einfo.h"
 #include "ada-tree.h"
 #include "gigi.h"
+#include "langhooks.h"
 
 /* We should avoid allocating more than ALLOCA_THRESHOLD bytes via alloca,
    for fear of running out of stack space.  If we need more, we use xmalloc
Index: gcc/ada/ada-tree.h
===================================================================
--- gcc/ada/ada-tree.h	(revision 133392)
+++ gcc/ada/ada-tree.h	(working copy)
@@ -32,12 +32,21 @@
 };
 #undef DEFTREECODE
 
+struct lang_identifier GTY(())
+{
+  struct tree_identifier common;
+
+  /* The identifier allocation code requires this field to be last.  */
+  struct ht_identifier id;
+};
+
 /* Ada uses the lang_decl and lang_type fields to hold a tree.  */
 union lang_tree_node
-  GTY((desc ("0"),
+  GTY((desc ("TREE_CODE (&%h.t) == IDENTIFIER_NODE"),
        chain_next ("(union lang_tree_node *)GENERIC_NEXT (&%h.t)")))
 {
   union tree_node GTY((tag ("0"))) t;
+  struct lang_identifier GTY((tag ("1"))) identifier;
 };
 struct lang_decl GTY(()) {tree t; };
 struct lang_type GTY(()) {tree t; };
Index: gcc/ada/utils.c
===================================================================
--- gcc/ada/utils.c	(revision 133392)
+++ gcc/ada/utils.c	(working copy)
@@ -42,6 +42,7 @@
 #include "tree-gimple.h"
 #include "tree-dump.h"
 #include "pointer-set.h"
+#include "langhooks.h"
 
 #include "ada.h"
 #include "types.h"
Index: gcc/ada/misc.c
===================================================================
--- gcc/ada/misc.c	(revision 133392)
+++ gcc/ada/misc.c	(working copy)
@@ -107,8 +107,6 @@
 
 #undef  LANG_HOOKS_NAME
 #define LANG_HOOKS_NAME			"GNU Ada"
-#undef  LANG_HOOKS_IDENTIFIER_SIZE
-#define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct tree_identifier)
 #undef  LANG_HOOKS_INIT
 #define LANG_HOOKS_INIT			gnat_init
 #undef  LANG_HOOKS_INIT_OPTIONS
Index: gcc/ada/decl.c
===================================================================
--- gcc/ada/decl.c	(revision 133392)
+++ gcc/ada/decl.c	(working copy)
@@ -35,6 +35,7 @@
 #include "obstack.h"
 #include "target.h"
 #include "expr.h"
+#include "langhooks.h"
 
 #include "ada.h"
 #include "types.h"
Index: gcc/ada/utils2.c
===================================================================
--- gcc/ada/utils2.c	(revision 133392)
+++ gcc/ada/utils2.c	(working copy)
@@ -45,6 +45,7 @@
 #include "einfo.h"
 #include "ada-tree.h"
 #include "gigi.h"
+#include "langhooks.h"
 
 static tree find_common_type (tree, tree);
 static bool contains_save_expr_p (tree);
Index: gcc/c-aux-info.c
===================================================================
--- gcc/c-aux-info.c	(revision 133392)
+++ gcc/c-aux-info.c	(working copy)
@@ -29,6 +29,7 @@
 #include "tree.h"
 #include "c-tree.h"
 #include "toplev.h"
+#include "langhooks.h"
 
 enum formals_style_enum {
   ansi,
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c	(revision 133392)
+++ gcc/c-decl.c	(working copy)
@@ -238,12 +238,20 @@
   struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */
   struct c_binding *tag_binding;    /* struct/union/enum tags */
   struct c_binding *label_binding;  /* labels */
+
+  /* This must be last, as we use the struct hack to store the
+     identifier characters at the end of the object.  */
+  struct cpp_hashnode node;
 };
 
 /* Validate c-lang.c's assumptions.  */
 extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate
 [(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1];
 
+extern char C_IDENTIFIER_OFFSET_isnt_accurate
+[(offsetof(struct lang_identifier, node.ident) == C_IDENTIFIER_OFFSET) ? 1 : -1];
+
+
 /* The resulting tree type.  */
 
 union lang_tree_node
Index: gcc/fortran/f95-lang.c
===================================================================
--- gcc/fortran/f95-lang.c	(revision 133392)
+++ gcc/fortran/f95-lang.c	(working copy)
@@ -55,6 +55,9 @@
 GTY(())
 {
   struct tree_identifier common;
+
+  /* The identifier allocation code requires this field to be last.  */
+  struct ht_identifier id;
 };
 
 /* The resulting tree type.  */
Index: gcc/fortran/iresolve.c
===================================================================
--- gcc/fortran/iresolve.c	(revision 133392)
+++ gcc/fortran/iresolve.c	(working copy)
@@ -33,6 +33,7 @@
 #include "tree.h"
 #include "gfortran.h"
 #include "intrinsic.h"
+#include "langhooks.h"
 
 /* Given printf-like arguments, return a stable version of the result string. 
 
Index: gcc/fortran/trans-decl.c
===================================================================
--- gcc/fortran/trans-decl.c	(revision 133392)
+++ gcc/fortran/trans-decl.c	(working copy)
@@ -42,6 +42,7 @@
 #include "trans-const.h"
 /* Only for gfc_trans_code.  Shouldn't need to include this.  */
 #include "trans-stmt.h"
+#include "langhooks.h"
 
 #define MAX_LABEL_VALUE 99999
 
Index: gcc/c-pretty-print.c
===================================================================
--- gcc/c-pretty-print.c	(revision 133392)
+++ gcc/c-pretty-print.c	(working copy)
@@ -29,6 +29,7 @@
 #include "c-tree.h"
 #include "tree-iterator.h"
 #include "diagnostic.h"
+#include "langhooks.h"
 
 /* The pretty-printer code is primarily designed to closely follow
    (GNU) C and C++ grammars.  That is to be contrasted with spaghetti
Index: gcc/langhooks.h
===================================================================
--- gcc/langhooks.h	(revision 133392)
+++ gcc/langhooks.h	(working copy)
@@ -242,6 +242,9 @@
      identifier nodes long enough for the language-specific slots.  */
   size_t identifier_size;
 
+  /* Offset of the ht_identifier sub-structure in a lang_identifier.  */
+  size_t identifier_offset;
+
   /* Determines the size of any language-specific tcc_constant or
      tcc_exceptional nodes.  Since it is called from make_node, the
      only information available is the tree code.  Expected to die
Index: gcc/print-rtl.c
===================================================================
--- gcc/print-rtl.c	(revision 133392)
+++ gcc/print-rtl.c	(working copy)
@@ -40,6 +40,7 @@
 #include "flags.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
+#include "langhooks.h"
 #endif
 
 static FILE *outfile;
Index: gcc/ggc.h
===================================================================
--- gcc/ggc.h	(revision 133392)
+++ gcc/ggc.h	(working copy)
@@ -118,7 +118,7 @@
 extern int ggc_marked_p	(const void *);
 
 /* Mark the entries in the string pool.  */
-extern void ggc_mark_stringpool	(void);
+extern void ggc_mark_stringpool	(bool);
 
 /* Call ggc_set_mark on all the roots.  */
 
@@ -134,7 +134,7 @@
 
 extern void gt_pch_p_S (void *, void *, gt_pointer_operator, void *);
 extern void gt_pch_n_S (const void *);
-extern void gt_ggc_m_S (void *);
+extern void gt_ggc_m_S (const void *);
 
 /* Initialize the string pool.  */
 extern void init_stringpool (void);
@@ -200,6 +200,9 @@
 /* When set, ggc_collect will do collection.  */
 extern bool ggc_force_collect;
 
+/* When true, protect the contents of the identifier hash table.  */
+extern bool ggc_protect_identifiers;
+
 /* The internal primitive.  */
 extern void *ggc_alloc_stat (size_t MEM_STAT_DECL);
 #define ggc_alloc(s) ggc_alloc_stat (s MEM_STAT_INFO)
Index: gcc/c-pragma.c
===================================================================
--- gcc/c-pragma.c	(revision 133392)
+++ gcc/c-pragma.c	(working copy)
@@ -37,6 +37,7 @@
 #include "target.h"
 #include "diagnostic.h"
 #include "opts.h"
+#include "langhooks.h"
 
 #define GCC_BAD(gmsgid) \
   do { warning (OPT_Wpragmas, gmsgid); return; } while (0)
Index: gcc/ggc-common.c
===================================================================
--- gcc/ggc-common.c	(revision 133392)
+++ gcc/ggc-common.c	(working copy)
@@ -50,6 +50,9 @@
 /* When set, ggc_collect will do collection.  */
 bool ggc_force_collect;
 
+/* When true, protect the contents of the identifier hash table.  */
+bool ggc_protect_identifiers = true;
+
 /* Statistics about the allocation.  */
 static ggc_statistics *ggc_stats;
 
@@ -103,7 +106,8 @@
       for (i = 0; i < rti->nelt; i++)
 	(*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
 
-  ggc_mark_stringpool ();
+  if (ggc_protect_identifiers)
+    ggc_mark_stringpool (true);
 
   /* Now scan all hash tables that have objects which are to be deleted if
      they are not already marked.  */
@@ -115,6 +119,9 @@
 	  htab_traverse_noresize (*cti->base, ggc_htab_delete, (void *) cti);
 	  ggc_set_mark ((*cti->base)->entries);
 	}
+
+  if (! ggc_protect_identifiers)
+    ggc_mark_stringpool (false);
 }
 
 /* Allocate a block of memory, then clear it.  */
Index: gcc/stringpool.c
===================================================================
--- gcc/stringpool.c	(revision 133392)
+++ gcc/stringpool.c	(working copy)
@@ -35,6 +35,7 @@
 #include "tree.h"
 #include "symtab.h"
 #include "cpplib.h"
+#include "langhooks.h"
 
 /* The "" allocated string.  */
 const char empty_string[] = "";
@@ -47,9 +48,8 @@
 };
 
 struct ht *ident_hash;
-static struct obstack string_stack;
 
-static hashnode alloc_node (hash_table *);
+static hashnode alloc_node (hash_table *, size_t);
 static int mark_ident (struct cpp_reader *, hashnode, const void *);
 
 static void *
@@ -66,14 +66,16 @@
   ident_hash = ht_create (14);
   ident_hash->alloc_node = alloc_node;
   ident_hash->alloc_subobject = stringpool_ggc_alloc;
-  gcc_obstack_init (&string_stack);
 }
 
 /* Allocate a hash node.  */
 static hashnode
-alloc_node (hash_table *table ATTRIBUTE_UNUSED)
+alloc_node (hash_table *table ATTRIBUTE_UNUSED, size_t length)
 {
-  return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
+  /* identifier_size includes 1 byte for the string, so we don't need
+     to add one for the \0.  */
+  size_t size = lang_hooks.identifier_size + length;
+  return GCC_IDENT_TO_HT_IDENT (build_identifier (size));
 }
 
 /* Allocate and return a string constant of length LENGTH, containing
@@ -85,6 +87,8 @@
 const char *
 ggc_alloc_string (const char *contents, int length)
 {
+  char *result;
+
   if (length == -1)
     length = strlen (contents);
 
@@ -93,8 +97,9 @@
   if (length == 1 && ISDIGIT (contents[0]))
     return digit_string (contents[0] - '0');
 
-  obstack_grow0 (&string_stack, contents, length);
-  return XOBFINISH (&string_stack, const char *);
+  result = ggc_alloc (length + 1);
+  memcpy (result, contents, length + 1);
+  return (const char *) result;
 }
 
 /* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
@@ -163,25 +168,26 @@
   return 1;
 }
 
+/* Decide whether an identifier should be removed.  */
+static int
+check_ident (hashnode h)
+{
+  return ggc_marked_p (HT_IDENT_TO_GCC_IDENT (h));
+}
+
 /* Mark the trees hanging off the identifier node for GGC.  These are
    handled specially (not using gengtype) because of the special
    treatment for strings.  */
 
 void
-ggc_mark_stringpool (void)
+ggc_mark_stringpool (bool marking)
 {
-  ht_forall (ident_hash, mark_ident, NULL);
+  if (marking)
+    ht_forall (ident_hash, mark_ident, NULL);
+  else
+    ht_remove_identifiers (ident_hash, check_ident);
 }
 
-/* Strings are _not_ GCed, but this routine exists so that a separate
-   roots table isn't needed for the few global variables that refer
-   to strings.  */
-
-void
-gt_ggc_m_S (void *x ATTRIBUTE_UNUSED)
-{
-}
-
 /* Pointer-walking routine for strings (not very interesting, since
    strings don't contain pointers).  */
 
Index: gcc/ggc-page.c
===================================================================
--- gcc/ggc-page.c	(revision 133392)
+++ gcc/ggc-page.c	(working copy)
@@ -1,5 +1,5 @@
 /* "Bag-of-pages" garbage collector for the GNU compiler.
-   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -31,6 +31,7 @@
 #include "timevar.h"
 #include "params.h"
 #include "tree-flow.h"
+#include "langhooks.h"
 
 /* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a
    file open.  Prefer either to valloc.  */
@@ -1256,6 +1257,58 @@
   return result;
 }
 
+void
+gt_ggc_m_S (const void *p)
+{
+  page_entry *entry;
+  unsigned bit, word;
+  unsigned long mask;
+  unsigned long offset;
+
+  if (!p || !ggc_allocated_p (p))
+    return;
+
+  /* Look up the page on which the object is alloced.  .  */
+  entry = lookup_page_table_entry (p);
+  gcc_assert (entry);
+
+  /* Calculate the index of the object on the page; this is its bit
+     position in the in_use_p bitmap.  Note that because a char* might
+     point to the middle of an object, we need special code here to
+     make sure P points to the start of an object.  */
+  offset = ((const char *) p - entry->page) % object_size_table[entry->order];
+  if (offset)
+    {
+      /* Here we've seen a char* which does not point to the beginning
+	 of an allocated object.  We assume it either points to the
+	 middle of an IDENTIFIER_NODE, or to the middle of a
+	 STRING_CST.  */
+      gcc_assert (offset == (lang_hooks.identifier_offset
+			     + offsetof (struct ht_identifier, str))
+		  || offset == offsetof (struct tree_string, str));
+      p = ((const char *) p) - offset;
+      gt_ggc_mx_lang_tree_node ((void *) p);
+      return;
+    }
+
+  bit = OFFSET_TO_BIT (((const char *) p) - entry->page, entry->order);
+  word = bit / HOST_BITS_PER_LONG;
+  mask = (unsigned long) 1 << (bit % HOST_BITS_PER_LONG);
+
+  /* If the bit was previously set, skip it.  */
+  if (entry->in_use_p[word] & mask)
+    return;
+
+  /* Otherwise set it, and decrement the free object count.  */
+  entry->in_use_p[word] |= mask;
+  entry->num_free_objects -= 1;
+
+  if (GGC_DEBUG_LEVEL >= 4)
+    fprintf (G.debug_file, "Marking %p\n", p);
+
+  return;
+}
+
 /* If P is not marked, marks it and return false.  Otherwise return true.
    P must have been allocated by the GC allocator; it mustn't point to
    static objects, stack variables, or memory allocated with malloc.  */
Index: gcc/tree-outof-ssa.c
===================================================================
--- gcc/tree-outof-ssa.c	(revision 133392)
+++ gcc/tree-outof-ssa.c	(working copy)
@@ -33,6 +33,7 @@
 #include "tree-ssa-live.h"
 #include "tree-pass.h"
 #include "toplev.h"
+#include "langhooks.h"
 
 
 /* Used to hold all the components required to do SSA PHI elimination.
Index: gcc/var-tracking.c
===================================================================
--- gcc/var-tracking.c	(revision 133392)
+++ gcc/var-tracking.c	(working copy)
@@ -105,6 +105,7 @@
 #include "expr.h"
 #include "timevar.h"
 #include "tree-pass.h"
+#include "langhooks.h"
 
 /* Type of micro operation.  */
 enum micro_operation_type
Index: gcc/c-common.h
===================================================================
--- gcc/c-common.h	(revision 133392)
+++ gcc/c-common.h	(working copy)
@@ -180,14 +180,16 @@
     CTI_MAX
 };
 
-#define C_RID_CODE(id)	(((struct c_common_identifier *) (id))->node.rid_code)
+#define C_RID_CODE(id) \
+  ((CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT (id)))->rid_code)
 
 /* Identifier part common to the C front ends.  Inherits from
    tree_identifier, despite appearances.  */
 struct c_common_identifier GTY(())
 {
   struct tree_common common;
-  struct cpp_hashnode node;
+  /* Any C-based FE has to have a cpp_hashnode in here, at the very
+     end.  */
 };
 
 #define wchar_type_node			c_global_trees[CTI_WCHAR_TYPE]
Index: gcc/langhooks-def.h
===================================================================
--- gcc/langhooks-def.h	(revision 133392)
+++ gcc/langhooks-def.h	(working copy)
@@ -82,6 +82,7 @@
 
 #define LANG_HOOKS_NAME			"GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct lang_identifier)
+#define LANG_HOOKS_IDENTIFIER_OFFSET    offsetof (struct lang_identifier, id)
 #define LANG_HOOKS_INIT			hook_bool_void_false
 #define LANG_HOOKS_FINISH		lhd_do_nothing
 #define LANG_HOOKS_PARSE_FILE		lhd_do_nothing_i
@@ -239,6 +240,7 @@
 #define LANG_HOOKS_INITIALIZER { \
   LANG_HOOKS_NAME, \
   LANG_HOOKS_IDENTIFIER_SIZE, \
+  LANG_HOOKS_IDENTIFIER_OFFSET, \
   LANG_HOOKS_TREE_SIZE, \
   LANG_HOOKS_INIT_OPTIONS, \
   LANG_HOOKS_INITIALIZE_DIAGNOSTICS, \
Index: libcpp/symtab.c
===================================================================
--- libcpp/symtab.c	(revision 133392)
+++ libcpp/symtab.c	(working copy)
@@ -1,5 +1,5 @@
 /* Hash tables.
-   Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003, 2004, 2007, 2008 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
@@ -31,7 +31,7 @@
    delete members from the table has been removed.  */
 
 static unsigned int calc_hash (const unsigned char *, size_t);
-static void ht_expand (hash_table *);
+static void ht_rehash (hash_table *, hashnode *, unsigned int, ht_rehash_fn);
 static double approx_sqrt (double);
 
 /* Calculate the hash of the string STR of length LEN.  */
@@ -107,6 +107,7 @@
   unsigned int index;
   size_t sizemask;
   hashnode node;
+  unsigned char *chars;
 
   sizemask = table->nslots - 1;
   index = hash & sizemask;
@@ -119,13 +120,7 @@
       if (node->hash_value == hash
 	  && HT_LEN (node) == (unsigned int) len
 	  && !memcmp (HT_STR (node), str, len))
-	{
-	  if (insert == HT_ALLOCED)
-	    /* The string we search for was placed at the end of the
-	       obstack.  Release it.  */
-	    obstack_free (&table->stack, (void *) str);
-	  return node;
-	}
+	return node;
 
       /* hash2 must be odd, so we're guaranteed to visit every possible
 	 location in the table during rehashing.  */
@@ -142,56 +137,58 @@
 	  if (node->hash_value == hash
 	      && HT_LEN (node) == (unsigned int) len
 	      && !memcmp (HT_STR (node), str, len))
-	    {
-	      if (insert == HT_ALLOCED)
-	      /* The string we search for was placed at the end of the
-		 obstack.  Release it.  */
-		obstack_free (&table->stack, (void *) str);
-	      return node;
-	    }
+	    return node;
 	}
     }
 
   if (insert == HT_NO_INSERT)
     return NULL;
 
-  node = (*table->alloc_node) (table);
+  node = (*table->alloc_node) (table, len);
   table->entries[index] = node;
 
   HT_LEN (node) = (unsigned int) len;
   node->hash_value = hash;
-  if (insert == HT_ALLOC)
-    HT_STR (node) = (const unsigned char *) obstack_copy0 (&table->stack,
-                                                           str, len);
-  else
-    HT_STR (node) = str;
 
+  /* It is ok to cast away const here.  */
+  chars = (unsigned char *) HT_STR (node);
+  strncpy ((char *) chars, (char *) str, len);
+  chars[len] = '\0';
+
   if (++table->nelements * 4 >= table->nslots * 3)
-    /* Must expand the string table.  */
-    ht_expand (table);
+    {
+      /* Must expand the string table.  */
+      unsigned int size = table->nslots * 2;
+      hashnode *nentries = XCNEWVEC (hashnode, size);
+      ht_rehash (table, nentries, size, NULL);
+    }
 
   return node;
 }
 
-/* Double the size of a hash table, re-hashing existing entries.  */
+/* Re-hash existing entries into a new array, with a new size.  If
+   PREDICATE is non-null, it is called for each entry; if it returns
+   false, the entry is not added to the new array.  */
 
 static void
-ht_expand (hash_table *table)
+ht_rehash (hash_table *table, hashnode *nentries, unsigned int size,
+	   ht_rehash_fn predicate)
 {
-  hashnode *nentries, *p, *limit;
-  unsigned int size, sizemask;
+  hashnode *p, *limit;
+  unsigned int sizemask;
+  unsigned int nelements = 0;
 
-  size = table->nslots * 2;
-  nentries = XCNEWVEC (hashnode, size);
   sizemask = size - 1;
 
   p = table->entries;
   limit = p + table->nslots;
   do
-    if (*p)
+    if (*p && (! predicate || (*predicate) (*p)))
       {
 	unsigned int index, hash, hash2;
 
+	++nelements;
+
 	hash = (*p)->hash_value;
 	index = hash & sizemask;
 
@@ -213,8 +210,20 @@
   table->entries_owned = true;
   table->entries = nentries;
   table->nslots = size;
+  table->nelements = nelements;
 }
 
+/* Bulk-remove entries from an identifier table according to the given
+   PREDICATE.  */
+void
+ht_remove_identifiers (hash_table *table, ht_rehash_fn predicate)
+{
+  hashnode *nentries = XCNEWVEC (hashnode, table->nslots);
+  if (! predicate)
+    abort ();
+  ht_rehash (table, nentries, table->nslots, predicate);
+}
+
 /* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
    the node, and V.  */
 void
Index: libcpp/include/cpplib.h
===================================================================
--- libcpp/include/cpplib.h	(revision 133392)
+++ libcpp/include/cpplib.h	(working copy)
@@ -562,8 +562,9 @@
   BT_COUNTER			/* `__COUNTER__' */
 };
 
-#define CPP_HASHNODE(HNODE)	((cpp_hashnode *) (HNODE))
-#define HT_NODE(NODE)		((ht_identifier *) (NODE))
+#define CPP_HASHNODE(HNODE) \
+  ((cpp_hashnode *) ((char *) (HNODE) - (offsetof (cpp_hashnode, ident))))
+#define HT_NODE(NODE)		(&((NODE)->ident))
 #define NODE_LEN(NODE)		HT_LEN (&(NODE)->ident)
 #define NODE_NAME(NODE)		HT_STR (&(NODE)->ident)
 
@@ -602,7 +603,6 @@
 
 struct cpp_hashnode GTY(())
 {
-  struct ht_identifier ident;
   unsigned int is_directive : 1;
   unsigned int directive_index : 7;	/* If is_directive,
 					   then index into directive table.
@@ -612,6 +612,7 @@
   unsigned char flags;			/* CPP flags.  */
 
   union _cpp_hashnode_value GTY ((desc ("CPP_HASHNODE_VALUE_IDX (%1)"))) value;
+  struct ht_identifier ident;
 };
 
 /* Call this first to get a handle to pass to other functions.
Index: libcpp/include/symtab.h
===================================================================
--- libcpp/include/symtab.h	(revision 133392)
+++ libcpp/include/symtab.h	(working copy)
@@ -1,5 +1,5 @@
 /* Hash tables.
-   Copyright (C) 2000, 2001, 2003, 2004, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2003, 2004, 2007, 2008 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
@@ -28,9 +28,9 @@
 typedef struct ht_identifier ht_identifier;
 struct ht_identifier GTY(())
 {
-  const unsigned char *str;
   unsigned int len;
   unsigned int hash_value;
+  const unsigned char str[1];
 };
 
 #define HT_LEN(NODE) ((NODE)->len)
@@ -39,7 +39,7 @@
 typedef struct ht hash_table;
 typedef struct ht_identifier *hashnode;
 
-enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED};
+enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC};
 
 /* An identifier hash table for cpplib and the front ends.  */
 struct ht
@@ -49,7 +49,7 @@
 
   hashnode *entries;
   /* Call back, allocate a node.  */
-  hashnode (*alloc_node) (hash_table *);
+  hashnode (*alloc_node) (hash_table *, size_t);
   /* Call back, allocate something that hangs off a node like a cpp_macro.  
      NULL means use the usual allocator.  */
   void * (*alloc_subobject) (size_t);
@@ -88,6 +88,13 @@
 typedef int (*ht_cb) (struct cpp_reader *, hashnode, const void *);
 extern void ht_forall (hash_table *, ht_cb, const void *);
 
+/* A predicate function used when removing entries from a table.
+   Returns zero if the entry should be removed.  */
+typedef int (*ht_rehash_fn) (hashnode);
+
+/* Remove entries from the table.  */
+extern void ht_remove_identifiers (hash_table *, ht_rehash_fn);
+
 /* Restore the hash table.  */
 extern void ht_load (hash_table *ht, hashnode *entries,
 		     unsigned int nslots, unsigned int nelements, bool own);
Index: libcpp/identifiers.c
===================================================================
--- libcpp/identifiers.c	(revision 133392)
+++ libcpp/identifiers.c	(working copy)
@@ -1,6 +1,6 @@
 /* Hash tables for the CPP library.
    Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
-   1999, 2000, 2001, 2002, 2007 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
    Written by Per Bothner, 1994.
    Based on CCCP program by Paul Rubin, June 1986
    Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -28,17 +28,18 @@
 #include "cpplib.h"
 #include "internal.h"
 
-static hashnode alloc_node (hash_table *);
+static hashnode alloc_node (hash_table *, size_t);
 
 /* Return an identifier node for hashtable.c.  Used by cpplib except
    when integrated with the C front ends.  */
 static hashnode
-alloc_node (hash_table *table)
+alloc_node (hash_table *table, size_t len)
 {
   cpp_hashnode *node;
+  size_t length = len + offsetof (cpp_hashnode, ident.str) + 1;
 
-  node = XOBNEW (&table->pfile->hash_ob, cpp_hashnode);
-  memset (node, 0, sizeof (cpp_hashnode));
+  node = (cpp_hashnode *) obstack_alloc (&table->pfile->hash_ob, length);
+  memset (node, 0, length);
   return HT_NODE (node);
 }
 
@@ -107,15 +108,31 @@
   return node && node->type == NT_MACRO;
 }
 
-/* We don't need a proxy since the hash table's identifier comes first
-   in cpp_hashnode.  However, in case this is ever changed, we have a
-   static assertion for it.  */
-extern char proxy_assertion_broken[offsetof (struct cpp_hashnode, ident) == 0 ? 1 : -1];
+/* Used to pass information from cpp_forall_identifiers through to the
+   user's callback.  */
+struct callback_info
+{
+  /* The user's callback.  */
+  cpp_cb cb;
+  /* The user's data.  */
+  void *v;
+};
 
+/* Handle mismatch between cpp_cb and ht_cb.  */
+static int
+cpp_ht_proxy (struct cpp_reader *reader, hashnode node, const void *ci)
+{
+  struct callback_info *info = (struct callback_info *) ci;
+  return (info->cb) (reader, CPP_HASHNODE (node), info->v);
+}
+
 /* For all nodes in the hashtable, callback CB with parameters PFILE,
    the node, and V.  */
 void
 cpp_forall_identifiers (cpp_reader *pfile, cpp_cb cb, void *v)
 {
-  ht_forall (pfile->hash_table, (ht_cb) cb, v);
+  struct callback_info info;
+  info.cb = cb;
+  info.v = v;
+  ht_forall (pfile->hash_table, cpp_ht_proxy, &info);
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]