[RFA] C++-ify typedef hash

Message ID 20180315215858.15647-1-tom@tromey.com
State New
Headers show
Series
  • [RFA] C++-ify typedef hash
Related show

Commit Message

Tom Tromey March 15, 2018, 9:58 p.m.
This changes the typedef_hash_table structure to be a C++ class.  It
adds constructors and destructors and changes some functions to be
methods of the class.  Then it changes the various users of this class
to adapt.  This allows for the removal of some cleanups.

Regression tested by the buildbot.

gdb/ChangeLog
2018-03-15  Tom Tromey  <tom@tromey.com>

	* typeprint.h (struct type_print_options) <local_typedefs,
	global_typedefs>: Remove "struct" keyword.
	(class typedef_hash_table): New class.
	(recursively_update_typedef_hash, add_template_parameters)
	(create_typedef_hash, free_typedef_hash, copy_typedef_hash)
	(find_typedef_in_hash): Don't declare.
	* typeprint.c (struct typedef_hash_table): Move to typeprint.h.
	(typedef_hash_table::recursively_update): Rename from
	recursively_update_typedef_hash.  Now a member.
	(typedef_hash_table::add_template_parameters): Rename from
	add_template_parameters.  Now a member.
	(typedef_hash_table::typedef_hash_table): Now a constructor;
	rename from create_typedef_hash.
	(typedef_hash_table::~typedef_hash_table): Now a destructor;
	rename from free_typedef_hash.
	(do_free_typedef_hash, make_cleanup_free_typedef_hash)
	(do_free_global_table): Remove.
	(typedef_hash_table::typedef_hash_table): New constructor; renamed
	from copy_type_recursive.
	(create_global_typedef_table): Remove.
	(typedef_hash_table::find_global_typedef): Now a member of
	typedef_hash_table.
	(typedef_hash_table::find_typedef): Rename from
	find_typedef_in_hash; now a member.
	(whatis_exp): Update.
	* extension.h (struct ext_lang_type_printers): Add constructor and
	destructor.
	(start_ext_lang_type_printers, free_ext_lang_type_printers): Don't
	declare.
	* extension.c (ext_lang_type_printers::ext_lang_type_printers):
	Now a constructor; rename from start_ext_lang_type_printers.
	(ext_lang_type_printers): Now a destructor; rename from
	free_ext_lang_type_printers.
	* c-typeprint.c (find_typedef_for_canonicalize, c_print_type_1):
	Update.
	(c_type_print_base_struct_union): Update.  Remove cleanups.
---
 gdb/ChangeLog     |  39 ++++++++++++++
 gdb/c-typeprint.c |  41 +++++++-------
 gdb/extension.c   |  16 ++----
 gdb/extension.h   |   9 ++--
 gdb/typeprint.c   | 156 ++++++++++++++----------------------------------------
 gdb/typeprint.h   |  53 +++++++++++++++----
 6 files changed, 152 insertions(+), 162 deletions(-)

-- 
2.13.6

Comments

Pedro Alves March 26, 2018, 3:13 p.m. | #1
Hi Tom,

Just a few remarks below.

On 03/15/2018 09:58 PM, Tom Tromey wrote:
>  

>  /* Iteratively try the type pretty-printers specified by PRINTERS

> @@ -463,8 +458,7 @@ apply_ext_lang_type_printers (struct ext_lang_type_printers *printers,

>  /* Call this after pretty-printing a type to release all memory held

>     by PRINTERS.  */


At least this comment should be updated -- there's no "PRINTERS"
parameter any longer.

>  

> -void

> -free_ext_lang_type_printers (struct ext_lang_type_printers *printers)

> +ext_lang_type_printers::~ext_lang_type_printers ()

