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]

[PATCH] move many gc hashtab to hash_table


From: Trevor Saunders <tsaunders@mozilla.com>

Hi,

This changes almost all of the ggc htab that don't use the if_marked option to
be hash_tables.  I added a for_user gty attribute so that types could be used
from user marking routines without either using the mangled names or being
referenced in a template argument which was previously the only way to get
gengtype to emit user callable marking routines.

bootstrapped + regtested on x86_64-unknown-linux-gnu, ran make all-gcc for
ppc64-linux, ppc64-apple-darwin, mips-elf, m32c-elf, mep-elf, and
x86_64-apple-darwin.  I haven't heard back yet on my request for a cfarm
account so I haven't tried bootstrapping on other archs, but more testing is
most welcome. Ok?

Trev


gcc/

* asan.c, cfgloop.c, cfgloop.h, cgraph.c, cgraph.h,
	config/darwin.c, config/m32c/m32c.c, config/mep/mep.c,
	config/mips/mips.c, config/rs6000/rs6000.c, dwarf2out.c,
	function.c, function.h, gimple-ssa.h, libfuncs.h, optabs.c,
	output.h, rtl.h, sese.c, symtab.c, tree-cfg.c, tree-dfa.c,
	tree-ssa.c, varasm.c: Use hash-table instead of hashtab.
	* doc/gty.texi (for_user): Document new option.
	* gengtype.c (create_user_defined_type): Don't try to get a struct for
	char.
	(walk_type): Don't error out on for_user option.
	(write_func_for_structure): Emit user marking routines if requested by
	for_user option.
	(write_local_func_for_structure): Likewise.
	(main): Mark types with for_user option as used.
	* ggc.h (gt_pch_nx): Add overload for unsigned int.
	* hash-map.h (hash_map::hash_entry::pch_nx_helper): AddOverloads.
	* hash-table.h (ggc_hasher): New struct.
	(hash_table::create_ggc): New function.
	(gt_pch_nx): New overload for hash_table.

java/

	* class.c, decl.c, except.c, expr.c, java-tree.h, lang.c: Use
	hash_table instead of hashtab.

objc/

	* objc-act.c: use hash_table instead of hashtab.

cp/

	* cp-gimplify.c, cp-tree.h, decl.c, mangle.c, name-lookup.c,
	pt.c, semantics.c, tree.c, typeck2.c: Use hash_table instead of
	hashtab.

fortran/

	* trans-decl.c, trans.c, trans.h: Use hash_table instead of hashtab.

c-family/

	* c-common.c: Use hash_table instead of hashtab.



diff --git a/gcc/asan.c b/gcc/asan.c
index f520eab..15d1d97 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2337,15 +2337,15 @@ initialize_sanitizer_builtins (void)
 /* Called via htab_traverse.  Count number of emitted
    STRING_CSTs in the constant hash table.  */
 
-static int
-count_string_csts (void **slot, void *data)
+int
+count_string_csts (constant_descriptor_tree **slot,
+		   unsigned HOST_WIDE_INT *data)
 {
-  struct constant_descriptor_tree *desc
-    = (struct constant_descriptor_tree *) *slot;
+  struct constant_descriptor_tree *desc = *slot;
   if (TREE_CODE (desc->value) == STRING_CST
       && TREE_ASM_WRITTEN (desc->value)
       && asan_protect_global (desc->value))
-    ++*((unsigned HOST_WIDE_INT *) data);
+    ++* data;
   return 1;
 }
 
@@ -2358,20 +2358,18 @@ struct asan_add_string_csts_data
   vec<constructor_elt, va_gc> *v;
 };
 
-/* Called via htab_traverse.  Call asan_add_global
+/* Called via hash_table::traverse.  Call asan_add_global
    on emitted STRING_CSTs from the constant hash table.  */
 
-static int
-add_string_csts (void **slot, void *data)
+int
+add_string_csts (constant_descriptor_tree **slot,
+		 asan_add_string_csts_data *aascd)
 {
-  struct constant_descriptor_tree *desc
-    = (struct constant_descriptor_tree *) *slot;
+  struct constant_descriptor_tree *desc = *slot;
   if (TREE_CODE (desc->value) == STRING_CST
       && TREE_ASM_WRITTEN (desc->value)
       && asan_protect_global (desc->value))
     {
-      struct asan_add_string_csts_data *aascd
-	= (struct asan_add_string_csts_data *) data;
       asan_add_global (SYMBOL_REF_DECL (XEXP (desc->rtl, 0)),
 		       aascd->type, aascd->v);
     }
@@ -2406,8 +2404,9 @@ asan_finish_file (void)
     if (TREE_ASM_WRITTEN (vnode->decl)
 	&& asan_protect_global (vnode->decl))
       ++gcount;
-  htab_t const_desc_htab = constant_pool_htab ();
-  htab_traverse (const_desc_htab, count_string_csts, &gcount);
+  hash_table<tree_descriptor_hasher> *const_desc_htab = constant_pool_htab ();
+  const_desc_htab->traverse<unsigned HOST_WIDE_INT *, count_string_csts>
+    (&gcount);
   if (gcount)
     {
       tree type = asan_global_struct (), var, ctor;
@@ -2431,7 +2430,8 @@ asan_finish_file (void)
       struct asan_add_string_csts_data aascd;
       aascd.type = TREE_TYPE (type);
       aascd.v = v;
-      htab_traverse (const_desc_htab, add_string_csts, &aascd);
+      const_desc_htab->traverse<asan_add_string_csts_data *, add_string_csts>
+       	(&aascd);
       ctor = build_constructor (type, v);
       TREE_CONSTANT (ctor) = 1;
       TREE_STATIC (ctor) = 1;
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index b16d030..b27df18 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -4799,23 +4799,28 @@ c_apply_type_quals_to_decl (int type_quals, tree decl)
     }
 }
 
+struct c_type_hasher : ggc_hasher<tree>
+{
+  static hashval_t hash (tree);
+  static bool equal (tree, tree);
+};
+
 /* Hash function for the problem of multiple type definitions in
    different files.  This must hash all types that will compare
    equal via comptypes to the same value.  In practice it hashes
    on some of the simple stuff and leaves the details to comptypes.  */
 
