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 *);
 