>  {



- of the contained objects.  */
> +

> +class typedef_hash_table

> +{

> +public:

> +

> +  /* Create a new typedef-lookup hash table.  */

> +  typedef_hash_table ();

> +

> +  ~typedef_hash_table ();

> +

> +  /* Copy a typedef hash.  */

> +  typedef_hash_table (const typedef_hash_table *);


This method's prototype gave me pause -- is there a reason this
isn't a regular copy ctor?

>  

> -void add_template_parameters (struct typedef_hash_table *, struct type *);

> +  typedef_hash_table &operator= (const typedef_hash_table &) = delete;

>  

> -struct typedef_hash_table *create_typedef_hash (void);

> +  /* Add typedefs from T to the hash table TABLE.  */

> +  void recursively_update (struct type *);

>  

> -void free_typedef_hash (struct typedef_hash_table *);

> +  /* Add template parameters from T to the typedef hash TABLE.  */

> +  void add_template_parameters (struct type *t);

>  

> -struct cleanup *make_cleanup_free_typedef_hash (struct typedef_hash_table *);

> +  /* Look up the type T in the typedef hash table FLAGS.  If T


But FLAGS isn't a hash table, right?  The original comment said:

 /* Look up the type T in the typedef hash table in with FLAGS.
                                                 ^^^^^^^

I wonder whether that was a typo for "within".

Maybe this could say something about local/global too.

Thanks,
Pedro Alves
Tom Tromey March 27, 2018, 3:10 a.m. | #2
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:


Pedro> At least this comment should be updated -- there's no "PRINTERS"
Pedro> parameter any longer.

I just removed this comment, since I couldn't think of a useful comment
to put before a destructor.

>> +  /* Copy a typedef hash.  */

>> +  typedef_hash_table (const typedef_hash_table *);


Pedro> This method's prototype gave me pause -- is there a reason this
Pedro> isn't a regular copy ctor?

I've changed it.  I think this was something I meant to do and then
forgot to complete.

Pedro> But FLAGS isn't a hash table, right?  The original comment said:
Pedro>  /* Look up the type T in the typedef hash table in with FLAGS.
Pedro>                                                  ^^^^^^^
Pedro> I wonder whether that was a typo for "within".
Pedro> Maybe this could say something about local/global too.

I've rewritten this comment, let me know what you think.

Tom

commit cc694e06afaf2072e6e02465ca6f6d33849fb9b3
Author: Tom Tromey <tom@tromey.com>
Date:   Wed Mar 14 16:38:02 2018 -0600

    C++-ify typedef hash
    
    This changes the typedef_hash_table structure to be a C++ class.  It
    adds constructors and destructors and changes some functions to be
    methods of the class.  Then it changes the various users of this class
    to adapt.  This allows for the removal of some cleanups.
    
    Regression tested by the buildbot.
    
    gdb/ChangeLog
    2018-03-15  Tom Tromey  <tom@tromey.com>
    
            * typeprint.h (struct type_print_options) <local_typedefs,
            global_typedefs>: Remove "struct" keyword.
            (class typedef_hash_table): New class.
            (recursively_update_typedef_hash, add_template_parameters)
            (create_typedef_hash, free_typedef_hash, copy_typedef_hash)
            (find_typedef_in_hash): Don't declare.
            * typeprint.c (struct typedef_hash_table): Move to typeprint.h.
            (typedef_hash_table::recursively_update): Rename from
            recursively_update_typedef_hash.  Now a member.
            (typedef_hash_table::add_template_parameters): Rename from
            add_template_parameters.  Now a member.
            (typedef_hash_table::typedef_hash_table): Now a constructor;
            rename from create_typedef_hash.
            (typedef_hash_table::~typedef_hash_table): Now a destructor;
            rename from free_typedef_hash.
            (do_free_typedef_hash, make_cleanup_free_typedef_hash)
            (do_free_global_table): Remove.
            (typedef_hash_table::typedef_hash_table): New constructor; renamed
            from copy_type_recursive.
            (create_global_typedef_table): Remove.
            (typedef_hash_table::find_global_typedef): Now a member of
            typedef_hash_table.
            (typedef_hash_table::find_typedef): Rename from
            find_typedef_in_hash; now a member.
            (whatis_exp): Update.
            * extension.h (struct ext_lang_type_printers): Add constructor and
            destructor.
            (start_ext_lang_type_printers, free_ext_lang_type_printers): Don't
            declare.
            * extension.c (ext_lang_type_printers::ext_lang_type_printers):
            Now a constructor; rename from start_ext_lang_type_printers.
            (ext_lang_type_printers): Now a destructor; rename from
            free_ext_lang_type_printers.
            * c-typeprint.c (find_typedef_for_canonicalize, c_print_type_1):
            Update.
            (c_type_print_base_struct_union): Update.  Remove cleanups.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 47e6cff43d..59c2a99b47 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,42 @@
+2018-03-15  Tom Tromey  <tom@tromey.com>
+
+	* typeprint.h (struct type_print_options) <local_typedefs,
+	global_typedefs>: Remove "struct" keyword.
+	(class typedef_hash_table): New class.
+	(recursively_update_typedef_hash, add_template_parameters)
+	(create_typedef_hash, free_typedef_hash, copy_typedef_hash)
+	(find_typedef_in_hash): Don't declare.
+	* typeprint.c (struct typedef_hash_table): Move to typeprint.h.
+	(typedef_hash_table::recursively_update): Rename from
+	recursively_update_typedef_hash.  Now a member.
+	(typedef_hash_table::add_template_parameters): Rename from
+	add_template_parameters.  Now a member.
+	(typedef_hash_table::typedef_hash_table): Now a constructor;
+	rename from create_typedef_hash.
+	(typedef_hash_table::~typedef_hash_table): Now a destructor;
+	rename from free_typedef_hash.
+	(do_free_typedef_hash, make_cleanup_free_typedef_hash)
+	(do_free_global_table): Remove.
+	(typedef_hash_table::typedef_hash_table): New constructor; renamed
+	from copy_type_recursive.
+	(create_global_typedef_table): Remove.
+	(typedef_hash_table::find_global_typedef): Now a member of
+	typedef_hash_table.
+	(typedef_hash_table::find_typedef): Rename from
+	find_typedef_in_hash; now a member.
+	(whatis_exp): Update.
+	* extension.h (struct ext_lang_type_printers): Add constructor and
+	destructor.
+	(start_ext_lang_type_printers, free_ext_lang_type_printers): Don't
+	declare.
+	* extension.c (ext_lang_type_printers::ext_lang_type_printers):
+	Now a constructor; rename from start_ext_lang_type_printers.
+	(ext_lang_type_printers): Now a destructor; rename from
+	free_ext_lang_type_printers.
+	* c-typeprint.c (find_typedef_for_canonicalize, c_print_type_1):
+	Update.
+	(c_type_print_base_struct_union): Update.  Remove cleanups.
+
 2018-03-26  Simon Marchi  <simon.marchi@ericsson.com>
 
 	* dwarf2read.c (DEF_VEC_I(offset_type)): Remove.
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 2e9ed1bc28..1a8af78669 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -68,12 +68,13 @@ static void c_type_print_base_1 (struct type *type, struct ui_file *stream,
 
 
 /* A callback function for cp_canonicalize_string_full that uses
-   find_typedef_in_hash.  */
+   typedef_hash_table::find_typedef.  */
 
 static const char *
 find_typedef_for_canonicalize (struct type *t, void *data)
 {
-  return find_typedef_in_hash ((const struct type_print_options *) data, t);
+  return typedef_hash_table::find_typedef
+    ((const struct type_print_options *) data, t);
 }
 
 /* Print NAME on STREAM.  If the 'raw' field of FLAGS is not set,
@@ -114,7 +115,7 @@ c_print_type_1 (struct type *type,
   if (show > 0)
     type = check_typedef (type);
 
-  local_name = find_typedef_in_hash (flags, type);
+  local_name = typedef_hash_table::find_typedef (flags, type);
   if (local_name != NULL)
     {
       fputs_filtered (local_name, stream);
@@ -1109,21 +1110,18 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
 				struct print_offset_data *podata)
 {
   struct type_print_options local_flags = *flags;
-  struct type_print_options semi_local_flags = *flags;
-  struct cleanup *local_cleanups = make_cleanup (null_cleanup, NULL);
-
   local_flags.local_typedefs = NULL;
-  semi_local_flags.local_typedefs = NULL;
 
+  std::unique_ptr<typedef_hash_table> hash_holder;
   if (!flags->raw)
     {
       if (flags->local_typedefs)
 	local_flags.local_typedefs
-	  = copy_typedef_hash (flags->local_typedefs);
+	  = new typedef_hash_table (*flags->local_typedefs);
       else
-	local_flags.local_typedefs = create_typedef_hash ();
+	local_flags.local_typedefs = new typedef_hash_table ();
 
-      make_cleanup_free_typedef_hash (local_flags.local_typedefs);
+      hash_holder.reset (local_flags.local_typedefs);
     }
 
   c_type_print_modifier (type, stream, 0, 1);
@@ -1164,18 +1162,25 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
       c_type_print_template_args (&local_flags, type, stream);
 
       /* Add in template parameters when printing derivation info.  */
-      add_template_parameters (local_flags.local_typedefs, type);
+      if (local_flags.local_typedefs != NULL)
+	local_flags.local_typedefs->add_template_parameters (type);
       cp_type_print_derivation_info (stream, type, &local_flags);
 
       /* This holds just the global typedefs and the template
 	 parameters.  */
-      semi_local_flags.local_typedefs
-	= copy_typedef_hash (local_flags.local_typedefs);
-      if (semi_local_flags.local_typedefs)
-	make_cleanup_free_typedef_hash (semi_local_flags.local_typedefs);
+      struct type_print_options semi_local_flags = *flags;
+      semi_local_flags.local_typedefs = NULL;
 
-      /* Now add in the local typedefs.  */
-      recursively_update_typedef_hash (local_flags.local_typedefs, type);
+      std::unique_ptr<typedef_hash_table> semi_holder;
+      if (local_flags.local_typedefs != nullptr)
+	{
+	  semi_local_flags.local_typedefs
+	    = new typedef_hash_table (*local_flags.local_typedefs);
+	  semi_holder.reset (semi_local_flags.local_typedefs);
+
+	  /* Now add in the local typedefs.  */
+	  local_flags.local_typedefs->recursively_update (type);
+	}
 
       fprintf_filtered (stream, "{\n");
 
@@ -1518,8 +1523,6 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
 
       fprintfi_filtered (level, stream, "}");
     }
-
-  do_cleanups (local_cleanups);
 }
 
 /* Print the name of the type (or the ultimate pointer target,
diff --git a/gdb/extension.c b/gdb/extension.c
index 4e3b3e94bb..e5c014667a 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -405,21 +405,16 @@ auto_load_ext_lang_scripts_for_objfile (struct objfile *objfile)
    We don't know in advance which extension language will provide a
    pretty-printer for the type, so all are initialized.  */
 