-static hashval_t
-c_type_hash (const void *p)
+hashval_t
+c_type_hasher::hash (tree t)
 {
   int n_elements;
   int shift, size;
-  const_tree const t = (const_tree) p;
   tree t2;
   switch (TREE_CODE (t))
     {
     /* For pointers, hash on pointee type plus some swizzling.  */
     case POINTER_TYPE:
-      return c_type_hash (TREE_TYPE (t)) ^ 0x3003003;
+      return hash (TREE_TYPE (t)) ^ 0x3003003;
     /* Hash on number of elements and total size.  */
     case ENUMERAL_TYPE:
       shift = 3;
@@ -4847,7 +4852,13 @@ c_type_hash (const void *p)
   return ((size << 24) | (n_elements << shift));
 }
 
-static GTY((param_is (union tree_node))) htab_t type_hash_table;
+bool
+c_type_hasher::equal (tree t1, tree t2)
+{
+  return lang_hooks.types_compatible_p (t1, t2);
+}
+
+static GTY(()) hash_table<c_type_hasher> *type_hash_table;
 
 /* Return the typed-based alias set for T, which may be an expression
    or a type.  Return -1 if we don't do anything special.  */
@@ -4856,7 +4867,6 @@ alias_set_type
 c_common_get_alias_set (tree t)
 {
   tree u;
-  PTR *slot;
 
   /* For VLAs, use the alias set of the element type rather than the
      default of alias set 0 for types compared structurally.  */
@@ -4949,10 +4959,8 @@ c_common_get_alias_set (tree t)
   /* Look up t in hash table.  Only one of the compatible types within each
      alias set is recorded in the table.  */
   if (!type_hash_table)
-    type_hash_table = htab_create_ggc (1021, c_type_hash,
-	    (htab_eq) lang_hooks.types_compatible_p,
-	    NULL);
-  slot = htab_find_slot (type_hash_table, t, INSERT);
+    type_hash_table = hash_table<c_type_hasher>::create_ggc (1021);
+  tree *slot = type_hash_table->find_slot (t, INSERT);
   if (*slot != NULL)
     {
       TYPE_ALIAS_SET (t) = TYPE_ALIAS_SET ((tree)*slot);
diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index 6a488b3..0eaadde 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -958,31 +958,26 @@ get_loop_body_in_bfs_order (const struct loop *loop)
 
 /* Hash function for struct loop_exit.  */
 
-static hashval_t
-loop_exit_hash (const void *ex)
+hashval_t
+loop_exit_hasher::hash (loop_exit *exit)
 {
-  const struct loop_exit *const exit = (const struct loop_exit *) ex;
-
   return htab_hash_pointer (exit->e);
 }
 
 /* Equality function for struct loop_exit.  Compares with edge.  */
 
-static int
-loop_exit_eq (const void *ex, const void *e)
+bool
+loop_exit_hasher::equal (loop_exit *exit, edge e)
 {
-  const struct loop_exit *const exit = (const struct loop_exit *) ex;
-
   return exit->e == e;
 }
 
 /* Frees the list of loop exit descriptions EX.  */
 
-static void
-loop_exit_free (void *ex)
+void
+loop_exit_hasher::remove (loop_exit *exit)
 {
-  struct loop_exit *exit = (struct loop_exit *) ex, *next;
-
+  loop_exit *next;
   for (; exit; exit = next)
     {
       next = exit->next_e;
@@ -999,8 +994,7 @@ loop_exit_free (void *ex)
 static struct loop_exit *
 get_exit_descriptions (edge e)
 {
-  return (struct loop_exit *) htab_find_with_hash (current_loops->exits, e,
-			                           htab_hash_pointer (e));
+  return current_loops->exits->find_with_hash (e, htab_hash_pointer (e));
 }
 
 /* Updates the lists of loop exits in that E appears.
@@ -1012,7 +1006,6 @@ get_exit_descriptions (edge e)
 void
 rescan_loop_exit (edge e, bool new_edge, bool removed)
 {
-  void **slot;
   struct loop_exit *exits = NULL, *exit;
   struct loop *aloop, *cloop;
 
@@ -1045,20 +1038,20 @@ rescan_loop_exit (edge e, bool new_edge, bool removed)
   if (!exits && new_edge)
     return;
 
-  slot = htab_find_slot_with_hash (current_loops->exits, e,
-				   htab_hash_pointer (e),
-				   exits ? INSERT : NO_INSERT);
+  loop_exit **slot
+    = current_loops->exits->find_slot_with_hash (e, htab_hash_pointer (e),
+						 exits ? INSERT : NO_INSERT);
   if (!slot)
     return;
 
   if (exits)
     {
       if (*slot)
-	loop_exit_free (*slot);
+	loop_exit_hasher::remove (*slot);
       *slot = exits;
     }
   else
-    htab_clear_slot (current_loops->exits, slot);
+    current_loops->exits->clear_slot (slot);
 }
 
 /* For each loop, record list of exit edges, and start maintaining these
@@ -1079,9 +1072,8 @@ record_loop_exits (void)
   loops_state_set (LOOPS_HAVE_RECORDED_EXITS);
 
   gcc_assert (current_loops->exits == NULL);
-  current_loops->exits = htab_create_ggc (2 * number_of_loops (cfun),
-					  loop_exit_hash, loop_exit_eq,
-					  loop_exit_free);
+  current_loops->exits
+    = hash_table<loop_exit_hasher>::create_ggc (2 * number_of_loops (cfun));
 
   FOR_EACH_BB_FN (bb, cfun)
     {
@@ -1095,17 +1087,17 @@ record_loop_exits (void)
 /* Dumps information about the exit in *SLOT to FILE.
    Callback for htab_traverse.  */
 
-static int
-dump_recorded_exit (void **slot, void *file)
+int
+dump_recorded_exit (loop_exit **slot, FILE *file)
 {
-  struct loop_exit *exit = (struct loop_exit *) *slot;
+  struct loop_exit *exit = *slot;
   unsigned n = 0;
   edge e = exit->e;
 
   for (; exit != NULL; exit = exit->next_e)
     n++;
 
-  fprintf ((FILE*) file, "Edge %d->%d exits %u loops\n",
+  fprintf (file, "Edge %d->%d exits %u loops\n",
 	   e->src->index, e->dest->index, n);
 
   return 1;
@@ -1119,7 +1111,7 @@ dump_recorded_exits (FILE *file)
 {
   if (!current_loops->exits)
     return;
-  htab_traverse (current_loops->exits, dump_recorded_exit, file);
+  current_loops->exits->traverse<FILE *, dump_recorded_exit> (file);
 }
 
 /* Releases lists of loop exits.  */
@@ -1128,7 +1120,7 @@ void
 release_recorded_exits (void)
 {
   gcc_assert (loops_state_satisfies_p (LOOPS_HAVE_RECORDED_EXITS));
-  htab_delete (current_loops->exits);
+  current_loops->exits->empty ();
   current_loops->exits = NULL;
   loops_state_clear (LOOPS_HAVE_RECORDED_EXITS);
 }
@@ -1623,7 +1615,7 @@ verify_loop_structure (void)
 	    }
 	}
 
-      if (n_exits != htab_elements (current_loops->exits))
+      if (n_exits != current_loops->exits->elements ())
 	{
 	  error ("too many loop exits recorded");
 	  err = 1;
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index eff0213..432f8fe 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -76,7 +76,7 @@ struct GTY ((chain_next ("%h.next"))) nb_iter_bound {
 
 /* Description of the loop exit.  */
 
-struct GTY (()) loop_exit {
+struct GTY ((for_user)) loop_exit {
   /* The exit edge.  */
   edge e;
 
@@ -88,6 +88,15 @@ struct GTY (()) loop_exit {
   struct loop_exit *next_e;
 };
 
+struct loop_exit_hasher : ggc_hasher<loop_exit *>
+{
+  typedef edge compare_type;
+
+  static hashval_t hash (loop_exit *);
+  static bool equal (loop_exit *, edge);
+  static void remove (loop_exit *);
+};
+
 typedef struct loop *loop_p;
 
 /* An integer estimation of the number of iterations.  Estimate_state
@@ -229,7 +238,7 @@ struct GTY (()) loops {
   /* Maps edges to the list of their descriptions as loop exits.  Edges
      whose sources or destinations have loop_father == NULL (which may
      happen during the cfg manipulations) should not appear in EXITS.  */
-  htab_t GTY((param_is (struct loop_exit))) exits;
+  hash_table<loop_exit_hasher> *GTY(()) exits;
 
   /* Pointer to root of loop hierarchy tree.  */
   struct loop *tree_root;
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index fdcaf79..cb9bfc5 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -103,30 +103,34 @@ struct cgraph_2node_hook_list {
   struct cgraph_2node_hook_list *next;
 };
 
+/* Hash descriptor for cgraph_function_version_info.  */
+
+struct function_version_hasher : ggc_hasher<cgraph_function_version_info *>
+{
+  static hashval_t hash (cgraph_function_version_info *);
+  static bool equal (cgraph_function_version_info *,
+		     cgraph_function_version_info *);
+};
+
 /* Map a cgraph_node to cgraph_function_version_info using this htab.
    The cgraph_function_version_info has a THIS_NODE field that is the
    corresponding cgraph_node..  */
 
-static GTY((param_is (cgraph_function_version_info))) htab_t
-  cgraph_fnver_htab = NULL;
+static GTY(()) hash_table<function_version_hasher> *cgraph_fnver_htab = NULL;
 
 /* Hash function for cgraph_fnver_htab.  */
-static hashval_t
-cgraph_fnver_htab_hash (const void *ptr)
+hashval_t
+function_version_hasher::hash (cgraph_function_version_info *ptr)
 {
-  int uid = ((const cgraph_function_version_info *)ptr)->this_node->uid;
+  int uid = ptr->this_node->uid;
   return (hashval_t)(uid);
 }
 
 /* eq function for cgraph_fnver_htab.  */
-static int
-cgraph_fnver_htab_eq (const void *p1, const void *p2)
+bool
+function_version_hasher::equal (cgraph_function_version_info *n1,
+			       	cgraph_function_version_info *n2)
 {
-  const cgraph_function_version_info *n1
-    = (const cgraph_function_version_info *)p1;
-  const cgraph_function_version_info *n2
-    = (const cgraph_function_version_info *)p2;
-
   return n1->this_node->uid == n2->this_node->uid;
 }
 
@@ -138,17 +142,13 @@ static GTY(()) struct cgraph_function_version_info *
 cgraph_function_version_info *
 cgraph_node::function_version (void)
 {
-  cgraph_function_version_info *ret;
   cgraph_function_version_info key;
   key.this_node = this;
 
   if (cgraph_fnver_htab == NULL)
     return NULL;
 
-  ret = (cgraph_function_version_info *)
-    htab_find (cgraph_fnver_htab, &key);
-
-  return ret;
+  return cgraph_fnver_htab->find (&key);
 }
 
 /* Insert a new cgraph_function_version_info node into cgraph_fnver_htab
@@ -156,19 +156,15 @@ cgraph_node::function_version (void)
 cgraph_function_version_info *
 cgraph_node::insert_new_function_version (void)
 {
-  void **slot;
-  
   version_info_node = NULL;
   version_info_node = ggc_cleared_alloc<cgraph_function_version_info> ();
   version_info_node->this_node = this;
 
   if (cgraph_fnver_htab == NULL)
-    cgraph_fnver_htab = htab_create_ggc (2, cgraph_fnver_htab_hash,
-				         cgraph_fnver_htab_eq, NULL);
+    cgraph_fnver_htab = hash_table<function_version_hasher>::create_ggc (2);
 
-  slot = htab_find_slot (cgraph_fnver_htab, version_info_node, INSERT);
-  gcc_assert (slot != NULL);
-  *slot = version_info_node;
+  *cgraph_fnver_htab->find_slot (version_info_node, INSERT)
+    = version_info_node;
   return version_info_node;
 }
 
@@ -195,7 +191,7 @@ cgraph_node::delete_function_version (tree decl)
     decl_v->next->prev = decl_v->prev;
 
   if (cgraph_fnver_htab != NULL)
-    htab_remove_elt (cgraph_fnver_htab, decl_v);
+    cgraph_fnver_htab->remove_elt (decl_v);
 
   decl_node->remove ();
 }
@@ -596,18 +592,18 @@ cgraph_node::get_for_asmname (tree asmname)
 
 /* Returns a hash value for X (which really is a cgraph_edge).  */
 
-static hashval_t
-edge_hash (const void *x)
+hashval_t
+cgraph_edge_hasher::hash (cgraph_edge *e)
 {
-  return htab_hash_pointer (((const cgraph_edge *) x)->call_stmt);
+  return htab_hash_pointer (e->call_stmt);
 }
 
 /* Return nonzero if the call_stmt of of cgraph_edge X is stmt *Y.  */
 
-static int
-edge_eq (const void *x, const void *y)
+inline bool
+cgraph_edge_hasher::equal (cgraph_edge *x, gimple y)
 {
-  return ((const cgraph_edge *) x)->call_stmt == y;
+  return x->call_stmt == y;
 }
 
 /* Add call graph edge E to call site hash of its caller.  */
@@ -615,12 +611,10 @@ edge_eq (const void *x, const void *y)
 static inline void
 cgraph_update_edge_in_call_site_hash (cgraph_edge *e)
 {
-  void **slot;
-  slot = htab_find_slot_with_hash (e->caller->call_site_hash,
-				   e->call_stmt,
-				   htab_hash_pointer (e->call_stmt),
-				   INSERT);
-  *slot = e;
+  gimple call = e->call_stmt;
+  *e->caller->call_site_hash->find_slot_with_hash (call,
+						   htab_hash_pointer (call),
+						   INSERT) = e;
 }
 
 /* Add call graph edge E to call site hash of its caller.  */
@@ -628,15 +622,13 @@ cgraph_update_edge_in_call_site_hash (cgraph_edge *e)
 static inline void
 cgraph_add_edge_to_call_site_hash (cgraph_edge *e)
 {
-  void **slot;
   /* There are two speculative edges for every statement (one direct,
      one indirect); always hash the direct one.  */
   if (e->speculative && e->indirect_unknown_callee)
     return;
-  slot = htab_find_slot_with_hash (e->caller->call_site_hash,
-				   e->call_stmt,
-				   htab_hash_pointer (e->call_stmt),
-				   INSERT);
+  cgraph_edge **slot = e->caller->call_site_hash->find_slot_with_hash
+				   (e->call_stmt,
+				    htab_hash_pointer (e->call_stmt), INSERT);
   if (*slot)
     {
       gcc_assert (((cgraph_edge *)*slot)->speculative);
@@ -658,9 +650,8 @@ cgraph_node::get_edge (gimple call_stmt)
   int n = 0;
 
   if (call_site_hash)
-    return (cgraph_edge *)
-      htab_find_with_hash (call_site_hash, call_stmt,
-      	                   htab_hash_pointer (call_stmt));
+    return call_site_hash->find_with_hash (call_stmt,
+					   htab_hash_pointer (call_stmt));
 
   /* This loop may turn out to be performance problem.  In such case adding
      hashtables into call nodes with very many edges is probably best
@@ -684,7 +675,7 @@ cgraph_node::get_edge (gimple call_stmt)
 
   if (n > 100)
     {
-      call_site_hash = htab_create_ggc (120, edge_hash, edge_eq, NULL);
+      call_site_hash = hash_table<cgraph_edge_hasher>::create_ggc (120);
       for (e2 = callees; e2; e2 = e2->next_callee)
 	cgraph_add_edge_to_call_site_hash (e2);
       for (e2 = indirect_calls; e2; e2 = e2->next_callee)
@@ -722,9 +713,8 @@ cgraph_edge::set_call_stmt (gimple new_stmt, bool update_speculative)
   if (caller->call_site_hash
       && (!speculative || !indirect_unknown_callee))
     {
-      htab_remove_elt_with_hash (caller->call_site_hash,
-				 call_stmt,
-				 htab_hash_pointer (call_stmt));
+      caller->call_site_hash->remove_elt_with_hash
+	(call_stmt, htab_hash_pointer (call_stmt));
     }
 
   cgraph_edge *e = this;
@@ -935,9 +925,8 @@ cgraph_edge::remove_caller (void)
 	caller->callees = next_callee;
     }
   if (caller->call_site_hash)
-    htab_remove_elt_with_hash (caller->call_site_hash,
-			       call_stmt,
-			       htab_hash_pointer (call_stmt));
+    caller->call_site_hash->remove_elt_with_hash (call_stmt,
+						  htab_hash_pointer (call_stmt));
 }
 
 /* Put the edge onto the free list.  */
@@ -1556,7 +1545,7 @@ cgraph_node::remove_callees (void)
   callees = NULL;
   if (call_site_hash)
     {
-      htab_delete (call_site_hash);
+      call_site_hash->empty ();
       call_site_hash = NULL;
     }
 }
@@ -1735,7 +1724,7 @@ cgraph_node::remove (void)
   decl = NULL;
   if (call_site_hash)
     {
-      htab_delete (call_site_hash);
+      call_site_hash->empty ();
       call_site_hash = NULL;
     }
 
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index fb41b01..8b0d4fd 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -42,7 +42,7 @@ enum symtab_type
 /* Section names are stored as reference counted strings in GGC safe hashtable
    (to make them survive through PCH).  */
 
-struct GTY(()) section_hash_entry_d
+struct GTY((for_user)) section_hash_entry_d
 {
   int ref_count;
   char *name;  /* As long as this datastructure stays in GGC, we can not put
@@ -52,6 +52,14 @@ struct GTY(()) section_hash_entry_d
 
 typedef struct section_hash_entry_d section_hash_entry;
 
+struct section_name_hasher : ggc_hasher<section_hash_entry *>
+{
+  typedef const char *compare_type;
+
+  static hashval_t hash (section_hash_entry *);
+  static bool equal (section_hash_entry *, const char *);
+};
+
 enum availability
 {
   /* Not yet set by cgraph_function_body_availability.  */
@@ -704,7 +712,7 @@ struct GTY(()) cgraph_simd_clone {
 };
 
 /* Function Multiversioning info.  */
-struct GTY(()) cgraph_function_version_info {
+struct GTY((for_user)) cgraph_function_version_info {
   /* The cgraph_node for which the function version info is stored.  */
   cgraph_node *this_node;
   /* Chains all the semantically identical function versions.  The
@@ -743,6 +751,14 @@ enum cgraph_inline_failed_type_t
 
 struct cgraph_edge;
 
+struct cgraph_edge_hasher : ggc_hasher<cgraph_edge *>
+{
+  typedef gimple compare_type;
+
+  static hashval_t hash (cgraph_edge *);
+  static bool equal (cgraph_edge *, gimple);
+};
+
 /* The cgraph data structure.
    Each function decl has assigned cgraph_node listing callees and callers.  */
 
@@ -1172,7 +1188,7 @@ public:
   cgraph_node *clone_of;
   /* For functions with many calls sites it holds map from call expression
      to the edge to speed up cgraph_edge function.  */
-  htab_t GTY((param_is (cgraph_edge))) call_site_hash;
+  hash_table<cgraph_edge_hasher> *GTY(()) call_site_hash;
   /* Declaration node used to be clone of. */
   tree former_clone_of;
 
@@ -1395,7 +1411,8 @@ struct GTY(()) cgraph_indirect_call_info
   unsigned by_ref : 1;
 };
 
-struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgraph_edge {
+struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"),
+	    for_user)) cgraph_edge {
   friend class cgraph_node;
 
   /* Remove the edge in the cgraph.  */
@@ -1724,6 +1741,20 @@ enum symtab_state
   FINISHED
 };
 
+struct asmname_hasher
+{
+  typedef symtab_node *value_type;
+  typedef const_tree compare_type;
+  typedef int store_values_directly;
+
+  static hashval_t hash (symtab_node *n);
+  static bool equal (symtab_node *n, const_tree t);
+  static void ggc_mx (symtab_node *n);
+  static void pch_nx (symtab_node *&);
+  static void pch_nx (symtab_node *&, gt_pointer_operator, void *);
+  static void remove (symtab_node *) {}
+};
+
 class GTY((tag ("SYMTAB"))) symbol_table
 {
 public:
@@ -1960,10 +1991,10 @@ public:
   bool cpp_implicit_aliases_done;
 
   /* Hash table used to hold sectoons.  */
-  htab_t GTY((param_is (section_hash_entry))) section_hash;
+  hash_table<section_name_hasher> *GTY(()) section_hash;
 
   /* Hash table used to convert assembler names into nodes.  */
-  htab_t GTY((param_is (symtab_node))) assembler_name_hash;
+  hash_table<asmname_hasher> *assembler_name_hash;
 
   /* Hash table used to hold init priorities.  */
   hash_map<symtab_node *, symbol_priority_map> *init_priority_hash;
@@ -1996,11 +2027,7 @@ private:
   /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL.  */
   static bool decl_assembler_name_equal (tree decl, const_tree asmname);
 
-  /* Returns a hash code for P.  */
-  static hashval_t hash_node_by_assembler_name (const void *p);
-
-  /* Returns nonzero if P1 and P2 are equal.  */
-  static int eq_assembler_name (const void *p1, const void *p2);
+  friend struct asmname_hasher;
 
   /* List of hooks triggered when an edge is removed.  */
   cgraph_edge_hook_list * GTY((skip)) m_first_edge_removal_hook;
@@ -2022,6 +2049,41 @@ extern GTY(()) symbol_table *symtab;
 
 extern vec<cgraph_node *> cgraph_new_nodes;
 
+inline hashval_t
+asmname_hasher::hash (symtab_node *n)
+{
+  return symbol_table::decl_assembler_name_hash
+    (DECL_ASSEMBLER_NAME (n->decl));
+}
+
+inline bool
+asmname_hasher::equal (symtab_node *n, const_tree t)
+{
+  return symbol_table::decl_assembler_name_equal (n->decl, t);
+}
+
+extern void gt_ggc_mx (symtab_node *&);
+
+inline void
+asmname_hasher::ggc_mx (symtab_node *n)
+{
+  gt_ggc_mx (n);
+}
+
+extern void gt_pch_nx (symtab_node *&);
+
+inline void
+asmname_hasher::pch_nx (symtab_node *&n)
+{
+  gt_pch_nx (n);
+}
+
+inline void
+asmname_hasher::pch_nx (symtab_node *&n, gt_pointer_operator op, void *cookie)
+{
+  op (&n, cookie);
+}
+
 /* In cgraph.c  */
 void release_function_body (tree);
 cgraph_indirect_call_info *cgraph_allocate_init_indirect_info (void);
@@ -2476,7 +2538,7 @@ tree add_new_static_var (tree type);
    Each constant in memory thus far output is recorded
    in `const_desc_table'.  */
 
-struct GTY(()) constant_descriptor_tree {
+struct GTY((for_user)) constant_descriptor_tree {
   /* A MEM for the constant.  */
   rtx rtl;
 
@@ -2535,8 +2597,14 @@ varpool_node::all_refs_explicit_p ()
 	  && !force_output);
 }
 
+struct tree_descriptor_hasher : ggc_hasher<constant_descriptor_tree *>
+{
+  static hashval_t hash (constant_descriptor_tree *);
+  static bool equal (constant_descriptor_tree *, constant_descriptor_tree *);
+};
+
 /* Constant pool accessor function.  */
-htab_t constant_pool_htab (void);
+hash_table<tree_descriptor_hasher> *constant_pool_htab (void);
 
 /* Return node that alias is aliasing.  */
 
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
index 60c8d1e..34dc9aa 100644
--- a/gcc/config/darwin.c
+++ b/gcc/config/darwin.c
@@ -450,7 +450,7 @@ machopic_should_output_picbase_label (void)
 /* The suffix attached to stub symbols.  */
 #define STUB_SUFFIX "$stub"
 
-typedef struct GTY (()) machopic_indirection
+typedef struct GTY ((for_user)) machopic_indirection
 {
   /* The SYMBOL_REF for the entity referenced.  */
   rtx symbol;
@@ -463,29 +463,33 @@ typedef struct GTY (()) machopic_indirection
   bool used;
 } machopic_indirection;
 
+struct indirection_hasher : ggc_hasher<machopic_indirection *>
+{
+  typedef const char *compare_type;
+  static hashval_t hash (machopic_indirection *);
+  static bool equal (machopic_indirection *, const char *);
+};
+
 /* A table mapping stub names and non-lazy pointer names to
    SYMBOL_REFs for the stubbed-to and pointed-to entities.  */
 
-static GTY ((param_is (struct machopic_indirection))) htab_t
-  machopic_indirections;
+static GTY (()) hash_table<indirection_hasher> *machopic_indirections;
 
 /* Return a hash value for a SLOT in the indirections hash table.  */
 
-static hashval_t
-machopic_indirection_hash (const void *slot)
+hashval_t
+indirection_hasher::hash (machopic_indirection *p)
 {
-  const machopic_indirection *p = (const machopic_indirection *) slot;
   return htab_hash_string (p->ptr_name);
 }
 
 /* Returns true if the KEY is the same as that associated with
    SLOT.  */
 
-static int
-machopic_indirection_eq (const void *slot, const void *key)
+bool
+indirection_hasher::equal (machopic_indirection *s, const char *k)
 {
-  return strcmp (((const machopic_indirection *) slot)->ptr_name,
-		 (const char *) key) == 0;
+  return strcmp (s->ptr_name, k) == 0;
 }
 
 /* Return the name of the non-lazy pointer (if STUB_P is false) or
@@ -498,7 +502,6 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
   const char *name = XSTR (sym_ref, 0);
   size_t namelen = strlen (name);
   machopic_indirection *p;
-  void ** slot;
   bool needs_quotes;
   const char *suffix;
   const char *prefix = user_label_prefix;
@@ -548,16 +551,15 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
   sprintf (buffer, "&%sL%s%s%s%s", quote, prefix, name, suffix, quote);
 
   if (!machopic_indirections)
-    machopic_indirections = htab_create_ggc (37,
-					     machopic_indirection_hash,
-					     machopic_indirection_eq,
-					     /*htab_del=*/NULL);
+    machopic_indirections = hash_table<indirection_hasher>::create_ggc (37);
 
-  slot = htab_find_slot_with_hash (machopic_indirections, buffer,
-				   htab_hash_string (buffer), INSERT);
+  machopic_indirection **slot
+    = machopic_indirections->find_slot_with_hash (buffer,
+						  htab_hash_string (buffer),
+						  INSERT);
   if (*slot)
     {
-      p = (machopic_indirection *) *slot;
+      p = *slot;
     }
   else
     {
@@ -589,11 +591,8 @@ machopic_mcount_stub_name (void)
 void
 machopic_validate_stub_or_non_lazy_ptr (const char *name)
 {
-  machopic_indirection *p;
-
-  p = ((machopic_indirection *)
-       (htab_find_with_hash (machopic_indirections, name,
-			     htab_hash_string (name))));
+  machopic_indirection *p
+    = machopic_indirections->find_with_hash (name, htab_hash_string (name));
   if (p && ! p->used)
     {
       const char *real_name;
@@ -1062,11 +1061,10 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
    DATA is the FILE* for assembly output.  Called from
    htab_traverse.  */
 
-static int
-machopic_output_indirection (void **slot, void *data)
+int
+machopic_output_indirection (machopic_indirection **slot, FILE *asm_out_file)
 {
-  machopic_indirection *p = *((machopic_indirection **) slot);
-  FILE *asm_out_file = (FILE *) data;
+  machopic_indirection *p = *slot;
   rtx symbol;
   const char *sym_name;
   const char *ptr_name;
@@ -1180,9 +1178,8 @@ void
 machopic_finish (FILE *asm_out_file)
 {
   if (machopic_indirections)
-    htab_traverse_noresize (machopic_indirections,
-			    machopic_output_indirection,
-			    asm_out_file);
+    machopic_indirections
+      ->traverse_noresize<FILE *, machopic_output_indirection> (asm_out_file);
 }
 
 int
@@ -3254,17 +3251,20 @@ static enum built_in_function darwin_builtin_cfstring;
 /* Store all constructed constant CFStrings in a hash table so that
    they get uniqued properly.  */
 
-typedef struct GTY (()) cfstring_descriptor {
+typedef struct GTY ((for_user)) cfstring_descriptor {
   /* The string literal.  */
   tree literal;
   /* The resulting constant CFString.  */
   tree constructor;
 } cfstring_descriptor;
 
-static GTY ((param_is (struct cfstring_descriptor))) htab_t cfstring_htab;
+struct cfstring_hasher : ggc_hasher<cfstring_descriptor *>
+{
+  static hashval_t hash (cfstring_descriptor *);
+  static bool equal (cfstring_descriptor *, cfstring_descriptor *);
+};
 
-static hashval_t cfstring_hash (const void *);
-static int cfstring_eq (const void *, const void *);
+static GTY (()) hash_table<cfstring_hasher> *cfstring_htab;
 
 static tree
 add_builtin_field_decl (tree type, const char *name, tree **chain)
@@ -3347,7 +3347,7 @@ darwin_init_cfstring_builtins (unsigned builtin_cfstring)
   rest_of_decl_compilation (cfstring_class_reference, 0, 0);
   
   /* Initialize the hash table used to hold the constant CFString objects.  */
-  cfstring_htab = htab_create_ggc (31, cfstring_hash, cfstring_eq, NULL);
+  cfstring_htab = hash_table<cfstring_hasher>::create_ggc (31);
 
   return cfstring_type_node;
 }
@@ -3421,10 +3421,10 @@ darwin_libc_has_function (enum function_class fn_class)
   return true;
 }
 
-static hashval_t
-cfstring_hash (const void *ptr)
+hashval_t
+cfstring_hasher::hash (cfstring_descriptor *ptr)
 {
-  tree str = ((const struct cfstring_descriptor *)ptr)->literal;
+  tree str = ptr->literal;
   const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str);
   int i, len = TREE_STRING_LENGTH (str);
   hashval_t h = len;
@@ -3435,11 +3435,11 @@ cfstring_hash (const void *ptr)
   return h;
 }
 
-static int
-cfstring_eq (const void *ptr1, const void *ptr2)
+bool
+cfstring_hasher::equal (cfstring_descriptor *ptr1, cfstring_descriptor *ptr2)
 {
-  tree str1 = ((const struct cfstring_descriptor *)ptr1)->literal;
-  tree str2 = ((const struct cfstring_descriptor *)ptr2)->literal;
+  tree str1 = ptr1->literal;
+  tree str2 = ptr2->literal;
   int len1 = TREE_STRING_LENGTH (str1);
 
   return (len1 == TREE_STRING_LENGTH (str2)
@@ -3451,7 +3451,6 @@ tree
 darwin_build_constant_cfstring (tree str)
 {
   struct cfstring_descriptor *desc, key;
-  void **loc;
   tree addr;
 
   if (!str)
@@ -3473,8 +3472,8 @@ darwin_build_constant_cfstring (tree str)
 
   /* Perhaps we already constructed a constant CFString just like this one? */
   key.literal = str;
-  loc = htab_find_slot (cfstring_htab, &key, INSERT);
-  desc = (struct cfstring_descriptor *) *loc;
+  cfstring_descriptor **loc = cfstring_htab->find_slot (&key, INSERT);
+  desc = *loc;
 
   if (!desc)
     {
@@ -3550,7 +3549,6 @@ bool
 darwin_cfstring_p (tree str)
 {
   struct cfstring_descriptor key;
-  void **loc;
 
   if (!str)
     return false;
@@ -3564,7 +3562,7 @@ darwin_cfstring_p (tree str)
     return false;
 
   key.literal = str;
-  loc = htab_find_slot (cfstring_htab, &key, NO_INSERT);
+  cfstring_descriptor **loc = cfstring_htab->find_slot (&key, NO_INSERT);
   
   if (loc)
     return true;
@@ -3576,10 +3574,9 @@ void
 darwin_enter_string_into_cfstring_table (tree str)
 {
   struct cfstring_descriptor key;
-  void **loc;
 
   key.literal = str;
-  loc = htab_find_slot (cfstring_htab, &key, INSERT);
+  cfstring_descriptor **loc = cfstring_htab->find_slot (&key, INSERT);
 
   if (!*loc)
     {
diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c
index 71723c8..fc89821 100644
--- a/gcc/config/m32c/m32c.c
+++ b/gcc/config/m32c/m32c.c
@@ -3035,66 +3035,41 @@ m32c_insert_attributes (tree node ATTRIBUTE_UNUSED,
 }
 
 
-struct GTY(()) pragma_entry {
-  const char *varname;
-  unsigned address;
+struct pragma_traits : default_hashmap_traits
+{
+  static hashval_t hash (const char *str) { return htab_hash_string (str); }
+  static bool
+  equal_keys (const char *a, const char *b)
+  {
+    return !strcmp (a, b);
+  }
 };
-typedef struct pragma_entry pragma_entry;
 
 /* Hash table of pragma info.  */
-static GTY((param_is (pragma_entry))) htab_t pragma_htab;
-
-static int
-pragma_entry_eq (const void *p1, const void *p2)
-{
-  const pragma_entry *old = (const pragma_entry *) p1;
-  const char *new_name = (const char *) p2;
-
-  return strcmp (old->varname, new_name) == 0;
-}
-
-static hashval_t
-pragma_entry_hash (const void *p)
-{
-  const pragma_entry *old = (const pragma_entry *) p;
-  return htab_hash_string (old->varname);
-}
+static GTY(()) hash_map<const char *, unsigned, pragma_traits> *pragma_htab;
 
 void
 m32c_note_pragma_address (const char *varname, unsigned address)
 {
-  pragma_entry **slot;
-
   if (!pragma_htab)
-    pragma_htab = htab_create_ggc (31, pragma_entry_hash,
-				    pragma_entry_eq, NULL);
+    pragma_htab
+      = hash_map<const char *, unsigned, pragma_traits>::create_ggc (31);
 
-  slot = (pragma_entry **)
-    htab_find_slot_with_hash (pragma_htab, varname,
-			      htab_hash_string (varname), INSERT);
-
-  if (!*slot)
-    {
-      *slot = ggc_alloc<pragma_entry> ();
-      (*slot)->varname = ggc_strdup (varname);
-    }
-  (*slot)->address = address;
+  const char *name = ggc_strdup (varname);
+  unsigned int *slot = &pragma_htab->get_or_insert (name);
+  *slot = address;
 }
 
 static bool
 m32c_get_pragma_address (const char *varname, unsigned *address)
 {
-  pragma_entry **slot;
-
   if (!pragma_htab)
     return false;
 
-  slot = (pragma_entry **)
-    htab_find_slot_with_hash (pragma_htab, varname,
-			      htab_hash_string (varname), NO_INSERT);
-  if (slot && *slot)
+  unsigned int *slot = pragma_htab->get (varname);
+  if (slot)
     {
-      *address = (*slot)->address;
+      *address = *slot;
       return true;
     }
   return false;
diff --git a/gcc/config/mep/mep.c b/gcc/config/mep/mep.c
index 1c0e80b..03ecc96 100644
--- a/gcc/config/mep/mep.c
+++ b/gcc/config/mep/mep.c
@@ -4061,69 +4061,53 @@ mep_can_inline_p (tree caller, tree callee)
 struct GTY(()) pragma_entry {
   int used;
   int flag;
-  const char *funcname;
 };
-typedef struct pragma_entry pragma_entry;
 
-/* Hash table of farcall-tagged sections.  */
-static GTY((param_is (pragma_entry))) htab_t pragma_htab;
-
-static int
-pragma_entry_eq (const void *p1, const void *p2)
+struct pragma_traits : default_hashmap_traits
 {
-  const pragma_entry *old = (const pragma_entry *) p1;
-  const char *new_name = (const char *) p2;
-
-  return strcmp (old->funcname, new_name) == 0;
-}
+  static hashval_t hash (const char *s) { return htab_hash_string (s); }
+  static bool
+  equal_keys (const char *a, const char *b)
+  {
+    return strcmp (a, b) == 0;
+  }
+};
 
-static hashval_t
-pragma_entry_hash (const void *p)
-{
-  const pragma_entry *old = (const pragma_entry *) p;
-  return htab_hash_string (old->funcname);
-}
+/* Hash table of farcall-tagged sections.  */
+static GTY(()) hash_map<const char *, pragma_entry, pragma_traits> *
+  pragma_htab;
 
 static void
 mep_note_pragma_flag (const char *funcname, int flag)
 {
-  pragma_entry **slot;
-
   if (!pragma_htab)
-    pragma_htab = htab_create_ggc (31, pragma_entry_hash,
-				    pragma_entry_eq, NULL);
-
-  slot = (pragma_entry **)
-    htab_find_slot_with_hash (pragma_htab, funcname,
-			      htab_hash_string (funcname), INSERT);
+    pragma_htab
+      = hash_map<const char *, pragma_entry, pragma_traits>::create_ggc (31);
 
-  if (!*slot)
+  bool existed;
+  const char *name = ggc_strdup (funcname);
+  pragma_entry *slot = &pragma_htab->get_or_insert (name, &existed);
+  if (!existed)
     {
-      *slot = ggc_alloc<pragma_entry> ();
-      (*slot)->flag = 0;
-      (*slot)->used = 0;
-      (*slot)->funcname = ggc_strdup (funcname);
+      slot->flag = 0;
+      slot->used = 0;
     }
-  (*slot)->flag |= flag;
+  slot->flag |= flag;
 }
 
 static bool
 mep_lookup_pragma_flag (const char *funcname, int flag)
 {
-  pragma_entry **slot;
-
   if (!pragma_htab)
     return false;
 
   if (funcname[0] == '@' && funcname[2] == '.')
     funcname += 3;
 
-  slot = (pragma_entry **)
-    htab_find_slot_with_hash (pragma_htab, funcname,
-			      htab_hash_string (funcname), NO_INSERT);
-  if (slot && *slot && ((*slot)->flag & flag))
+  pragma_entry *slot = pragma_htab->get (funcname);
+  if (slot && (slot->flag & flag))
     {
-      (*slot)->used |= flag;
+      slot->used |= flag;
       return true;
     }
   return false;
@@ -4153,14 +4137,13 @@ mep_note_pragma_disinterrupt (const char *funcname)
   mep_note_pragma_flag (funcname, FUNC_DISINTERRUPT);
 }
 
-static int
-note_unused_pragma_disinterrupt (void **slot, void *data ATTRIBUTE_UNUSED)
+bool
+note_unused_pragma_disinterrupt (const char *const &s, const pragma_entry &e,
+				 void *)
 {
-  const pragma_entry *d = (const pragma_entry *)(*slot);
-
-  if ((d->flag & FUNC_DISINTERRUPT)
-      && !(d->used & FUNC_DISINTERRUPT))
-    warning (0, "\"#pragma disinterrupt %s\" not used", d->funcname);
+  if ((e.flag & FUNC_DISINTERRUPT)
+      && !(e.used & FUNC_DISINTERRUPT))
+    warning (0, "\"#pragma disinterrupt %s\" not used", s);
   return 1;
 }
 
@@ -4168,7 +4151,7 @@ void
 mep_file_cleanups (void)
 {
   if (pragma_htab)
-    htab_traverse (pragma_htab, note_unused_pragma_disinterrupt, NULL);
+    pragma_htab->traverse<void *, note_unused_pragma_disinterrupt> (NULL);
 }
 
 /* These three functions provide a bridge between the pramgas that
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 723057e..af72da5 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -1202,28 +1202,20 @@ static int mips_register_move_cost (enum machine_mode, reg_class_t,
 				    reg_class_t);
 static unsigned int mips_function_arg_boundary (enum machine_mode, const_tree);
 
-/* This hash table keeps track of implicit "mips16" and "nomips16" attributes
-   for -mflip_mips16.  It maps decl names onto a boolean mode setting.  */
-struct GTY (())  mflip_mips16_entry {
-  const char *name;
-  bool mips16_p;
-};
-static GTY ((param_is (struct mflip_mips16_entry))) htab_t mflip_mips16_htab;
-
-/* Hash table callbacks for mflip_mips16_htab.  */
-
-static hashval_t
-mflip_mips16_htab_hash (const void *entry)
+struct mips16_flip_traits : default_hashmap_traits
 {
-  return htab_hash_string (((const struct mflip_mips16_entry *) entry)->name);
-}
+  static hashval_t hash (const char *s) { return htab_hash_string (s); }
+  static bool
+  equal_keys (const char *a, const char *b)
+  {
+    return !strcmp (a, b);
+  }
+};
 
-static int
-mflip_mips16_htab_eq (const void *entry, const void *name)
-{
-  return strcmp (((const struct mflip_mips16_entry *) entry)->name,
-		 (const char *) name) == 0;
-}
+/* This hash table keeps track of implicit "mips16" and "nomips16" attributes
+   for -mflip_mips16.  It maps decl names onto a boolean mode setting.  */
+static GTY (()) hash_map<const char *, bool, mips16_flip_traits> *
+  mflip_mips16_htab;
 
 /* True if -mflip-mips16 should next add an attribute for the default MIPS16
    mode, false if it should next add an attribute for the opposite mode.  */
@@ -1236,10 +1228,7 @@ static GTY(()) bool mips16_flipper;
 static bool
 mflip_mips16_use_mips16_p (tree decl)
 {
-  struct mflip_mips16_entry *entry;
   const char *name;
-  hashval_t hash;
-  void **slot;
   bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;
 
   /* Use the opposite of the command-line setting for anonymous decls.  */
@@ -1247,22 +1236,19 @@ mflip_mips16_use_mips16_p (tree decl)
     return !base_is_mips16;
 
   if (!mflip_mips16_htab)
-    mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
-					 mflip_mips16_htab_eq, NULL);
+    mflip_mips16_htab
+      = hash_map<const char *, bool, mips16_flip_traits>::create_ggc (37);
 
   name = IDENTIFIER_POINTER (DECL_NAME (decl));
-  hash = htab_hash_string (name);
-  slot = htab_find_slot_with_hash (mflip_mips16_htab, name, hash, INSERT);
-  entry = (struct mflip_mips16_entry *) *slot;
-  if (!entry)
+
+  bool existed;
+  bool *slot = &mflip_mips16_htab->get_or_insert (name, &existed);
+  if (!existed)
     {
       mips16_flipper = !mips16_flipper;
-      entry = ggc_alloc<mflip_mips16_entry> ();
-      entry->name = name;
-      entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
-      *slot = entry;
+      *slot = mips16_flipper ? !base_is_mips16 : base_is_mips16;
     }
-  return entry->mips16_p;
+  return *slot;
 }
 
 /* Predicates to test for presence of "near" and "far"/"long_call"
@@ -6391,34 +6377,29 @@ mips_load_call_address (enum mips_call_type type, rtx dest, rtx addr)
     }
 }
 
+struct local_alias_traits : default_hashmap_traits
+{
+  static hashval_t hash (rtx);
+  static bool equal_keys (rtx, rtx);
+};
+
 /* Each locally-defined hard-float MIPS16 function has a local symbol
    associated with it.  This hash table maps the function symbol (FUNC)
    to the local symbol (LOCAL). */
-struct GTY(()) mips16_local_alias {
-  rtx func;
-  rtx local;
-};
-static GTY ((param_is (struct mips16_local_alias))) htab_t mips16_local_aliases;
+static GTY (()) hash_map<rtx, rtx, local_alias_traits> *mips16_local_aliases;
 
 /* Hash table callbacks for mips16_local_aliases.  */
 
-static hashval_t
-mips16_local_aliases_hash (const void *entry)
+hashval_t
+local_alias_traits::hash (rtx func)
 {
-  const struct mips16_local_alias *alias;
-
-  alias = (const struct mips16_local_alias *) entry;
-  return htab_hash_string (XSTR (alias->func, 0));
+  return htab_hash_string (XSTR (func, 0));
 }
 
-static int
-mips16_local_aliases_eq (const void *entry1, const void *entry2)
+bool
+local_alias_traits::equal_keys (rtx func1, rtx func2)
 {
-  const struct mips16_local_alias *alias1, *alias2;
-
-  alias1 = (const struct mips16_local_alias *) entry1;
-  alias2 = (const struct mips16_local_alias *) entry2;
-  return rtx_equal_p (alias1->func, alias2->func);
+  return rtx_equal_p (func1, func2);
 }
 
 /* FUNC is the symbol for a locally-defined hard-float MIPS16 function.
@@ -6427,21 +6408,17 @@ mips16_local_aliases_eq (const void *entry1, const void *entry2)
 static rtx
 mips16_local_alias (rtx func)
 {
-  struct mips16_local_alias *alias, tmp_alias;
-  void **slot;
-
   /* Create the hash table if this is the first call.  */
   if (mips16_local_aliases == NULL)
-    mips16_local_aliases = htab_create_ggc (37, mips16_local_aliases_hash,
-					    mips16_local_aliases_eq, NULL);
+    mips16_local_aliases
+      = hash_map<rtx, rtx, local_alias_traits>::create_ggc (37);
 
   /* Look up the function symbol, creating a new entry if need be.  */
-  tmp_alias.func = func;
-  slot = htab_find_slot (mips16_local_aliases, &tmp_alias, INSERT);
+  bool existed;
+  rtx *slot = &mips16_local_aliases->get_or_insert (func, &existed);
   gcc_assert (slot != NULL);
 
-  alias = (struct mips16_local_alias *) *slot;
-  if (alias == NULL)
+  if (!existed)
     {
       const char *func_name, *local_name;
       rtx local;
@@ -6455,12 +6432,9 @@ mips16_local_alias (rtx func)
       SYMBOL_REF_FLAGS (local) = SYMBOL_REF_FLAGS (func) | SYMBOL_FLAG_LOCAL;
 
       /* Create a new structure to represent the mapping.  */
-      alias = ggc_alloc<struct mips16_local_alias> ();
-      alias->func = func;
-      alias->local = local;
-      *slot = alias;
+      *slot = local;
     }
-  return alias->local;
+  return *slot;
 }
 
 /* A chained list of functions for which mips16_build_call_stub has already
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 16847aa..6e270cd 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1174,7 +1174,7 @@ rtl_opt_pass *make_pass_analyze_swaps (gcc::context*);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
-struct GTY(()) toc_hash_struct
+struct GTY((for_user)) toc_hash_struct
 {
   /* `key' will satisfy CONSTANT_P; in fact, it will satisfy
      ASM_OUTPUT_SPECIAL_POOL_ENTRY_P.  */
@@ -1183,18 +1183,30 @@ struct GTY(()) toc_hash_struct
   int labelno;
 };
 
-static GTY ((param_is (struct toc_hash_struct))) htab_t toc_hash_table;
+struct toc_hasher : ggc_hasher<toc_hash_struct *>
+{
+  static hashval_t hash (toc_hash_struct *);
+  static bool equal (toc_hash_struct *, toc_hash_struct *);
+};
+
+static GTY (()) hash_table<toc_hasher> *toc_hash_table;
 
 /* Hash table to keep track of the argument types for builtin functions.  */
 
-struct GTY(()) builtin_hash_struct
+struct GTY((for_user)) builtin_hash_struct
 {
   tree type;
   enum machine_mode mode[4];	/* return value + 3 arguments.  */
   unsigned char uns_p[4];	/* and whether the types are unsigned.  */
 };
 
-static GTY ((param_is (struct builtin_hash_struct))) htab_t builtin_hash_table;
+struct builtin_hasher : ggc_hasher<builtin_hash_struct *>
+{
+  static hashval_t hash (builtin_hash_struct *);
+  static bool equal (builtin_hash_struct *, builtin_hash_struct *);
+};
+
+static GTY (()) hash_table<builtin_hasher> *builtin_hash_table;
 
 
 /* Default register names.  */
@@ -15114,13 +15126,11 @@ htm_init_builtins (void)
 
 /* Hash function for builtin functions with up to 3 arguments and a return
    type.  */
-static unsigned
-builtin_hash_function (const void *hash_entry)
+hashval_t
+builtin_hasher::hash (builtin_hash_struct *bh)
 {
   unsigned ret = 0;
   int i;
-  const struct builtin_hash_struct *bh =
-    (const struct builtin_hash_struct *) hash_entry;
 
   for (i = 0; i < 4; i++)
     {
@@ -15132,12 +15142,9 @@ builtin_hash_function (const void *hash_entry)
 }
 
 /* Compare builtin hash entries H1 and H2 for equivalence.  */
-static int
-builtin_hash_eq (const void *h1, const void *h2)
+bool
+builtin_hasher::equal (builtin_hash_struct *p1, builtin_hash_struct *p2)
 {
-  const struct builtin_hash_struct *p1 = (const struct builtin_hash_struct *) h1;
-  const struct builtin_hash_struct *p2 = (const struct builtin_hash_struct *) h2;
-
   return ((p1->mode[0] == p2->mode[0])
 	  && (p1->mode[1] == p2->mode[1])
 	  && (p1->mode[2] == p2->mode[2])
@@ -15158,7 +15165,6 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0,
 {
   struct builtin_hash_struct h;
   struct builtin_hash_struct *h2;
-  void **found;
   int num_args = 3;
   int i;
   tree ret_type = NULL_TREE;
@@ -15166,8 +15172,7 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0,
 
   /* Create builtin_hash_table.  */
   if (builtin_hash_table == NULL)
-    builtin_hash_table = htab_create_ggc (1500, builtin_hash_function,
-					  builtin_hash_eq, NULL);
+    builtin_hash_table = hash_table<builtin_hasher>::create_ggc (1500);
 
   h.type = NULL_TREE;
   h.mode[0] = mode_ret;
@@ -15323,18 +15328,18 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0,
 		     GET_MODE_NAME (m));
     }
 
-  found = htab_find_slot (builtin_hash_table, &h, INSERT);
+  builtin_hash_struct **found = builtin_hash_table->find_slot (&h, INSERT);
   if (*found == NULL)
     {
       h2 = ggc_alloc<builtin_hash_struct> ();
       *h2 = h;
-      *found = (void *)h2;
+      *found = h2;
 
       h2->type = build_function_type_list (ret_type, arg_type[0], arg_type[1],
 					   arg_type[2], NULL_TREE);
     }
 
-  return ((struct builtin_hash_struct *)(*found))->type;
+  return (*found)->type;
 }
 
 static void
@@ -25562,24 +25567,21 @@ rs6000_hash_constant (rtx k)
   return result;
 }
 
-static unsigned
-toc_hash_function (const void *hash_entry)
+hashval_t
+toc_hasher::hash (toc_hash_struct *thc)
 {
-  const struct toc_hash_struct *thc =
-    (const struct toc_hash_struct *) hash_entry;
   return rs6000_hash_constant (thc->key) ^ thc->key_mode;
 }
 
 /* Compare H1 and H2 for equivalence.  */
 
-static int
-toc_hash_eq (const void *h1, const void *h2)
+bool
+toc_hasher::equal (toc_hash_struct *h1, toc_hash_struct *h2)
 {
-  rtx r1 = ((const struct toc_hash_struct *) h1)->key;
-  rtx r2 = ((const struct toc_hash_struct *) h2)->key;
+  rtx r1 = h1->key;
+  rtx r2 = h2->key;
 
-  if (((const struct toc_hash_struct *) h1)->key_mode
-      != ((const struct toc_hash_struct *) h2)->key_mode)
+  if (h1->key_mode != h2->key_mode)
     return 0;
 
   return rtx_equal_p (r1, r2);
@@ -25666,20 +25668,18 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
   if (TARGET_TOC && GET_CODE (x) != LABEL_REF)
     {
       struct toc_hash_struct *h;
-      void * * found;
 
       /* Create toc_hash_table.  This can't be done at TARGET_OPTION_OVERRIDE
 	 time because GGC is not initialized at that point.  */
       if (toc_hash_table == NULL)
-	toc_hash_table = htab_create_ggc (1021, toc_hash_function,
-					  toc_hash_eq, NULL);
+	toc_hash_table = hash_table<toc_hasher>::create_ggc (1021);
 
       h = ggc_alloc<toc_hash_struct> ();
       h->key = x;
       h->key_mode = mode;
       h->labelno = labelno;
 
-      found = htab_find_slot (toc_hash_table, h, INSERT);
+      toc_hash_struct **found = toc_hash_table->find_slot (h, INSERT);
       if (*found == NULL)
 	*found = h;
       else  /* This is indeed a duplicate.
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index e2bf547..22703b7 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -758,20 +758,18 @@ is_invisiref_parm (const_tree t)
 
 /* Return true if the uid in both int tree maps are equal.  */
 
-int
-cxx_int_tree_map_eq (const void *va, const void *vb)
+bool
+cxx_int_tree_map_hasher::equal (cxx_int_tree_map *a, cxx_int_tree_map *b)
 {
-  const struct cxx_int_tree_map *a = (const struct cxx_int_tree_map *) va;
-  const struct cxx_int_tree_map *b = (const struct cxx_int_tree_map *) vb;
   return (a->uid == b->uid);
 }
 
 /* Hash a UID in a cxx_int_tree_map.  */
 
 unsigned int
-cxx_int_tree_map_hash (const void *item)
+cxx_int_tree_map_hasher::hash (cxx_int_tree_map *item)
 {
-  return ((const struct cxx_int_tree_map *)item)->uid;
+  return item->uid;
 }
 
 /* A stable comparison routine for use with splay trees and DECLs.  */
@@ -911,9 +909,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
     {
       struct cxx_int_tree_map *h, in;
       in.uid = DECL_UID (stmt);
-      h = (struct cxx_int_tree_map *)
-	  htab_find_with_hash (cp_function_chain->extern_decl_map,
-			       &in, in.uid);
+      h = cp_function_chain->extern_decl_map->find_with_hash (&in, in.uid);
       if (h)
 	{
 	  *stmt_p = h->to;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fe1651e..b116e64 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1133,13 +1133,24 @@ struct GTY(()) saved_scope {
 
 extern GTY(()) struct saved_scope *scope_chain;
 
-struct GTY(()) cxx_int_tree_map {
+struct GTY((for_user)) cxx_int_tree_map {
   unsigned int uid;
   tree to;
 };
 
-extern unsigned int cxx_int_tree_map_hash (const void *);
-extern int cxx_int_tree_map_eq (const void *, const void *);
+struct cxx_int_tree_map_hasher : ggc_hasher<cxx_int_tree_map *>
+{
+  static hashval_t hash (cxx_int_tree_map *);
+  static bool equal (cxx_int_tree_map *, cxx_int_tree_map *);
+};
+
+struct named_label_entry;
+
+struct named_label_hasher : ggc_hasher<named_label_entry *>
+{
+  static hashval_t hash (named_label_entry *);
+  static bool equal (named_label_entry *, named_label_entry *);
+};
 
 /* Global state pertinent to the current function.  */
 
@@ -1165,13 +1176,13 @@ struct GTY(()) language_function {
   /* True if this function can throw an exception.  */
   BOOL_BITFIELD can_throw : 1;
 
-  htab_t GTY((param_is(struct named_label_entry))) x_named_labels;
+  hash_table<named_label_hasher> *x_named_labels;
   cp_binding_level *bindings;
   vec<tree, va_gc> *x_local_names;
   /* Tracking possibly infinite loops.  This is a vec<tree> only because
      vec<bool> doesn't work with gtype.  */
   vec<tree, va_gc> *infinite_loops;
-  htab_t GTY((param_is (struct cxx_int_tree_map))) extern_decl_map;
+  hash_table<cxx_int_tree_map_hasher> *extern_decl_map;
 };
 
 /* The current C++-specific per-function global variables.  */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7856dd8..d0ece00 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "tree-hasher.h"
 #include "stringpool.h"
 #include "stor-layout.h"
 #include "varasm.h"
@@ -88,8 +89,6 @@ static int member_function_or_else (tree, tree, enum overload_flags);
 static void bad_specifiers (tree, enum bad_spec_place, int, int, int, int,
 			    int);
 static void check_for_uninitialized_const_var (tree);
-static hashval_t typename_hash (const void *);
-static int typename_compare (const void *, const void *);
 static tree local_variable_p_walkfn (tree *, int *, void *);
 static tree record_builtin_java_type (const char *, int);
 static const char *tag_name (enum tag_types);
@@ -210,7 +209,7 @@ struct GTY((chain_next ("%h.next"))) named_label_use_entry {
    we can clear out their names' definitions at the end of the
    function, and so we can check the validity of jumps to these labels.  */
 
-struct GTY(()) named_label_entry {
+struct GTY((for_user)) named_label_entry {
   /* The decl itself.  */
   tree label_decl;
 
@@ -394,11 +393,10 @@ pop_label (tree label, tree old_value)
    go out of scope.  BLOCK is the top-level block for the
    function.  */
 
-static int
-pop_labels_1 (void **slot, void *data)
+int
+pop_labels_1 (named_label_entry **slot, tree block)
 {
-  struct named_label_entry *ent = (struct named_label_entry *) *slot;
-  tree block = (tree) data;
+  struct named_label_entry *ent = *slot;
 
   pop_label (ent->label_decl, NULL_TREE);
 
@@ -407,7 +405,7 @@ pop_labels_1 (void **slot, void *data)
   DECL_CHAIN (ent->label_decl) = BLOCK_VARS (block);
   BLOCK_VARS (block) = ent->label_decl;
 
-  htab_clear_slot (named_labels, slot);
+  named_labels->clear_slot (slot);
 
   return 1;
 }
@@ -417,7 +415,7 @@ pop_labels (tree block)
 {
   if (named_labels)
     {
-      htab_traverse (named_labels, pop_labels_1, block);
+      named_labels->traverse<tree, pop_labels_1> (block);
       named_labels = NULL;
     }
 }
@@ -428,13 +426,12 @@ static void
 pop_local_label (tree label, tree old_value)
 {
   struct named_label_entry dummy;
-  void **slot;
 
   pop_label (label, old_value);
 
   dummy.label_decl = label;
-  slot = htab_find_slot (named_labels, &dummy, NO_INSERT);
-  htab_clear_slot (named_labels, slot);
+  named_label_entry **slot = named_labels->find_slot (&dummy, NO_INSERT);
+  named_labels->clear_slot (slot);
 }
 
 /* The following two routines are used to interface to Objective-C++.
@@ -474,11 +471,10 @@ objc_mark_locals_volatile (void *enclosing_blk)
 
 /* Update data for defined and undefined labels when leaving a scope.  */
 
-static int
-poplevel_named_label_1 (void **slot, void *data)
+int
+poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl)
 {
-  struct named_label_entry *ent = (struct named_label_entry *) *slot;
-  cp_binding_level *bl = (cp_binding_level *) data;
+  named_label_entry *ent = *slot;
   cp_binding_level *obl = bl->level_chain;
 
   if (ent->binding_level == bl)
@@ -585,8 +581,8 @@ poplevel (int keep, int reverse, int functionbody)
   /* Any uses of undefined labels, and any defined labels, now operate
      under constraints of next binding contour.  */
   if (cfun && !functionbody && named_labels)
-    htab_traverse (named_labels, poplevel_named_label_1,
-		   current_binding_level);
+    named_labels->traverse<cp_binding_level *, poplevel_named_label_1>
+		   (current_binding_level);
 
   /* Get the decls in the order they were written.
      Usually current_binding_level->names is in reverse order.
@@ -2717,19 +2713,16 @@ redeclaration_error_message (tree newdecl, tree olddecl)
 
 /* Hash and equality functions for the named_label table.  */
 
-static hashval_t
-named_label_entry_hash (const void *data)
+hashval_t
+named_label_hasher::hash (named_label_entry *ent)
 {
-  const struct named_label_entry *ent = (const struct named_label_entry *) data;
   return DECL_UID (ent->label_decl);
 }
 
-static int
-named_label_entry_eq (const void *a, const void *b)
+bool
+named_label_hasher::equal (named_label_entry *a, named_label_entry *b)
 {
-  const struct named_label_entry *ent_a = (const struct named_label_entry *) a;
-  const struct named_label_entry *ent_b = (const struct named_label_entry *) b;
-  return ent_a->label_decl == ent_b->label_decl;
+  return a->label_decl == b->label_decl;
 }
 
 /* Create a new label, named ID.  */
@@ -2738,7 +2731,6 @@ static tree
 make_label_decl (tree id, int local_p)
 {
   struct named_label_entry *ent;
-  void **slot;
   tree decl;
 
   decl = build_decl (input_location, LABEL_DECL, id, void_type_node);
@@ -2756,8 +2748,7 @@ make_label_decl (tree id, int local_p)
 
   /* Create the label htab for the function on demand.  */
   if (!named_labels)
-    named_labels = htab_create_ggc (13, named_label_entry_hash,
-				    named_label_entry_eq, NULL);
+    named_labels = hash_table<named_label_hasher>::create_ggc (13);
 
   /* Record this label on the list of labels used in this function.
      We do this before calling make_label_decl so that we get the
@@ -2765,7 +2756,7 @@ make_label_decl (tree id, int local_p)
   ent = ggc_cleared_alloc<named_label_entry> ();
   ent->label_decl = decl;
 
-  slot = htab_find_slot (named_labels, ent, INSERT);
+  named_label_entry **slot = named_labels->find_slot (ent, INSERT);
   gcc_assert (*slot == NULL);
   *slot = ent;
 
@@ -2979,7 +2970,7 @@ check_goto (tree decl)
     return;
 
   dummy.label_decl = decl;
-  ent = (struct named_label_entry *) htab_find (named_labels, &dummy);
+  ent = named_labels->find (&dummy);
   gcc_assert (ent != NULL);
 
   /* If the label hasn't been defined yet, defer checking.  */
@@ -3089,7 +3080,7 @@ define_label_1 (location_t location, tree name)
   decl = lookup_label (name);
 
   dummy.label_decl = decl;
-  ent = (struct named_label_entry *) htab_find (named_labels, &dummy);
+  ent = named_labels->find (&dummy);
   gcc_assert (ent != NULL);
 
   /* After labels, make any new cleanups in the function go into their
@@ -3264,50 +3255,50 @@ finish_case_label (location_t loc, tree low_value, tree high_value)
   return r;
 }
 
-/* Hash a TYPENAME_TYPE.  K is really of type `tree'.  */
-
-static hashval_t
-typename_hash (const void* k)
-{
-  hashval_t hash;
-  const_tree const t = (const_tree) k;
-
-  hash = (htab_hash_pointer (TYPE_CONTEXT (t))
-	  ^ htab_hash_pointer (TYPE_IDENTIFIER (t)));
-
-  return hash;
-}
-
-typedef struct typename_info {
+struct typename_info {
   tree scope;
   tree name;
   tree template_id;
   bool enum_p;
   bool class_p;
-} typename_info;
-
-/* Compare two TYPENAME_TYPEs.  K1 is really of type `tree', K2 is
-   really of type `typename_info*'  */
+};
 
-static int
-typename_compare (const void * k1, const void * k2)
+struct typename_hasher : ggc_hasher<tree>
 {
-  const_tree const t1 = (const_tree) k1;
-  const typename_info *const t2 = (const typename_info *) k2;
+  typedef typename_info *compare_type;
 
-  return (TYPE_IDENTIFIER (t1) == t2->name
-	  && TYPE_CONTEXT (t1) == t2->scope
-	  && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
-	  && TYPENAME_IS_ENUM_P (t1) == t2->enum_p
-	  && TYPENAME_IS_CLASS_P (t1) == t2->class_p);
-}
+  /* Hash a TYPENAME_TYPE.  */
+
+  static hashval_t
+  hash (tree t)
+  {
+    hashval_t hash;
+
+    hash = (htab_hash_pointer (TYPE_CONTEXT (t))
+	    ^ htab_hash_pointer (TYPE_IDENTIFIER (t)));
+
+    return hash;
+  }
+
+  /* Compare two TYPENAME_TYPEs.  */
+
+  static bool
+  equal (tree t1, const typename_info *t2)
+  {
+    return (TYPE_IDENTIFIER (t1) == t2->name
+	    && TYPE_CONTEXT (t1) == t2->scope
+	    && TYPENAME_TYPE_FULLNAME (t1) == t2->template_id
+	    && TYPENAME_IS_ENUM_P (t1) == t2->enum_p
+	    && TYPENAME_IS_CLASS_P (t1) == t2->class_p);
+  }
+};
 
 /* Build a TYPENAME_TYPE.  If the type is `typename T::t', CONTEXT is
    the type of `T', NAME is the IDENTIFIER_NODE for `t'.
 
    Returns the new TYPENAME_TYPE.  */
 
-static GTY ((param_is (union tree_node))) htab_t typename_htab;
+static GTY (()) hash_table<typename_hasher> *typename_htab;
 
 static tree
 build_typename_type (tree context, tree name, tree fullname,
@@ -3316,12 +3307,11 @@ build_typename_type (tree context, tree name, tree fullname,
   tree t;
   tree d;
   typename_info ti;
-  void **e;
+  tree *e;
   hashval_t hash;
 
   if (typename_htab == NULL)
-    typename_htab = htab_create_ggc (61, &typename_hash,
-				     &typename_compare, NULL);
+    typename_htab = hash_table<typename_hasher>::create_ggc (61);
 
   ti.scope = FROB_CONTEXT (context);
   ti.name = name;
@@ -3334,9 +3324,9 @@ build_typename_type (tree context, tree name, tree fullname,
 	   ^ htab_hash_pointer (ti.name));
 
   /* See if we already have this type.  */
-  e = htab_find_slot_with_hash (typename_htab, &ti, hash, INSERT);
+  e = typename_htab->find_slot_with_hash (&ti, hash, INSERT);
   if (*e)
-    t = (tree) *e;
+    t = *e;
   else
     {
       /* Build the TYPENAME_TYPE.  */
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 6e6aa8a..6b8f706 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "tree-hasher.h"
 #include "stor-layout.h"
 #include "stringpool.h"
 #include "tm_p.h"
@@ -3690,26 +3691,32 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
   return result;
 }
 
+struct conv_type_hasher : ggc_hasher<tree>
+{
+  static hashval_t hash (tree);
+  static bool equal (tree, tree);
+};
+
 /* This hash table maps TYPEs to the IDENTIFIER for a conversion
    operator to TYPE.  The nodes are IDENTIFIERs whose TREE_TYPE is the
    TYPE.  */
 
-static GTY ((param_is (union tree_node))) htab_t conv_type_names;
+static GTY (()) hash_table<conv_type_hasher> *conv_type_names;
 
 /* Hash a node (VAL1) in the table.  */
 
-static hashval_t
-hash_type (const void *val)
+hashval_t
+conv_type_hasher::hash (tree val)
 {
-  return (hashval_t) TYPE_UID (TREE_TYPE ((const_tree) val));
+  return (hashval_t) TYPE_UID (TREE_TYPE (val));
 }
 
 /* Compare VAL1 (a node in the table) with VAL2 (a TYPE).  */
 
-static int
-compare_type (const void *val1, const void *val2)
+bool
+conv_type_hasher::equal (tree val1, tree val2)
 {
-  return TREE_TYPE ((const_tree) val1) == (const_tree) val2;
+  return TREE_TYPE (val1) == val2;
 }
 
 /* Return an identifier for the mangled unqualified name for a
@@ -3719,25 +3726,25 @@ compare_type (const void *val1, const void *val2)
 tree
 mangle_conv_op_name_for_type (const tree type)
 {
-  void **slot;
+  tree *slot;
   tree identifier;
 
   if (type == error_mark_node)
     return error_mark_node;
 
   if (conv_type_names == NULL)
-    conv_type_names = htab_create_ggc (31, &hash_type, &compare_type, NULL);
+    conv_type_names = hash_table<conv_type_hasher>::create_ggc (31);
 
-  slot = htab_find_slot_with_hash (conv_type_names, type,
-				   (hashval_t) TYPE_UID (type), INSERT);
-  identifier = (tree)*slot;
+  slot = conv_type_names->find_slot_with_hash (type,
+					       (hashval_t) TYPE_UID (type),
+					       INSERT);
+  identifier = *slot;
   if (!identifier)
     {
       char buffer[64];
 
        /* Create a unique name corresponding to TYPE.  */
-      sprintf (buffer, "operator %lu",
-	       (unsigned long) htab_elements (conv_type_names));
+      sprintf (buffer, "operator %lu", conv_type_names->elements ());
       identifier = get_identifier (buffer);
       *slot = identifier;
 
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index ebcbb5c..d42bcac 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -766,22 +766,19 @@ pushdecl_maybe_friend_1 (tree x, bool is_friend)
 		   middle end.  */
 		{
 		  struct cxx_int_tree_map *h;
-		  void **loc;
 
 		  TREE_PUBLIC (x) = TREE_PUBLIC (t);
 
 		  if (cp_function_chain->extern_decl_map == NULL)
 		    cp_function_chain->extern_decl_map
-		      = htab_create_ggc (20, cxx_int_tree_map_hash,
-					 cxx_int_tree_map_eq, NULL);
+		      = hash_table<cxx_int_tree_map_hasher>::create_ggc (20);
 
 		  h = ggc_alloc<cxx_int_tree_map> ();
 		  h->uid = DECL_UID (x);
 		  h->to = t;
-		  loc = htab_find_slot_with_hash
-			  (cp_function_chain->extern_decl_map, h,
-			   h->uid, INSERT);
-		  *(struct cxx_int_tree_map **) loc = h;
+		  cxx_int_tree_map **loc = cp_function_chain->extern_decl_map
+		    ->find_slot (h, INSERT);
+		  *loc = h;
 		}
 	    }
 	  else if (TREE_CODE (t) == PARM_DECL)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d1dddff..a5d681d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -80,18 +80,22 @@ static tree cur_stmt_expr;
 /* True if we've recursed into fn_type_unification too many times.  */
 static bool excessive_deduction_depth;
 
-typedef struct GTY(()) spec_entry
+struct GTY((for_user)) spec_entry
 {
   tree tmpl;
   tree args;
   tree spec;
-} spec_entry;
+};
+
+struct spec_hasher : ggc_hasher<spec_entry *>
+{
+  static hashval_t hash (spec_entry *);
+  static bool equal (spec_entry *, spec_entry *);
+};
 
-static GTY ((param_is (spec_entry)))
-  htab_t decl_specializations;
+static GTY (()) hash_table<spec_hasher> *decl_specializations;
 
-static GTY ((param_is (spec_entry)))
-  htab_t type_specializations;
+static GTY (()) hash_table<spec_hasher> *type_specializations;
 
 /* Contains canonical template parameter types. The vector is indexed by
    the TEMPLATE_TYPE_IDX of the template parameter. Each element is a
@@ -153,7 +157,6 @@ static bool inline_needs_template_parms (tree, bool);
 static void push_inline_template_parms_recursive (tree, int);
 static tree retrieve_local_specialization (tree);
 static void register_local_specialization (tree, tree);
-static hashval_t hash_specialization (const void *p);
 static tree reduce_template_parm_level (tree, tree, int, tree, tsubst_flags_t);
 static int mark_template_parm (tree, void *);
 static int template_parm_this_level_p (tree, void *);
@@ -931,18 +934,18 @@ maybe_process_partial_specialization (tree type)
 		     new member specialization template.  */
 		  spec_entry elt;
 		  spec_entry *entry;
-		  void **slot;
 
 		  elt.tmpl = most_general_template (tmpl);
 		  elt.args = CLASSTYPE_TI_ARGS (inst);
 		  elt.spec = inst;
 
-		  htab_remove_elt (type_specializations, &elt);
+		  type_specializations->remove_elt (&elt);
 
 		  elt.tmpl = tmpl;
 		  elt.args = INNERMOST_TEMPLATE_ARGS (elt.args);
 
-		  slot = htab_find_slot (type_specializations, &elt, INSERT);
+		  spec_entry **slot
+		    = type_specializations->find_slot (&elt, INSERT);
 		  entry = ggc_alloc<spec_entry> ();
 		  *entry = elt;
 		  *slot = entry;
@@ -1085,7 +1088,7 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash)
     {
       spec_entry *found;
       spec_entry elt;
-      htab_t specializations;
+      hash_table<spec_hasher> *specializations;
 
       elt.tmpl = tmpl;
       elt.args = args;
@@ -1097,8 +1100,8 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash)
 	specializations = decl_specializations;
 
       if (hash == 0)
-	hash = hash_specialization (&elt);
-      found = (spec_entry *) htab_find_with_hash (specializations, &elt, hash);
+	hash = spec_hasher::hash (&elt);
+      found = specializations->find_with_hash (&elt, hash);
       if (found)
 	return found->spec;
     }
@@ -1343,7 +1346,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
 			 hashval_t hash)
 {
   tree fn;
-  void **slot = NULL;
+  spec_entry **slot = NULL;
   spec_entry elt;
 
   gcc_assert ((TREE_CODE (tmpl) == TEMPLATE_DECL && DECL_P (spec))
@@ -1376,10 +1379,10 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
       elt.spec = spec;
 
       if (hash == 0)
-	hash = hash_specialization (&elt);
+	hash = spec_hasher::hash (&elt);
 
       slot =
-	htab_find_slot_with_hash (decl_specializations, &elt, hash, INSERT);
+	decl_specializations->find_slot_with_hash (&elt, hash, INSERT);
       if (*slot)
 	fn = ((spec_entry *) *slot)->spec;
       else
@@ -1500,11 +1503,9 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend,
 
 int comparing_specializations;
 
-static int
-eq_specializations (const void *p1, const void *p2)
+bool
+spec_hasher::equal (spec_entry *e1, spec_entry *e2)
 {
-  const spec_entry *e1 = (const spec_entry *)p1;
-  const spec_entry *e2 = (const spec_entry *)p2;
   int equal;
 
   ++comparing_specializations;
@@ -1527,10 +1528,9 @@ hash_tmpl_and_args (tree tmpl, tree args)
 /* Returns a hash for a spec_entry node based on the TMPL and ARGS members,
    ignoring SPEC.  */
 
-static hashval_t
-hash_specialization (const void *p)
+hashval_t
+spec_hasher::hash (spec_entry *e)
 {
-  const spec_entry *e = (const spec_entry *)p;
   return hash_tmpl_and_args (e->tmpl, e->args);
 }
 
@@ -1709,7 +1709,7 @@ reregister_specialization (tree spec, tree tinfo, tree new_spec)
   elt.args = TI_ARGS (tinfo);
   elt.spec = NULL_TREE;
 
-  entry = (spec_entry *) htab_find (decl_specializations, &elt);
+  entry = decl_specializations->find (&elt);
   if (entry != NULL)
     {
       gcc_assert (entry->spec == spec || entry->spec == new_spec);
@@ -7417,7 +7417,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 {
   tree templ = NULL_TREE, parmlist;
   tree t;
-  void **slot;
+  spec_entry **slot;
   spec_entry *entry;
   spec_entry elt;
   hashval_t hash;
@@ -7683,9 +7683,8 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
       /* If we already have this specialization, return it.  */
       elt.tmpl = gen_tmpl;
       elt.args = arglist;
-      hash = hash_specialization (&elt);
-      entry = (spec_entry *) htab_find_with_hash (type_specializations,
-						  &elt, hash);
+      hash = spec_hasher::hash (&elt);
+      entry = type_specializations->find_with_hash (&elt, hash);
 
       if (entry)
 	return entry->spec;
@@ -7929,8 +7928,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
       SET_TYPE_TEMPLATE_INFO (t, build_template_info (found, arglist));
 
       elt.spec = t;
-      slot = htab_find_slot_with_hash (type_specializations,
-				       &elt, hash, INSERT);
+      slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT);
       entry = ggc_alloc<spec_entry> ();
       *entry = elt;
       *slot = entry;
@@ -8651,7 +8649,7 @@ tsubst_friend_function (tree decl, tree args)
 		      elt.args = DECL_TI_ARGS (spec);
 		      elt.spec = NULL_TREE;
 
-		      htab_remove_elt (decl_specializations, &elt);
+		      decl_specializations->remove_elt (&elt);
 
 		      DECL_TI_ARGS (spec)
 			= add_outermost_template_args (new_args,
@@ -22304,14 +22302,8 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx)
 void
 init_template_processing (void)
 {
-  decl_specializations = htab_create_ggc (37,
-					  hash_specialization,
-					  eq_specializations,
-					  ggc_free);
-  type_specializations = htab_create_ggc (37,
-					  hash_specialization,
-					  eq_specializations,
-					  ggc_free);
+  decl_specializations = hash_table<spec_hasher>::create_ggc (37);
+  type_specializations = hash_table<spec_hasher>::create_ggc (37);
 }
 
 /* Print stats about the template hash tables for -fstats.  */
@@ -22320,13 +22312,13 @@ void
 print_template_statistics (void)
 {
   fprintf (stderr, "decl_specializations: size %ld, %ld elements, "
-	   "%f collisions\n", (long) htab_size (decl_specializations),
-	   (long) htab_elements (decl_specializations),
-	   htab_collisions (decl_specializations));
+	   "%f collisions\n", decl_specializations->size (),
+	   decl_specializations->elements (),
+	   decl_specializations->collisions ());
   fprintf (stderr, "type_specializations: size %ld, %ld elements, "
-	   "%f collisions\n", (long) htab_size (type_specializations),
-	   (long) htab_elements (type_specializations),
-	   htab_collisions (type_specializations));
+	   "%f collisions\n", type_specializations->size (),
+	   type_specializations->elements (),
+	   type_specializations->collisions ());
 }
 
 #include "gt-cp-pt.h"
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7569826..7bf73f0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -7557,35 +7557,38 @@ ensure_literal_type_for_constexpr_object (tree decl)
 
 /* Representation of entries in the constexpr function definition table.  */
 
-typedef struct GTY(()) constexpr_fundef {
+struct GTY((for_user)) constexpr_fundef {
   tree decl;
   tree body;
-} constexpr_fundef;
+};
+
+struct constexpr_fundef_hasher : ggc_hasher<constexpr_fundef *>
+{
+  static hashval_t hash (constexpr_fundef *);
+  static bool equal (constexpr_fundef *, constexpr_fundef *);
+};
 
 /* This table holds all constexpr function definitions seen in
    the current translation unit.  */
 
-static GTY ((param_is (constexpr_fundef))) htab_t constexpr_fundef_table;
+static GTY (()) hash_table<constexpr_fundef_hasher> *constexpr_fundef_table;
 
 /* Utility function used for managing the constexpr function table.
    Return true if the entries pointed to by P and Q are for the
    same constexpr function.  */
 
-static inline int
-constexpr_fundef_equal (const void *p, const void *q)
+inline bool
+constexpr_fundef_hasher::equal (constexpr_fundef *lhs, constexpr_fundef *rhs)
 {
-  const constexpr_fundef *lhs = (const constexpr_fundef *) p;
-  const constexpr_fundef *rhs = (const constexpr_fundef *) q;
   return lhs->decl == rhs->decl;
 }
 
 /* Utility function used for managing the constexpr function table.
    Return a hash value for the entry pointed to by Q.  */
 
-static inline hashval_t
-constexpr_fundef_hash (const void *p)
+inline hashval_t
+constexpr_fundef_hasher::hash (constexpr_fundef *fundef)
 {
-  const constexpr_fundef *fundef = (const constexpr_fundef *) p;
   return DECL_UID (fundef->decl);
 }
 
@@ -7599,7 +7602,7 @@ retrieve_constexpr_fundef (tree fun)
     return NULL;
 
   fundef.decl = fun;
-  return (constexpr_fundef *) htab_find (constexpr_fundef_table, &fundef);
+  return constexpr_fundef_table->find (&fundef);
 }
 
 /* Check whether the parameter and return types of FUN are valid for a
@@ -8165,14 +8168,12 @@ register_constexpr_fundef (tree fun, tree body)
 
   /* Create the constexpr function table if necessary.  */
   if (constexpr_fundef_table == NULL)
-    constexpr_fundef_table = htab_create_ggc (101,
-                                              constexpr_fundef_hash,
-                                              constexpr_fundef_equal,
-                                              ggc_free);
+    constexpr_fundef_table
+      = hash_table<constexpr_fundef_hasher>::create_ggc (101);
+
   entry.decl = fun;
   entry.body = body;
-  slot = (constexpr_fundef **)
-    htab_find_slot (constexpr_fundef_table, &entry, INSERT);
+  slot = constexpr_fundef_table->find_slot (&entry, INSERT);
 
   gcc_assert (*slot == NULL);
   *slot = ggc_alloc<constexpr_fundef> ();
@@ -8225,7 +8226,7 @@ explain_invalid_constexpr_fn (tree fun)
    along with the bindings of parameters to their arguments, for
    the purpose of compile time evaluation.  */
 
-typedef struct GTY(()) constexpr_call {
+struct GTY((for_user)) constexpr_call {
   /* Description of the constexpr function definition.  */
   constexpr_fundef *fundef;
   /* Parameter bindings environment.  A TREE_LIST where each TREE_PURPOSE
@@ -8243,39 +8244,42 @@ typedef struct GTY(()) constexpr_call {
   /* The hash of this call; we remember it here to avoid having to
      recalculate it when expanding the hash table.  */
   hashval_t hash;
-} constexpr_call;
+};
+
+struct constexpr_call_hasher : ggc_hasher<constexpr_call *>
+{
+  static hashval_t hash (constexpr_call *);
+  static bool equal (constexpr_call *, constexpr_call *);
+		     };
 
 /* A table of all constexpr calls that have been evaluated by the
    compiler in this translation unit.  */
 
-static GTY ((param_is (constexpr_call))) htab_t constexpr_call_table;
+static GTY (()) hash_table<constexpr_call_hasher> *constexpr_call_table;
 
 static tree cxx_eval_constant_expression (const constexpr_call *, tree,
 					  bool, bool, bool *, bool *);
 
 /* Compute a hash value for a constexpr call representation.  */
 
-static hashval_t
-constexpr_call_hash (const void *p)
+inline hashval_t
+constexpr_call_hasher::hash (constexpr_call *info)
 {
-  const constexpr_call *info = (const constexpr_call *) p;
   return info->hash;
 }
 
-/* Return 1 if the objects pointed to by P and Q represent calls
+/* Return true if the objects pointed to by P and Q represent calls
    to the same constexpr function with the same arguments.
-   Otherwise, return 0.  */
+   Otherwise, return false.  */
 
-static int
-constexpr_call_equal (const void *p, const void *q)
+bool
+constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs)
 {
-  const constexpr_call *lhs = (const constexpr_call *) p;
-  const constexpr_call *rhs = (const constexpr_call *) q;
   tree lhs_bindings;
   tree rhs_bindings;
   if (lhs == rhs)
     return 1;
-  if (!constexpr_fundef_equal (lhs->fundef, rhs->fundef))
+  if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef))
     return 0;
   lhs_bindings = lhs->bindings;
   rhs_bindings = rhs->bindings;
@@ -8298,10 +8302,7 @@ static void
 maybe_initialize_constexpr_call_table (void)
 {
   if (constexpr_call_table == NULL)
-    constexpr_call_table = htab_create_ggc (101,
-                                            constexpr_call_hash,
-                                            constexpr_call_equal,
-                                            ggc_free);
+    constexpr_call_table = hash_table<constexpr_call_hasher>::create_ggc (101);
 }
 
 /* Return true if T designates the implied `this' parameter.  */
@@ -8610,12 +8611,11 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
 
   new_call.hash
     = iterative_hash_template_arg (new_call.bindings,
-				   constexpr_fundef_hash (new_call.fundef));
+				   constexpr_fundef_hasher::hash (new_call.fundef));
 
   /* If we have seen this call before, we are done.  */
   maybe_initialize_constexpr_call_table ();
-  slot = (constexpr_call **)
-    htab_find_slot (constexpr_call_table, &new_call, INSERT);
+  slot = constexpr_call_table->find_slot (&new_call, INSERT);
   entry = *slot;
   if (entry == NULL)
     {
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2247eb5..c097f75 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "tree-hasher.h"
 #include "stor-layout.h"
 #include "print-tree.h"
 #include "tree-iterator.h"
@@ -40,9 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 
 static tree bot_manip (tree *, int *, void *);
 static tree bot_replace (tree *, int *, void *);
-static int list_hash_eq (const void *, const void *);
 static hashval_t list_hash_pieces (tree, tree, tree);
-static hashval_t list_hash (const void *);
 static tree build_target_expr (tree, tree, tsubst_flags_t);
 static tree count_trees_r (tree *, int *, void *);
 static tree verify_stmt_tree_r (tree *, int *, void *);
@@ -722,13 +721,26 @@ rvalue (tree expr)
 }
 
 
+struct cplus_array_info
+{
+  tree type;
+  tree domain;
+};
+
+struct cplus_array_hasher : ggc_hasher<tree>
+{
+  typedef cplus_array_info *compare_type;
+
+  static hashval_t hash (tree t);
+  static bool equal (tree, cplus_array_info *);
+};
+
 /* Hash an ARRAY_TYPE.  K is really of type `tree'.  */
 
-static hashval_t
-cplus_array_hash (const void* k)
+hashval_t
+cplus_array_hasher::hash (tree t)
 {
   hashval_t hash;
-  const_tree const t = (const_tree) k;
 
   hash = TYPE_UID (TREE_TYPE (t));
   if (TYPE_DOMAIN (t))
@@ -736,26 +748,18 @@ cplus_array_hash (const void* k)
   return hash;
 }
 
-typedef struct cplus_array_info {
-  tree type;
-  tree domain;
-} cplus_array_info;
-
 /* Compare two ARRAY_TYPEs.  K1 is really of type `tree', K2 is really
    of type `cplus_array_info*'. */
 
-static int
-cplus_array_compare (const void * k1, const void * k2)
+bool
+cplus_array_hasher::equal (tree t1, cplus_array_info *t2)
 {
-  const_tree const t1 = (const_tree) k1;
-  const cplus_array_info *const t2 = (const cplus_array_info*) k2;
-
   return (TREE_TYPE (t1) == t2->type && TYPE_DOMAIN (t1) == t2->domain);
 }
 
 /* Hash table containing dependent array types, which are unsuitable for
    the language-independent type hash table.  */
-static GTY ((param_is (union tree_node))) htab_t cplus_array_htab;
+static GTY (()) hash_table<cplus_array_hasher> *cplus_array_htab;
 
 /* Build an ARRAY_TYPE without laying it out.  */
 
@@ -813,13 +817,11 @@ build_cplus_array_type (tree elt_type, tree index_type)
     {
       /* Since type_hash_canon calls layout_type, we need to use our own
 	 hash table.  */
-      void **e;
       cplus_array_info cai;
       hashval_t hash;
 
       if (cplus_array_htab == NULL)
-	cplus_array_htab = htab_create_ggc (61, &cplus_array_hash,
-					    &cplus_array_compare, NULL);
+	cplus_array_htab = hash_table<cplus_array_hasher>::create_ggc (61);
       
       hash = TYPE_UID (elt_type);
       if (index_type)
@@ -827,7 +829,7 @@ build_cplus_array_type (tree elt_type, tree index_type)
       cai.type = elt_type;
       cai.domain = index_type;
 
-      e = htab_find_slot_with_hash (cplus_array_htab, &cai, hash, INSERT); 
+      tree *e = cplus_array_htab->find_slot_with_hash (&cai, hash, INSERT); 
       if (*e)
 	/* We have found the type: we're done.  */
 	return (tree) *e;
@@ -1617,14 +1619,6 @@ copy_binfo (tree binfo, tree type, tree t, tree *igo_prev, int virt)
 /* Hashing of lists so that we don't make duplicates.
    The entry point is `list_hash_canon'.  */
 
-/* Now here is the hash table.  When recording a list, it is added
-   to the slot whose index is the hash code mod the table size.
-   Note that the hash table is used for several kinds of lists.
-   While all these live in the same table, they are completely independent,
-   and the hash code is computed differently for each of these.  */
-
-static GTY ((param_is (union tree_node))) htab_t list_hash_table;
-
 struct list_proxy
 {
   tree purpose;
@@ -1632,15 +1626,28 @@ struct list_proxy
   tree chain;
 };
 
+struct list_hasher : ggc_hasher<tree>
+{
+  typedef list_proxy *compare_type;
+
+  static hashval_t hash (tree);
+  static bool equal (tree, list_proxy *);
+};
+
+/* Now here is the hash table.  When recording a list, it is added
+   to the slot whose index is the hash code mod the table size.
+   Note that the hash table is used for several kinds of lists.
+   While all these live in the same table, they are completely independent,
+   and the hash code is computed differently for each of these.  */
+
+static GTY (()) hash_table<list_hasher> *list_hash_table;
+
 /* Compare ENTRY (an entry in the hash table) with DATA (a list_proxy
    for a node we are thinking about adding).  */
 
-static int
-list_hash_eq (const void* entry, const void* data)
+bool
+list_hasher::equal (tree t, list_proxy *proxy)
 {
-  const_tree const t = (const_tree) entry;
-  const struct list_proxy *const proxy = (const struct list_proxy *) data;
-
   return (TREE_VALUE (t) == proxy->value
 	  && TREE_PURPOSE (t) == proxy->purpose
 	  && TREE_CHAIN (t) == proxy->chain);
@@ -1671,10 +1678,9 @@ list_hash_pieces (tree purpose, tree value, tree chain)
 
 /* Hash an already existing TREE_LIST.  */
 
-static hashval_t
-list_hash (const void* p)
+hashval_t
+list_hasher::hash (tree t)
 {
-  const_tree const t = (const_tree) p;
   return list_hash_pieces (TREE_PURPOSE (t),
 			   TREE_VALUE (t),
 			   TREE_CHAIN (t));
@@ -1688,7 +1694,7 @@ tree
 hash_tree_cons (tree purpose, tree value, tree chain)
 {
   int hashcode = 0;
-  void **slot;
+  tree *slot;
   struct list_proxy proxy;
 
   /* Hash the list node.  */
@@ -1699,8 +1705,7 @@ hash_tree_cons (tree purpose, tree value, tree chain)
   proxy.value = value;
   proxy.chain = chain;
   /* See if it is already in the table.  */
-  slot = htab_find_slot_with_hash (list_hash_table, &proxy, hashcode,
-				   INSERT);
+  slot = list_hash_table->find_slot_with_hash (&proxy, hashcode, INSERT);
   /* If not, create a new node.  */
   if (!*slot)
     *slot = tree_cons (purpose, value, chain);
@@ -3646,7 +3651,7 @@ cp_save_expr (tree expr)
 void
 init_tree (void)
 {
-  list_hash_table = htab_create_ggc (31, list_hash, list_hash_eq, NULL);
+  list_hash_table = hash_table<list_hasher>::create_ggc (61);
 }
 
 /* Returns the kind of special function that DECL (a FUNCTION_DECL)
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 0a851f1..ad69668 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -135,7 +135,7 @@ cxx_readonly_error (tree arg, enum lvalue_use errstring)
 /* Structure that holds information about declarations whose type was
    incomplete and we could not check whether it was abstract or not.  */
 
-struct GTY((chain_next ("%h.next"))) pending_abstract_type {
+struct GTY((chain_next ("%h.next"), for_user)) pending_abstract_type {
   /* Declaration which we are checking for abstractness. It is either
      a DECL node, or an IDENTIFIER_NODE if we do not have a full
      declaration available.  */
@@ -155,15 +155,19 @@ struct GTY((chain_next ("%h.next"))) pending_abstract_type {
   struct pending_abstract_type* next;
 };
 
+struct abstract_type_hasher : ggc_hasher<pending_abstract_type *>
+{
+  typedef tree compare_type;
+  static hashval_t hash (pending_abstract_type *);
+  static bool equal (pending_abstract_type *, tree);
+};
 
 /* Compute the hash value of the node VAL. This function is used by the
    hash table abstract_pending_vars.  */
 
-static hashval_t
-pat_calc_hash (const void* val)
+hashval_t
+abstract_type_hasher::hash (pending_abstract_type *pat)
 {
-  const struct pending_abstract_type *pat =
-     (const struct pending_abstract_type *) val;
   return (hashval_t) TYPE_UID (pat->type);
 }
 
@@ -171,21 +175,16 @@ pat_calc_hash (const void* val)
 /* Compare node VAL1 with the type VAL2. This function is used by the
    hash table abstract_pending_vars.  */
 
-static int
-pat_compare (const void* val1, const void* val2)
+bool
+abstract_type_hasher::equal (pending_abstract_type *pat1, tree type2)
 {
-  const struct pending_abstract_type *const pat1 =
-     (const struct pending_abstract_type *) val1;
-  const_tree const type2 = (const_tree)val2;
-
   return (pat1->type == type2);
 }
 
 /* Hash table that maintains pending_abstract_type nodes, for which we still
    need to check for type abstractness.  The key of the table is the type
    of the declaration.  */
-static GTY ((param_is (struct pending_abstract_type)))
-htab_t abstract_pending_vars = NULL;
+static GTY (()) hash_table<abstract_type_hasher> *abstract_pending_vars = NULL;
 
 static int abstract_virtuals_error_sfinae (tree, tree, abstract_class_use, tsubst_flags_t);
 
@@ -197,7 +196,6 @@ static int abstract_virtuals_error_sfinae (tree, tree, abstract_class_use, tsubs
 void
 complete_type_check_abstract (tree type)
 {
-  void **slot;
   struct pending_abstract_type *pat;
   location_t cur_loc = input_location;
 
@@ -207,11 +205,12 @@ complete_type_check_abstract (tree type)
     return;
 
   /* Retrieve the list of pending declarations for this type.  */
-  slot = htab_find_slot_with_hash (abstract_pending_vars, type,
-				   (hashval_t)TYPE_UID (type), NO_INSERT);
+  pending_abstract_type **slot
+    = abstract_pending_vars->find_slot_with_hash (type, TYPE_UID (type),
+						  NO_INSERT);
   if (!slot)
     return;
-  pat = (struct pending_abstract_type*)*slot;
+  pat = *slot;
   gcc_assert (pat);
 
   /* If the type is not abstract, do not do anything.  */
@@ -244,7 +243,7 @@ complete_type_check_abstract (tree type)
 	}
     }
 
-  htab_clear_slot (abstract_pending_vars, slot);
+  abstract_pending_vars->clear_slot (slot);
 
   input_location = cur_loc;
 }
@@ -282,17 +281,17 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
      name.  */
   if (!COMPLETE_TYPE_P (type) && (complain & tf_error))
     {
-      void **slot;
       struct pending_abstract_type *pat;
 
       gcc_assert (!decl || DECL_P (decl) || identifier_p (decl));
 
       if (!abstract_pending_vars)
-	abstract_pending_vars = htab_create_ggc (31, &pat_calc_hash,
-						&pat_compare, NULL);
+	abstract_pending_vars
+	  = hash_table<abstract_type_hasher>::create_ggc (31);
 
-      slot = htab_find_slot_with_hash (abstract_pending_vars, type,
-				      (hashval_t)TYPE_UID (type), INSERT);
+      pending_abstract_type **slot
+       	= abstract_pending_vars->find_slot_with_hash (type, TYPE_UID (type),
+						      INSERT);
 
       pat = ggc_alloc<pending_abstract_type> ();
       pat->type = type;
@@ -302,7 +301,7 @@ abstract_virtuals_error_sfinae (tree decl, tree type, abstract_class_use use,
 		    ? DECL_SOURCE_LOCATION (decl)
 		    : input_location);
 
-      pat->next = (struct pending_abstract_type *) *slot;
+      pat->next = *slot;
       *slot = pat;
 
       return 0;
diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi
index e50eef6..609cfce 100644
--- a/gcc/doc/gty.texi
+++ b/gcc/doc/gty.texi
@@ -197,6 +197,12 @@ If @code{skip} is applied to a field, the type machinery will ignore it.
 This is somewhat dangerous; the only safe use is in a union when one
 field really isn't ever used.
 
+@findex for_user
+Use this to mark types that need to be marked by user gc routines, but are not
+refered to in a template argument.  So if you have some user gc type T1 and a
+non user gc type T2 you can give T2 the for_user option so that the marking
+functions for T1 can call non mangled functions to mark T2.
+
 @findex desc
 @findex tag
 @findex default
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index a64038c..02f7f03 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -205,7 +205,7 @@ static GTY(()) section *debug_frame_section;
 
 static GTY(()) vec<dw_fde_ref, va_gc> *fde_vec;
 
-struct GTY(()) indirect_string_node {
+struct GTY((for_user)) indirect_string_node {
   const char *str;
   unsigned int refcount;
   enum dwarf_form form;
@@ -213,7 +213,15 @@ struct GTY(()) indirect_string_node {
   unsigned int index;
 };
 
-static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
+struct indirect_string_hasher : ggc_hasher<indirect_string_node *>
+{
+  typedef const char *compare_type;
+
+  static hashval_t hash (indirect_string_node *);
+  static bool equal (indirect_string_node *, const char *);
+};
+
+static GTY (()) hash_table<indirect_string_hasher> *debug_str_hash;
 
 /* With split_debug_info, both the comp_dir and dwo_name go in the
    main object file, rather than the dwo, similar to the force_direct
@@ -234,8 +242,7 @@ static GTY ((param_is (struct indirect_string_node))) htab_t debug_str_hash;
    main object file.  This limits the complexity to just the places
    that need it.  */
 
-static GTY ((param_is (struct indirect_string_node)))
-  htab_t skeleton_debug_str_hash;
+static GTY (()) hash_table<indirect_string_hasher> *skeleton_debug_str_hash;
 
 static GTY(()) int dw2_string_counter;
 
@@ -1235,7 +1242,7 @@ dwarf2out_switch_text_section (void)
    for emitting location expressions.  */
 
 /* Data about a single source file.  */
-struct GTY(()) dwarf_file_data {
+struct GTY((for_user)) dwarf_file_data {
   const char * filename;
   int emitted_number;
 };
@@ -1258,7 +1265,7 @@ enum ate_kind {
   ate_kind_label
 };
 
-typedef struct GTY(()) addr_table_entry_struct {
+typedef struct GTY((for_user)) addr_table_entry_struct {
   enum ate_kind kind;
   unsigned int refcount;
   unsigned int index;
@@ -2417,7 +2424,6 @@ build_cfa_aligned_loc (dw_cfa_location *cfa,
 /* And now, the support for symbolic debugging information.  */
 
 /* .debug_str support.  */
-static int output_indirect_string (void **, void *);
 
 static void dwarf2out_init (const char *);
 static void dwarf2out_finish (const char *);
@@ -2589,7 +2595,7 @@ dw_attr_node;
    The children of each node form a circular list linked by
    die_sib.  die_child points to the node *before* the "first" child node.  */
 
-typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct {
+typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
   union die_symbol_or_type_node
     {
       const char * GTY ((tag ("0"))) die_symbol;
@@ -2775,16 +2781,37 @@ static GTY(()) limbo_die_node *limbo_die_list;
    DW_AT_{,MIPS_}linkage_name once their DECL_ASSEMBLER_NAMEs are set.  */
 static GTY(()) limbo_die_node *deferred_asm_name;
 
+struct dwarf_file_hasher : ggc_hasher<dwarf_file_data *>
+{
+  typedef const char *compare_type;
+
+  static hashval_t hash (dwarf_file_data *);
+  static bool equal (dwarf_file_data *, const char *);
+};
+
 /* Filenames referenced by this compilation unit.  */
-static GTY((param_is (struct dwarf_file_data))) htab_t file_table;
+static GTY(()) hash_table<dwarf_file_hasher> *file_table;
 
+struct decl_die_hasher : ggc_hasher<die_node *>
+{
+  typedef tree compare_type;
+
+  static hashval_t hash (die_node *);
+  static bool equal (die_node *, tree);
+};
 /* A hash table of references to DIE's that describe declarations.
    The key is a DECL_UID() which is a unique number identifying each decl.  */
-static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
+static GTY (()) hash_table<decl_die_hasher> *decl_die_table;
+
+struct block_die_hasher : ggc_hasher<die_struct *>
+{
+  static hashval_t hash (die_struct *);
+  static bool equal (die_struct *, die_struct *);
+};
 
 /* A hash table of references to DIE's that describe COMMON blocks.
    The key is DECL_UID() ^ die_parent.  */
-static GTY ((param_is (struct die_struct))) htab_t common_block_die_table;
+static GTY (()) hash_table<block_die_hasher> *common_block_die_table;
 
 typedef struct GTY(()) die_arg_entry_struct {
     dw_die_ref die;
@@ -2808,7 +2835,7 @@ struct GTY ((chain_next ("%h.next"))) var_loc_node {
 };
 
 /* Variable location list.  */
-struct GTY (()) var_loc_list_def {
+struct GTY ((for_user)) var_loc_list_def {
   struct var_loc_node * GTY (()) first;
 
   /* Pointer to the last but one or last element of the
@@ -2840,8 +2867,16 @@ struct GTY ((chain_next ("%h.next"))) call_arg_loc_node {
 };
 
 
+struct decl_loc_hasher : ggc_hasher<var_loc_list *>
+{
+  typedef const_tree compare_type;
+
+  static hashval_t hash (var_loc_list *);
+  static bool equal (var_loc_list *, const_tree);
+};
+
 /* Table of decl location linked lists.  */
-static GTY ((param_is (var_loc_list))) htab_t decl_loc_table;
+static GTY (()) hash_table<decl_loc_hasher> *decl_loc_table;
 
 /* Head and tail of call_arg_loc chain.  */
 static GTY (()) struct call_arg_loc_node *call_arg_locations;
@@ -2857,7 +2892,7 @@ static int tail_call_site_count = -1;
 static vec<dw_die_ref> block_map;
 
 /* A cached location list.  */
-struct GTY (()) cached_dw_loc_list_def {
+struct GTY ((for_user)) cached_dw_loc_list_def {
   /* The DECL_UID of the decl that this entry describes.  */
   unsigned int decl_id;
 
@@ -2866,8 +2901,17 @@ struct GTY (()) cached_dw_loc_list_def {
 };
 typedef struct cached_dw_loc_list_def cached_dw_loc_list;
 
+struct dw_loc_list_hasher : ggc_hasher<cached_dw_loc_list *>
+{
+
+  typedef const_tree compare_type;
+  
+  static hashval_t hash (cached_dw_loc_list *);
+  static bool equal (cached_dw_loc_list *, const_tree);
+};
+
 /* Table of cached location lists.  */
-static GTY ((param_is (cached_dw_loc_list))) htab_t cached_dw_loc_list_table;
+static GTY (()) hash_table<dw_loc_list_hasher> *cached_dw_loc_list_table;
 
 /* A pointer to the base of a list of references to DIE's that
    are uniquely identified by their tag, presence/absence of
@@ -3005,8 +3049,6 @@ static void add_AT_double (dw_die_ref, enum dwarf_attribute,
 static inline void add_AT_vec (dw_die_ref, enum dwarf_attribute, unsigned int,
 			       unsigned int, unsigned char *);
 static void add_AT_data8 (dw_die_ref, enum dwarf_attribute, unsigned char *);
-static hashval_t debug_str_do_hash (const void *);
-static int debug_str_eq (const void *, const void *);
 static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *);
 static inline const char *AT_string (dw_attr_ref);
 static enum dwarf_form AT_string_form (dw_attr_ref);
@@ -3051,13 +3093,7 @@ static dw_die_ref lookup_type_die (tree);
 static dw_die_ref strip_naming_typedef (tree, dw_die_ref);
 static dw_die_ref lookup_type_die_strip_naming_typedef (tree);
 static void equate_type_number_to_die (tree, dw_die_ref);
-static hashval_t decl_die_table_hash (const void *);
-static int decl_die_table_eq (const void *, const void *);
 static dw_die_ref lookup_decl_die (tree);
-static hashval_t common_block_die_table_hash (const void *);
-static int common_block_die_table_eq (const void *, const void *);
-static hashval_t decl_loc_table_hash (const void *);
-static int decl_loc_table_eq (const void *, const void *);
 static var_loc_list *lookup_decl_loc (const_tree);
 static void equate_decl_number_to_die (tree, dw_die_ref);
 static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *);
@@ -3911,29 +3947,28 @@ add_AT_low_high_pc (dw_die_ref die, const char *lbl_low, const char *lbl_high,
 
 /* Hash and equality functions for debug_str_hash.  */
 
-static hashval_t
-debug_str_do_hash (const void *x)
+hashval_t
+indirect_string_hasher::hash (indirect_string_node *x)
 {
-  return htab_hash_string (((const struct indirect_string_node *)x)->str);
+  return htab_hash_string (x->str);
 }
 
-static int
-debug_str_eq (const void *x1, const void *x2)
+bool
+indirect_string_hasher::equal (indirect_string_node *x1, const char *x2)
 {
-  return strcmp ((((const struct indirect_string_node *)x1)->str),
-		 (const char *)x2) == 0;
+  return strcmp (x1->str, x2) == 0;
 }
 
 /* Add STR to the given string hash table.  */
 
 static struct indirect_string_node *
-find_AT_string_in_table (const char *str, htab_t table)
+find_AT_string_in_table (const char *str,
+			 hash_table<indirect_string_hasher> *table)
 {
   struct indirect_string_node *node;
-  void **slot;
 
-  slot = htab_find_slot_with_hash (table, str,
-				   htab_hash_string (str), INSERT);
+  indirect_string_node **slot
+    = table->find_slot_with_hash (str, htab_hash_string (str), INSERT);
   if (*slot == NULL)
     {
       node = ggc_cleared_alloc<indirect_string_node> ();
@@ -3941,7 +3976,7 @@ find_AT_string_in_table (const char *str, htab_t table)
       *slot = node;
     }
   else
-    node = (struct indirect_string_node *) *slot;
+    node = *slot;
 
   node->refcount++;
   return node;
@@ -3953,8 +3988,7 @@ static struct indirect_string_node *
 find_AT_string (const char *str)
 {
   if (! debug_str_hash)
-    debug_str_hash = htab_create_ggc (10, debug_str_do_hash,
-				      debug_str_eq, NULL);
+    debug_str_hash = hash_table<indirect_string_hasher>::create_ggc (10);
 
   return find_AT_string_in_table (str, debug_str_hash);
 }
@@ -4183,16 +4217,21 @@ AT_loc_list_ptr (dw_attr_ref a)
   return &a->dw_attr_val.v.val_loc_list;
 }
 
+struct addr_hasher : ggc_hasher<addr_table_entry *>
+{
+  static hashval_t hash (addr_table_entry *);
+  static bool equal (addr_table_entry *, addr_table_entry *);
+};
+
 /* Table of entries into the .debug_addr section.  */
 
-static GTY ((param_is (addr_table_entry))) htab_t addr_index_table;
+static GTY (()) hash_table<addr_hasher> *addr_index_table;
 
 /* Hash an address_table_entry.  */
 
-static hashval_t
-addr_table_entry_do_hash (const void *x)
+hashval_t
+addr_hasher::hash (addr_table_entry *a)
 {
-  const addr_table_entry *a = (const addr_table_entry *) x;
   inchash::hash hstate;
   switch (a->kind)
     {
@@ -4213,12 +4252,9 @@ addr_table_entry_do_hash (const void *x)
 
 /* Determine equality for two address_table_entries.  */
 
-static int
-addr_table_entry_eq (const void *x1, const void *x2)
+bool
+addr_hasher::equal (addr_table_entry *a1, addr_table_entry *a2)
 {
-  const addr_table_entry *a1 = (const addr_table_entry *) x1;
-  const addr_table_entry *a2 = (const addr_table_entry *) x2;
-
   if (a1->kind != a2->kind)
     return 0;
   switch (a1->kind)
@@ -4261,14 +4297,12 @@ add_addr_table_entry (void *addr, enum ate_kind kind)
 {
   addr_table_entry *node;
   addr_table_entry finder;
-  void **slot;
 
   gcc_assert (dwarf_split_debug_info);
   if (! addr_index_table)
-    addr_index_table = htab_create_ggc (10, addr_table_entry_do_hash,
-                                        addr_table_entry_eq, NULL);
+    addr_index_table = hash_table<addr_hasher>::create_ggc (10);
   init_addr_table_entry (&finder, kind, addr);
-  slot = htab_find_slot (addr_index_table, &finder, INSERT);
+  addr_table_entry **slot = addr_index_table->find_slot (&finder, INSERT);
 
   if (*slot == HTAB_EMPTY_ENTRY)
     {
@@ -4277,7 +4311,7 @@ add_addr_table_entry (void *addr, enum ate_kind kind)
       *slot = node;
     }
   else
-    node = (addr_table_entry *) *slot;
+    node = *slot;
 
   node->refcount++;
   return node;
@@ -4317,11 +4351,10 @@ remove_loc_list_addr_table_entries (dw_loc_descr_ref descr)
    because the indexing code relies on htab_traverse to traverse nodes
    in the same order for each run. */
 
-static int
-index_addr_table_entry (void **h, void *v)
+int
+index_addr_table_entry (addr_table_entry **h, unsigned int *index)
 {
-  addr_table_entry *node = (addr_table_entry *) *h;
-  unsigned int *index = (unsigned int *) v;
+  addr_table_entry *node = *h;
 
   /* Don't index unreferenced nodes.  */
   if (node->refcount == 0)
@@ -4916,18 +4949,18 @@ equate_type_number_to_die (tree type, dw_die_ref type_die)
 
 /* Returns a hash value for X (which really is a die_struct).  */
 
-static hashval_t
-decl_die_table_hash (const void *x)
+inline hashval_t
+decl_die_hasher::hash (die_node *x)
 {
-  return (hashval_t) ((const_dw_die_ref) x)->decl_id;
+  return (hashval_t) x->decl_id;
 }
 
 /* Return nonzero if decl_id of die_struct X is the same as UID of decl *Y.  */
 
-static int
-decl_die_table_eq (const void *x, const void *y)
+inline bool
+decl_die_hasher::equal (die_node *x, tree y)
 {
-  return (((const_dw_die_ref) x)->decl_id == DECL_UID ((const_tree) y));
+  return (x->decl_id == DECL_UID (y));
 }
 
 /* Return the DIE associated with a given declaration.  */
@@ -4935,24 +4968,24 @@ decl_die_table_eq (const void *x, const void *y)
 static inline dw_die_ref
 lookup_decl_die (tree decl)
 {
-  return (dw_die_ref) htab_find_with_hash (decl_die_table, decl, DECL_UID (decl));
+  return decl_die_table->find_with_hash (decl, DECL_UID (decl));
 }
 
 /* Returns a hash value for X (which really is a var_loc_list).  */
 
-static hashval_t
-decl_loc_table_hash (const void *x)
+inline hashval_t
+decl_loc_hasher::hash (var_loc_list *x)
 {
-  return (hashval_t) ((const var_loc_list *) x)->decl_id;
+  return (hashval_t) x->decl_id;
 }
 
 /* Return nonzero if decl_id of var_loc_list X is the same as
    UID of decl *Y.  */
 
-static int
-decl_loc_table_eq (const void *x, const void *y)
+inline bool
+decl_loc_hasher::equal (var_loc_list *x, const_tree y)
 {
-  return (((const var_loc_list *) x)->decl_id == DECL_UID ((const_tree) y));
+  return (x->decl_id == DECL_UID (y));
 }
 
 /* Return the var_loc list associated with a given declaration.  */
@@ -4962,26 +4995,24 @@ lookup_decl_loc (const_tree decl)
 {
   if (!decl_loc_table)
     return NULL;
-  return (var_loc_list *)
-    htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl));
+  return decl_loc_table->find_with_hash (decl, DECL_UID (decl));
 }
 
 /* Returns a hash value for X (which really is a cached_dw_loc_list_list).  */
 
-static hashval_t
-cached_dw_loc_list_table_hash (const void *x)
+inline hashval_t
+dw_loc_list_hasher::hash (cached_dw_loc_list *x)
 {
-  return (hashval_t) ((const cached_dw_loc_list *) x)->decl_id;
+  return (hashval_t) x->decl_id;
 }
 
 /* Return nonzero if decl_id of cached_dw_loc_list X is the same as
    UID of decl *Y.  */
 
-static int
-cached_dw_loc_list_table_eq (const void *x, const void *y)
+inline bool
+dw_loc_list_hasher::equal (cached_dw_loc_list *x, const_tree y)
 {
-  return (((const cached_dw_loc_list *) x)->decl_id
-	  == DECL_UID ((const_tree) y));
+  return (x->decl_id == DECL_UID (y));
 }
 
 /* Equate a DIE to a particular declaration.  */
@@ -4990,10 +5021,8 @@ static void
 equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
 {
   unsigned int decl_id = DECL_UID (decl);
-  void **slot;
 
-  slot = htab_find_slot_with_hash (decl_die_table, decl, decl_id, INSERT);
-  *slot = decl_die;
+  *decl_die_table->find_slot_with_hash (decl, decl_id, INSERT) = decl_die;
   decl_die->decl_id = decl_id;
 }
 
@@ -5141,7 +5170,6 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
 {
   unsigned int decl_id;
   var_loc_list *temp;
-  void **slot;
   struct var_loc_node *loc = NULL;
   HOST_WIDE_INT bitsize = -1, bitpos = -1;
 
@@ -5169,7 +5197,8 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
     }
 
   decl_id = DECL_UID (decl);
-  slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
+  var_loc_list **slot
+    = decl_loc_table->find_slot_with_hash (decl, decl_id, INSERT);
   if (*slot == NULL)
     {
       temp = ggc_cleared_alloc<var_loc_list> ();
@@ -5177,7 +5206,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
       *slot = temp;
     }
   else
-    temp = (var_loc_list *) *slot;
+    temp = *slot;
 
   /* For PARM_DECLs try to keep around the original incoming value,
      even if that means we'll emit a zero-range .debug_loc entry.  */
@@ -9040,8 +9069,8 @@ add_skeleton_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind,
   struct indirect_string_node *node;
 
   if (! skeleton_debug_str_hash)
-    skeleton_debug_str_hash = htab_create_ggc (10, debug_str_do_hash,
-                                               debug_str_eq, NULL);
+    skeleton_debug_str_hash
+      = hash_table<indirect_string_hasher>::create_ggc (10);
 
   node = find_AT_string_in_table (str, skeleton_debug_str_hash);
   find_string_form (node);
@@ -9742,11 +9771,10 @@ struct file_name_acquire_data
 
 /* Traversal function for the hash table.  */
 
-static int
-file_name_acquire (void ** slot, void *data)
+int
+file_name_acquire (dwarf_file_data **slot, file_name_acquire_data *fnad)
 {
-  struct file_name_acquire_data *fnad = (struct file_name_acquire_data *) data;
-  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
+  struct dwarf_file_data *d = *slot;
   struct file_info *fi;
   const char *f;
 
@@ -9821,7 +9849,7 @@ output_file_names (void)
   fnad.files = files;
   fnad.used_files = 0;
   fnad.max_files = numfiles;
-  htab_traverse (file_table, file_name_acquire, &fnad);
+  file_table->traverse<file_name_acquire_data *, file_name_acquire> (&fnad);
   gcc_assert (fnad.used_files == fnad.max_files);
 
   qsort (files, numfiles, sizeof (files[0]), file_info_cmp);
@@ -15815,7 +15843,6 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
   dw_loc_list_ref list;
   var_loc_list *loc_list;
   cached_dw_loc_list *cache;
-  void **slot;
 
   if (TREE_CODE (decl) == ERROR_MARK)
     return false;
@@ -15859,8 +15886,7 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
     cache_p = false;
   if (cache_p)
     {
-      cache = (cached_dw_loc_list *)
-	htab_find_with_hash (cached_dw_loc_list_table, decl, DECL_UID (decl));
+      cache = cached_dw_loc_list_table->find_with_hash (decl, DECL_UID (decl));
       if (cache)
 	list = cache->loc_list;
     }
@@ -15871,8 +15897,10 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
 	 BLOCK_NONLOCALIZED_VARS and if the list has at least two elements.  */
       if (cache_p && list && list->dw_loc_next)
 	{
-	  slot = htab_find_slot_with_hash (cached_dw_loc_list_table, decl,
-					   DECL_UID (decl), INSERT);
+	  cached_dw_loc_list **slot
+	    = cached_dw_loc_list_table->find_slot_with_hash (decl,
+							     DECL_UID (decl),
+							     INSERT);
 	  cache = ggc_cleared_alloc<cached_dw_loc_list> ();
 	  cache->decl_id = DECL_UID (decl);
 	  cache->loc_list = list;
@@ -17994,8 +18022,8 @@ dwarf2out_abstract_function (tree decl)
   tree save_fn;
   tree context;
   int was_abstract;
-  htab_t old_decl_loc_table;
-  htab_t old_cached_dw_loc_list_table;
+  hash_table<decl_loc_hasher> *old_decl_loc_table;
+  hash_table<dw_loc_list_hasher> *old_cached_dw_loc_list_table;
   int old_call_site_count, old_tail_call_site_count;
   struct call_arg_loc_node *old_call_arg_locations;
 
@@ -18073,9 +18101,9 @@ premark_used_types_helper (tree const &type, void *)
    marked as unused by prune_unused_types. The DIE of the type is marked
    only if the global variable using the type will actually be emitted.  */
 
-static int
-premark_types_used_by_global_vars_helper (void **slot,
-					  void *data ATTRIBUTE_UNUSED)
+int
+premark_types_used_by_global_vars_helper (types_used_by_vars_entry **slot,
+					  void *)
 {
   struct types_used_by_vars_entry *entry;
   dw_die_ref die;
@@ -18115,8 +18143,8 @@ static void
 premark_types_used_by_global_vars (void)
 {
   if (types_used_by_vars_hash)
-    htab_traverse (types_used_by_vars_hash,
-		   premark_types_used_by_global_vars_helper, NULL);
+    types_used_by_vars_hash
+      ->traverse<void *, premark_types_used_by_global_vars_helper> (NULL);
 }
 
 /* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE
@@ -18780,22 +18808,19 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
 
 /* Returns a hash value for X (which really is a die_struct).  */
 
-static hashval_t
-common_block_die_table_hash (const void *x)
+hashval_t
+block_die_hasher::hash (die_struct *d)
 {
-  const_dw_die_ref d = (const_dw_die_ref) x;
   return (hashval_t) d->decl_id ^ htab_hash_pointer (d->die_parent);
 }
 
 /* Return nonzero if decl_id and die_parent of die_struct X is the same
    as decl_id and die_parent of die_struct Y.  */
 
-static int
-common_block_die_table_eq (const void *x, const void *y)
+bool
+block_die_hasher::equal (die_struct *x, die_struct *y)
 {
-  const_dw_die_ref d = (const_dw_die_ref) x;
-  const_dw_die_ref e = (const_dw_die_ref) y;
-  return d->decl_id == e->decl_id && d->die_parent == e->die_parent;
+  return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
 }
 
 /* Generate a DIE to represent a declared data object.
@@ -18860,19 +18885,17 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	}
 
       if (common_block_die_table == NULL)
-	common_block_die_table
-	  = htab_create_ggc (10, common_block_die_table_hash,
-			     common_block_die_table_eq, NULL);
+	common_block_die_table = hash_table<block_die_hasher>::create_ggc (10);
 
       com_die_arg.decl_id = DECL_UID (com_decl);
       com_die_arg.die_parent = context_die;
-      com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg);
+      com_die = common_block_die_table->find (&com_die_arg);
       loc = loc_list_from_tree (com_decl, 2);
       if (com_die == NULL)
 	{
 	  const char *cnam
 	    = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (com_decl));
-	  void **slot;
+	  die_node **slot;
 
 	  com_die = new_die (DW_TAG_common_block, context_die, decl);
 	  add_name_and_src_coords_attributes (com_die, com_decl);
@@ -18888,8 +18911,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	  if (want_pubnames ())
 	    add_pubname_string (cnam, com_die); /* ??? needed? */
 	  com_die->decl_id = DECL_UID (com_decl);
-	  slot = htab_find_slot (common_block_die_table, com_die, INSERT);
-	  *slot = (void *) com_die;
+	  slot = common_block_die_table->find_slot (com_die, INSERT);
+	  *slot = com_die;
 	}
       else if (get_AT (com_die, DW_AT_location) == NULL && loc)
 	{
@@ -21065,8 +21088,8 @@ dwarf2out_function_decl (tree decl)
   call_site_count = -1;
   tail_call_site_count = -1;
   block_map.release ();
-  htab_empty (decl_loc_table);
-  htab_empty (cached_dw_loc_list_table);
+  decl_loc_table->empty ();
+  cached_dw_loc_list_table->empty ();
 }
 
 /* Output a marker (i.e. a label) for the beginning of the generated code for
@@ -21120,19 +21143,15 @@ dwarf2out_ignore_block (const_tree block)
 
 /* Hash table routines for file_hash.  */
 
-static int
-file_table_eq (const void *p1_p, const void *p2_p)
+bool
+dwarf_file_hasher::equal (dwarf_file_data *p1, const char *p2)
 {
-  const struct dwarf_file_data *const p1 =
-    (const struct dwarf_file_data *) p1_p;
-  const char *const p2 = (const char *) p2_p;
   return filename_cmp (p1->filename, p2) == 0;
 }
 
-static hashval_t
-file_table_hash (const void *p_p)
+hashval_t
+dwarf_file_hasher::hash (dwarf_file_data *p)
 {
-  const struct dwarf_file_data *const p = (const struct dwarf_file_data *) p_p;
   return htab_hash_string (p->filename);
 }
 
@@ -21150,7 +21169,6 @@ file_table_hash (const void *p_p)
 static struct dwarf_file_data *
 lookup_filename (const char *file_name)
 {
-  void ** slot;
   struct dwarf_file_data * created;
 
   /* Check to see if the file name that was searched on the previous
@@ -21161,10 +21179,11 @@ lookup_filename (const char *file_name)
     return file_table_last_lookup;
 
   /* Didn't match the previous lookup, search the table.  */
-  slot = htab_find_slot_with_hash (file_table, file_name,
-				   htab_hash_string (file_name), INSERT);
+  dwarf_file_data **slot
+    = file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
+				       INSERT);
   if (*slot)
-    return (struct dwarf_file_data *) *slot;
+    return *slot;
 
   created = ggc_alloc<dwarf_file_data> ();
   created->filename = file_name;
@@ -21524,10 +21543,10 @@ dwarf2out_var_location (rtx_insn *loc_note)
 
 /* Note in one location list that text section has changed.  */
 
-static int
-var_location_switch_text_section_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+int
+var_location_switch_text_section_1 (var_loc_list **slot, void *)
 {
-  var_loc_list *list = (var_loc_list *) *slot;
+  var_loc_list *list = *slot;
   if (list->first)
     list->last_before_switch
       = list->last->next ? list->last->next : list->last;
@@ -21542,7 +21561,7 @@ var_location_switch_text_section (void)
   if (decl_loc_table == NULL)
     return;
 
-  htab_traverse (decl_loc_table, var_location_switch_text_section_1, NULL);
+  decl_loc_table->traverse<void *, var_location_switch_text_section_1> (NULL);
 }
 
 /* Create a new line number table.  */
@@ -21651,13 +21670,12 @@ dwarf2out_begin_function (tree fun)
    Set have_multiple_function_sections to true in that case and
    terminate htab traversal.  */
 
-static int
-find_empty_loc_ranges_at_text_label (void **slot, void *)
+int
+find_empty_loc_ranges_at_text_label (var_loc_list **slot, int)
 {
-  var_loc_list *entry;
+  var_loc_list *entry = *slot;
   struct var_loc_node *node;
 
-  entry = (var_loc_list *) *slot;
   node = entry->first;
   if (node && node->next && node->next->label)
     {
@@ -21688,8 +21706,7 @@ dwarf2out_end_function (unsigned int)
       && !have_multiple_function_sections
       && first_loclabel_num_not_at_text_label
       && decl_loc_table)
-    htab_traverse (decl_loc_table, find_empty_loc_ranges_at_text_label,
-		   NULL);
+    decl_loc_table->traverse<int, find_empty_loc_ranges_at_text_label> (0);
   in_first_function_p = false;
   maybe_at_text_label_p = false;
 }
@@ -22302,21 +22319,16 @@ static void
 dwarf2out_init (const char *filename ATTRIBUTE_UNUSED)
 {
   /* Allocate the file_table.  */
-  file_table = htab_create_ggc (50, file_table_hash,
-				file_table_eq, NULL);
+  file_table = hash_table<dwarf_file_hasher>::create_ggc (50);
 
   /* Allocate the decl_die_table.  */
-  decl_die_table = htab_create_ggc (10, decl_die_table_hash,
-				    decl_die_table_eq, NULL);
+  decl_die_table = hash_table<decl_die_hasher>::create_ggc (10);
 
   /* Allocate the decl_loc_table.  */
-  decl_loc_table = htab_create_ggc (10, decl_loc_table_hash,
-				    decl_loc_table_eq, NULL);
+  decl_loc_table = hash_table<decl_loc_hasher>::create_ggc (10);
 
   /* Allocate the cached_dw_loc_list_table.  */
-  cached_dw_loc_list_table
-    = htab_create_ggc (10, cached_dw_loc_list_table_hash,
-		       cached_dw_loc_list_table_eq, NULL);
+  cached_dw_loc_list_table = hash_table<dw_loc_list_hasher>::create_ggc (10);
 
   /* Allocate the initial hunk of the decl_scope_table.  */
   vec_alloc (decl_scope_table, 256);
@@ -22449,11 +22461,10 @@ dwarf2out_assembly_start (void)
    because the indexing code relies on htab_traverse to traverse nodes
    in the same order for each run. */
 
-static int
-index_string (void **h, void *v)
+int
+index_string (indirect_string_node **h, unsigned int *index)
 {
-  struct indirect_string_node *node = (struct indirect_string_node *) *h;
-  unsigned int *index = (unsigned int *) v;
+  indirect_string_node *node = *h;
 
   find_string_form (node);
   if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
@@ -22469,11 +22480,10 @@ index_string (void **h, void *v)
    htab_traverse.  Output the offset to a string and update the
    current offset.  */
 
-static int
-output_index_string_offset (void **h, void *v)
+int
+output_index_string_offset (indirect_string_node **h, unsigned int *offset)
 {
-  struct indirect_string_node *node = (struct indirect_string_node *) *h;
-  unsigned int *offset = (unsigned int *) v;
+  indirect_string_node *node = *h;
 
   if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
     {
@@ -22490,11 +22500,10 @@ output_index_string_offset (void **h, void *v)
 /* A helper function for dwarf2out_finish called through
    htab_traverse.  Output the indexed string.  */
 
-static int
-output_index_string (void **h, void *v)
+int
+output_index_string (indirect_string_node **h, unsigned int *cur_idx)
 {
-  struct indirect_string_node *node = (struct indirect_string_node *) *h;
-  unsigned int *cur_idx = (unsigned int *) v;
+  struct indirect_string_node *node = *h;
 
   if (node->form == DW_FORM_GNU_str_index && node->refcount > 0)
     {
@@ -22510,10 +22519,10 @@ output_index_string (void **h, void *v)
 /* A helper function for dwarf2out_finish called through
    htab_traverse.  Emit one queued .debug_str string.  */
 
-static int
-output_indirect_string (void **h, void *v ATTRIBUTE_UNUSED)
+int
+output_indirect_string (indirect_string_node **h, void *)
 {
-  struct indirect_string_node *node = (struct indirect_string_node *) *h;
+  struct indirect_string_node *node = *h;
 
   node->form = find_string_form (node);
   if (node->form == DW_FORM_strp && node->refcount > 0)
@@ -22532,33 +22541,30 @@ output_indirect_strings (void)
 {
   switch_to_section (debug_str_section);
   if (!dwarf_split_debug_info)
-    htab_traverse (debug_str_hash, output_indirect_string, NULL);
+    debug_str_hash->traverse<void *, output_indirect_string> (NULL);
   else
     {
       unsigned int offset = 0;
       unsigned int cur_idx = 0;
 
-      htab_traverse (skeleton_debug_str_hash, output_indirect_string, NULL);
+      skeleton_debug_str_hash->traverse<void *, output_indirect_string> (NULL);
 
       switch_to_section (debug_str_offsets_section);
-      htab_traverse_noresize (debug_str_hash,
-                              output_index_string_offset,
-                              &offset);
+      debug_str_hash->traverse_noresize
+	<unsigned int *, output_index_string_offset> (&offset);
       switch_to_section (debug_str_dwo_section);
-      htab_traverse_noresize (debug_str_hash,
-                              output_index_string,
-                              &cur_idx);
+      debug_str_hash->traverse_noresize<unsigned int *, output_index_string>
+	(&cur_idx);
     }
 }
 
 /* Callback for htab_traverse to assign an index to an entry in the
    table, and to write that entry to the .debug_addr section.  */
 
-static int
-output_addr_table_entry (void **slot, void *data)
+int
+output_addr_table_entry (addr_table_entry **slot, unsigned int *cur_index)
 {
-  addr_table_entry *entry = (addr_table_entry *) *slot;
-  unsigned int *cur_index = (unsigned int *)data;
+  addr_table_entry *entry = *slot;
 
   if (entry->refcount == 0)
     {
@@ -22599,11 +22605,12 @@ static void
 output_addr_table (void)
 {
   unsigned int index = 0;
-  if (addr_index_table == NULL || htab_size (addr_index_table) == 0)
+  if (addr_index_table == NULL || addr_index_table->size () == 0)
     return;
 
   switch_to_section (debug_addr_section);
-  htab_traverse_noresize (addr_index_table, output_addr_table_entry, &index);
+  addr_index_table
+    ->traverse_noresize<unsigned int *, output_addr_table_entry> (&index);
 }
 
 #if ENABLE_ASSERT_CHECKING
@@ -22858,10 +22865,10 @@ prune_unused_types_update_strings (dw_die_ref die)
 	if (s->refcount
 	    == ((DEBUG_STR_SECTION_FLAGS & SECTION_MERGE) ? 1 : 2))
 	  {
-	    void ** slot;
-	    slot = htab_find_slot_with_hash (debug_str_hash, s->str,
-					     htab_hash_string (s->str),
-					     INSERT);
+	    indirect_string_node **slot
+	      = debug_str_hash->find_slot_with_hash (s->str,
+						     htab_hash_string (s->str),
+						     INSERT);
 	    gcc_assert (*slot == NULL);
 	    *slot = s;
 	  }
@@ -22949,9 +22956,9 @@ prune_unused_types (void)
     prune_unused_types_mark (base_type, 1);
 
   if (debug_str_hash)
-    htab_empty (debug_str_hash);
+    debug_str_hash->empty ();
   if (skeleton_debug_str_hash)
-    htab_empty (skeleton_debug_str_hash);
+    skeleton_debug_str_hash->empty ();
   prune_unused_types_prune (comp_unit_die ());
   for (node = limbo_die_list; node; node = node->next)
     prune_unused_types_prune (node->die);
@@ -22968,11 +22975,10 @@ prune_unused_types (void)
 
 /* Set the parameter to true if there are any relative pathnames in
    the file table.  */
-static int
-file_table_relative_p (void ** slot, void *param)
+int
+file_table_relative_p (dwarf_file_data **slot, bool *p)
 {
-  bool *p = (bool *) param;
-  struct dwarf_file_data *d = (struct dwarf_file_data *) *slot;
+  struct dwarf_file_data *d = *slot;
   if (!IS_ABSOLUTE_PATH (d->filename))
     {
       *p = true;
@@ -24221,7 +24227,7 @@ dwarf2out_finish (const char *filename)
   else if (get_AT (comp_unit_die (), DW_AT_comp_dir) == NULL)
     {
       bool p = false;
-      htab_traverse (file_table, file_table_relative_p, &p);
+      file_table->traverse<bool *, file_table_relative_p> (&p);
       if (p)
 	add_comp_dir_attribute (comp_unit_die ());
     }
@@ -24443,8 +24449,9 @@ dwarf2out_finish (const char *filename)
       if (addr_index_table != NULL)
         {
           unsigned int index = 0;
-          htab_traverse_noresize (addr_index_table,
-                                  index_addr_table_entry, &index);
+          addr_index_table
+	    ->traverse_noresize<unsigned int *, index_addr_table_entry>
+	    (&index);
         }
     }
 
@@ -24463,7 +24470,7 @@ dwarf2out_finish (const char *filename)
          skeleton die attrs are added when the skeleton type unit is
          created, so ensure it is created by this point.  */
       add_top_level_skeleton_die_attrs (main_comp_unit_die);
-      htab_traverse_noresize (debug_str_hash, index_string, &index);
+      debug_str_hash->traverse_noresize<unsigned int *, index_string> (&index);
     }
 
   /* Output all of the compilation units.  We put the main one last so that
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index 7184504..9280fea 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -4228,72 +4228,62 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
   gfc_add_init_cleanup (block, gfc_finish_block (&tmpblock), NULL_TREE);
 }
 
-static GTY ((param_is (struct module_htab_entry))) htab_t module_htab;
-
-/* Hash and equality functions for module_htab.  */
-
-static hashval_t
-module_htab_do_hash (const void *x)
+struct module_hasher : ggc_hasher<module_htab_entry *>
 {
-  return htab_hash_string (((const struct module_htab_entry *)x)->name);
-}
+  typedef const char *compare_type;
 
-static int
-module_htab_eq (const void *x1, const void *x2)
-{
-  return strcmp ((((const struct module_htab_entry *)x1)->name),
-		 (const char *)x2) == 0;
-}
+  static hashval_t hash (module_htab_entry *s) { return htab_hash_string (s); }
+  static bool
+  equal (module_htab_entry *a, const char *b)
+  {
+    return !strcmp (a->name, b);
+  }
+};
+
+static GTY (()) hash_table<module_hasher> *module_htab;
 
 /* Hash and equality functions for module_htab's decls.  */
 
-static hashval_t
-module_htab_decls_hash (const void *x)
+hashval_t
+module_decl_hasher::hash (tree t)
 {
-  const_tree t = (const_tree) x;
   const_tree n = DECL_NAME (t);
   if (n == NULL_TREE)
     n = TYPE_NAME (TREE_TYPE (t));
   return htab_hash_string (IDENTIFIER_POINTER (n));
 }
 
-static int
-module_htab_decls_eq (const void *x1, const void *x2)
+bool
+module_decl_hasher::equal (tree t1, const char *x2)
 {
-  const_tree t1 = (const_tree) x1;
   const_tree n1 = DECL_NAME (t1);
   if (n1 == NULL_TREE)
     n1 = TYPE_NAME (TREE_TYPE (t1));
-  return strcmp (IDENTIFIER_POINTER (n1), (const char *) x2) == 0;
+  return strcmp (IDENTIFIER_POINTER (n1), x2) == 0;
 }
 
 struct module_htab_entry *
 gfc_find_module (const char *name)
 {
-  void **slot;
-
   if (! module_htab)
-    module_htab = htab_create_ggc (10, module_htab_do_hash,
-				   module_htab_eq, NULL);
+    module_htab = hash_table<module_hasher>::create_ggc (10);
 
-  slot = htab_find_slot_with_hash (module_htab, name,
-				   htab_hash_string (name), INSERT);
+  module_htab_entry **slot
+    = module_htab->find_slot_with_hash (name, htab_hash_string (name), INSERT);
   if (*slot == NULL)
     {
       module_htab_entry *entry = ggc_cleared_alloc<module_htab_entry> ();
 
       entry->name = gfc_get_string (name);
-      entry->decls = htab_create_ggc (10, module_htab_decls_hash,
-				      module_htab_decls_eq, NULL);
-      *slot = (void *) entry;
+      entry->decls = hash_table<module_decl_hasher>::create_ggc (10);
+      *slot = entry;
     }
-  return (struct module_htab_entry *) *slot;
+  return *slot;
 }
 
 void
 gfc_module_add_decl (struct module_htab_entry *entry, tree decl)
 {
-  void **slot;
   const char *name;
 
   if (DECL_NAME (decl))
@@ -4303,10 +4293,11 @@ gfc_module_add_decl (struct module_htab_entry *entry, tree decl)
       gcc_assert (TREE_CODE (decl) == TYPE_DECL);
       name = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl)));
     }
-  slot = htab_find_slot_with_hash (entry->decls, name,
-				   htab_hash_string (name), INSERT);
+  tree *slot
+    = entry->decls->find_slot_with_hash (name, htab_hash_string (name),
+					 INSERT);
   if (*slot == NULL)
-    *slot = (void *) decl;
+    *slot = decl;
 }
 
 static struct module_htab_entry *cur_module;
@@ -4485,14 +4476,13 @@ gfc_trans_use_stmts (gfc_namespace * ns)
       for (rent = use_stmt->rename; rent; rent = rent->next)
 	{
 	  tree decl, local_name;
-	  void **slot;
 
 	  if (rent->op != INTRINSIC_NONE)
 	    continue;
 
-	  slot = htab_find_slot_with_hash (entry->decls, rent->use_name,
-					   htab_hash_string (rent->use_name),
-					   INSERT);
+						 hashval_t hash = htab_hash_string (rent->use_name);
+	  tree *slot = entry->decls->find_slot_with_hash (rent->use_name, hash,
+							  INSERT);
 	  if (*slot == NULL)
 	    {
 	      gfc_symtree *st;
@@ -4547,7 +4537,7 @@ gfc_trans_use_stmts (gfc_namespace * ns)
 	      else
 		{
 		  *slot = error_mark_node;
-		  htab_clear_slot (entry->decls, slot);
+		  entry->decls->clear_slot (slot);
 		  continue;
 		}
 	      *slot = decl;
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index dbaa7d7..b707023 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -1963,7 +1963,7 @@ gfc_generate_module_code (gfc_namespace * ns)
   entry = gfc_find_module (ns->proc_name->name);
   if (entry->namespace_decl)
     /* Buggy sourcecode, using a module before defining it?  */
-    htab_empty (entry->decls);
+    entry->decls->empty ();
   entry->namespace_decl = ns->proc_name->backend_decl;
 
   gfc_generate_module_vars (ns);
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 03136e6..23e184c 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -571,10 +571,18 @@ void gfc_generate_module_vars (gfc_namespace *);
 /* Get the appropriate return statement for a procedure.  */
 tree gfc_generate_return (void);
 
-struct GTY(()) module_htab_entry {
+struct module_decl_hasher : ggc_hasher<tree_node *>
+{
+  typedef const char *compare_type;
+
+  static hashval_t hash (tree);
+  static bool equal (tree, const char *);
+};
+
+struct GTY((for_user)) module_htab_entry {
   const char *name;
   tree namespace_decl;
-  htab_t GTY ((param_is (union tree_node))) decls;
+  hash_table<module_decl_hasher> *GTY (()) decls;
 };
 
 struct module_htab_entry *gfc_find_module (const char *);
diff --git a/gcc/function.c b/gcc/function.c
index ac50f4a..71b5f0d 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -108,7 +108,7 @@ static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
   htab_t epilogue_insn_hash;
 
 
-htab_t types_used_by_vars_hash = NULL;
+hash_table<used_type_hasher> *types_used_by_vars_hash = NULL;
 vec<tree, va_gc> *types_used_by_cur_var_decl;
 
 /* Forward declarations.  */
@@ -540,18 +540,24 @@ struct GTY(()) temp_slot {
   HOST_WIDE_INT full_size;
 };
 
-/* A table of addresses that represent a stack slot.  The table is a mapping
-   from address RTXen to a temp slot.  */
-static GTY((param_is(struct temp_slot_address_entry))) htab_t temp_slot_address_table;
-static size_t n_temp_slots_in_use;
-
-/* Entry for the above hash table.  */
-struct GTY(()) temp_slot_address_entry {
+/* Entry for the below hash table.  */
+struct GTY((for_user)) temp_slot_address_entry {
   hashval_t hash;
   rtx address;
   struct temp_slot *temp_slot;
 };
 
+struct temp_address_hasher : ggc_hasher<temp_slot_address_entry *>
+{
+  static hashval_t hash (temp_slot_address_entry *);
+  static bool equal (temp_slot_address_entry *, temp_slot_address_entry *);
+};
+
+/* A table of addresses that represent a stack slot.  The table is a mapping
+   from address RTXen to a temp slot.  */
+static GTY(()) hash_table<temp_address_hasher> *temp_slot_address_table;
+static size_t n_temp_slots_in_use;
+
 /* Removes temporary slot TEMP from LIST.  */
 
 static void
@@ -634,21 +640,17 @@ temp_slot_address_compute_hash (struct temp_slot_address_entry *t)
 }
 
 /* Return the hash value for an address -> temp slot mapping.  */
-static hashval_t
-temp_slot_address_hash (const void *p)
+hashval_t
+temp_address_hasher::hash (temp_slot_address_entry *t)
 {
-  const struct temp_slot_address_entry *t;
-  t = (const struct temp_slot_address_entry *) p;
   return t->hash;
 }
 
 /* Compare two address -> temp slot mapping entries.  */
-static int
-temp_slot_address_eq (const void *p1, const void *p2)
+bool
+temp_address_hasher::equal (temp_slot_address_entry *t1,
+			    temp_slot_address_entry *t2)
 {
-  const struct temp_slot_address_entry *t1, *t2;
-  t1 = (const struct temp_slot_address_entry *) p1;
-  t2 = (const struct temp_slot_address_entry *) p2;
   return exp_equiv_p (t1->address, t2->address, 0, true);
 }
 
@@ -656,24 +658,21 @@ temp_slot_address_eq (const void *p1, const void *p2)
 static void
 insert_temp_slot_address (rtx address, struct temp_slot *temp_slot)
 {
-  void **slot;
   struct temp_slot_address_entry *t = ggc_alloc<temp_slot_address_entry> ();
   t->address = address;
   t->temp_slot = temp_slot;
   t->hash = temp_slot_address_compute_hash (t);
-  slot = htab_find_slot_with_hash (temp_slot_address_table, t, t->hash, INSERT);
-  *slot = t;
+  *temp_slot_address_table->find_slot_with_hash (t, t->hash, INSERT) = t;
 }
 
 /* Remove an address -> temp slot mapping entry if the temp slot is
    not in use anymore.  Callback for remove_unused_temp_slot_addresses.  */
-static int
-remove_unused_temp_slot_addresses_1 (void **slot, void *data ATTRIBUTE_UNUSED)
+int
+remove_unused_temp_slot_addresses_1 (temp_slot_address_entry **slot, void *)
 {
-  const struct temp_slot_address_entry *t;
-  t = (const struct temp_slot_address_entry *) *slot;
+  const struct temp_slot_address_entry *t = *slot;
   if (! t->temp_slot->in_use)
-    htab_clear_slot (temp_slot_address_table, slot);
+    temp_slot_address_table->clear_slot (slot);
   return 1;
 }
 
@@ -683,11 +682,10 @@ remove_unused_temp_slot_addresses (void)
 {
   /* Use quicker clearing if there aren't any active temp slots.  */
   if (n_temp_slots_in_use)
-    htab_traverse (temp_slot_address_table,
-		   remove_unused_temp_slot_addresses_1,
-		   NULL);
+    temp_slot_address_table->traverse
+      <void *, remove_unused_temp_slot_addresses_1> (NULL);
   else
-    htab_empty (temp_slot_address_table);
+    temp_slot_address_table->empty ();
 }
 
 /* Find the temp slot corresponding to the object at address X.  */
@@ -703,8 +701,7 @@ find_temp_slot_from_address (rtx x)
   tmp.address = x;
   tmp.temp_slot = NULL;
   tmp.hash = temp_slot_address_compute_hash (&tmp);
-  t = (struct temp_slot_address_entry *)
-    htab_find_with_hash (temp_slot_address_table, &tmp, tmp.hash);
+  t = temp_slot_address_table->find_with_hash (&tmp, tmp.hash);
   if (t)
     return t->temp_slot;
 
@@ -1195,12 +1192,9 @@ init_temp_slots (void)
 
   /* Set up the table to map addresses to temp slots.  */
   if (! temp_slot_address_table)
-    temp_slot_address_table = htab_create_ggc (32,
-					       temp_slot_address_hash,
-					       temp_slot_address_eq,
-					       NULL);
+    temp_slot_address_table = hash_table<temp_address_hasher>::create_ggc (32);
   else
-    htab_empty (temp_slot_address_table);
+    temp_slot_address_table->empty ();
 }
 
 /* Functions and data structures to keep track of the values hard regs
@@ -6145,24 +6139,17 @@ hash_types_used_by_vars_entry (const struct types_used_by_vars_entry *entry)
 /* Hash function of the types_used_by_vars_entry hash table.  */
 
 hashval_t
-types_used_by_vars_do_hash (const void *x)
+used_type_hasher::hash (types_used_by_vars_entry *entry)
 {
-  const struct types_used_by_vars_entry *entry =
-    (const struct types_used_by_vars_entry *) x;
-
   return hash_types_used_by_vars_entry (entry);
 }
 
 /*Equality function of the types_used_by_vars_entry hash table.  */
 
-int
-types_used_by_vars_eq (const void *x1, const void *x2)
+bool
+used_type_hasher::equal (types_used_by_vars_entry *e1,
+			 types_used_by_vars_entry *e2)
 {
-  const struct types_used_by_vars_entry *e1 =
-    (const struct types_used_by_vars_entry *) x1;
-  const struct types_used_by_vars_entry *e2 =
-    (const struct types_used_by_vars_entry *)x2;
-
   return (e1->var_decl == e2->var_decl && e1->type == e2->type);
 }
 
@@ -6173,16 +6160,15 @@ types_used_by_var_decl_insert (tree type, tree var_decl)
 {
   if (type != NULL && var_decl != NULL)
     {
-      void **slot;
+      types_used_by_vars_entry **slot;
       struct types_used_by_vars_entry e;
       e.var_decl = var_decl;
       e.type = type;
       if (types_used_by_vars_hash == NULL)
-	types_used_by_vars_hash =
-	  htab_create_ggc (37, types_used_by_vars_do_hash,
-			   types_used_by_vars_eq, NULL);
-      slot = htab_find_slot_with_hash (types_used_by_vars_hash, &e,
-				       hash_types_used_by_vars_entry (&e), INSERT);
+	types_used_by_vars_hash
+	  = hash_table<used_type_hasher>::create_ggc (37);
+
+      slot = types_used_by_vars_hash->find_slot (&e, INSERT);
       if (*slot == NULL)
 	{
 	  struct types_used_by_vars_entry *entry;
diff --git a/gcc/function.h b/gcc/function.h
index e71210d..a8d9f6a 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -703,21 +703,24 @@ extern int virtuals_instantiated;
 /* Nonzero if at least one trampoline has been created.  */
 extern int trampolines_created;
 
-struct GTY(()) types_used_by_vars_entry {
+struct GTY((for_user)) types_used_by_vars_entry {
   tree type;
   tree var_decl;
 };
 
+struct used_type_hasher : ggc_hasher<types_used_by_vars_entry *>
+{
+  static hashval_t hash (types_used_by_vars_entry *);
+  static bool equal (types_used_by_vars_entry *, types_used_by_vars_entry *);
+};
+
 /* Hash table making the relationship between a global variable
    and the types it references in its initializer. The key of the
    entry is a referenced type, and the value is the DECL of the global
    variable. types_use_by_vars_do_hash and types_used_by_vars_eq below are
    the hash and equality functions to use for this hash table.  */
-extern GTY((param_is (struct types_used_by_vars_entry))) htab_t
-  types_used_by_vars_hash;
+extern GTY(()) hash_table<used_type_hasher> *types_used_by_vars_hash;
 
-hashval_t types_used_by_vars_do_hash (const void*);
-int types_used_by_vars_eq (const void *, const void *);
 void types_used_by_var_decl_insert (tree type, tree var_decl);
 
 /* During parsing of a global variable, this vector contains the types
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index c1f9e69..bc88eb8 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -648,6 +648,12 @@ create_user_defined_type (const char *type_name, struct fileloc *pos)
 	  if (is_ptr)
 	    offset_to_star = star - type_id;
 
+	  if (strstr (type_id, "char*"))
+	    {
+	  type_id = strtoken (0, ",>", &next);
+	  continue;
+	    }
+
 	  char *field_name = xstrdup (type_id);
 
 	  type_p arg_type;
@@ -2845,6 +2851,8 @@ walk_type (type_p t, struct walk_type_data *d)
       ;
     else if (strcmp (oo->name, "variable_size") == 0)
       ;
+    else if (strcmp (oo->name, "for_user") == 0)
+      ;
     else
       error_at_line (d->line, "unknown option `%s'\n", oo->name);
 
@@ -3642,7 +3650,6 @@ write_user_func_for_structure_body (type_p s, const char *prefix,
   oprintf (d->of, "}\n");
 }
 
-
 /* Emit the user-callable functions needed to mark all the types used
    by the user structure S.  PREFIX is the prefix to use to
    distinguish ggc and pch markers.  D contains data needed to pass to
@@ -3712,6 +3719,8 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
 
   memset (&d, 0, sizeof (d));
   d.of = get_output_file_for_structure (s, param);
+
+  bool for_user = false;
   for (opt = s->u.s.opt; opt; opt = opt->next)
     if (strcmp (opt->name, "chain_next") == 0
 	&& opt->kind == OPTION_STRING)
@@ -3725,6 +3734,8 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
     else if (strcmp (opt->name, "mark_hook") == 0
 	     && opt->kind == OPTION_STRING)
       mark_hook_name = opt->info.string;
+    else if (strcmp (opt->name, "for_user") == 0)
+      for_user = true;
   if (chain_prev != NULL && chain_next == NULL)
     error_at_line (&s->u.s.line, "chain_prev without chain_next");
   if (chain_circular != NULL && chain_next != NULL)
@@ -3868,6 +3879,12 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
 
   if (orig_s->kind == TYPE_USER_STRUCT)
     write_user_marking_functions (orig_s, wtd, &d);
+
+  if (for_user)
+    {
+      write_user_func_for_structure_body (orig_s, wtd->prefix, &d);
+      write_user_func_for_structure_ptr (d.of, orig_s, wtd);
+    }
 }
 
 
@@ -4244,6 +4261,13 @@ write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param)
   /* Write user-callable entry points for the PCH walking routines.  */
   if (orig_s->kind == TYPE_USER_STRUCT)
     write_pch_user_walking_functions (s, &d);
+
+  for (options_p o = s->u.s.opt; o; o = o->next)
+    if (strcmp (o->name, "for_user") == 0)
+      {
+	write_pch_user_walking_for_structure_body (s, &d);
+	break;
+      }
 }
 
 /* Write out local marker routines for STRUCTURES and PARAM_STRUCTS.  */
@@ -5690,6 +5714,19 @@ main (int argc, char **argv)
      hence enlarge the param_structs list of types.  */
   set_gc_used (variables);
 
+  for (type_p t = structures; t; t = t->next)
+    {
+      bool for_user = false;
+      for (options_p o = t->u.s.opt; o; o = o->next)
+	if (strcmp (o->name, "for_user") == 0)
+	  {
+	    for_user = true;
+	    break;
+	  }
+
+      if (for_user)
+	set_gc_used_type (t, GC_POINTED_TO, NULL);
+    }
  /* The state at this point is read from the state input file or by
     parsing source files and optionally augmented by parsing plugin
     source files.  Write it now.  */
diff --git a/gcc/ggc.h b/gcc/ggc.h
index 6280c43..dc21520 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -358,4 +358,9 @@ gt_pch_nx (int)
 {
 }
 
+static inline void
+gt_pch_nx (unsigned int)
+{
+}
+
 #endif
diff --git a/gcc/gimple-ssa.h b/gcc/gimple-ssa.h
index d2e62a9..c023956 100644
--- a/gcc/gimple-ssa.h
+++ b/gcc/gimple-ssa.h
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_GIMPLE_SSA_H
 
 #include "hash-map.h"
+#include "tree-hasher.h"
 #include "tree-ssa-operands.h"
 
 /* This structure is used to map a gimple statement to a label,
@@ -32,6 +33,25 @@ struct GTY(()) tm_restart_node {
   tree label_or_list;
 };
 
+struct ssa_name_hasher : ggc_hasher<tree>
+{
+  /* Hash a tree in a uid_decl_map.  */
+
+  static hashval_t
+  hash (tree item)
+  {
+    return item->ssa_name.var->decl_minimal.uid;
+  }
+
+  /* Return true if the DECL_UID in both trees are equal.  */
+
+  static bool
+  equal (tree a, tree b)
+{
+  return (a->ssa_name.var->decl_minimal.uid == b->ssa_name.var->decl_minimal.uid);
+}
+};
+
 /* Gimple dataflow datastructure. All publicly available fields shall have
    gimple_ accessor defined, all publicly modifiable fields should have
    gimple_set accessor.  */
@@ -63,7 +83,7 @@ struct GTY(()) gimple_df {
      means that the first reference to this variable in the function is a
      USE or a VUSE.  In those cases, the SSA renamer creates an SSA name
      for this variable with an empty defining statement.  */
-  htab_t GTY((param_is (union tree_node))) default_defs;
+  hash_table<ssa_name_hasher> *default_defs;
 
   /* True if there are any symbols that need to be renamed.  */
   unsigned int ssa_renaming_needed : 1;
diff --git a/gcc/hash-map.h b/gcc/hash-map.h
index c65e1e5..4988fe4 100644
--- a/gcc/hash-map.h
+++ b/gcc/hash-map.h
@@ -168,6 +168,16 @@ class GTY((user)) hash_map
 	{
 	}
 
+    static void
+      pch_nx_helper (unsigned int, gt_pointer_operator, void *)
+	{
+	}
+
+    static void
+      pch_nx_helper (bool, gt_pointer_operator, void *)
+	{
+	}
+
     template<typename T>
       static void
       pch_nx_helper (T *&x, gt_pointer_operator op, void *cookie)
diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 028b7de..2493f2e 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -198,6 +198,7 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "ggc.h"
 #include "hashtab.h"
+#include <new>
 
 template<typename, typename, typename> class hash_map;
 template<typename, typename> class hash_set;
@@ -301,6 +302,38 @@ pointer_hash <Type>::equal (const value_type &existing,
   return existing == candidate;
 }
 
+/* Hasher for entry in gc memory.  */
+
+template<typename T>
+struct ggc_hasher
+{
+  typedef T value_type;
+  typedef T compare_type;
+  typedef int store_values_directly;
+
+  static void remove (T) {}
+
+  static void
+  ggc_mx (T p)
+  {
+    extern void gt_ggc_mx (T &);
+    gt_ggc_mx (p);
+  }
+
+  static void
+  pch_nx (T &p)
+  {
+  extern void gt_pch_nx (T &);
+  gt_pch_nx (p);
+  }
+
+  static void
+  pch_nx (T &p, gt_pointer_operator op, void *cookie)
+  {
+    op (&p, cookie);
+  }
+};
+
 
 /* Table of primes and their inversion information.  */
 
@@ -1004,6 +1037,16 @@ public:
   explicit hash_table (size_t, bool ggc = false);
   ~hash_table ();
 
+  /* Create a hash_table in gc memory.  */
+
+  static hash_table *
+  create_ggc (size_t n)
+  {
+    hash_table *table = ggc_alloc<hash_table> ();
+    new (table) hash_table (n, true);
+    return table;
+  }
+
   /* Current size (in entries) of the hash table.  */
   size_t size () const { return m_size; }
 
@@ -1110,9 +1153,15 @@ public:
 private:
   template<typename T> friend void gt_ggc_mx (hash_table<T> *);
   template<typename T> friend void gt_pch_nx (hash_table<T> *);
-  template<typename T> friend void hashtab_entry_note_pointers (void *, void *, gt_pointer_operator, void *);
-  template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *);
-  template<typename T, typename U> friend void gt_pch_nx (hash_set<T, U> *, gt_pointer_operator, void *);
+  template<typename T> friend void
+    hashtab_entry_note_pointers (void *, void *, gt_pointer_operator, void *);
+  template<typename T, typename U, typename V> friend void
+  gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *);
+  template<typename T, typename U> friend void gt_pch_nx (hash_set<T, U> *,
+							  gt_pointer_operator,
+							  void *);
+  template<typename T> friend void gt_pch_nx (hash_table<T> *,
+					      gt_pointer_operator, void *);
 
   value_type *find_empty_slot_for_expand (hashval_t);
   void expand ();
@@ -1598,7 +1647,7 @@ template<typename D>
 static void
 gt_pch_nx (hash_table<D> *h)
 {
-  bool success ATTRIBUTE_UNUSED
+  bool success
     = gt_pch_note_object (h->m_entries, h, hashtab_entry_note_pointers<D>);
   gcc_checking_assert (success);
   for (size_t i = 0; i < h->m_size; i++)
@@ -1611,4 +1660,11 @@ gt_pch_nx (hash_table<D> *h)
     }
 }
 
+template<typename D>
+static inline void
+gt_pch_nx (hash_table<D> *h, gt_pointer_operator op, void *cookie)
+{
+  op (&h->m_entries, cookie);
+}
+
 #endif /* TYPED_HASHTAB_H */
diff --git a/gcc/java/class.c b/gcc/java/class.c
index 0d51165..25af697 100644
--- a/gcc/java/class.c
+++ b/gcc/java/class.c
@@ -774,7 +774,7 @@ add_method_1 (tree this_class, int access_flags, tree name, tree function_type)
   /* Initialize the initialized (static) class table. */
   if (access_flags & ACC_STATIC)
     DECL_FUNCTION_INITIALIZED_CLASS_TABLE (fndecl) =
-      htab_create_ggc (50, htab_hash_pointer, htab_eq_pointer, NULL);
+      hash_table<ict_hasher>::create_ggc (50);
 
   DECL_CHAIN (fndecl) = TYPE_METHODS (this_class);
   TYPE_METHODS (this_class) = fndecl;
@@ -3070,14 +3070,12 @@ build_assertion_table_entry (tree code, tree op1, tree op2)
 /* Add an entry to the type assertion table. Callback used during hashtable
    traversal.  */
 
-static int
-add_assertion_table_entry (void **htab_entry, void *ptr)
+int
+add_assertion_table_entry (type_assertion **slot, vec<constructor_elt, va_gc> **v)
 {
   tree entry;
   tree code_val, op1_utf8, op2_utf8;
-  vec<constructor_elt, va_gc> **v
-      = ((vec<constructor_elt, va_gc> **) ptr);
-  type_assertion *as = (type_assertion *) *htab_entry;
+  type_assertion *as = *slot;
 
   code_val = build_int_cst (NULL_TREE, as->assertion_code);
 
@@ -3103,11 +3101,12 @@ static tree
 emit_assertion_table (tree klass)
 {
   tree null_entry, ctor, table_decl;
-  htab_t assertions_htab = TYPE_ASSERTIONS (klass);
+  hash_table<type_assertion_hasher> *assertions_htab = TYPE_ASSERTIONS (klass);
   vec<constructor_elt, va_gc> *v = NULL;
 
   /* Iterate through the hash table.  */
-  htab_traverse (assertions_htab, add_assertion_table_entry, &v);
+  assertions_htab
+    ->traverse<vec<constructor_elt, va_gc> **, add_assertion_table_entry> (&v);
 
   /* Finish with a null entry.  */
   null_entry = build_assertion_table_entry (integer_zero_node,
@@ -3146,36 +3145,28 @@ init_class_processing (void)
   gcc_obstack_init (&temporary_obstack);
 }
 
-static hashval_t java_treetreehash_hash (const void *);
-static int java_treetreehash_compare (const void *, const void *);
-
 /* A hash table mapping trees to trees.  Used generally.  */
 
 #define JAVA_TREEHASHHASH_H(t) ((hashval_t)TYPE_UID (t))
 
-static hashval_t
-java_treetreehash_hash (const void *k_p)
+hashval_t
+treetreehasher::hash (treetreehash_entry *k)
 {
-  const struct treetreehash_entry *const k
-    = (const struct treetreehash_entry *) k_p;
   return JAVA_TREEHASHHASH_H (k->key);
 }
 
-static int
-java_treetreehash_compare (const void * k1_p, const void * k2_p)
+bool
+treetreehasher::equal (treetreehash_entry *k1, tree k2)
 {
-  const struct treetreehash_entry *const k1
-    = (const struct treetreehash_entry *) k1_p;
-  const_tree const k2 = (const_tree) k2_p;
   return (k1->key == k2);
 }
 
 tree 
-java_treetreehash_find (htab_t ht, tree t)
+java_treetreehash_find (hash_table<treetreehasher> *ht, tree t)
 {
   struct treetreehash_entry *e;
   hashval_t hv = JAVA_TREEHASHHASH_H (t);
-  e = (struct treetreehash_entry *) htab_find_with_hash (ht, t, hv);
+  e = ht->find_with_hash (t, hv);
   if (e == NULL)
     return NULL;
   else
@@ -3183,13 +3174,12 @@ java_treetreehash_find (htab_t ht, tree t)
 }
 
 tree *
-java_treetreehash_new (htab_t ht, tree t)
+java_treetreehash_new (hash_table<treetreehasher> *ht, tree t)
 {
-  void **e;
   struct treetreehash_entry *tthe;
   hashval_t hv = JAVA_TREEHASHHASH_H (t);
 
-  e = htab_find_slot_with_hash (ht, t, hv, INSERT);
+  treetreehash_entry **e = ht->find_slot_with_hash (t, hv, INSERT);
   if (*e == NULL)
     {
       tthe = ggc_cleared_alloc<treetreehash_entry> ();
@@ -3197,15 +3187,14 @@ java_treetreehash_new (htab_t ht, tree t)
       *e = tthe;
     }
   else
-    tthe = (struct treetreehash_entry *) *e;
+    tthe = *e;
   return &tthe->value;
 }
 
-htab_t
+hash_table<treetreehasher> *
 java_treetreehash_create (size_t size)
 {
-  return htab_create_ggc (size, java_treetreehash_hash,
-			  java_treetreehash_compare, NULL);
+  return hash_table<treetreehasher>::create_ggc (size);
 }
 
 /* Break down qualified IDENTIFIER into package and class-name components.
diff --git a/gcc/java/decl.c b/gcc/java/decl.c
index 607aece..7271ea7 100644
--- a/gcc/java/decl.c
+++ b/gcc/java/decl.c
@@ -1846,8 +1846,8 @@ end_java_method (void)
 	 variable to the block_body */
       fbody = DECL_SAVED_TREE (fndecl);
       block_body = BIND_EXPR_BODY (fbody);
-      htab_traverse (DECL_FUNCTION_INIT_TEST_TABLE (fndecl),
-		     attach_init_test_initialization_flags, block_body);
+      hash_table<treetreehasher> *ht = DECL_FUNCTION_INIT_TEST_TABLE (fndecl);
+      ht->traverse<tree, attach_init_test_initialization_flags> (block_body);
     }
 
   finish_method (fndecl);
diff --git a/gcc/java/except.c b/gcc/java/except.c
index 47c76e8..492e977 100644
--- a/gcc/java/except.c
+++ b/gcc/java/except.c
@@ -433,10 +433,10 @@ prepare_eh_table_type (tree type)
   return exp;
 }
 
-static int
-expand_catch_class (void **entry, void *x ATTRIBUTE_UNUSED)
+int
+expand_catch_class (treetreehash_entry **entry, int)
 {
-  struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
+  struct treetreehash_entry *ite = *entry;
   tree addr = TREE_VALUE ((tree)ite->value);
   tree decl;
   STRIP_NOPS (addr);
@@ -452,9 +452,7 @@ void
 java_expand_catch_classes (tree this_class)
 {
   if (TYPE_TO_RUNTIME_MAP (this_class))
-    htab_traverse 
-      (TYPE_TO_RUNTIME_MAP (this_class),
-       expand_catch_class, NULL);
+    TYPE_TO_RUNTIME_MAP (this_class)->traverse<int, expand_catch_class> (0);
 }
 
 /* Build and push the variable that will hold the exception object
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index 51b8f0f..877f1b0 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -398,22 +398,19 @@ pop_type (tree type)
 
 /* Return true if two type assertions are equal.  */
 
-static int
-type_assertion_eq (const void * k1_p, const void * k2_p)
+bool
+type_assertion_hasher::equal (type_assertion *k1, type_assertion *k2)
 {
-  const type_assertion k1 = *(const type_assertion *)k1_p;
-  const type_assertion k2 = *(const type_assertion *)k2_p;
-  return (k1.assertion_code == k2.assertion_code
-          && k1.op1 == k2.op1
-	  && k1.op2 == k2.op2);
+  return (k1->assertion_code == k2->assertion_code
+          && k1->op1 == k2->op1
+	  && k1->op2 == k2->op2);
 }
 
 /* Hash a type assertion.  */
 
-static hashval_t
-type_assertion_hash (const void *p)
+hashval_t
+type_assertion_hasher::hash (type_assertion *k_p)
 {
-  const type_assertion *k_p = (const type_assertion *) p;
   hashval_t hash = iterative_hash (&k_p->assertion_code, sizeof
 				   k_p->assertion_code, 0);
 
@@ -449,15 +446,14 @@ type_assertion_hash (const void *p)
 void
 add_type_assertion (tree klass, int assertion_code, tree op1, tree op2)
 {
-  htab_t assertions_htab;
+  hash_table<type_assertion_hasher> *assertions_htab;
   type_assertion as;
-  void **as_pp;
+  type_assertion **as_pp;
 
   assertions_htab = TYPE_ASSERTIONS (klass);
   if (assertions_htab == NULL)
     {
-      assertions_htab = htab_create_ggc (7, type_assertion_hash, 
-					 type_assertion_eq, NULL);
+      assertions_htab = hash_table<type_assertion_hasher>::create_ggc (7);
       TYPE_ASSERTIONS (current_class) = assertions_htab;
     }
 
@@ -465,14 +461,14 @@ add_type_assertion (tree klass, int assertion_code, tree op1, tree op2)
   as.op1 = op1;
   as.op2 = op2;
 
-  as_pp = htab_find_slot (assertions_htab, &as, INSERT);
+  as_pp = assertions_htab->find_slot (&as, INSERT);
 
   /* Don't add the same assertion twice.  */
   if (*as_pp)
     return;
 
   *as_pp = ggc_alloc<type_assertion> ();
-  **(type_assertion **)as_pp = as;
+  **as_pp = as;
 }
 
 
@@ -1946,10 +1942,9 @@ pop_arguments (tree method_type)
 /* Attach to PTR (a block) the declaration found in ENTRY. */
 
 int
-attach_init_test_initialization_flags (void **entry, void *ptr)
+attach_init_test_initialization_flags (treetreehash_entry **slot, tree block)
 {
-  tree block = (tree)ptr;
-  struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
+  treetreehash_entry *ite = *slot;
 
   if (block != error_mark_node)
     {
diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h
index e832f44..40b687d 100644
--- a/gcc/java/java-tree.h
+++ b/gcc/java/java-tree.h
@@ -710,6 +710,25 @@ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
        && TREE_CODE (TREE_TYPE (NODE)) != POINTER_TYPE) \
    || TREE_CODE (NODE) == REAL_CST)
 
+struct GTY((for_user)) treetreehash_entry {
+  tree key;
+  tree value;
+};
+
+struct treetreehasher : ggc_hasher<treetreehash_entry *>
+{
+  typedef tree compare_type;
+
+  static hashval_t hash (treetreehash_entry *);
+  static bool equal (treetreehash_entry *, tree);
+};
+
+struct ict_hasher : ggc_hasher<tree_node *>
+{
+  static hashval_t hash (tree t) { return htab_hash_pointer (t); }
+  static bool equal (tree a, tree b) { return a == b; }
+};
+
 /* DECL_LANG_SPECIFIC for FUNCTION_DECLs. */
 struct GTY(()) lang_decl_func {
   /*  tree chain; not yet used. */
@@ -726,10 +745,10 @@ struct GTY(()) lang_decl_func {
   tree exc_obj;			/* Decl holding the exception object.  */
 
   /* Class initialization test variables  */
-  htab_t GTY ((param_is (struct treetreehash_entry))) init_test_table;
+  hash_table<treetreehasher> *init_test_table;
 				
   /* Initialized (static) Class Table */
-  htab_t GTY ((param_is (union tree_node))) ict;
+  hash_table<ict_hasher> *ict;
 
   unsigned int native : 1;	/* Nonzero if this is a native method  */
   unsigned int strictfp : 1;
@@ -742,11 +761,6 @@ struct GTY(()) lang_decl_func {
   unsigned int varargs : 1;	/* Varargs method.  */
 };
 
-struct GTY(()) treetreehash_entry {
-  tree key;
-  tree value;
-};
-
 /* These represent the possible assertion_codes that can be emitted in the
    type assertion table.  */
 enum
@@ -778,15 +792,21 @@ typedef enum
   JV_ANNOTATION_DEFAULT_KIND
 } jv_attr_kind;
 
-typedef struct GTY(()) type_assertion {
+typedef struct GTY((for_user)) type_assertion {
   int assertion_code; /* 'opcode' for the type of this assertion. */
   tree op1;           /* First operand. */
   tree op2;           /* Second operand. */
 } type_assertion;
 
-extern tree java_treetreehash_find (htab_t, tree);
-extern tree * java_treetreehash_new (htab_t, tree);
-extern htab_t java_treetreehash_create (size_t size);
+struct type_assertion_hasher : ggc_hasher<type_assertion *>
+{
+  static hashval_t hash (type_assertion *);
+  static bool equal (type_assertion *, type_assertion *);
+};
+
+extern tree java_treetreehash_find (hash_table<treetreehasher> *, tree);
+extern tree * java_treetreehash_new (hash_table<treetreehasher> *, tree);
+extern hash_table<treetreehasher> *java_treetreehash_create (size_t size);
 
 /* DECL_LANG_SPECIFIC for VAR_DECL, PARM_DECL and sometimes FIELD_DECL
    (access methods on outer class fields) and final fields. */
@@ -893,11 +913,11 @@ struct GTY(()) lang_type {
 				   type matcher.  */
   vec<constructor_elt, va_gc> *catch_classes;
 
-  htab_t GTY ((param_is (struct treetreehash_entry))) type_to_runtime_map;   
+  hash_table<treetreehasher> *type_to_runtime_map;   
                                 /* The mapping of classes to exception region
 				   markers.  */
 
-  htab_t GTY ((param_is (struct type_assertion))) type_assertions;
+  hash_table<type_assertion_hasher> *type_assertions;
 				/* Table of type assertions to be evaluated 
   				   by the runtime when this class is loaded. */
 
@@ -1013,7 +1033,7 @@ extern void maybe_rewrite_invocation (tree *, vec<tree, va_gc> **, tree *,
 extern tree build_known_method_ref (tree, tree, tree, tree, vec<tree, va_gc> *,
 				    tree);
 extern tree build_class_init (tree, tree);
-extern int attach_init_test_initialization_flags (void **, void *);
+extern int attach_init_test_initialization_flags (treetreehash_entry **, tree);
 extern tree build_invokevirtual (tree, tree, tree);
 extern tree build_invokeinterface (tree, tree);
 extern tree build_jni_stub (tree);
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 8a68691..7f0b09d 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -57,8 +57,6 @@ static void put_decl_string (const char *, int);
 static void put_decl_node (tree, int);
 static void java_print_error_function (diagnostic_context *, const char *,
 				       diagnostic_info *);
-static int merge_init_test_initialization (void * *, void *);
-static int inline_init_test_initialization (void * *, void *);
 static bool java_dump_tree (void *, tree);
 static void dump_compound_expr (dump_info_p, tree);
 static bool java_decl_ok_for_sibcall (const_tree);
@@ -713,10 +711,10 @@ decl_constant_value (tree decl)
 /* Create a mapping from a boolean variable in a method being inlined
    to one in the scope of the method being inlined into.  */
 
-static int
-merge_init_test_initialization (void **entry, void *x)
+int
+merge_init_test_initialization (treetreehash_entry **entry, void *x)
 {
-  struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
+  struct treetreehash_entry *ite = *entry;
   splay_tree decl_map = (splay_tree)x;
   splay_tree_node n;
   tree *init_test_decl;
@@ -761,9 +759,8 @@ merge_init_test_initialization (void **entry, void *x)
 void
 java_inlining_merge_static_initializers (tree fn, void *decl_map)
 {
-  htab_traverse
-    (DECL_FUNCTION_INIT_TEST_TABLE (fn),
-     merge_init_test_initialization, decl_map);
+    DECL_FUNCTION_INIT_TEST_TABLE (fn)
+      ->traverse<void *, merge_init_test_initialization> (decl_map);
 }
 
 /* Lookup a DECL_FUNCTION_INIT_TEST_TABLE entry in the method we're
@@ -772,10 +769,10 @@ java_inlining_merge_static_initializers (tree fn, void *decl_map)
    from the variable in the inlined class to the corresponding
    pre-existing one.  */
 
-static int
-inline_init_test_initialization (void **entry, void *x)
+int
+inline_init_test_initialization (treetreehash_entry **entry, void *x)
 {
-  struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
+  struct treetreehash_entry *ite = *entry;
   splay_tree decl_map = (splay_tree)x;
 
   tree h = java_treetreehash_find
@@ -796,9 +793,8 @@ inline_init_test_initialization (void **entry, void *x)
 void
 java_inlining_map_static_initializers (tree fn, void *decl_map)
 {
-  htab_traverse
-    (DECL_FUNCTION_INIT_TEST_TABLE (fn),
-     inline_init_test_initialization, decl_map);
+  DECL_FUNCTION_INIT_TEST_TABLE (fn)
+    ->traverse<void *, inline_init_test_initialization> (decl_map);
 }
 
 /* Avoid voluminous output for deep recursion of compound exprs.  */
diff --git a/gcc/libfuncs.h b/gcc/libfuncs.h
index 5cc32b3..ea067bd 100644
--- a/gcc/libfuncs.h
+++ b/gcc/libfuncs.h
@@ -55,11 +55,19 @@ enum libfunc_index
    We use the same hashtable for normal optabs and conversion optabs.  In
    the first case mode2 is forced to VOIDmode.  */
 
-struct GTY(()) libfunc_entry {
+struct GTY((for_user)) libfunc_entry {
   int op, mode1, mode2;
   rtx libfunc;
 };
 
+/* Descriptor for libfunc_entry.  */
+
+struct libfunc_hasher : ggc_hasher<libfunc_entry *>
+{
+  static hashval_t hash (libfunc_entry *);
+  static bool equal (libfunc_entry *, libfunc_entry *);
+};
+
 /* Target-dependent globals.  */
 struct GTY(()) target_libfuncs {
   /* SYMBOL_REF rtx's for the library functions that are called
@@ -67,7 +75,7 @@ struct GTY(()) target_libfuncs {
   rtx x_libfunc_table[LTI_MAX];
 
   /* Hash table used to convert declarations into nodes.  */
-  htab_t GTY((param_is (struct libfunc_entry))) x_libfunc_hash;
+  hash_table<libfunc_hasher> *GTY(()) x_libfunc_hash;
 };
 
 extern GTY(()) struct target_libfuncs default_target_libfuncs;
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index df59981..a703c42 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -253,7 +253,7 @@ vec<tree, va_gc> *local_variables_to_volatilize = NULL;
 /* Store all constructed constant strings in a hash table so that
    they get uniqued properly.  */
 
-struct GTY(()) string_descriptor {
+struct GTY((for_user)) string_descriptor {
   /* The literal argument .  */
   tree literal;
 
@@ -261,7 +261,13 @@ struct GTY(()) string_descriptor {
   tree constructor;
 };
 
-static GTY((param_is (struct string_descriptor))) htab_t string_htab;
+struct objc_string_hasher : ggc_hasher<string_descriptor *>
+{
+  static hashval_t hash (string_descriptor *);
+  static bool equal (string_descriptor *, string_descriptor *);
+};
+
+static GTY(()) hash_table<objc_string_hasher> *string_htab;
 
 FILE *gen_declaration_file;
 
@@ -3107,10 +3113,10 @@ my_build_string_pointer (int len, const char *str)
   return build1 (ADDR_EXPR, ptrtype, string);
 }
 
-static hashval_t
-string_hash (const void *ptr)
+hashval_t
+objc_string_hasher::hash (string_descriptor *ptr)
 {
-  const_tree const str = ((const struct string_descriptor *)ptr)->literal;
+  const_tree const str = ptr->literal;
   const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str);
   int i, len = TREE_STRING_LENGTH (str);
   hashval_t h = len;
@@ -3121,11 +3127,11 @@ string_hash (const void *ptr)
   return h;
 }
 
-static int
-string_eq (const void *ptr1, const void *ptr2)
+bool
+objc_string_hasher::equal (string_descriptor *ptr1, string_descriptor *ptr2)
 {
-  const_tree const str1 = ((const struct string_descriptor *)ptr1)->literal;
-  const_tree const str2 = ((const struct string_descriptor *)ptr2)->literal;
+  const_tree const str1 = ptr1->literal;
+  const_tree const str2 = ptr2->literal;
   int len1 = TREE_STRING_LENGTH (str1);
 
   return (len1 == TREE_STRING_LENGTH (str2)
@@ -3147,7 +3153,6 @@ objc_build_string_object (tree string)
   int length;
   tree addr;
   struct string_descriptor *desc, key;
-  void **loc;
 
   /* We should be passed a STRING_CST.  */
   gcc_checking_assert (TREE_CODE (string) == STRING_CST);
@@ -3198,8 +3203,8 @@ objc_build_string_object (tree string)
 
   /* Perhaps we already constructed a constant string just like this one? */
   key.literal = string;
-  loc = htab_find_slot (string_htab, &key, INSERT);
-  desc = (struct string_descriptor *) *loc;
+  string_descriptor **loc = string_htab->find_slot (&key, INSERT);
+  desc = *loc;
 
   if (!desc)
     {
@@ -5776,8 +5781,7 @@ hash_init (void)
   alias_name_map = objc_map_alloc_ggc (200);
 
   /* Initialize the hash table used to hold the constant string objects.  */
-  string_htab = htab_create_ggc (31, string_hash,
-				   string_eq, NULL);
+  string_htab = hash_table<objc_string_hasher>::create_ggc (31);
 }
 
 /* Use the following to add a method to class_method_map or
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 605615d..d55a6bb 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-config.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tree-hasher.h"
 #include "stor-layout.h"
 #include "stringpool.h"
 #include "varasm.h"
@@ -73,20 +74,17 @@ void debug_optab_libfuncs (void);
 
 /* Used for libfunc_hash.  */
 
-static hashval_t
-hash_libfunc (const void *p)
+hashval_t
+libfunc_hasher::hash (libfunc_entry *e)
 {
-  const struct libfunc_entry *const e = (const struct libfunc_entry *) p;
   return ((e->mode1 + e->mode2 * NUM_MACHINE_MODES) ^ e->op);
 }
 
 /* Used for libfunc_hash.  */
 
-static int
-eq_libfunc (const void *p, const void *q)
+bool
+libfunc_hasher::equal (libfunc_entry *e1, libfunc_entry *e2)
 {
-  const struct libfunc_entry *const e1 = (const struct libfunc_entry *) p;
-  const struct libfunc_entry *const e2 = (const struct libfunc_entry *) q;
   return e1->op == e2->op && e1->mode1 == e2->mode1 && e1->mode2 == e2->mode2;
 }
 
@@ -109,8 +107,7 @@ convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
   e.op = optab;
   e.mode1 = mode1;
   e.mode2 = mode2;
-  slot = (struct libfunc_entry **)
-    htab_find_slot (libfunc_hash, &e, NO_INSERT);
+  slot = libfunc_hash->find_slot (&e, NO_INSERT);
   if (!slot)
     {
       const struct convert_optab_libcall_d *d
@@ -120,8 +117,7 @@ convert_optab_libfunc (convert_optab optab, enum machine_mode mode1,
 	return NULL;
 
       d->libcall_gen (optab, d->libcall_basename, mode1, mode2);
-      slot = (struct libfunc_entry **)
-	htab_find_slot (libfunc_hash, &e, NO_INSERT);
+      slot = libfunc_hash->find_slot (&e, NO_INSERT);
       if (!slot)
 	return NULL;
     }
@@ -146,8 +142,7 @@ optab_libfunc (optab optab, enum machine_mode mode)
   e.op = optab;
   e.mode1 = mode;
   e.mode2 = VOIDmode;
-  slot = (struct libfunc_entry **)
-    htab_find_slot (libfunc_hash, &e, NO_INSERT);
+  slot = libfunc_hash->find_slot (&e, NO_INSERT);
   if (!slot)
     {
       const struct optab_libcall_d *d
@@ -157,8 +152,7 @@ optab_libfunc (optab optab, enum machine_mode mode)
 	return NULL;
 
       d->libcall_gen (optab, d->libcall_basename, d->libcall_suffix, mode);
-      slot = (struct libfunc_entry **)
-	htab_find_slot (libfunc_hash, &e, NO_INSERT);
+      slot = libfunc_hash->find_slot (&e, NO_INSERT);
       if (!slot)
 	return NULL;
     }
@@ -6100,22 +6094,25 @@ gen_satfractuns_conv_libfunc (convert_optab tab,
   gen_interclass_conv_libfunc (tab, opname, tmode, fmode);
 }
 
-/* A table of previously-created libfuncs, hashed by name.  */
-static GTY ((param_is (union tree_node))) htab_t libfunc_decls;
-
 /* Hashtable callbacks for libfunc_decls.  */
 
-static hashval_t
-libfunc_decl_hash (const void *entry)
+struct libfunc_decl_hasher : ggc_hasher<tree>
 {
-  return IDENTIFIER_HASH_VALUE (DECL_NAME ((const_tree) entry));
-}
+  static hashval_t
+  hash (tree entry)
+  {
+    return IDENTIFIER_HASH_VALUE (DECL_NAME (entry));
+  }
 
-static int
-libfunc_decl_eq (const void *entry1, const void *entry2)
-{
-  return DECL_NAME ((const_tree) entry1) == (const_tree) entry2;
-}
+  static bool
+  equal (tree decl, tree name)
+  {
+    return DECL_NAME (decl) == name;
+  }
+};
+
+/* A table of previously-created libfuncs, hashed by name.  */
+static GTY (()) hash_table<libfunc_decl_hasher> *libfunc_decls;
 
 /* Build a decl for a libfunc named NAME. */
 
@@ -6143,18 +6140,16 @@ rtx
 init_one_libfunc (const char *name)
 {
   tree id, decl;
-  void **slot;
   hashval_t hash;
 
   if (libfunc_decls == NULL)
-    libfunc_decls = htab_create_ggc (37, libfunc_decl_hash,
-				     libfunc_decl_eq, NULL);
+    libfunc_decls = hash_table<libfunc_decl_hasher>::create_ggc (37);
 
   /* See if we have already created a libfunc decl for this function.  */
   id = get_identifier (name);
   hash = IDENTIFIER_HASH_VALUE (id);
-  slot = htab_find_slot_with_hash (libfunc_decls, id, hash, INSERT);
-  decl = (tree) *slot;
+  tree *slot = libfunc_decls->find_slot_with_hash (id, hash, INSERT);
+  decl = *slot;
   if (decl == NULL)
     {
       /* Create a new decl, so that it can be passed to
@@ -6171,12 +6166,11 @@ rtx
 set_user_assembler_libfunc (const char *name, const char *asmspec)
 {
   tree id, decl;
-  void **slot;
   hashval_t hash;
 
   id = get_identifier (name);
   hash = IDENTIFIER_HASH_VALUE (id);
-  slot = htab_find_slot_with_hash (libfunc_decls, id, hash, NO_INSERT);
+  tree *slot = libfunc_decls->find_slot_with_hash (id, hash, NO_INSERT);
   gcc_assert (slot);
   decl = (tree) *slot;
   set_user_assembler_name (decl, asmspec);
@@ -6200,7 +6194,7 @@ set_optab_libfunc (optab op, enum machine_mode mode, const char *name)
     val = init_one_libfunc (name);
   else
     val = 0;
-  slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+  slot = libfunc_hash->find_slot (&e, INSERT);
   if (*slot == NULL)
     *slot = ggc_alloc<libfunc_entry> ();
   (*slot)->op = op;
@@ -6228,7 +6222,7 @@ set_conv_libfunc (convert_optab optab, enum machine_mode tmode,
     val = init_one_libfunc (name);
   else
     val = 0;
-  slot = (struct libfunc_entry **) htab_find_slot (libfunc_hash, &e, INSERT);
+  slot = libfunc_hash->find_slot (&e, INSERT);
   if (*slot == NULL)
     *slot = ggc_alloc<libfunc_entry> ();
   (*slot)->op = optab;
@@ -6244,9 +6238,9 @@ void
 init_optabs (void)
 {
   if (libfunc_hash)
-    htab_empty (libfunc_hash);
+    libfunc_hash->empty ();
   else
-    libfunc_hash = htab_create_ggc (10, hash_libfunc, eq_libfunc, NULL);
+    libfunc_hash = hash_table<libfunc_hasher>::create_ggc (10);
 
   /* Fill in the optabs with the insns we support.  */
   init_all_optabs (this_fn_optabs);
diff --git a/gcc/output.h b/gcc/output.h
index 62f0532..f1ac57b 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -486,7 +486,7 @@ struct GTY(()) noswitch_section {
 };
 
 /* Information about a section, which may be named or unnamed.  */
-union GTY ((desc ("SECTION_STYLE (&(%h))"))) section {
+union GTY ((desc ("SECTION_STYLE (&(%h))"), for_user)) section {
   struct section_common GTY ((skip)) common;
   struct named_section GTY ((tag ("SECTION_NAMED"))) named;
   struct unnamed_section GTY ((tag ("SECTION_UNNAMED"))) unnamed;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index e73f731..6ce0dce 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -224,7 +224,7 @@ struct GTY(()) block_symbol {
 
 /* Describes a group of objects that are to be placed together in such
    a way that their relative positions are known.  */
-struct GTY(()) object_block {
+struct GTY((for_user)) object_block {
   /* The section in which these objects should be placed.  */
   section *sect;
 
diff --git a/gcc/sese.c b/gcc/sese.c
index 735248c..71a752e 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -618,9 +618,9 @@ if_region_set_false_region (ifsese if_region, sese region)
   edge exit_region = SESE_EXIT (region);
   basic_block before_region = entry_region->src;
   basic_block last_in_region = exit_region->src;
-  void **slot = htab_find_slot_with_hash (current_loops->exits, exit_region,
-					  htab_hash_pointer (exit_region),
-					  NO_INSERT);
+  hashval_t hash = htab_hash_pointer (exit_region);
+  loop_exit **slot
+    = current_loops->exits->find_slot_with_hash (exit_region, hash, NO_INSERT);
 
   entry_region->flags = false_edge->flags;
   false_edge->flags = exit_region->flags;
@@ -644,11 +644,11 @@ if_region_set_false_region (ifsese if_region, sese region)
       struct loop_exit *loop_exit = ggc_cleared_alloc<struct loop_exit> ();
 
       memcpy (loop_exit, *((struct loop_exit **) slot), sizeof (struct loop_exit));
-      htab_clear_slot (current_loops->exits, slot);
+      current_loops->exits->clear_slot (slot);
 
-      slot = htab_find_slot_with_hash (current_loops->exits, false_edge,
-				       htab_hash_pointer (false_edge),
-				       INSERT);
+							hashval_t hash = htab_hash_pointer (false_edge);
+      slot = current_loops->exits->find_slot_with_hash (false_edge, hash,
+							INSERT);
       loop_exit->e = false_edge;
       *slot = loop_exit;
       false_edge->src->loop_father->exits->next = loop_exit;
diff --git a/gcc/symtab.c b/gcc/symtab.c
index f23bd83..d99546f 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -83,15 +83,6 @@ symbol_table::decl_assembler_name_hash (const_tree asmname)
 }
 
 
-/* Returns a hash code for P.  */
-
-hashval_t
-symbol_table::hash_node_by_assembler_name (const void *p)
-{
-  const symtab_node *n = (const symtab_node *) p;
-  return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->decl));
-}
-
 /* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL.  */
 
 bool
@@ -150,14 +141,6 @@ symbol_table::decl_assembler_name_equal (tree decl, const_tree asmname)
 
 /* Returns nonzero if P1 and P2 are equal.  */
 
-int
-symbol_table::eq_assembler_name (const void *p1, const void *p2)
-{
-  const symtab_node *n1 = (const symtab_node *) p1;
-  const_tree name = (const_tree)p2;
-  return (decl_assembler_name_equal (n1->decl, name));
-}
-
 /* Insert NODE to assembler name hash.  */
 
 void
@@ -170,19 +153,18 @@ symbol_table::insert_to_assembler_name_hash (symtab_node *node,
 		       && !node->next_sharing_asm_name);
   if (assembler_name_hash)
     {
-      void **aslot;
+      symtab_node **aslot;
       cgraph_node *cnode;
       tree decl = node->decl;
 
       tree name = DECL_ASSEMBLER_NAME (node->decl);
 
-      aslot = htab_find_slot_with_hash (assembler_name_hash, name,
-					decl_assembler_name_hash (name),
-					INSERT);
+      hashval_t hash = decl_assembler_name_hash (name);
+      aslot = assembler_name_hash->find_slot_with_hash (name, hash, INSERT);
       gcc_assert (*aslot != node);
       node->next_sharing_asm_name = (symtab_node *)*aslot;
       if (*aslot != NULL)
-	((symtab_node *)*aslot)->previous_sharing_asm_name = node;
+	(*aslot)->previous_sharing_asm_name = node;
       *aslot = node;
 
       /* Update also possible inline clones sharing a decl.  */
@@ -217,13 +199,13 @@ symbol_table::unlink_from_assembler_name_hash (symtab_node *node,
       else
 	{
 	  tree name = DECL_ASSEMBLER_NAME (node->decl);
-          void **slot;
-	  slot = htab_find_slot_with_hash (assembler_name_hash, name,
-					   decl_assembler_name_hash (name),
-					   NO_INSERT);
+          symtab_node **slot;
+	  hashval_t hash = decl_assembler_name_hash (name);
+	  slot = assembler_name_hash->find_slot_with_hash (name, hash,
+							   NO_INSERT);
 	  gcc_assert (*slot == node);
 	  if (!node->next_sharing_asm_name)
-	    htab_clear_slot (assembler_name_hash, slot);
+	    assembler_name_hash->clear_slot (slot);
 	  else
 	    *slot = node->next_sharing_asm_name;
 	}
@@ -256,9 +238,7 @@ symbol_table::symtab_initialize_asm_name_hash (void)
   symtab_node *node;
   if (!assembler_name_hash)
     {
-      assembler_name_hash =
-	htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name,
-			 NULL);
+      assembler_name_hash = hash_table<asmname_hasher>::create_ggc (10);
       FOR_EACH_SYMBOL (node)
 	insert_to_assembler_name_hash (node, false);
     }
@@ -322,20 +302,17 @@ resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution)
 
 /* Hash sections by their names.  */
 
-static hashval_t
-hash_section_hash_entry (const void *p)
+hashval_t
+section_name_hasher::hash (section_hash_entry *n)
 {
-  const section_hash_entry *n = (const section_hash_entry *) p;
   return htab_hash_string (n->name);
 }
 
 /* Return true if section P1 name equals to P2.  */
 
-static int
-eq_sections (const void *p1, const void *p2)
+bool
+section_name_hasher::equal (section_hash_entry *n1, const char *name)
 {
-  const section_hash_entry *n1 = (const section_hash_entry *) p1;
-  const char *name = (const char *)p2;
   return n1->name == name || !strcmp (n1->name, name);
 }
 
@@ -936,16 +913,16 @@ symtab_node *
 symtab_node::get_for_asmname (const_tree asmname)
 {
   symtab_node *node;
-  void **slot;
 
   symtab->symtab_initialize_asm_name_hash ();
-  slot = htab_find_slot_with_hash (symtab->assembler_name_hash, asmname,
-				   symtab->decl_assembler_name_hash (asmname),
-				   NO_INSERT);
+  hashval_t hash = symtab->decl_assembler_name_hash (asmname);
+  symtab_node **slot
+    = symtab->assembler_name_hash->find_slot_with_hash (asmname, hash,
+							NO_INSERT);
 
   if (slot)
     {
-      node = (symtab_node *) *slot;
+      node = *slot;
       return node;
     }
   return NULL;
@@ -1382,7 +1359,7 @@ void
 symtab_node::set_section_for_node (const char *section)
 {
   const char *current = get_section ();
-  void **slot;
+  section_hash_entry **slot;
 
   if (current == section
       || (current && section
@@ -1394,11 +1371,11 @@ symtab_node::set_section_for_node (const char *section)
       x_section->ref_count--;
       if (!x_section->ref_count)
 	{
-	  slot = htab_find_slot_with_hash (symtab->section_hash, x_section->name,
-					   htab_hash_string (x_section->name),
-					   INSERT);
+	  hashval_t hash = htab_hash_string (x_section->name);
+	  slot = symtab->section_hash->find_slot_with_hash (x_section->name,
+							    hash, INSERT);
 	  ggc_free (x_section);
-	  htab_clear_slot (symtab->section_hash, slot);
+	  symtab->section_hash->clear_slot (slot);
 	}
       x_section = NULL;
     }
@@ -1408,11 +1385,10 @@ symtab_node::set_section_for_node (const char *section)
       return;
     }
   if (!symtab->section_hash)
-    symtab->section_hash = htab_create_ggc (10, hash_section_hash_entry,
-				    eq_sections, NULL);
-  slot = htab_find_slot_with_hash (symtab->section_hash, section,
-				   htab_hash_string (section),
-				   INSERT);
+    symtab->section_hash = hash_table<section_name_hasher>::create_ggc (10);
+  slot = symtab->section_hash->find_slot_with_hash (section,
+						    htab_hash_string (section),
+						    INSERT);
   if (*slot)
     x_section = (section_hash_entry *)*slot;
   else
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index e88842a..cdab639 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -6980,11 +6980,12 @@ move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
       if (loops_for_fn (saved_cfun)->exits)
 	FOR_EACH_EDGE (e, ei, bb->succs)
 	  {
-	    void **slot = htab_find_slot_with_hash
-		(loops_for_fn (saved_cfun)->exits, e,
-		 htab_hash_pointer (e), NO_INSERT);
+	    struct loops *l = loops_for_fn (saved_cfun);
+	    loop_exit **slot
+	      = l->exits->find_slot_with_hash (e, htab_hash_pointer (e),
+					       NO_INSERT);
 	    if (slot)
-	      htab_clear_slot (loops_for_fn (saved_cfun)->exits, slot);
+	      l->exits->clear_slot (slot);
 	  }
     }
 
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 8459043..9e39028 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -322,7 +322,7 @@ ssa_default_def (struct function *fn, tree var)
 	      || TREE_CODE (var) == RESULT_DECL);
   in.var = (tree)&ind;
   ind.uid = DECL_UID (var);
-  return (tree) htab_find_with_hash (DEFAULT_DEFS (fn), &in, DECL_UID (var));
+  return DEFAULT_DEFS (fn)->find_with_hash ((tree)&in, DECL_UID (var));
 }
 
 /* Insert the pair VAR's UID, DEF into the default_defs hashtable
@@ -333,7 +333,6 @@ set_ssa_default_def (struct function *fn, tree var, tree def)
 {
   struct tree_decl_minimal ind;
   struct tree_ssa_name in;
-  void **loc;
 
   gcc_assert (TREE_CODE (var) == VAR_DECL
 	      || TREE_CODE (var) == PARM_DECL
@@ -342,25 +341,26 @@ set_ssa_default_def (struct function *fn, tree var, tree def)
   ind.uid = DECL_UID (var);
   if (!def)
     {
-      loc = htab_find_slot_with_hash (DEFAULT_DEFS (fn), &in,
-				      DECL_UID (var), NO_INSERT);
+      tree *loc = DEFAULT_DEFS (fn)->find_slot_with_hash ((tree)&in,
+							  DECL_UID (var),
+							  NO_INSERT);
       if (loc)
 	{
 	  SSA_NAME_IS_DEFAULT_DEF (*(tree *)loc) = false;
-	  htab_clear_slot (DEFAULT_DEFS (fn), loc);
+	  DEFAULT_DEFS (fn)->clear_slot (loc);
 	}
       return;
     }
   gcc_assert (TREE_CODE (def) == SSA_NAME && SSA_NAME_VAR (def) == var);
-  loc = htab_find_slot_with_hash (DEFAULT_DEFS (fn), &in,
-                                  DECL_UID (var), INSERT);
+  tree *loc = DEFAULT_DEFS (fn)->find_slot_with_hash ((tree)&in,
+						      DECL_UID (var), INSERT);
 
   /* Default definition might be changed by tail call optimization.  */
   if (*loc)
-    SSA_NAME_IS_DEFAULT_DEF (*(tree *) loc) = false;
+    SSA_NAME_IS_DEFAULT_DEF (*loc) = false;
 
    /* Mark DEF as the default definition for VAR.  */
-  *(tree *) loc = def;
+  *loc = def;
   SSA_NAME_IS_DEFAULT_DEF (def) = true;
 }
 
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index b6b3718..f05db17 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1055,24 +1055,6 @@ err:
   internal_error ("verify_ssa failed");
 }
 
-/* Return true if the DECL_UID in both trees are equal.  */
-
-static int
-uid_ssaname_map_eq (const void *va, const void *vb)
-{
-  const_tree a = (const_tree) va;
-  const_tree b = (const_tree) vb;
-  return (a->ssa_name.var->decl_minimal.uid == b->ssa_name.var->decl_minimal.uid);
-}
-
-/* Hash a tree in a uid_decl_map.  */
-
-static unsigned int
-uid_ssaname_map_hash (const void *item)
-{
-  return ((const_tree)item)->ssa_name.var->decl_minimal.uid;
-}
-
 
 /* Initialize global DFA and SSA structures.  */
 
@@ -1080,8 +1062,7 @@ void
 init_tree_ssa (struct function *fn)
 {
   fn->gimple_df = ggc_cleared_alloc<gimple_df> ();
-  fn->gimple_df->default_defs = htab_create_ggc (20, uid_ssaname_map_hash,
-				                 uid_ssaname_map_eq, NULL);
+  fn->gimple_df->default_defs = hash_table<ssa_name_hasher>::create_ggc (20);
   pt_solution_reset (&fn->gimple_df->escaped);
   init_ssanames (fn, 0);
 }
@@ -1153,7 +1134,7 @@ delete_tree_ssa (void)
   if (ssa_operands_active (cfun))
     fini_ssa_operands (cfun);
 
-  htab_delete (cfun->gimple_df->default_defs);
+  cfun->gimple_df->default_defs->empty ();
   cfun->gimple_df->default_defs = NULL;
   pt_solution_reset (&cfun->gimple_df->escaped);
   if (cfun->gimple_df->decls_to_pointers != NULL)
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 0b99b39..abb743b 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -110,8 +110,6 @@ static int contains_pointers_p (tree);
 static bool incorporeal_function_p (tree);
 #endif
 static void decode_addr_const (tree, struct addr_const *);
-static hashval_t const_desc_hash (const void *);
-static int const_desc_eq (const void *, const void *);
 static hashval_t const_hash_1 (const tree);
 static int compare_constant (const tree, const tree);
 static void output_constant_def_contents (rtx);
@@ -175,11 +173,27 @@ static GTY(()) section *unnamed_sections;
   ((TREE_CODE (DECL) == FUNCTION_DECL || TREE_CODE (DECL) == VAR_DECL) \
    && DECL_SECTION_NAME (DECL) != NULL)
 
+struct section_hasher : ggc_hasher<section *>
+{
+  typedef const char *compare_type;
+
+  static hashval_t hash (section *);
+  static bool equal (section *, const char *);
+};
+
 /* Hash table of named sections.  */
-static GTY((param_is (section))) htab_t section_htab;
+static GTY(()) hash_table<section_hasher> *section_htab;
+
+struct object_block_hasher : ggc_hasher<object_block *>
+{
+  typedef const section *compare_type;
+
+  static hashval_t hash (object_block *);
+  static bool equal (object_block *, const section *);
+};
 
 /* A table of object_blocks, indexed by section.  */
-static GTY((param_is (struct object_block))) htab_t object_block_htab;
+static GTY(()) hash_table<object_block_hasher> *object_block_htab;
 
 /* The next number to use for internal anchor labels.  */
 static GTY(()) int anchor_labelno;
@@ -189,19 +203,15 @@ static GTY(()) struct rtx_constant_pool *shared_constant_pool;
 
 /* Helper routines for maintaining section_htab.  */
 
-static int
-section_entry_eq (const void *p1, const void *p2)
+bool
+section_hasher::equal (section *old, const char *new_name)
 {
-  const section *old = (const section *) p1;
-  const char *new_name = (const char *) p2;
-
   return strcmp (old->named.name, new_name) == 0;
 }
 
-static hashval_t
-section_entry_hash (const void *p)
+hashval_t
+section_hasher::hash (section *old)
 {
-  const section *old = (const section *) p;
   return htab_hash_string (old->named.name);
 }
 
@@ -217,19 +227,15 @@ hash_section (section *sect)
 
 /* Helper routines for maintaining object_block_htab.  */
 
-static int
-object_block_entry_eq (const void *p1, const void *p2)
+inline bool
+object_block_hasher::equal (object_block *old, const section *new_section)
 {
-  const struct object_block *old = (const struct object_block *) p1;
-  const section *new_section = (const section *) p2;
-
   return old->sect == new_section;
 }
 
-static hashval_t
-object_block_entry_hash (const void *p)
+hashval_t
+object_block_hasher::hash (object_block *old)
 {
-  const struct object_block *old = (const struct object_block *) p;
   return hash_section (old->sect);
 }
 
@@ -273,9 +279,8 @@ get_section (const char *name, unsigned int flags, tree decl)
 {
   section *sect, **slot;
 
-  slot = (section **)
-    htab_find_slot_with_hash (section_htab, name,
-			      htab_hash_string (name), INSERT);
+  slot = section_htab->find_slot_with_hash (name, htab_hash_string (name),
+					    INSERT);
   flags |= SECTION_NAMED;
   if (*slot == NULL)
     {
@@ -350,14 +355,14 @@ static struct object_block *
 get_block_for_section (section *sect)
 {
   struct object_block *block;
-  void **slot;
 
   if (sect == NULL)
     return NULL;
 
-  slot = htab_find_slot_with_hash (object_block_htab, sect,
-				   hash_section (sect), INSERT);
-  block = (struct object_block *) *slot;
+  object_block **slot
+    = object_block_htab->find_slot_with_hash (sect, hash_section (sect),
+					      INSERT);
+  block = *slot;
   if (block == NULL)
     {
       block = ggc_cleared_alloc<object_block> ();
@@ -2824,15 +2829,13 @@ decode_addr_const (tree exp, struct addr_const *value)
   value->offset = offset;
 }
 
-
-static GTY((param_is (struct constant_descriptor_tree)))
-     htab_t const_desc_htab;
+static GTY(()) hash_table<tree_descriptor_hasher> *const_desc_htab;
 
 static void maybe_output_constant_def_contents (struct constant_descriptor_tree *, int);
 
 /* Constant pool accessor function.  */
 
-htab_t
+hash_table<tree_descriptor_hasher> *
 constant_pool_htab (void)
 {
   return const_desc_htab;
@@ -2840,10 +2843,10 @@ constant_pool_htab (void)
 
 /* Compute a hash code for a constant expression.  */
 
-static hashval_t
-const_desc_hash (const void *ptr)
+hashval_t
+tree_descriptor_hasher::hash (constant_descriptor_tree *ptr)
 {
-  return ((const struct constant_descriptor_tree *)ptr)->hash;
+  return ptr->hash;
 }
 
 static hashval_t
@@ -2956,13 +2959,10 @@ const_hash_1 (const tree exp)
 }
 
 /* Wrapper of compare_constant, for the htab interface.  */
-static int
-const_desc_eq (const void *p1, const void *p2)
+bool
+tree_descriptor_hasher::equal (constant_descriptor_tree *c1,
+			       constant_descriptor_tree *c2)
 {
-  const struct constant_descriptor_tree *const c1
-    = (const struct constant_descriptor_tree *) p1;
-  const struct constant_descriptor_tree *const c2
-    = (const struct constant_descriptor_tree *) p2;
   if (c1->hash != c2->hash)
     return 0;
   return compare_constant (c1->value, c2->value);
@@ -3264,15 +3264,15 @@ output_constant_def (tree exp, int defer)
 {
   struct constant_descriptor_tree *desc;
   struct constant_descriptor_tree key;
-  void **loc;
 
   /* Look up EXP in the table of constant descriptors.  If we didn't find
      it, create a new one.  */
   key.value = exp;
   key.hash = const_hash_1 (exp);
-  loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
+  constant_descriptor_tree **loc
+    = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT);
 
-  desc = (struct constant_descriptor_tree *) *loc;
+  desc = *loc;
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
@@ -3387,13 +3387,12 @@ output_constant_def_contents (rtx symbol)
 rtx
 lookup_constant_def (tree exp)
 {
-  struct constant_descriptor_tree *desc;
   struct constant_descriptor_tree key;
 
   key.value = exp;
   key.hash = const_hash_1 (exp);
-  desc = (struct constant_descriptor_tree *)
-    htab_find_with_hash (const_desc_htab, &key, key.hash);
+  constant_descriptor_tree *desc
+    = const_desc_htab->find_with_hash (&key, key.hash);
 
   return (desc ? desc->rtl : NULL_RTX);
 }
@@ -3407,16 +3406,16 @@ tree
 tree_output_constant_def (tree exp)
 {
   struct constant_descriptor_tree *desc, key;
-  void **loc;
   tree decl;
 
   /* Look up EXP in the table of constant descriptors.  If we didn't find
      it, create a new one.  */
   key.value = exp;
   key.hash = const_hash_1 (exp);
-  loc = htab_find_slot_with_hash (const_desc_htab, &key, key.hash, INSERT);
+  constant_descriptor_tree **loc
+    = const_desc_htab->find_slot_with_hash (&key, key.hash, INSERT);
 
-  desc = (struct constant_descriptor_tree *) *loc;
+  desc = *loc;
   if (desc == 0)
     {
       desc = build_constant_desc (exp);
@@ -3429,6 +3428,25 @@ tree_output_constant_def (tree exp)
   return decl;
 }
 
+struct GTY((chain_next ("%h.next"), for_user)) constant_descriptor_rtx {
+  struct constant_descriptor_rtx *next;
+  rtx mem;
+  rtx sym;
+  rtx constant;
+  HOST_WIDE_INT offset;
+  hashval_t hash;
+  enum machine_mode mode;
+  unsigned int align;
+  int labelno;
+  int mark;
+};
+
+struct const_rtx_desc_hasher : ggc_hasher<constant_descriptor_rtx *>
+{
+  static hashval_t hash (constant_descriptor_rtx *);
+  static bool equal (constant_descriptor_rtx *, constant_descriptor_rtx *);
+};
+
 /* Used in the hash tables to avoid outputting the same constant
    twice.  Unlike 'struct constant_descriptor_tree', RTX constants
    are output once per function, not once per file.  */
@@ -3445,44 +3463,25 @@ struct GTY(()) rtx_constant_pool {
      It is used on RISC machines where immediate integer arguments and
      constant addresses are restricted so that such constants must be stored
      in memory.  */
-  htab_t GTY((param_is (struct constant_descriptor_rtx))) const_rtx_htab;
+  hash_table<const_rtx_desc_hasher> *const_rtx_htab;
 
   /* Current offset in constant pool (does not include any
      machine-specific header).  */
   HOST_WIDE_INT offset;
 };
 
-struct GTY((chain_next ("%h.next"))) constant_descriptor_rtx {
-  struct constant_descriptor_rtx *next;
-  rtx mem;
-  rtx sym;
-  rtx constant;
-  HOST_WIDE_INT offset;
-  hashval_t hash;
-  enum machine_mode mode;
-  unsigned int align;
-  int labelno;
-  int mark;
-};
-
 /* Hash and compare functions for const_rtx_htab.  */
 
-static hashval_t
-const_desc_rtx_hash (const void *ptr)
+hashval_t
+const_rtx_desc_hasher::hash (constant_descriptor_rtx *desc)
 {
-  const struct constant_descriptor_rtx *const desc
-    = (const struct constant_descriptor_rtx *) ptr;
   return desc->hash;
 }
 
-static int
-const_desc_rtx_eq (const void *a, const void *b)
+bool
+const_rtx_desc_hasher::equal (constant_descriptor_rtx *x,
+			      constant_descriptor_rtx *y)
 {
-  const struct constant_descriptor_rtx *const x
-    = (const struct constant_descriptor_rtx *) a;
-  const struct constant_descriptor_rtx *const y
-    = (const struct constant_descriptor_rtx *) b;
-
   if (x->mode != y->mode)
     return 0;
   return rtx_equal_p (x->constant, y->constant);
@@ -3585,8 +3584,7 @@ create_constant_pool (void)
   struct rtx_constant_pool *pool;
 
   pool = ggc_alloc<rtx_constant_pool> ();
-  pool->const_rtx_htab = htab_create_ggc (31, const_desc_rtx_hash,
-					  const_desc_rtx_eq, NULL);
+  pool->const_rtx_htab = hash_table<const_rtx_desc_hasher>::create_ggc (31);
   pool->first = NULL;
   pool->last = NULL;
   pool->offset = 0;
@@ -3624,7 +3622,7 @@ force_const_mem (enum machine_mode mode, rtx x)
   rtx def, symbol;
   hashval_t hash;
   unsigned int align;
-  void **slot;
+  constant_descriptor_rtx **slot;
 
   /* If we're not allowed to drop X into the constant pool, don't.  */
   if (targetm.cannot_force_const_mem (mode, x))
@@ -3642,8 +3640,8 @@ force_const_mem (enum machine_mode mode, rtx x)
   tmp.constant = x;
   tmp.mode = mode;
   hash = const_rtx_hash (x);
-  slot = htab_find_slot_with_hash (pool->const_rtx_htab, &tmp, hash, INSERT);
-  desc = (struct constant_descriptor_rtx *) *slot;
+  slot = pool->const_rtx_htab->find_slot_with_hash (&tmp, hash, INSERT);
+  desc = *slot;
 
   /* If the constant was already present, return its memory.  */
   if (desc)
@@ -5923,12 +5921,9 @@ make_decl_one_only (tree decl, tree comdat_group)
 void
 init_varasm_once (void)
 {
-  section_htab = htab_create_ggc (31, section_entry_hash,
-				  section_entry_eq, NULL);
-  object_block_htab = htab_create_ggc (31, object_block_entry_hash,
-				       object_block_entry_eq, NULL);
-  const_desc_htab = htab_create_ggc (1009, const_desc_hash,
-				     const_desc_eq, NULL);
+  section_htab = hash_table<section_hasher>::create_ggc (31);
+  object_block_htab = hash_table<object_block_hasher>::create_ggc (31);
+  const_desc_htab = hash_table<tree_descriptor_hasher>::create_ggc (1009);
 
   const_alias_set = new_alias_set ();
   shared_constant_pool = create_constant_pool ();
@@ -7255,10 +7250,10 @@ output_object_block (struct object_block *block)
 /* A htab_traverse callback used to call output_object_block for
    each member of object_block_htab.  */
 
-static int
-output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
+int
+output_object_block_htab (object_block **slot, void *)
 {
-  output_object_block ((struct object_block *) (*slot));
+  output_object_block (*slot);
   return 1;
 }
 
@@ -7267,7 +7262,7 @@ output_object_block_htab (void **slot, void *data ATTRIBUTE_UNUSED)
 void
 output_object_blocks (void)
 {
-  htab_traverse (object_block_htab, output_object_block_htab, NULL);
+  object_block_htab->traverse<void *, output_object_block_htab> (NULL);
 }
 
 /* This function provides a possible implementation of the
-- 
2.1.1


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