-struct ext_lang_type_printers *
-start_ext_lang_type_printers (void)
+ext_lang_type_printers::ext_lang_type_printers ()
 {
-  struct ext_lang_type_printers *printers
-    = XCNEW (struct ext_lang_type_printers);
   int i;
   const struct extension_language_defn *extlang;
 
   ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
     {
       if (extlang->ops->start_type_printers != NULL)
-	extlang->ops->start_type_printers (extlang, printers);
+	extlang->ops->start_type_printers (extlang, this);
     }
-
-  return printers;
 }
 
 /* Iteratively try the type pretty-printers specified by PRINTERS
@@ -460,11 +455,7 @@ apply_ext_lang_type_printers (struct ext_lang_type_printers *printers,
   return NULL;
 }
 
-/* Call this after pretty-printing a type to release all memory held
-   by PRINTERS.  */
-
-void
-free_ext_lang_type_printers (struct ext_lang_type_printers *printers)
+ext_lang_type_printers::~ext_lang_type_printers ()
 {
   int i;
   const struct extension_language_defn *extlang;
@@ -472,10 +463,8 @@ free_ext_lang_type_printers (struct ext_lang_type_printers *printers)
   ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
     {
       if (extlang->ops->free_type_printers != NULL)
-	extlang->ops->free_type_printers (extlang, printers);
+	extlang->ops->free_type_printers (extlang, this);
     }
-
-  xfree (printers);
 }
 
 /* Try to pretty-print a value of type TYPE located at VAL's contents
diff --git a/gdb/extension.h b/gdb/extension.h
index 943792db29..191e91c8a5 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -147,6 +147,11 @@ enum ext_lang_bp_stop
 
 struct ext_lang_type_printers
 {
+  ext_lang_type_printers ();
+  ~ext_lang_type_printers ();
+
+  DISABLE_COPY_AND_ASSIGN (ext_lang_type_printers);
+
   /* Type-printers from Python.  */
   void *py_type_printers;
 };
@@ -274,13 +279,9 @@ extern void eval_ext_lang_from_control_command (struct command_line *cmd);
 
 extern void auto_load_ext_lang_scripts_for_objfile (struct objfile *);
 
-extern struct ext_lang_type_printers *start_ext_lang_type_printers (void);
-
 extern char *apply_ext_lang_type_printers (struct ext_lang_type_printers *,
 					   struct type *);
 
-extern void free_ext_lang_type_printers (struct ext_lang_type_printers *);
-
 extern int apply_ext_lang_val_pretty_printer
   (struct type *type,
    LONGEST embedded_offset, CORE_ADDR address,
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index c098a3f426..222fc0a06b 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -65,19 +65,6 @@ static struct type_print_options default_ptype_flags =
 
 
 
-/* A hash table holding typedef_field objects.  This is more
-   complicated than an ordinary hash because it must also track the
-   lifetime of some -- but not all -- of the contained objects.  */
-
-struct typedef_hash_table
-{
-  /* The actual hash table.  */
-  htab_t table;
-
-  /* Storage for typedef_field objects that must be synthesized.  */
-  struct obstack storage;
-};
-
 /* A hash function for a typedef_field.  */
 
 static hashval_t
@@ -100,23 +87,19 @@ eq_typedef_field (const void *a, const void *b)
   return types_equal (tfa->type, tfb->type);
 }
 
-/* Add typedefs from T to the hash table TABLE.  */
+/* See typeprint.h.  */
 
 void
-recursively_update_typedef_hash (struct typedef_hash_table *table,
-				 struct type *t)
+typedef_hash_table::recursively_update (struct type *t)
 {
   int i;
 
-  if (table == NULL)
-    return;
-
   for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
     {
       struct decl_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
       void **slot;
 
-      slot = htab_find_slot (table->table, tdef, INSERT);
+      slot = htab_find_slot (m_table, tdef, INSERT);
       /* Only add a given typedef name once.  Really this shouldn't
 	 happen; but it is safe enough to do the updates breadth-first
 	 and thus use the most specific typedef.  */
@@ -126,19 +109,16 @@ recursively_update_typedef_hash (struct typedef_hash_table *table,
 
   /* Recurse into superclasses.  */
   for (i = 0; i < TYPE_N_BASECLASSES (t); ++i)
-    recursively_update_typedef_hash (table, TYPE_BASECLASS (t, i));
+    recursively_update (TYPE_BASECLASS (t, i));
 }
 
-/* Add template parameters from T to the typedef hash TABLE.  */
+/* See typeprint.h.  */
 
 void
-add_template_parameters (struct typedef_hash_table *table, struct type *t)
+typedef_hash_table::add_template_parameters (struct type *t)
 {
   int i;
 
-  if (table == NULL)
-    return;
-
   for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
     {
       struct decl_field *tf;
@@ -148,61 +128,32 @@ add_template_parameters (struct typedef_hash_table *table, struct type *t)
       if (SYMBOL_CLASS (TYPE_TEMPLATE_ARGUMENT (t, i)) != LOC_TYPEDEF)
 	continue;
 
-      tf = XOBNEW (&table->storage, struct decl_field);
+      tf = XOBNEW (&m_storage, struct decl_field);
       tf->name = SYMBOL_LINKAGE_NAME (TYPE_TEMPLATE_ARGUMENT (t, i));
       tf->type = SYMBOL_TYPE (TYPE_TEMPLATE_ARGUMENT (t, i));
 
-      slot = htab_find_slot (table->table, tf, INSERT);
+      slot = htab_find_slot (m_table, tf, INSERT);
       if (*slot == NULL)
 	*slot = tf;
     }
 }
 
-/* Create a new typedef-lookup hash table.  */
+/* See typeprint.h.  */
 
-struct typedef_hash_table *
-create_typedef_hash (void)
+typedef_hash_table::typedef_hash_table ()
 {
-  struct typedef_hash_table *result;
-
-  result = XNEW (struct typedef_hash_table);
-  result->table = htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
-				     NULL, xcalloc, xfree);
-  obstack_init (&result->storage);
-
-  return result;
+  m_table = htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
+			       NULL, xcalloc, xfree);
 }
 
 /* Free a typedef field table.  */
 
-void
-free_typedef_hash (struct typedef_hash_table *table)
+typedef_hash_table::~typedef_hash_table ()
 {
-  if (table != NULL)
-    {
-      htab_delete (table->table);
-      obstack_free (&table->storage, NULL);
-      xfree (table);
-    }
+  htab_delete (m_table);
 }
 
-/* A cleanup for freeing a typedef_hash_table.  */
-
-static void
-do_free_typedef_hash (void *arg)
-{
-  free_typedef_hash ((struct typedef_hash_table *) arg);
-}
-
-/* Return a new cleanup that frees TABLE.  */
-
-struct cleanup *
-make_cleanup_free_typedef_hash (struct typedef_hash_table *table)
-{
-  return make_cleanup (do_free_typedef_hash, table);
-}
-
-/* Helper function for copy_typedef_hash.  */
+/* Helper function for typedef_hash_table::copy.  */
 
 static int
 copy_typedef_hash_element (void **slot, void *nt)
@@ -217,42 +168,14 @@ copy_typedef_hash_element (void **slot, void *nt)
   return 1;
 }
 
-/* Copy a typedef hash.  */
-
-struct typedef_hash_table *
-copy_typedef_hash (struct typedef_hash_table *table)
-{
-  struct typedef_hash_table *result;
-
-  if (table == NULL)
-    return NULL;
-
-  result = create_typedef_hash ();
-  htab_traverse_noresize (table->table, copy_typedef_hash_element,
-			  result->table);
-  return result;
-}
-
-/* A cleanup to free the global typedef hash.  */
-
-static void
-do_free_global_table (void *arg)
-{
-  struct type_print_options *flags = (struct type_print_options *) arg;
-
-  free_typedef_hash (flags->global_typedefs);
-  free_ext_lang_type_printers (flags->global_printers);
-}
-
-/* Create the global typedef hash.  */
+/* See typeprint.h.  */
 
-static struct cleanup *
-create_global_typedef_table (struct type_print_options *flags)
+typedef_hash_table::typedef_hash_table (const typedef_hash_table &table)
 {
-  gdb_assert (flags->global_typedefs == NULL && flags->global_printers == NULL);
-  flags->global_typedefs = create_typedef_hash ();
-  flags->global_printers = start_ext_lang_type_printers ();
-  return make_cleanup (do_free_global_table, flags);
+  m_table = htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
+			       NULL, xcalloc, xfree);
+  htab_traverse_noresize (table.m_table, copy_typedef_hash_element,
+			  m_table);
 }
 
 /* Look up the type T in the global typedef hash.  If it is found,
@@ -260,9 +183,9 @@ create_global_typedef_table (struct type_print_options *flags)
    type-printers, if any, given by start_script_type_printers and return the
    result.  A NULL return means that the name was not found.  */
 
-static const char *
-find_global_typedef (const struct type_print_options *flags,
-		     struct type *t)
+const char *
+typedef_hash_table::find_global_typedef (const struct type_print_options *flags,
+					 struct type *t)
 {
   char *applied;
   void **slot;
@@ -274,7 +197,7 @@ find_global_typedef (const struct type_print_options *flags,
   tf.name = NULL;
   tf.type = t;
 
-  slot = htab_find_slot (flags->global_typedefs->table, &tf, INSERT);
+  slot = htab_find_slot (flags->global_typedefs->m_table, &tf, INSERT);
   if (*slot != NULL)
     {
       new_tf = (struct decl_field *) *slot;
@@ -283,7 +206,7 @@ find_global_typedef (const struct type_print_options *flags,
 
   /* Put an entry into the hash table now, in case
      apply_ext_lang_type_printers recurses.  */
-  new_tf = XOBNEW (&flags->global_typedefs->storage, struct decl_field);
+  new_tf = XOBNEW (&flags->global_typedefs->m_storage, struct decl_field);
   new_tf->name = NULL;
   new_tf->type = t;
 
@@ -294,7 +217,7 @@ find_global_typedef (const struct type_print_options *flags,
   if (applied != NULL)
     {
       new_tf->name
-	= (const char *) obstack_copy0 (&flags->global_typedefs->storage,
+	= (const char *) obstack_copy0 (&flags->global_typedefs->m_storage,
 					applied, strlen (applied));
       xfree (applied);
     }
@@ -302,13 +225,11 @@ find_global_typedef (const struct type_print_options *flags,
   return new_tf->name;
 }
 
-/* Look up the type T in the typedef hash table in with FLAGS.  If T
-   is in the table, return its short (class-relative) typedef name.
-   Otherwise return NULL.  If the table is NULL, this always returns
-   NULL.  */
+/* See typeprint.h.  */
 
 const char *
-find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
+typedef_hash_table::find_typedef (const struct type_print_options *flags,
+				  struct type *t)
 {
   if (flags->local_typedefs != NULL)
     {
@@ -316,7 +237,7 @@ find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
 
       tf.name = NULL;
       tf.type = t;
-      found = (struct decl_field *) htab_find (flags->local_typedefs->table,
+      found = (struct decl_field *) htab_find (flags->local_typedefs->m_table,
 					       &tf);
 
       if (found != NULL)
@@ -406,7 +327,6 @@ static void
 whatis_exp (const char *exp, int show)
 {
   struct value *val;
-  struct cleanup *old_chain;
   struct type *real_type = NULL;
   struct type *type;
   int full = 0;
@@ -415,8 +335,6 @@ whatis_exp (const char *exp, int show)
   struct value_print_options opts;
   struct type_print_options flags = default_ptype_flags;
 
-  old_chain = make_cleanup (null_cleanup, NULL);
-
   if (exp)
     {
       if (*exp == '/')
@@ -526,8 +444,16 @@ whatis_exp (const char *exp, int show)
 
   printf_filtered ("type = ");
 
+  std::unique_ptr<typedef_hash_table> table_holder;
+  std::unique_ptr<ext_lang_type_printers> printer_holder;
   if (!flags.raw)
-    create_global_typedef_table (&flags);
+    {
+      table_holder.reset (new typedef_hash_table);
+      flags.global_typedefs = table_holder.get ();
+
+      printer_holder.reset (new ext_lang_type_printers);
+      flags.global_printers = printer_holder.get ();
+    }
 
   if (real_type)
     {
@@ -540,8 +466,6 @@ whatis_exp (const char *exp, int show)
 
   LA_PRINT_TYPE (type, "", gdb_stdout, show, 0, &flags);
   printf_filtered ("\n");
-
-  do_cleanups (old_chain);
 }
 
 static void
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index ba9588a118..895eebd50a 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -19,6 +19,8 @@
 #ifndef TYPEPRINT_H
 #define TYPEPRINT_H
 
+#include "gdb_obstack.h"
+
 enum language;
 struct ui_file;
 struct typedef_hash_table;
@@ -57,11 +59,11 @@ struct type_print_options
 
   /* If not NULL, a local typedef hash table used when printing a
      type.  */
-  struct typedef_hash_table *local_typedefs;
+  typedef_hash_table *local_typedefs;
 
   /* If not NULL, a global typedef hash table used when printing a
      type.  */
-  struct typedef_hash_table *global_typedefs;
+  typedef_hash_table *global_typedefs;
 
   /* The list of type printers associated with the global typedef
      table.  This is intentionally opaque.  */
@@ -70,21 +72,51 @@ struct type_print_options
 
 extern const struct type_print_options type_print_raw_options;
 
-void recursively_update_typedef_hash (struct typedef_hash_table *,
-				      struct type *);
+/* A hash table holding typedef_field objects.  This is more
+   complicated than an ordinary hash because it must also track the
+   lifetime of some -- but not all -- of the contained objects.  */
+
+class typedef_hash_table
+{
+public:
+
+  /* Create a new typedef-lookup hash table.  */
+  typedef_hash_table ();
+
+  ~typedef_hash_table ();
+
+  /* Copy a typedef hash.  */
+  typedef_hash_table (const typedef_hash_table &);
 
-void add_template_parameters (struct typedef_hash_table *, struct type *);
+  typedef_hash_table &operator= (const typedef_hash_table &) = delete;
 
-struct typedef_hash_table *create_typedef_hash (void);
+  /* Add typedefs from T to the hash table TABLE.  */
+  void recursively_update (struct type *);
 
-void free_typedef_hash (struct typedef_hash_table *);
+  /* Add template parameters from T to the typedef hash TABLE.  */
+  void add_template_parameters (struct type *t);
 
-struct cleanup *make_cleanup_free_typedef_hash (struct typedef_hash_table *);
+  /* Look up the type T in the typedef hash tables contained in FLAGS.
+     The local table is searched first, then the global table (either
+     table can be NULL, in which case it is skipped).  If T is in a
+     table, return its short (class-relative) typedef name.  Otherwise
+     return NULL.  */
+  static const char *find_typedef (const struct type_print_options *flags,
+				   struct type *t);
 
-struct typedef_hash_table *copy_typedef_hash (struct typedef_hash_table *);
+private:
+
+  static const char *find_global_typedef (const struct type_print_options *flags,
+					  struct type *t);
+
+
+  /* The actual hash table.  */
+  htab_t m_table;
+
+  /* Storage for typedef_field objects that must be synthesized.  */
+  auto_obstack m_storage;
+};
 
-const char *find_typedef_in_hash (const struct type_print_options *,
-				  struct type *);
 
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
Pedro Alves March 27, 2018, 10:33 a.m. | #3
On 03/27/2018 04:10 AM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

> 

> Pedro> At least this comment should be updated -- there's no "PRINTERS"

> Pedro> parameter any longer.

> 

> I just removed this comment, since I couldn't think of a useful comment

> to put before a destructor.

> 

>>> +  /* Copy a typedef hash.  */

>>> +  typedef_hash_table (const typedef_hash_table *);

> 

> Pedro> This method's prototype gave me pause -- is there a reason this

> Pedro> isn't a regular copy ctor?

> 

> I've changed it.  I think this was something I meant to do and then

> forgot to complete.

> 

> Pedro> But FLAGS isn't a hash table, right?  The original comment said:

> Pedro>  /* Look up the type T in the typedef hash table in with FLAGS.

> Pedro>                                                  ^^^^^^^

> Pedro> I wonder whether that was a typo for "within".

> Pedro> Maybe this could say something about local/global too.

> 

> I've rewritten this comment, let me know what you think.


LGTM.

Thanks,
Pedro Alves

Patch

diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 2e9ed1bc28..08cef9008d 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -68,12 +68,13 @@  static void c_type_print_base_1 (struct type *type, struct ui_file *stream,
 
 
 /* A callback function for cp_canonicalize_string_full that uses
-   find_typedef_in_hash.  */
+   typedef_hash_table::find_typedef.  */
 
 static const char *
 find_typedef_for_canonicalize (struct type *t, void *data)
 {
-  return find_typedef_in_hash ((const struct type_print_options *) data, t);
+  return typedef_hash_table::find_typedef
+    ((const struct type_print_options *) data, t);
 }
 
 /* Print NAME on STREAM.  If the 'raw' field of FLAGS is not set,
@@ -114,7 +115,7 @@  c_print_type_1 (struct type *type,
   if (show > 0)
     type = check_typedef (type);
 
-  local_name = find_typedef_in_hash (flags, type);
+  local_name = typedef_hash_table::find_typedef (flags, type);
   if (local_name != NULL)
     {
       fputs_filtered (local_name, stream);
@@ -1109,21 +1110,18 @@  c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
 				struct print_offset_data *podata)
 {
   struct type_print_options local_flags = *flags;
-  struct type_print_options semi_local_flags = *flags;
-  struct cleanup *local_cleanups = make_cleanup (null_cleanup, NULL);
-
   local_flags.local_typedefs = NULL;
-  semi_local_flags.local_typedefs = NULL;
 
+  std::unique_ptr<typedef_hash_table> hash_holder;
   if (!flags->raw)
     {
       if (flags->local_typedefs)
 	local_flags.local_typedefs
-	  = copy_typedef_hash (flags->local_typedefs);
+	  = new typedef_hash_table (flags->local_typedefs);
       else
-	local_flags.local_typedefs = create_typedef_hash ();
+	local_flags.local_typedefs = new typedef_hash_table ();
 
-      make_cleanup_free_typedef_hash (local_flags.local_typedefs);
+      hash_holder.reset (local_flags.local_typedefs);
     }
 
   c_type_print_modifier (type, stream, 0, 1);
@@ -1164,18 +1162,25 @@  c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
       c_type_print_template_args (&local_flags, type, stream);
 
       /* Add in template parameters when printing derivation info.  */
-      add_template_parameters (local_flags.local_typedefs, type);
+      if (local_flags.local_typedefs != NULL)
+	local_flags.local_typedefs->add_template_parameters (type);
       cp_type_print_derivation_info (stream, type, &local_flags);
 
       /* This holds just the global typedefs and the template
 	 parameters.  */
-      semi_local_flags.local_typedefs
-	= copy_typedef_hash (local_flags.local_typedefs);
-      if (semi_local_flags.local_typedefs)
-	make_cleanup_free_typedef_hash (semi_local_flags.local_typedefs);
+      struct type_print_options semi_local_flags = *flags;
+      semi_local_flags.local_typedefs = NULL;
 
-      /* Now add in the local typedefs.  */
-      recursively_update_typedef_hash (local_flags.local_typedefs, type);
+      std::unique_ptr<typedef_hash_table> semi_holder;
+      if (local_flags.local_typedefs != nullptr)
+	{
+	  semi_local_flags.local_typedefs
+	    = new typedef_hash_table (local_flags.local_typedefs);
+	  semi_holder.reset (semi_local_flags.local_typedefs);
+
+	  /* Now add in the local typedefs.  */
+	  local_flags.local_typedefs->recursively_update (type);
+	}
 
       fprintf_filtered (stream, "{\n");
 
@@ -1518,8 +1523,6 @@  c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
 
       fprintfi_filtered (level, stream, "}");
     }
-
-  do_cleanups (local_cleanups);
 }
 
 /* Print the name of the type (or the ultimate pointer target,
diff --git a/gdb/extension.c b/gdb/extension.c
index 67f83b4bcd..59de8fbcd1 100644
--- a/gdb/extension.c
+++ b/gdb/extension.c
@@ -405,21 +405,16 @@  auto_load_ext_lang_scripts_for_objfile (struct objfile *objfile)
    We don't know in advance which extension language will provide a
    pretty-printer for the type, so all are initialized.  */
 
-struct ext_lang_type_printers *
-start_ext_lang_type_printers (void)
+ext_lang_type_printers::ext_lang_type_printers ()
 {
-  struct ext_lang_type_printers *printers
-    = XCNEW (struct ext_lang_type_printers);
   int i;
   const struct extension_language_defn *extlang;
 
   ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
     {
       if (extlang->ops->start_type_printers != NULL)
-	extlang->ops->start_type_printers (extlang, printers);
+	extlang->ops->start_type_printers (extlang, this);
     }
-
-  return printers;
 }
 
 /* Iteratively try the type pretty-printers specified by PRINTERS
@@ -463,8 +458,7 @@  apply_ext_lang_type_printers (struct ext_lang_type_printers *printers,
 /* Call this after pretty-printing a type to release all memory held
    by PRINTERS.  */
 
-void
-free_ext_lang_type_printers (struct ext_lang_type_printers *printers)
+ext_lang_type_printers::~ext_lang_type_printers ()
 {
   int i;
   const struct extension_language_defn *extlang;
@@ -472,10 +466,8 @@  free_ext_lang_type_printers (struct ext_lang_type_printers *printers)
   ALL_ENABLED_EXTENSION_LANGUAGES (i, extlang)
     {
       if (extlang->ops->free_type_printers != NULL)
-	extlang->ops->free_type_printers (extlang, printers);
+	extlang->ops->free_type_printers (extlang, this);
     }
-
-  xfree (printers);
 }
 
 /* Try to pretty-print a value of type TYPE located at VAL's contents
diff --git a/gdb/extension.h b/gdb/extension.h
index 943792db29..191e91c8a5 100644
--- a/gdb/extension.h
+++ b/gdb/extension.h
@@ -147,6 +147,11 @@  enum ext_lang_bp_stop
 
 struct ext_lang_type_printers
 {
+  ext_lang_type_printers ();
+  ~ext_lang_type_printers ();
+
+  DISABLE_COPY_AND_ASSIGN (ext_lang_type_printers);
+
   /* Type-printers from Python.  */
   void *py_type_printers;
 };
@@ -274,13 +279,9 @@  extern void eval_ext_lang_from_control_command (struct command_line *cmd);
 
 extern void auto_load_ext_lang_scripts_for_objfile (struct objfile *);
 
-extern struct ext_lang_type_printers *start_ext_lang_type_printers (void);
-
 extern char *apply_ext_lang_type_printers (struct ext_lang_type_printers *,
 					   struct type *);
 
-extern void free_ext_lang_type_printers (struct ext_lang_type_printers *);
-
 extern int apply_ext_lang_val_pretty_printer
   (struct type *type,
    LONGEST embedded_offset, CORE_ADDR address,
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index c098a3f426..ee4a5652d6 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -65,19 +65,6 @@  static struct type_print_options default_ptype_flags =
 
 
 
-/* A hash table holding typedef_field objects.  This is more
-   complicated than an ordinary hash because it must also track the
-   lifetime of some -- but not all -- of the contained objects.  */
-
-struct typedef_hash_table
-{
-  /* The actual hash table.  */
-  htab_t table;
-
-  /* Storage for typedef_field objects that must be synthesized.  */
-  struct obstack storage;
-};
-
 /* A hash function for a typedef_field.  */
 
 static hashval_t
@@ -100,23 +87,19 @@  eq_typedef_field (const void *a, const void *b)
   return types_equal (tfa->type, tfb->type);
 }
 
-/* Add typedefs from T to the hash table TABLE.  */
+/* See typeprint.h.  */
 
 void
-recursively_update_typedef_hash (struct typedef_hash_table *table,
-				 struct type *t)
+typedef_hash_table::recursively_update (struct type *t)
 {
   int i;
 
-  if (table == NULL)
-    return;
-
   for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
     {
       struct decl_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
       void **slot;
 
-      slot = htab_find_slot (table->table, tdef, INSERT);
+      slot = htab_find_slot (m_table, tdef, INSERT);
       /* Only add a given typedef name once.  Really this shouldn't
 	 happen; but it is safe enough to do the updates breadth-first
 	 and thus use the most specific typedef.  */
@@ -126,19 +109,16 @@  recursively_update_typedef_hash (struct typedef_hash_table *table,
 
   /* Recurse into superclasses.  */
   for (i = 0; i < TYPE_N_BASECLASSES (t); ++i)
-    recursively_update_typedef_hash (table, TYPE_BASECLASS (t, i));
+    recursively_update (TYPE_BASECLASS (t, i));
 }
 
-/* Add template parameters from T to the typedef hash TABLE.  */
+/* See typeprint.h.  */
 
 void
-add_template_parameters (struct typedef_hash_table *table, struct type *t)
+typedef_hash_table::add_template_parameters (struct type *t)
 {
   int i;
 
-  if (table == NULL)
-    return;
-
   for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
     {
       struct decl_field *tf;
@@ -148,61 +128,32 @@  add_template_parameters (struct typedef_hash_table *table, struct type *t)
       if (SYMBOL_CLASS (TYPE_TEMPLATE_ARGUMENT (t, i)) != LOC_TYPEDEF)
 	continue;
 
-      tf = XOBNEW (&table->storage, struct decl_field);
+      tf = XOBNEW (&m_storage, struct decl_field);
       tf->name = SYMBOL_LINKAGE_NAME (TYPE_TEMPLATE_ARGUMENT (t, i));
       tf->type = SYMBOL_TYPE (TYPE_TEMPLATE_ARGUMENT (t, i));
 
-      slot = htab_find_slot (table->table, tf, INSERT);
+      slot = htab_find_slot (m_table, tf, INSERT);
       if (*slot == NULL)
 	*slot = tf;
     }
 }
 
-/* Create a new typedef-lookup hash table.  */
+/* See typeprint.h.  */
 
-struct typedef_hash_table *
-create_typedef_hash (void)
+typedef_hash_table::typedef_hash_table ()
 {
-  struct typedef_hash_table *result;
-
-  result = XNEW (struct typedef_hash_table);
-  result->table = htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
-				     NULL, xcalloc, xfree);
-  obstack_init (&result->storage);
-
-  return result;
+  m_table = htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
+			       NULL, xcalloc, xfree);
 }
 
 /* Free a typedef field table.  */
 
-void
-free_typedef_hash (struct typedef_hash_table *table)
+typedef_hash_table::~typedef_hash_table ()
 {
-  if (table != NULL)
-    {
-      htab_delete (table->table);
-      obstack_free (&table->storage, NULL);
-      xfree (table);
-    }
+  htab_delete (m_table);
 }
 
-/* A cleanup for freeing a typedef_hash_table.  */
-
-static void
-do_free_typedef_hash (void *arg)
-{
-  free_typedef_hash ((struct typedef_hash_table *) arg);
-}
-
-/* Return a new cleanup that frees TABLE.  */
-
-struct cleanup *
-make_cleanup_free_typedef_hash (struct typedef_hash_table *table)
-{
-  return make_cleanup (do_free_typedef_hash, table);
-}
-
-/* Helper function for copy_typedef_hash.  */
+/* Helper function for typedef_hash_table::copy.  */
 
 static int
 copy_typedef_hash_element (void **slot, void *nt)
@@ -217,42 +168,14 @@  copy_typedef_hash_element (void **slot, void *nt)
   return 1;
 }
 
-/* Copy a typedef hash.  */
-
-struct typedef_hash_table *
-copy_typedef_hash (struct typedef_hash_table *table)
-{
-  struct typedef_hash_table *result;
-
-  if (table == NULL)
-    return NULL;
-
-  result = create_typedef_hash ();
-  htab_traverse_noresize (table->table, copy_typedef_hash_element,
-			  result->table);
-  return result;
-}
-
-/* A cleanup to free the global typedef hash.  */
-
-static void
-do_free_global_table (void *arg)
-{
-  struct type_print_options *flags = (struct type_print_options *) arg;
-
-  free_typedef_hash (flags->global_typedefs);
-  free_ext_lang_type_printers (flags->global_printers);
-}
-
-/* Create the global typedef hash.  */
+/* See typeprint.h.  */
 
-static struct cleanup *
-create_global_typedef_table (struct type_print_options *flags)
+typedef_hash_table::typedef_hash_table (const typedef_hash_table *table)
 {
-  gdb_assert (flags->global_typedefs == NULL && flags->global_printers == NULL);
-  flags->global_typedefs = create_typedef_hash ();
-  flags->global_printers = start_ext_lang_type_printers ();
-  return make_cleanup (do_free_global_table, flags);
+  m_table = htab_create_alloc (10, hash_typedef_field, eq_typedef_field,
+			       NULL, xcalloc, xfree);
+  htab_traverse_noresize (table->m_table, copy_typedef_hash_element,
+			  m_table);
 }
 
 /* Look up the type T in the global typedef hash.  If it is found,
@@ -260,9 +183,9 @@  create_global_typedef_table (struct type_print_options *flags)
    type-printers, if any, given by start_script_type_printers and return the
    result.  A NULL return means that the name was not found.  */
 
-static const char *
-find_global_typedef (const struct type_print_options *flags,
-		     struct type *t)
+const char *
+typedef_hash_table::find_global_typedef (const struct type_print_options *flags,
+					 struct type *t)
 {
   char *applied;
   void **slot;
@@ -274,7 +197,7 @@  find_global_typedef (const struct type_print_options *flags,
   tf.name = NULL;
   tf.type = t;
 
-  slot = htab_find_slot (flags->global_typedefs->table, &tf, INSERT);
+  slot = htab_find_slot (flags->global_typedefs->m_table, &tf, INSERT);
   if (*slot != NULL)
     {
       new_tf = (struct decl_field *) *slot;
@@ -283,7 +206,7 @@  find_global_typedef (const struct type_print_options *flags,
 
   /* Put an entry into the hash table now, in case
      apply_ext_lang_type_printers recurses.  */
-  new_tf = XOBNEW (&flags->global_typedefs->storage, struct decl_field);
+  new_tf = XOBNEW (&flags->global_typedefs->m_storage, struct decl_field);
   new_tf->name = NULL;
   new_tf->type = t;
 
@@ -294,7 +217,7 @@  find_global_typedef (const struct type_print_options *flags,
   if (applied != NULL)
     {
       new_tf->name
-	= (const char *) obstack_copy0 (&flags->global_typedefs->storage,
+	= (const char *) obstack_copy0 (&flags->global_typedefs->m_storage,
 					applied, strlen (applied));
       xfree (applied);
     }
@@ -302,13 +225,11 @@  find_global_typedef (const struct type_print_options *flags,
   return new_tf->name;
 }
 
-/* Look up the type T in the typedef hash table in with FLAGS.  If T
-   is in the table, return its short (class-relative) typedef name.
-   Otherwise return NULL.  If the table is NULL, this always returns
-   NULL.  */
+/* See typeprint.h.  */
 
 const char *
-find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
+typedef_hash_table::find_typedef (const struct type_print_options *flags,
+				  struct type *t)
 {
   if (flags->local_typedefs != NULL)
     {
@@ -316,7 +237,7 @@  find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
 
       tf.name = NULL;
       tf.type = t;
-      found = (struct decl_field *) htab_find (flags->local_typedefs->table,
+      found = (struct decl_field *) htab_find (flags->local_typedefs->m_table,
 					       &tf);
 
       if (found != NULL)
@@ -406,7 +327,6 @@  static void
 whatis_exp (const char *exp, int show)
 {
   struct value *val;
-  struct cleanup *old_chain;
   struct type *real_type = NULL;
   struct type *type;
   int full = 0;
@@ -415,8 +335,6 @@  whatis_exp (const char *exp, int show)
   struct value_print_options opts;
   struct type_print_options flags = default_ptype_flags;
 
-  old_chain = make_cleanup (null_cleanup, NULL);
-
   if (exp)
     {
       if (*exp == '/')
@@ -526,8 +444,16 @@  whatis_exp (const char *exp, int show)
 
   printf_filtered ("type = ");
 
+  std::unique_ptr<typedef_hash_table> table_holder;
+  std::unique_ptr<ext_lang_type_printers> printer_holder;
   if (!flags.raw)
-    create_global_typedef_table (&flags);
+    {
+      table_holder.reset (new typedef_hash_table);
+      flags.global_typedefs = table_holder.get ();
+
+      printer_holder.reset (new ext_lang_type_printers);
+      flags.global_printers = printer_holder.get ();
+    }
 
   if (real_type)
     {
@@ -540,8 +466,6 @@  whatis_exp (const char *exp, int show)
 
   LA_PRINT_TYPE (type, "", gdb_stdout, show, 0, &flags);
   printf_filtered ("\n");
-
-  do_cleanups (old_chain);
 }
 
 static void
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index ba9588a118..87b0783fdb 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -19,6 +19,8 @@ 
 #ifndef TYPEPRINT_H
 #define TYPEPRINT_H
 
+#include "gdb_obstack.h"
+
 enum language;
 struct ui_file;
 struct typedef_hash_table;
@@ -57,11 +59,11 @@  struct type_print_options
 
   /* If not NULL, a local typedef hash table used when printing a
      type.  */
-  struct typedef_hash_table *local_typedefs;
+  typedef_hash_table *local_typedefs;
 
   /* If not NULL, a global typedef hash table used when printing a
      type.  */
-  struct typedef_hash_table *global_typedefs;
+  typedef_hash_table *global_typedefs;
 
   /* The list of type printers associated with the global typedef
      table.  This is intentionally opaque.  */
@@ -70,21 +72,50 @@  struct type_print_options
 
 extern const struct type_print_options type_print_raw_options;
 
-void recursively_update_typedef_hash (struct typedef_hash_table *,
-				      struct type *);
+/* A hash table holding typedef_field objects.  This is more
+   complicated than an ordinary hash because it must also track the
+   lifetime of some -- but not all -- of the contained objects.  */
+
+class typedef_hash_table
+{
+public:
+
+  /* Create a new typedef-lookup hash table.  */
+  typedef_hash_table ();
+
+  ~typedef_hash_table ();
+
+  /* Copy a typedef hash.  */
+  typedef_hash_table (const typedef_hash_table *);
 
-void add_template_parameters (struct typedef_hash_table *, struct type *);
+  typedef_hash_table &operator= (const typedef_hash_table &) = delete;
 
-struct typedef_hash_table *create_typedef_hash (void);
+  /* Add typedefs from T to the hash table TABLE.  */
+  void recursively_update (struct type *);
 
-void free_typedef_hash (struct typedef_hash_table *);
+  /* Add template parameters from T to the typedef hash TABLE.  */
+  void add_template_parameters (struct type *t);
 
-struct cleanup *make_cleanup_free_typedef_hash (struct typedef_hash_table *);
+  /* Look up the type T in the typedef hash table FLAGS.  If T
+     is in the table, return its short (class-relative) typedef name.
+     Otherwise return NULL.  If the table is NULL, this always returns
+     NULL.  */
+  static const char *find_typedef (const struct type_print_options *flags,
+				   struct type *t);
 
-struct typedef_hash_table *copy_typedef_hash (struct typedef_hash_table *);
+private:
+
+  static const char *find_global_typedef (const struct type_print_options *flags,
+					  struct type *t);
+
+
+  /* The actual hash table.  */
+  htab_t m_table;
+
+  /* Storage for typedef_field objects that must be synthesized.  */
+  auto_obstack m_storage;
+};
 
-const char *find_typedef_in_hash (const struct type_print_options *,
-				  struct type *);
 
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);