public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 8/9] class-local typedef substitutions
@ 2012-09-07 18:51 Tom Tromey
  2012-09-08  8:00 ` Eli Zaretskii
  2012-09-21 19:32 ` Tom Tromey
  0 siblings, 2 replies; 9+ messages in thread
From: Tom Tromey @ 2012-09-07 18:51 UTC (permalink / raw)
  To: gdb-patches

This patch implements class-local typedef substitutions for the C++
type printer.  That is, when printing a type, gdb will now look at
template argument names (if any) and typedefs defined in the class
body, and substitute those names when printing type names.

This generally makes the output more readable.  The '/r' flag to ptype
can be used to disable this transform for those cases where one wants
to see the raw type.

Unfortunately DWARF does not tell us whether a type originally came
from a template argument or not.  So in a case like this:

    template<typename T> class X {
      int a;
      T b;
    };

... if you display the type X<int>, both fields will appear to be of
type T.

I'm considering filing a GCC and/or DWARF feature request to fix this;
but meanwhile I think this isn't very serious, and the substitutions
are usually preferable.

Built and regtested on x86-64 F16.

	* NEWS: Update.
	* c-typeprint.c (find_typedef_for_canonicalize,
	print_name_maybe_canonical): New functions.
	(c_print_type): Look up type name.
	(cp_type_print_derivation_info): Add flags argument.  Use
	print_name_maybe_canonical.
	(cp_type_print_method_args): Add wrapping.
	(c_type_print_varspec_prefix): Use print_name_maybe_canonical.
	(c_type_print_template_args): New function.
	(c_type_print_base): Change wrapping.
	<TYPE_CODE_STRUCT>: Possibly create a typedef hash, and do
	type name lookups.
	* gdbtypes.c (types_equal): No longer static.
	* gdbtypes.h (types_equal): Declare.
	* typeprint.c (type_print_raw_options, default_ptype_flags):
	Update.
	(struct typedef_hash_table): New.
	(hash_typedef_field, eq_typedef_field,
	recursively_update_typedef_hash, add_template_parameters,
	create_typedef_hash, free_typedef_hash, do_free_typedef_hash,
	make_cleanup_free_typedef_hash, copy_typedef_hash_element,
	copy_typedef_hash, find_typedef_in_hash): New functions.
	* typeprint.h (struct type_print_options) <local_typedefs>:
	New field.
	(recursively_update_typedef_hash, add_template_parameters,
	create_typedef_hash, free_typedef_hash,
	make_cleanup_free_typedef_hash, copy_typedef_hash,
	find_typedef_in_hash): Declare.

	* gdb.cp/ptype-flags.cc: New file.
	* gdb.cp/ptype-flags.exp: New file.
	* gdb.cp/templates.exp: Use ptype/r.
	(test_ptype_of_templates, test_template_typedef): Likewise.
	* lib/cp-support.exp (cp_test_ptype_class): Add in_ptype_arg
	argument.  Handle template names and template parameters.
---
 gdb/NEWS                             |   15 +
 gdb/c-typeprint.c                    |  617 +++++++++++++++++++++-------------
 gdb/gdbtypes.c                       |    2 +-
 gdb/gdbtypes.h                       |    2 +
 gdb/testsuite/gdb.cp/ptype-flags.cc  |   47 +++
 gdb/testsuite/gdb.cp/ptype-flags.exp |   85 +++++
 gdb/testsuite/gdb.cp/templates.exp   |   46 ++--
 gdb/testsuite/lib/cp-support.exp     |   17 +-
 gdb/typeprint.c                      |  196 +++++++++++-
 gdb/typeprint.h                      |   21 ++
 10 files changed, 785 insertions(+), 263 deletions(-)
 create mode 100644 gdb/testsuite/gdb.cp/ptype-flags.cc
 create mode 100644 gdb/testsuite/gdb.cp/ptype-flags.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index dba6937..e625e25 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 7.5
 
+* The 'ptype' and 'whatis' commands now accept an argument to control
+  type formatting.
+
 * Python scripting
 
   ** Vectors can be created with gdb.Type.vector.
@@ -39,6 +42,18 @@ pi [command]
 py [command]
   "py" is a new alias for "python".
 
+* New options
+
+set print type methods (on|off)
+show print type methods
+  Control whether method declarations are displayed by "ptype".
+  The default is to show them.
+
+set print type typedefs (on|off)
+show print type typedefs
+  Control whether typedef definitions are displayed by "ptype".
+  The default is to show them.
+
 * MI changes
 
   ** Command parameter changes are now notified using new async record
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 371f002..4fe5059 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -34,6 +34,7 @@
 #include "jv-lang.h"
 #include "gdb_string.h"
 #include <errno.h>
+#include "cp-support.h"
 
 static void c_type_print_varspec_prefix (struct type *,
 					 struct ui_file *,
@@ -45,6 +46,37 @@ static void c_type_print_modifier (struct type *,
 				   struct ui_file *,
 				   int, int);
 \f
+
+/* A callback function for cp_canonicalize_string_full that uses
+   find_typedef_in_hash.  */
+
+static const char *
+find_typedef_for_canonicalize (struct type *t, void *data)
+{
+  return find_typedef_in_hash (data, t);
+}
+
+/* Print NAME on STREAM.  If the 'local_typedefs' field of FLAGS is
+   not NULL, canonicalize NAME using the local typedefs first.  */
+
+static void
+print_name_maybe_canonical (const char *name,
+			    const struct type_print_options *flags,
+			    struct ui_file *stream)
+{
+  char *s = NULL;
+
+  if (flags->local_typedefs != NULL)
+    s = cp_canonicalize_string_full (name,
+				     find_typedef_for_canonicalize,
+				     (void *) flags);
+
+  fputs_filtered (s ? s : name, stream);
+  xfree (s);
+}
+
+\f
+
 /* LEVEL is the depth to indent lines by.  */
 
 void
@@ -57,26 +89,37 @@ c_print_type (struct type *type,
   enum type_code code;
   int demangled_args;
   int need_post_space;
+  const char *local_name;
 
   if (show > 0)
     CHECK_TYPEDEF (type);
 
-  c_type_print_base (type, stream, show, level, flags);
-  code = TYPE_CODE (type);
-  if ((varstring != NULL && *varstring != '\0')
-  /* Need a space if going to print stars or brackets;
-     but not if we will print just a type name.  */
-      || ((show > 0 || TYPE_NAME (type) == 0)
-	  && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
-	      || code == TYPE_CODE_METHOD
-	      || code == TYPE_CODE_ARRAY
-	      || code == TYPE_CODE_MEMBERPTR
-	      || code == TYPE_CODE_METHODPTR
-	      || code == TYPE_CODE_REF)))
-    fputs_filtered (" ", stream);
-  need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
-  c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
-			       flags);
+  local_name = find_typedef_in_hash (flags, type);
+  if (local_name != NULL)
+    {
+      fputs_filtered (local_name, stream);
+      if (varstring != NULL && *varstring != '\0')
+	fputs_filtered (" ", stream);
+    }
+  else
+    {
+      c_type_print_base (type, stream, show, level, flags);
+      code = TYPE_CODE (type);
+      if ((varstring != NULL && *varstring != '\0')
+	  /* Need a space if going to print stars or brackets;
+	     but not if we will print just a type name.  */
+	  || ((show > 0 || TYPE_NAME (type) == 0)
+	      && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+		  || code == TYPE_CODE_METHOD
+		  || code == TYPE_CODE_ARRAY
+		  || code == TYPE_CODE_MEMBERPTR
+		  || code == TYPE_CODE_METHODPTR
+		  || code == TYPE_CODE_REF)))
+	fputs_filtered (" ", stream);
+      need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
+      c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
+				   flags);
+    }
 
   if (varstring != NULL)
     {
@@ -84,10 +127,13 @@ c_print_type (struct type *type,
 
       /* For demangled function names, we have the arglist as part of
          the name, so don't print an additional pair of ()'s.  */
-
-      demangled_args = strchr (varstring, '(') != NULL;
-      c_type_print_varspec_suffix (type, stream, show,
-				   0, demangled_args, flags);
+      if (local_name == NULL)
+	{
+	  demangled_args = strchr (varstring, '(') != NULL;
+	  c_type_print_varspec_suffix (type, stream, show,
+				       0, demangled_args,
+				       flags);
+	}
     }
 }
 
@@ -138,13 +184,15 @@ c_print_typedef (struct type *type,
 
 static void
 cp_type_print_derivation_info (struct ui_file *stream,
-			       struct type *type)
+			       struct type *type,
+			       const struct type_print_options *flags)
 {
   const char *name;
   int i;
 
   for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
     {
+      wrap_here ("        ");
       fputs_filtered (i == 0 ? ": " : ", ", stream);
       fprintf_filtered (stream, "%s%s ",
 			BASETYPE_VIA_PUBLIC (type, i)
@@ -152,7 +200,10 @@ cp_type_print_derivation_info (struct ui_file *stream,
 				      ? "protected" : "private"),
 			BASETYPE_VIA_VIRTUAL (type, i) ? " virtual" : "");
       name = type_name_no_tag (TYPE_BASECLASS (type, i));
-      fprintf_filtered (stream, "%s", name ? name : "(null)");
+      if (name)
+	print_name_maybe_canonical (name, flags, stream);
+      else
+	fprintf_filtered (stream, "(null)");
     }
   if (i > 0)
     {
@@ -190,7 +241,10 @@ cp_type_print_method_args (struct type *mtype, const char *prefix,
 	  if (i == nargs && varargs)
 	    fprintf_filtered (stream, ", ...");
 	  else if (i < nargs)
-	    fprintf_filtered (stream, ", ");
+	    {
+	      fprintf_filtered (stream, ", ");
+	      wrap_here ("        ");
+	    }
 	}
     }
   else if (varargs)
@@ -262,7 +316,7 @@ c_type_print_varspec_prefix (struct type *type,
 				   stream, show, 0, 0, flags);
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
-	fputs_filtered (name, stream);
+	print_name_maybe_canonical (name, flags, stream);
       else
 	c_type_print_base (TYPE_DOMAIN_TYPE (type),
 			   stream, -1, passed_a_ptr, flags);
@@ -275,7 +329,7 @@ c_type_print_varspec_prefix (struct type *type,
       fprintf_filtered (stream, "(");
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
-	fputs_filtered (name, stream);
+	print_name_maybe_canonical (name, flags, stream);
       else
 	c_type_print_base (TYPE_DOMAIN_TYPE (type),
 			   stream, -1, passed_a_ptr, flags);
@@ -694,6 +748,56 @@ c_type_print_varspec_suffix (struct type *type,
     }
 }
 
+/* A helper for c_type_print_base that displays template
+   parameters and their bindings, if needed.
+
+   TABLE is the local bindings table to use.  If NULL, no printing is
+   done.  Note that, at this point, TABLE won't have any useful
+   information in it -- but it is also used as a flag to
+   print_name_maybe_canonical to activate searching the global typedef
+   table.
+
+   TYPE is the type whose template arguments are being displayed.
+
+   STREAM is the stream on which to print.  */
+
+static void
+c_type_print_template_args (const struct type_print_options *flags,
+			    struct type *type, struct ui_file *stream)
+{
+  int first = 1, i;
+
+  if (flags->raw)
+    return;
+
+  for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i)
+    {
+      struct symbol *sym = TYPE_TEMPLATE_ARGUMENT (type, i);
+
+      if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+	continue;
+
+      if (first)
+	{
+	  wrap_here ("    ");
+	  fprintf_filtered (stream, _("[with %s = "),
+			    SYMBOL_LINKAGE_NAME (sym));
+	  first = 0;
+	}
+      else
+	{
+	  fputs_filtered (", ", stream);
+	  wrap_here ("         ");
+	  fprintf_filtered (stream, "%s = ", SYMBOL_LINKAGE_NAME (sym));
+	}
+
+      c_print_type (SYMBOL_TYPE (sym), "", stream, -1, 0, flags);
+    }
+
+  if (!first)
+    fputs_filtered (_("] "), stream);
+}
+
 /* Print the name of the type (or the ultimate pointer target,
    function value or array element), or the description of a structure
    or union.
@@ -728,7 +832,6 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 
   QUIT;
 
-  wrap_here ("    ");
   if (type == NULL)
     {
       fputs_filtered (_("<type unknown>"), stream);
@@ -746,7 +849,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       && TYPE_NAME (type) != NULL)
     {
       c_type_print_modifier (type, stream, 0, 1);
-      fputs_filtered (TYPE_NAME (type), stream);
+      print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
       return;
     }
 
@@ -775,193 +878,234 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
-      c_type_print_modifier (type, stream, 0, 1);
-      if (TYPE_CODE (type) == TYPE_CODE_UNION)
-	fprintf_filtered (stream, "union ");
-      else if (TYPE_DECLARED_CLASS (type))
-	fprintf_filtered (stream, "class ");
-      else
-	fprintf_filtered (stream, "struct ");
-
-      /* Print the tag if it exists.  The HP aCC compiler emits a
-         spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed
-         enum}" tag for unnamed struct/union/enum's, which we don't
-         want to print.  */
-      if (TYPE_TAG_NAME (type) != NULL
-	  && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
-	{
-	  fputs_filtered (TYPE_TAG_NAME (type), stream);
-	  if (show > 0)
-	    fputs_filtered (" ", stream);
-	}
-      wrap_here ("    ");
-      if (show < 0)
-	{
-	  /* If we just printed a tag name, no need to print anything
-	     else.  */
-	  if (TYPE_TAG_NAME (type) == NULL)
-	    fprintf_filtered (stream, "{...}");
-	}
-      else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
-	{
-	  struct type *basetype;
-	  int vptr_fieldno;
-
-	  cp_type_print_derivation_info (stream, type);
-
-	  fprintf_filtered (stream, "{\n");
-	  if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0
-	      && TYPE_TYPEDEF_FIELD_COUNT (type) == 0)
-	    {
-	      if (TYPE_STUB (type))
-		fprintfi_filtered (level + 4, stream,
-				   _("<incomplete type>\n"));
-	      else
-		fprintfi_filtered (level + 4, stream,
-				   _("<no data fields>\n"));
-	    }
-
-	  /* Start off with no specific section type, so we can print
-	     one for the first field we find, and use that section type
-	     thereafter until we find another type.  */
-
-	  section_type = s_none;
-
-	  /* For a class, if all members are private, there's no need
-	     for a "private:" label; similarly, for a struct or union
-	     masquerading as a class, if all members are public, there's
-	     no need for a "public:" label.  */
-
-	  if (TYPE_DECLARED_CLASS (type))
-	    {
-	      QUIT;
-	      len = TYPE_NFIELDS (type);
-	      for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-		if (!TYPE_FIELD_PRIVATE (type, i))
-		  {
-		    need_access_label = 1;
-		    break;
-		  }
-	      QUIT;
-	      if (!need_access_label)
-		{
-		  len2 = TYPE_NFN_FIELDS (type);
-		  for (j = 0; j < len2; j++)
+      {
+	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;
+
+	if (!flags->raw)
+	  {
+	    if (flags->local_typedefs)
+	      local_flags.local_typedefs
+		= copy_typedef_hash (flags->local_typedefs);
+	    else
+	      local_flags.local_typedefs = create_typedef_hash ();
+
+	    make_cleanup_free_typedef_hash (local_flags.local_typedefs);
+	  }
+
+	c_type_print_modifier (type, stream, 0, 1);
+	if (TYPE_CODE (type) == TYPE_CODE_UNION)
+	  fprintf_filtered (stream, "union ");
+	else if (TYPE_DECLARED_CLASS (type))
+	  fprintf_filtered (stream, "class ");
+	else
+	  fprintf_filtered (stream, "struct ");
+
+	/* Print the tag if it exists.  The HP aCC compiler emits a
+	   spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed
+	   enum}" tag for unnamed struct/union/enum's, which we don't
+	   want to print.  */
+	if (TYPE_TAG_NAME (type) != NULL
+	    && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
+	  {
+	    /* Passing '&local_flags' here is somewhat obscure.  We
+	       only want to do name canonicalization for the class tag
+	       using the global and enclosing typedefs (there aren't
+	       actually any local ones yet), and if the user hasn't
+	       requested raw printing.  Passing the local flags
+	       achieves this, due to how they are initialized.  */
+	    print_name_maybe_canonical (TYPE_TAG_NAME (type), &local_flags,
+					stream);
+	    if (show > 0)
+	      fputs_filtered (" ", stream);
+	  }
+
+	if (show < 0)
+	  {
+	    /* If we just printed a tag name, no need to print anything
+	       else.  */
+	    if (TYPE_TAG_NAME (type) == NULL)
+	      fprintf_filtered (stream, "{...}");
+	  }
+	else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
+	  {
+	    struct type *basetype;
+	    int vptr_fieldno;
+
+	    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);
+	    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);
+
+	    /* Now add in the local typedefs.  */
+	    recursively_update_typedef_hash (local_flags.local_typedefs, type);
+
+	    fprintf_filtered (stream, "{\n");
+	    if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0
+		&& TYPE_TYPEDEF_FIELD_COUNT (type) == 0)
+	      {
+		if (TYPE_STUB (type))
+		  fprintfi_filtered (level + 4, stream,
+				     _("<incomplete type>\n"));
+		else
+		  fprintfi_filtered (level + 4, stream,
+				     _("<no data fields>\n"));
+	      }
+
+	    /* Start off with no specific section type, so we can print
+	       one for the first field we find, and use that section type
+	       thereafter until we find another type.  */
+
+	    section_type = s_none;
+
+	    /* For a class, if all members are private, there's no need
+	       for a "private:" label; similarly, for a struct or union
+	       masquerading as a class, if all members are public, there's
+	       no need for a "public:" label.  */
+
+	    if (TYPE_DECLARED_CLASS (type))
+	      {
+		QUIT;
+		len = TYPE_NFIELDS (type);
+		for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+		  if (!TYPE_FIELD_PRIVATE (type, i))
 		    {
-		      len = TYPE_FN_FIELDLIST_LENGTH (type, j);
-		      for (i = 0; i < len; i++)
-			if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
-									j), i))
-			  {
-			    need_access_label = 1;
-			    break;
-			  }
-		      if (need_access_label)
-			break;
+		      need_access_label = 1;
+		      break;
 		    }
-		}
-	    }
-	  else
-	    {
-	      QUIT;
-	      len = TYPE_NFIELDS (type);
-	      for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-		if (TYPE_FIELD_PRIVATE (type, i)
-		    || TYPE_FIELD_PROTECTED (type, i))
+		QUIT;
+		if (!need_access_label)
 		  {
-		    need_access_label = 1;
-		    break;
+		    len2 = TYPE_NFN_FIELDS (type);
+		    for (j = 0; j < len2; j++)
+		      {
+			len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+			for (i = 0; i < len; i++)
+			  if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
+									  j), i))
+			    {
+			      need_access_label = 1;
+			      break;
+			    }
+			if (need_access_label)
+			  break;
+		      }
 		  }
-	      QUIT;
-	      if (!need_access_label)
-		{
-		  len2 = TYPE_NFN_FIELDS (type);
-		  for (j = 0; j < len2; j++)
+	      }
+	    else
+	      {
+		QUIT;
+		len = TYPE_NFIELDS (type);
+		for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+		  if (TYPE_FIELD_PRIVATE (type, i)
+		      || TYPE_FIELD_PROTECTED (type, i))
 		    {
-		      QUIT;
-		      len = TYPE_FN_FIELDLIST_LENGTH (type, j);
-		      for (i = 0; i < len; i++)
-			if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type,
-									 j), i)
-			    || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
-									  j),
-						      i))
-			  {
-			    need_access_label = 1;
-			    break;
-			  }
-		      if (need_access_label)
-			break;
+		      need_access_label = 1;
+		      break;
 		    }
-		}
-	    }
+		QUIT;
+		if (!need_access_label)
+		  {
+		    len2 = TYPE_NFN_FIELDS (type);
+		    for (j = 0; j < len2; j++)
+		      {
+			QUIT;
+			len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+			for (i = 0; i < len; i++)
+			  if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type,
+									   j), i)
+			      || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
+									    j),
+							i))
+			    {
+			      need_access_label = 1;
+			      break;
+			    }
+			if (need_access_label)
+			  break;
+		      }
+		  }
+	      }
 
-	  /* If there is a base class for this type,
-	     do not print the field that it occupies.  */
+	    /* If there is a base class for this type,
+	       do not print the field that it occupies.  */
 
-	  len = TYPE_NFIELDS (type);
-	  vptr_fieldno = get_vptr_fieldno (type, &basetype);
-	  for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-	    {
-	      QUIT;
+	    len = TYPE_NFIELDS (type);
+	    vptr_fieldno = get_vptr_fieldno (type, &basetype);
+	    for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+	      {
+		QUIT;
 
-	      /* If we have a virtual table pointer, omit it.  Even if
-		 virtual table pointers are not specifically marked in
-		 the debug info, they should be artificial.  */
-	      if ((i == vptr_fieldno && type == basetype)
-		  || TYPE_FIELD_ARTIFICIAL (type, i))
-		continue;
+		/* If we have a virtual table pointer, omit it.  Even if
+		   virtual table pointers are not specifically marked in
+		   the debug info, they should be artificial.  */
+		if ((i == vptr_fieldno && type == basetype)
+		    || TYPE_FIELD_ARTIFICIAL (type, i))
+		  continue;
 
-	      if (need_access_label)
-		{
-		  if (TYPE_FIELD_PROTECTED (type, i))
-		    {
-		      if (section_type != s_protected)
-			{
-			  section_type = s_protected;
-			  fprintfi_filtered (level + 2, stream,
-					     "protected:\n");
-			}
-		    }
-		  else if (TYPE_FIELD_PRIVATE (type, i))
-		    {
-		      if (section_type != s_private)
-			{
-			  section_type = s_private;
-			  fprintfi_filtered (level + 2, stream,
-					     "private:\n");
-			}
-		    }
-		  else
-		    {
-		      if (section_type != s_public)
-			{
-			  section_type = s_public;
-			  fprintfi_filtered (level + 2, stream,
-					     "public:\n");
-			}
-		    }
-		}
+		if (need_access_label)
+		  {
+		    if (TYPE_FIELD_PROTECTED (type, i))
+		      {
+			if (section_type != s_protected)
+			  {
+			    section_type = s_protected;
+			    fprintfi_filtered (level + 2, stream,
+					       "protected:\n");
+			  }
+		      }
+		    else if (TYPE_FIELD_PRIVATE (type, i))
+		      {
+			if (section_type != s_private)
+			  {
+			    section_type = s_private;
+			    fprintfi_filtered (level + 2, stream,
+					       "private:\n");
+			  }
+		      }
+		    else
+		      {
+			if (section_type != s_public)
+			  {
+			    section_type = s_public;
+			    fprintfi_filtered (level + 2, stream,
+					       "public:\n");
+			  }
+		      }
+		  }
 
-	      print_spaces_filtered (level + 4, stream);
-	      if (field_is_static (&TYPE_FIELD (type, i)))
-		fprintf_filtered (stream, "static ");
-	      c_print_type (TYPE_FIELD_TYPE (type, i),
-			    TYPE_FIELD_NAME (type, i),
-			    stream, show - 1, level + 4, flags);
-	      if (!field_is_static (&TYPE_FIELD (type, i))
-		  && TYPE_FIELD_PACKED (type, i))
-		{
-		  /* It is a bitfield.  This code does not attempt
-		     to look at the bitpos and reconstruct filler,
-		     unnamed fields.  This would lead to misleading
-		     results if the compiler does not put out fields
-		     for such things (I don't know what it does).  */
-		  fprintf_filtered (stream, " : %d",
-				    TYPE_FIELD_BITSIZE (type, i));
-		}
-	      fprintf_filtered (stream, ";\n");
-	    }
+		print_spaces_filtered (level + 4, stream);
+		if (field_is_static (&TYPE_FIELD (type, i)))
+		  fprintf_filtered (stream, "static ");
+		c_print_type (TYPE_FIELD_TYPE (type, i),
+			      TYPE_FIELD_NAME (type, i),
+			      stream, show - 1, level + 4,
+			      &local_flags);
+		if (!field_is_static (&TYPE_FIELD (type, i))
+		    && TYPE_FIELD_PACKED (type, i))
+		  {
+		    /* It is a bitfield.  This code does not attempt
+		       to look at the bitpos and reconstruct filler,
+		       unnamed fields.  This would lead to misleading
+		       results if the compiler does not put out fields
+		       for such things (I don't know what it does).  */
+		    fprintf_filtered (stream, " : %d",
+				      TYPE_FIELD_BITSIZE (type, i));
+		  }
+		fprintf_filtered (stream, ";\n");
+	      }
 
 	  /* If there are both fields and methods, put a blank line
 	     between them.  Make sure to count only method that we
@@ -1059,7 +1203,8 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 			   && !is_type_conversion_operator (type, i, j))
 		    {
 		      c_print_type (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
-				    "", stream, -1, 0, flags);
+				    "", stream, -1, 0,
+				    &local_flags);
 		      fputs_filtered (" ", stream);
 		    }
 		  if (TYPE_FN_FIELD_STUB (f, j))
@@ -1080,10 +1225,10 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 		  if (demangled_name == NULL)
 		    {
 		      /* In some cases (for instance with the HP
-		         demangling), if a function has more than 10
-		         arguments, the demangling will fail.
-		         Let's try to reconstruct the function
-		         signature from the symbol information.  */
+			 demangling), if a function has more than 10
+			 arguments, the demangling will fail.
+			 Let's try to reconstruct the function
+			 signature from the symbol information.  */
 		      if (!TYPE_FN_FIELD_STUB (f, j))
 			{
 			  int staticp = TYPE_FN_FIELD_STATIC_P (f, j);
@@ -1093,7 +1238,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 						     "",
 						     method_name,
 						     staticp,
-						     stream, flags);
+						     stream, &local_flags);
 			}
 		      else
 			fprintf_filtered (stream,
@@ -1140,30 +1285,40 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 	      if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0)
 		fprintf_filtered (stream, "\n");
 
-	      for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
-		{
-		  struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i);
+		for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
+		  {
+		    struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i);
+		    struct typedef_hash_table *table2;
+
+		    /* Dereference the typedef declaration itself.  */
+		    gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
+		    target = TYPE_TARGET_TYPE (target);
+
+		    print_spaces_filtered (level + 4, stream);
+		    fprintf_filtered (stream, "typedef ");
+
+		    /* We want to print typedefs with substitutions
+		       from the template parameters or globally-known
+		       typedefs but not local typedefs.  */
+		    c_print_type (target,
+				  TYPE_TYPEDEF_FIELD_NAME (type, i),
+				  stream, show - 1, level + 4,
+				  &semi_local_flags);
+		    fprintf_filtered (stream, ";\n");
+		  }
+	      }
 
-		  /* Dereference the typedef declaration itself.  */
-		  gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
-		  target = TYPE_TARGET_TYPE (target);
+	    fprintfi_filtered (level, stream, "}");
 
-		  print_spaces_filtered (level + 4, stream);
-		  fprintf_filtered (stream, "typedef ");
-		  c_print_type (target, TYPE_TYPEDEF_FIELD_NAME (type, i),
-				stream, show - 1, level + 4, flags);
-		  fprintf_filtered (stream, ";\n");
-		}
-	    }
-
-	  fprintfi_filtered (level, stream, "}");
+	    if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
+	      fprintfi_filtered (level,
+				 stream, _(" (Local at %s:%d)\n"),
+				 TYPE_LOCALTYPE_FILE (type),
+				 TYPE_LOCALTYPE_LINE (type));
+	  }
 
-	  if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
-	    fprintfi_filtered (level,
-			       stream, _(" (Local at %s:%d)\n"),
-			       TYPE_LOCALTYPE_FILE (type),
-			       TYPE_LOCALTYPE_LINE (type));
-	}
+	do_cleanups (local_cleanups);
+      }
       break;
 
     case TYPE_CODE_ENUM:
@@ -1177,7 +1332,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       if (TYPE_TAG_NAME (type) != NULL
 	  && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
 	{
-	  fputs_filtered (TYPE_TAG_NAME (type), stream);
+	  print_name_maybe_canonical (TYPE_TAG_NAME (type), flags, stream);
 	  if (show > 0)
 	    fputs_filtered (" ", stream);
 	}
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 21d9043..eff67d9 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -2406,7 +2406,7 @@ integer_types_same_name_p (const char *first, const char *second)
 /* Compares type A to type B returns 1 if the represent the same type
    0 otherwise.  */
 
-static int
+int
 types_equal (struct type *a, struct type *b)
 {
   /* Identical type pointers.  */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 991026b..f16c43d 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1657,4 +1657,6 @@ extern struct type *copy_type_recursive (struct objfile *objfile,
 
 extern struct type *copy_type (const struct type *type);
 
+extern int types_equal (struct type *, struct type *);
+
 #endif /* GDBTYPES_H */
diff --git a/gdb/testsuite/gdb.cp/ptype-flags.cc b/gdb/testsuite/gdb.cp/ptype-flags.cc
new file mode 100644
index 0000000..3077f73
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ptype-flags.cc
@@ -0,0 +1,47 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   */
+
+template<typename S>
+class Simple
+{
+  S val;
+};
+
+template<typename T>
+class Base
+{
+};
+
+template<typename T>
+class Holder : public Base<T>
+{
+public:
+  Simple<T> t;
+  Simple<T*> tstar;
+
+  typedef Simple< Simple<T> > Z;
+
+  Z z;
+
+  double method(void) { return 23.0; }
+};
+
+Holder<int> value;
+
+int main()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/ptype-flags.exp b/gdb/testsuite/gdb.cp/ptype-flags.exp
new file mode 100644
index 0000000..a992b9c
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ptype-flags.exp
@@ -0,0 +1,85 @@
+# Copyright 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set nl		"\[\r\n\]+"
+
+if { [skip_cplus_tests] } { continue }
+
+load_lib "cp-support.exp"
+
+standard_testfile .cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    return
+}
+
+gdb_test_no_output "set language c++" ""
+gdb_test_no_output "set width 0" ""
+
+proc do_check {name {flags ""} {show_typedefs 1} {show_methods 1} {raw 0}} {
+    set contents {
+	{ base "public Base<T>" }
+	{ field public "Simple<T> t;" }
+	{ field public "Simple<T*> tstar;" }
+    }
+
+    if {$raw} {
+	lappend contents { field public "Holder<int>::Z z;" }
+    } else {
+	lappend contents { field public "Z z;" }
+    }
+
+    if {$show_typedefs} {
+	lappend contents { typedef public "Simple<Simple<T> > Z;" }
+    }
+
+    if {$show_methods} {
+	lappend contents { method public "double method();" }
+    }
+
+    if {$raw} {
+	regsub -all -- "T" $contents "int" contents
+    }
+
+    cp_test_ptype_class value $name "class" "Holder<int>" $contents \
+	"" {} $flags
+}
+
+do_check "basic test"
+do_check "no methods" "/m" 1 0
+do_check "no typedefs" "/t" 0 1
+do_check "no methods or typedefs" "/mt" 0 0
+
+do_check "raw" "/r" 1 1 1
+do_check "raw no methods" "/rm" 1 0 1
+do_check "raw no typedefs" "/rt" 0 1 1
+do_check "raw no methods or typedefs" "/rmt" 0 0 1
+
+gdb_test_no_output "set print type methods off"
+do_check "basic test, default methods off" "" 1 0
+do_check "methods, default methods off" "/M" 1 1
+do_check "no typedefs, default methods off" "/t" 0 0
+do_check "methods, no typedefs, default methods off" "/Mt" 0 1
+
+gdb_test_no_output "set print type typedefs off"
+do_check "basic test, default methods+typedefs off" "" 0 0
+do_check "methods, default methods+typedefs off" "/M" 0 1
+do_check "typedefs, default methods+typedefs off" "/T" 1 0
+do_check "methods typedefs, default methods+typedefs off" "/MT" 1 1
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 47915b1..9ebb3bd 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -40,7 +40,7 @@ proc test_ptype_of_templates {} {
     global gdb_prompt
     global ws
 
-    gdb_test_multiple "ptype T5<int>" "ptype T5<int>" {
+    gdb_test_multiple "ptype/r T5<int>" "ptype T5<int>" {
 	-re "type = class T5<int> \{${ws}public:${ws}static int X;${ws}int x;${ws}int val;${ws}T5<int> & operator=\\(T5<int> const ?&\\);${ws}T5\\(int\\);${ws}T5\\((T5<int> const|const T5<int>) ?&\\);${ws}~T5\\((void|)\\);${ws}static void \\* operator new\\(unsigned( int| long)?\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\}\r\n$gdb_prompt $" {
 	    xfail "ptype T5<int> -- new without size_t"
 	}
@@ -63,7 +63,7 @@ proc test_ptype_of_templates {} {
 	}
     }
 
-    gdb_test_multiple "ptype t5i" "ptype t5i" {
+    gdb_test_multiple "ptype/r t5i" "ptype t5i" {
         -re "type = class T5<int> \\{${ws}public:${ws}static int X;${ws}int x;${ws}int val;\r\n${ws}T5\\(int\\);${ws}T5\\(T5<int> const ?&\\);${ws}~T5\\((void|)\\);${ws}static void \\* operator new\\(unsigned( int| long)?\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\\}\r\n$gdb_prompt $" {
 	    xfail "ptype T5<int> -- with several fixes from 4.17 -- without size_t"
 	}
@@ -226,11 +226,13 @@ proc test_template_typedef {} {
 proc test_template_args {} {
 
     set empty_re "Empty *<void *\\(FunctionArg *<int>\\)>"
-    gdb_test "ptype empty" \
-	"type = (struct|class) $empty_re {.*<no data fields>.*}"
+    gdb_test "ptype/r empty" \
+	"type = (struct|class) $empty_re {.*<no data fields>.*}" \
+	"ptype empty"
 
-    gdb_test "ptype arg" \
-	"type = (struct|class) FunctionArg<int> {.*int method\\($empty_re \\&\\);.*}"
+    gdb_test "ptype/r arg" \
+	"type = (struct|class) FunctionArg<int> {.*int method\\($empty_re \\&\\);.*}" \
+	"ptype arg"
 }
 
 proc do_tests {} {
@@ -291,7 +293,7 @@ gdb_test "print fvpchar" \
 # NOTE: carlton/2003-02-26: However, because of a bug in the way GDB
 # handles nested types, we don't get this right in the DWARF-2 case.
 
-gdb_test_multiple "ptype Foo" "ptype Foo" {
+gdb_test_multiple "ptype/r Foo" "ptype Foo" {
     -re "type = template <(class |)T> (class |)Foo \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Foo<volatile char \\*>\r\n\[ \t\]*(class |)Foo<char>\r\n\[ \t\]*(class |)Foo<int>\r\n$gdb_prompt $" {
 	pass "ptype Foo"
     }
@@ -312,7 +314,7 @@ gdb_test_multiple "ptype Foo" "ptype Foo" {
 
 # ptype Foo<int>
 
-gdb_test_multiple "ptype fint" "ptype fint" {
+gdb_test_multiple "ptype/r fint" "ptype fint" {
     -re "type = (class |)Foo<int> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int foo\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fint"
     }
@@ -323,7 +325,7 @@ gdb_test_multiple "ptype fint" "ptype fint" {
 
 # ptype Foo<char>
 
-gdb_test_multiple "ptype fchar" "ptype fchar" {
+gdb_test_multiple "ptype/r fchar" "ptype fchar" {
     -re "type = (class |)Foo<char> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*.*char foo\\(int, char\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fchar"
     }
@@ -334,7 +336,7 @@ gdb_test_multiple "ptype fchar" "ptype fchar" {
 
 # ptype Foo<volatile char *>
 
-gdb_test_multiple "ptype fvpchar" "ptype fvpchar" {
+gdb_test_multiple "ptype/r fvpchar" "ptype fvpchar" {
     -re "type = (class |)Foo<volatile char ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*char.*\\*t;\r\n\r\n\[ \t\]*.*char \\* foo\\(int,.*char.*\\*\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fvpchar"
     }
@@ -374,7 +376,7 @@ gdb_test_multiple "print Foo<volatile char*>::foo" "print Foo<volatile char*>::f
 # Template Bar<T, int>
 
 # same as Foo for g++
-gdb_test_multiple "ptype Bar" "ptype Bar" {
+gdb_test_multiple "ptype/r Bar" "ptype Bar" {
     -re "type = template <(class |)T, (class |)sz> (class |)Bar \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Bar<int,(\\(int\\)|)1>\r\n\[ \t\]*(class |)Bar<int,(\\(int\\)|)33>\r\n$gdb_prompt $" {
 	pass "ptype Bar"
     }
@@ -394,7 +396,7 @@ gdb_test_multiple "ptype Bar" "ptype Bar" {
 
 # ptype Bar<int,33>
 
-gdb_test_multiple "ptype bint" "ptype bint" {
+gdb_test_multiple "ptype/r bint" "ptype bint" {
     -re "type = (class |)Bar<int, ?(\\(int\\)|)33> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int bar\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bint"
     }
@@ -405,7 +407,7 @@ gdb_test_multiple "ptype bint" "ptype bint" {
 
 # ptype Bar<int, (4>3)>
 
-gdb_test_multiple "ptype bint2" "ptype bint2" {
+gdb_test_multiple "ptype/r bint2" "ptype bint2" {
     -re "type = (class |)Bar<int, ?(\\(int\\)|)1> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int bar\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bint2"
     }
@@ -417,7 +419,7 @@ gdb_test_multiple "ptype bint2" "ptype bint2" {
 # Template Baz<T, char>
 
 # Same as Foo, for g++
-gdb_test_multiple "ptype Baz" "ptype Baz" {
+gdb_test_multiple "ptype/r Baz" "ptype Baz" {
     -re "type = template <(class |)T, ?(class |)sz> (class |)Baz \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Baz<char,(\\(char\\)|)97>\r\n\[ \t\]*(class |)Baz<int,(\\(char\\)|)115>\r\n$gdb_prompt $" {
 	pass "ptype Baz"
     }
@@ -441,7 +443,7 @@ gdb_test_multiple "ptype Baz" "ptype Baz" {
 
 # ptype Baz<int, 's'>
 
-gdb_test_multiple "ptype bazint" "ptype bazint" {
+gdb_test_multiple "ptype/r bazint" "ptype bazint" {
     -re "type = (class |)Baz<int, ?(\\(char\\)|)(115|\\'s\\')> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int baz\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bazint"
     }
@@ -452,7 +454,7 @@ gdb_test_multiple "ptype bazint" "ptype bazint" {
 
 # ptype Baz<char, 'a'>
 
-gdb_test_multiple "ptype bazint2" "ptype bazint2" {
+gdb_test_multiple "ptype/r bazint2" "ptype bazint2" {
     -re "type = (class |)Baz<char, ?(\\(char\\)|)(97|\\'a\\')> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*.*char baz\\(int, char\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bazint2"
     }
@@ -463,7 +465,7 @@ gdb_test_multiple "ptype bazint2" "ptype bazint2" {
 
 # Template Qux<T, int (*f)(int) >
 # Same as Foo for g++
-gdb_test_multiple "ptype Qux" "ptype Qux" {
+gdb_test_multiple "ptype/r Qux" "ptype Qux" {
     -re "type = template <(class |)T, ?(class |)sz> (class |)Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Qux<int,&string>\r\n\[ \t\]*(class |)Qux<char,&string>\r\n$gdb_prompt $" {
 	pass "ptype Qux"
     }
@@ -486,7 +488,7 @@ gdb_test_multiple "ptype Qux" "ptype Qux" {
 
 # pt Qux<int,&string>
 
-gdb_test_multiple "ptype quxint" "ptype quxint" {
+gdb_test_multiple "ptype/r quxint" "ptype quxint" {
     -re "type = class Qux<int, ?& ?string> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int qux\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype quxint"
     }
@@ -505,7 +507,7 @@ gdb_test_multiple "ptype quxint" "ptype quxint" {
 # Template Spec<T1, T2>
 
 # Same as Foo for g++
-gdb_test_multiple "ptype Spec" "ptype Spec" {
+gdb_test_multiple "ptype/r Spec" "ptype Spec" {
     -re "type = template <(class |)T1, (class |)T2> (class |)Spec \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Spec<int,int \\*>\r\n\[ \t\]*(class |)Spec<int,char>\r\n$gdb_prompt $" {
 	pass "ptype Spec"
     }
@@ -524,7 +526,7 @@ gdb_test_multiple "ptype Spec" "ptype Spec" {
 
 # pt Spec<char,0>
 
-gdb_test_multiple "ptype siip" "ptype siip" {
+gdb_test_multiple "ptype/r siip" "ptype siip" {
     -re "type = class Spec<int, ?int ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\r\n\[ \t\]*.*int spec\\(int ?\\*\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype siip"
     }
@@ -535,7 +537,7 @@ gdb_test_multiple "ptype siip" "ptype siip" {
 
 # pt Garply<int>
 
-gdb_test_multiple "ptype Garply<int>" "ptype Garply<int>" {
+gdb_test_multiple "ptype/r Garply<int>" "ptype Garply<int>" {
     -re "type = class Garply<int> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int garply\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype Garply<int>"
     }
@@ -546,7 +548,7 @@ gdb_test_multiple "ptype Garply<int>" "ptype Garply<int>" {
 
 # ptype of nested template name
 
-gdb_test_multiple "ptype Garply<Garply<char> >" "ptype Garply<Garply<char> >" {
+gdb_test_multiple "ptype/r Garply<Garply<char> >" "ptype Garply<Garply<char> >" {
     -re "type = (class |)Garply<Garply<char> > \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*(class |)Garply<char> t;\r\n\r\n\[ \t\]*.*(class |)Garply<char> garply\\(int, (class |)Garply<char>\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype Garply<Garply<char> >"
     }
diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp
index b984f4d..827fda8 100644
--- a/gdb/testsuite/lib/cp-support.exp
+++ b/gdb/testsuite/lib/cp-support.exp
@@ -101,6 +101,8 @@ proc cp_check_errata { expected_string actual_string errata_table } {
 # demangler syntax adjustment, so you have to make a bigger table
 # with lines for each output variation.
 # 
+# IN_PTYPE_ARG are arguments to pass to ptype.  The default is "/r".
+#
 # gdb can vary the output of ptype in several ways:
 #
 # . CLASS/STRUCT
@@ -179,15 +181,16 @@ proc cp_check_errata { expected_string actual_string errata_table } {
 #
 # -- chastain 2004-08-07
 
-proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } } {
+proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } { in_ptype_arg /r } } {
     global gdb_prompt
     set wsopt "\[\r\n\t \]*"
 
-    # The test name defaults to the command.
+    # The test name defaults to the command, but without the
+    # arguments, for historical reasons.
 
     if { "$in_testname" == "" } then { set in_testname "ptype $in_exp" }
 
-    set in_command "ptype $in_exp"
+    set in_command "ptype${in_ptype_arg} $in_exp"
 
     # Save class tables in a history array for reuse.
 
@@ -233,13 +236,13 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
 
     set parse_okay 0
     gdb_test_multiple "$in_command" "$in_testname // parse failed" {
-	-re "type = (struct|class)${wsopt}(\[A-Za-z0-9_\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" {
+	-re "type = (struct|class)${wsopt}(\[^ \t\]*)${wsopt}(\\\[with .*\\\]${wsopt})?((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" {
 	    set parse_okay          1
 	    set actual_key          $expect_out(1,string)
 	    set actual_tag          $expect_out(2,string)
-	    set actual_base_string  $expect_out(3,string)
-	    set actual_body         $expect_out(5,string)
-	    set actual_tail         $expect_out(6,string)
+	    set actual_base_string  $expect_out(4,string)
+	    set actual_body         $expect_out(6,string)
+	    set actual_tail         $expect_out(7,string)
 	}
     }
     if { ! $parse_okay } then { return }
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 509b3ee..0e1c93c 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -51,7 +51,8 @@ const struct type_print_options type_print_raw_options =
 {
   1,				/* raw */
   1,				/* print_methods */
-  1				/* print_typedefs */
+  1,				/* print_typedefs */
+  NULL				/* local_typedefs */
 };
 
 /* The default flags for 'ptype' and 'whatis'.  */
@@ -60,11 +61,202 @@ static struct type_print_options default_ptype_flags =
 {
   0,				/* raw */
   1,				/* print_methods */
-  1				/* print_typedefs */
+  1,				/* print_typedefs */
+  NULL				/* local_typedefs */
 };
 
 \f
 
+/* 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
+hash_typedef_field (const void *p)
+{
+  const struct typedef_field *tf = p;
+  struct type *t = check_typedef (tf->type);
+
+  return htab_hash_string (TYPE_SAFE_NAME (t));
+}
+
+/* An equality function for a typedef field.  */
+
+static int
+eq_typedef_field (const void *a, const void *b)
+{
+  const struct typedef_field *tfa = a;
+  const struct typedef_field *tfb = b;
+
+  return types_equal (tfa->type, tfb->type);
+}
+
+/* Add typedefs from T to the hash table TABLE.  */
+
+void
+recursively_update_typedef_hash (struct typedef_hash_table *table,
+				 struct type *t)
+{
+  int i;
+
+  if (table == NULL)
+    return;
+
+  for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
+    {
+      struct typedef_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
+      void **slot;
+
+      slot = htab_find_slot (table->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.  */
+      if (*slot == NULL)
+	*slot = tdef;
+    }
+
+  /* Recurse into superclasses.  */
+  for (i = 0; i < TYPE_N_BASECLASSES (t); ++i)
+    recursively_update_typedef_hash (table, TYPE_BASECLASS (t, i));
+}
+
+/* Add template parameters from T to the typedef hash TABLE.  */
+
+void
+add_template_parameters (struct typedef_hash_table *table, struct type *t)
+{
+  int i;
+
+  if (table == NULL)
+    return;
+
+  for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
+    {
+      struct typedef_field *tf;
+      void **slot;
+
+      /* We only want type-valued template parameters in the hash.  */
+      if (SYMBOL_CLASS (TYPE_TEMPLATE_ARGUMENT (t, i)) != LOC_TYPEDEF)
+	continue;
+
+      tf = XOBNEW (&table->storage, struct typedef_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);
+      if (*slot == NULL)
+	*slot = tf;
+    }
+}
+
+/* Create a new typedef-lookup hash table.  */
+
+struct typedef_hash_table *
+create_typedef_hash (void)
+{
+  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;
+}
+
+/* Free a typedef field table.  */
+
+void
+free_typedef_hash (struct typedef_hash_table *table)
+{
+  if (table != NULL)
+    {
+      htab_delete (table->table);
+      obstack_free (&table->storage, NULL);
+      xfree (table);
+    }
+}
+
+/* A cleanup for freeing a typedef_hash_table.  */
+
+static void
+do_free_typedef_hash (void *arg)
+{
+  free_typedef_hash (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.  */
+
+static int
+copy_typedef_hash_element (void **slot, void *nt)
+{
+  htab_t new_table = nt;
+  void **new_slot;
+
+  new_slot = htab_find_slot (new_table, *slot, INSERT);
+  if (*new_slot == NULL)
+    *new_slot = *slot;
+
+  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;
+}
+
+/* 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.  */
+
+const char *
+find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
+{
+  struct typedef_field tf, *found;
+
+  if (flags->local_typedefs == NULL)
+    return NULL;
+
+  tf.name = NULL;
+  tf.type = t;
+  found = htab_find (flags->local_typedefs->table, &tf);
+
+  return found == NULL ? NULL : found->name;
+}
+
+\f
+
 /* Print a description of a type in the format of a 
    typedef for the current language.
    NEW is the new name for a type TYPE.  */
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 1e15097..71bac01 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -22,6 +22,7 @@
 
 enum language;
 struct ui_file;
+struct typedef_hash_table;
 
 struct type_print_options
 {
@@ -33,10 +34,30 @@ struct type_print_options
 
   /* True means print typedefs in a class.  */
   unsigned int print_typedefs : 1;
+
+  /* If not NULL, a local typedef hash table used when printing a
+     type.  */
+  struct typedef_hash_table *local_typedefs;
 };
 
 extern const struct type_print_options type_print_raw_options;
 
+void recursively_update_typedef_hash (struct typedef_hash_table *,
+				      struct type *);
+
+void add_template_parameters (struct typedef_hash_table *, struct type *);
+
+struct typedef_hash_table *create_typedef_hash (void);
+
+void free_typedef_hash (struct typedef_hash_table *);
+
+struct cleanup *make_cleanup_free_typedef_hash (struct typedef_hash_table *);
+
+struct typedef_hash_table *copy_typedef_hash (struct typedef_hash_table *);
+
+const char *find_typedef_in_hash (const struct type_print_options *,
+				  struct type *);
+
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
 void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-09-07 18:51 [PATCH 8/9] class-local typedef substitutions Tom Tromey
@ 2012-09-08  8:00 ` Eli Zaretskii
  2012-09-21 19:32 ` Tom Tromey
  1 sibling, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2012-09-08  8:00 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Date: Fri, 07 Sep 2012 12:50:27 -0600
> 
> --- a/gdb/NEWS
> +++ b/gdb/NEWS

This part is OK.

Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-09-07 18:51 [PATCH 8/9] class-local typedef substitutions Tom Tromey
  2012-09-08  8:00 ` Eli Zaretskii
@ 2012-09-21 19:32 ` Tom Tromey
  2012-10-31 19:18   ` Pedro Alves
  1 sibling, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2012-09-21 19:32 UTC (permalink / raw)
  To: gdb-patches

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> This patch implements class-local typedef substitutions for the C++
Tom> type printer.  That is, when printing a type, gdb will now look at
Tom> template argument names (if any) and typedefs defined in the class
Tom> body, and substitute those names when printing type names.

More testing revealed an oddity in this code (a latent bug exposed by
the subsequent Python patch); and the fix I chose required some changes
to some MI test cases as well.  The particular change was that
previously gdb could emit "long int" but now it will emit just "long" --
I consider this to be an ok (perhaps even preferable) change.

Built and regtested on x86-64 F16.

Tom

	* NEWS: Update.
	* c-typeprint.c (find_typedef_for_canonicalize,
	print_name_maybe_canonical): New functions.
	(c_print_type): Look up type name.
	(cp_type_print_derivation_info): Add flags argument.  Use
	print_name_maybe_canonical.
	(cp_type_print_method_args): Add wrapping.
	(c_type_print_varspec_prefix): Use print_name_maybe_canonical.
	(c_type_print_template_args): New function.
	(c_type_print_base): Change wrapping.
	<TYPE_CODE_STRUCT>: Possibly create a typedef hash, and do
	type name lookups.
	* gdbtypes.c (types_equal): No longer static.
	* gdbtypes.h (types_equal): Declare.
	* typeprint.c (type_print_raw_options, default_ptype_flags):
	Update.
	(struct typedef_hash_table): New.
	(hash_typedef_field, eq_typedef_field,
	recursively_update_typedef_hash, add_template_parameters,
	create_typedef_hash, free_typedef_hash, do_free_typedef_hash,
	make_cleanup_free_typedef_hash, copy_typedef_hash_element,
	copy_typedef_hash, find_typedef_in_hash): New functions.
	* typeprint.h (struct type_print_options) <local_typedefs>:
	New field.
	(recursively_update_typedef_hash, add_template_parameters,
	create_typedef_hash, free_typedef_hash,
	make_cleanup_free_typedef_hash, copy_typedef_hash,
	find_typedef_in_hash): Declare.

	* gdb.cp/ptype-flags.cc: New file.
	* gdb.cp/ptype-flags.exp: New file.
	* gdb.cp/templates.exp: Use ptype/r.
	(test_ptype_of_templates, test_template_typedef): Likewise.
	* lib/cp-support.exp (cp_test_ptype_class): Add in_ptype_arg
	argument.  Handle template names and template parameters.
	* gdb.mi/mi-var-cmd.exp: Accept "long" or "long int".
	* gdb.mi/mi-var-child.exp: Accept "long" or "long int".
	* gdb.mi/mi-var-display.exp: Accept "long" or "long int".
	* gdb.mi/mi2-var-child.exp: Accept "long" or "long int".
	* gdb.mi/mi2-var-cmd.exp: Accept "long" or "long int".
	* gdb.mi/mi2-var-display.exp: Accept "long" or "long int".
---
 gdb/NEWS                                 |   15 +
 gdb/c-typeprint.c                        |  613 +++++++++++++++++++-----------
 gdb/gdbtypes.c                           |    2 +-
 gdb/gdbtypes.h                           |    2 +
 gdb/testsuite/gdb.cp/ptype-flags.cc      |   47 +++
 gdb/testsuite/gdb.cp/ptype-flags.exp     |   85 ++++
 gdb/testsuite/gdb.cp/templates.exp       |   46 ++-
 gdb/testsuite/gdb.mi/mi-var-child.exp    |   75 ++--
 gdb/testsuite/gdb.mi/mi-var-cmd.exp      |    6 +-
 gdb/testsuite/gdb.mi/mi-var-display.exp  |   12 +-
 gdb/testsuite/gdb.mi/mi2-var-child.exp   |   42 +-
 gdb/testsuite/gdb.mi/mi2-var-cmd.exp     |    6 +-
 gdb/testsuite/gdb.mi/mi2-var-display.exp |   12 +-
 gdb/testsuite/lib/cp-support.exp         |   17 +-
 gdb/typeprint.c                          |  196 ++++++++++-
 gdb/typeprint.h                          |   21 +
 16 files changed, 858 insertions(+), 339 deletions(-)
 create mode 100644 gdb/testsuite/gdb.cp/ptype-flags.cc
 create mode 100644 gdb/testsuite/gdb.cp/ptype-flags.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index abd0932..d77de8d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 7.5
 
+* The 'ptype' and 'whatis' commands now accept an argument to control
+  type formatting.
+
 * Python scripting
 
   ** Vectors can be created with gdb.Type.vector.
@@ -47,6 +50,18 @@ py [command]
      (has been deprecated in GDB 7.5), and "info all-registers" should be used
      instead.
 
+* New options
+
+set print type methods (on|off)
+show print type methods
+  Control whether method declarations are displayed by "ptype".
+  The default is to show them.
+
+set print type typedefs (on|off)
+show print type typedefs
+  Control whether typedef definitions are displayed by "ptype".
+  The default is to show them.
+
 * MI changes
 
   ** Command parameter changes are now notified using new async record
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index f7a061d..6c07d3d 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -34,6 +34,7 @@
 #include "jv-lang.h"
 #include "gdb_string.h"
 #include <errno.h>
+#include "cp-support.h"
 
 static void c_type_print_varspec_prefix (struct type *,
 					 struct ui_file *,
@@ -45,6 +46,37 @@ static void c_type_print_modifier (struct type *,
 				   struct ui_file *,
 				   int, int);
 \f
+
+/* A callback function for cp_canonicalize_string_full that uses
+   find_typedef_in_hash.  */
+
+static const char *
+find_typedef_for_canonicalize (struct type *t, void *data)
+{
+  return find_typedef_in_hash (data, t);
+}
+
+/* Print NAME on STREAM.  If the 'raw' field of FLAGS is not set,
+   canonicalize NAME using the local typedefs first.  */
+
+static void
+print_name_maybe_canonical (const char *name,
+			    const struct type_print_options *flags,
+			    struct ui_file *stream)
+{
+  char *s = NULL;
+
+  if (!flags->raw)
+    s = cp_canonicalize_string_full (name,
+				     find_typedef_for_canonicalize,
+				     (void *) flags);
+
+  fputs_filtered (s ? s : name, stream);
+  xfree (s);
+}
+
+\f
+
 /* LEVEL is the depth to indent lines by.  */
 
 void
@@ -57,26 +89,37 @@ c_print_type (struct type *type,
   enum type_code code;
   int demangled_args;
   int need_post_space;
+  const char *local_name;
 
   if (show > 0)
     CHECK_TYPEDEF (type);
 
-  c_type_print_base (type, stream, show, level, flags);
-  code = TYPE_CODE (type);
-  if ((varstring != NULL && *varstring != '\0')
-  /* Need a space if going to print stars or brackets;
-     but not if we will print just a type name.  */
-      || ((show > 0 || TYPE_NAME (type) == 0)
-	  && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
-	      || code == TYPE_CODE_METHOD
-	      || code == TYPE_CODE_ARRAY
-	      || code == TYPE_CODE_MEMBERPTR
-	      || code == TYPE_CODE_METHODPTR
-	      || code == TYPE_CODE_REF)))
-    fputs_filtered (" ", stream);
-  need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
-  c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
-			       flags);
+  local_name = find_typedef_in_hash (flags, type);
+  if (local_name != NULL)
+    {
+      fputs_filtered (local_name, stream);
+      if (varstring != NULL && *varstring != '\0')
+	fputs_filtered (" ", stream);
+    }
+  else
+    {
+      c_type_print_base (type, stream, show, level, flags);
+      code = TYPE_CODE (type);
+      if ((varstring != NULL && *varstring != '\0')
+	  /* Need a space if going to print stars or brackets;
+	     but not if we will print just a type name.  */
+	  || ((show > 0 || TYPE_NAME (type) == 0)
+	      && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+		  || code == TYPE_CODE_METHOD
+		  || code == TYPE_CODE_ARRAY
+		  || code == TYPE_CODE_MEMBERPTR
+		  || code == TYPE_CODE_METHODPTR
+		  || code == TYPE_CODE_REF)))
+	fputs_filtered (" ", stream);
+      need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
+      c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
+				   flags);
+    }
 
   if (varstring != NULL)
     {
@@ -84,10 +127,13 @@ c_print_type (struct type *type,
 
       /* For demangled function names, we have the arglist as part of
          the name, so don't print an additional pair of ()'s.  */
-
-      demangled_args = strchr (varstring, '(') != NULL;
-      c_type_print_varspec_suffix (type, stream, show,
-				   0, demangled_args, flags);
+      if (local_name == NULL)
+	{
+	  demangled_args = strchr (varstring, '(') != NULL;
+	  c_type_print_varspec_suffix (type, stream, show,
+				       0, demangled_args,
+				       flags);
+	}
     }
 }
 
@@ -138,13 +184,15 @@ c_print_typedef (struct type *type,
 
 static void
 cp_type_print_derivation_info (struct ui_file *stream,
-			       struct type *type)
+			       struct type *type,
+			       const struct type_print_options *flags)
 {
   const char *name;
   int i;
 
   for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
     {
+      wrap_here ("        ");
       fputs_filtered (i == 0 ? ": " : ", ", stream);
       fprintf_filtered (stream, "%s%s ",
 			BASETYPE_VIA_PUBLIC (type, i)
@@ -152,7 +200,10 @@ cp_type_print_derivation_info (struct ui_file *stream,
 				      ? "protected" : "private"),
 			BASETYPE_VIA_VIRTUAL (type, i) ? " virtual" : "");
       name = type_name_no_tag (TYPE_BASECLASS (type, i));
-      fprintf_filtered (stream, "%s", name ? name : "(null)");
+      if (name)
+	print_name_maybe_canonical (name, flags, stream);
+      else
+	fprintf_filtered (stream, "(null)");
     }
   if (i > 0)
     {
@@ -190,7 +241,10 @@ cp_type_print_method_args (struct type *mtype, const char *prefix,
 	  if (i == nargs && varargs)
 	    fprintf_filtered (stream, ", ...");
 	  else if (i < nargs)
-	    fprintf_filtered (stream, ", ");
+	    {
+	      fprintf_filtered (stream, ", ");
+	      wrap_here ("        ");
+	    }
 	}
     }
   else if (varargs)
@@ -262,7 +316,7 @@ c_type_print_varspec_prefix (struct type *type,
 				   stream, show, 0, 0, flags);
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
-	fputs_filtered (name, stream);
+	print_name_maybe_canonical (name, flags, stream);
       else
 	c_type_print_base (TYPE_DOMAIN_TYPE (type),
 			   stream, -1, passed_a_ptr, flags);
@@ -275,7 +329,7 @@ c_type_print_varspec_prefix (struct type *type,
       fprintf_filtered (stream, "(");
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
-	fputs_filtered (name, stream);
+	print_name_maybe_canonical (name, flags, stream);
       else
 	c_type_print_base (TYPE_DOMAIN_TYPE (type),
 			   stream, -1, passed_a_ptr, flags);
@@ -696,6 +750,56 @@ c_type_print_varspec_suffix (struct type *type,
     }
 }
 
+/* A helper for c_type_print_base that displays template
+   parameters and their bindings, if needed.
+
+   TABLE is the local bindings table to use.  If NULL, no printing is
+   done.  Note that, at this point, TABLE won't have any useful
+   information in it -- but it is also used as a flag to
+   print_name_maybe_canonical to activate searching the global typedef
+   table.
+
+   TYPE is the type whose template arguments are being displayed.
+
+   STREAM is the stream on which to print.  */
+
+static void
+c_type_print_template_args (const struct type_print_options *flags,
+			    struct type *type, struct ui_file *stream)
+{
+  int first = 1, i;
+
+  if (flags->raw)
+    return;
+
+  for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i)
+    {
+      struct symbol *sym = TYPE_TEMPLATE_ARGUMENT (type, i);
+
+      if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+	continue;
+
+      if (first)
+	{
+	  wrap_here ("    ");
+	  fprintf_filtered (stream, _("[with %s = "),
+			    SYMBOL_LINKAGE_NAME (sym));
+	  first = 0;
+	}
+      else
+	{
+	  fputs_filtered (", ", stream);
+	  wrap_here ("         ");
+	  fprintf_filtered (stream, "%s = ", SYMBOL_LINKAGE_NAME (sym));
+	}
+
+      c_print_type (SYMBOL_TYPE (sym), "", stream, -1, 0, flags);
+    }
+
+  if (!first)
+    fputs_filtered (_("] "), stream);
+}
+
 /* Print the name of the type (or the ultimate pointer target,
    function value or array element), or the description of a structure
    or union.
@@ -730,7 +834,6 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 
   QUIT;
 
-  wrap_here ("    ");
   if (type == NULL)
     {
       fputs_filtered (_("<type unknown>"), stream);
@@ -748,7 +851,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       && TYPE_NAME (type) != NULL)
     {
       c_type_print_modifier (type, stream, 0, 1);
-      fputs_filtered (TYPE_NAME (type), stream);
+      print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
       return;
     }
 
@@ -777,193 +880,230 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
-      c_type_print_modifier (type, stream, 0, 1);
-      if (TYPE_CODE (type) == TYPE_CODE_UNION)
-	fprintf_filtered (stream, "union ");
-      else if (TYPE_DECLARED_CLASS (type))
-	fprintf_filtered (stream, "class ");
-      else
-	fprintf_filtered (stream, "struct ");
-
-      /* Print the tag if it exists.  The HP aCC compiler emits a
-         spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed
-         enum}" tag for unnamed struct/union/enum's, which we don't
-         want to print.  */
-      if (TYPE_TAG_NAME (type) != NULL
-	  && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
-	{
-	  fputs_filtered (TYPE_TAG_NAME (type), stream);
-	  if (show > 0)
-	    fputs_filtered (" ", stream);
-	}
-      wrap_here ("    ");
-      if (show < 0)
-	{
-	  /* If we just printed a tag name, no need to print anything
-	     else.  */
-	  if (TYPE_TAG_NAME (type) == NULL)
-	    fprintf_filtered (stream, "{...}");
-	}
-      else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
-	{
-	  struct type *basetype;
-	  int vptr_fieldno;
-
-	  cp_type_print_derivation_info (stream, type);
-
-	  fprintf_filtered (stream, "{\n");
-	  if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0
-	      && TYPE_TYPEDEF_FIELD_COUNT (type) == 0)
-	    {
-	      if (TYPE_STUB (type))
-		fprintfi_filtered (level + 4, stream,
-				   _("<incomplete type>\n"));
-	      else
-		fprintfi_filtered (level + 4, stream,
-				   _("<no data fields>\n"));
-	    }
-
-	  /* Start off with no specific section type, so we can print
-	     one for the first field we find, and use that section type
-	     thereafter until we find another type.  */
-
-	  section_type = s_none;
-
-	  /* For a class, if all members are private, there's no need
-	     for a "private:" label; similarly, for a struct or union
-	     masquerading as a class, if all members are public, there's
-	     no need for a "public:" label.  */
-
-	  if (TYPE_DECLARED_CLASS (type))
-	    {
-	      QUIT;
-	      len = TYPE_NFIELDS (type);
-	      for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-		if (!TYPE_FIELD_PRIVATE (type, i))
-		  {
-		    need_access_label = 1;
-		    break;
-		  }
-	      QUIT;
-	      if (!need_access_label)
-		{
-		  len2 = TYPE_NFN_FIELDS (type);
-		  for (j = 0; j < len2; j++)
+      {
+	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;
+
+	if (!flags->raw)
+	  {
+	    if (flags->local_typedefs)
+	      local_flags.local_typedefs
+		= copy_typedef_hash (flags->local_typedefs);
+	    else
+	      local_flags.local_typedefs = create_typedef_hash ();
+
+	    make_cleanup_free_typedef_hash (local_flags.local_typedefs);
+	  }
+
+	c_type_print_modifier (type, stream, 0, 1);
+	if (TYPE_CODE (type) == TYPE_CODE_UNION)
+	  fprintf_filtered (stream, "union ");
+	else if (TYPE_DECLARED_CLASS (type))
+	  fprintf_filtered (stream, "class ");
+	else
+	  fprintf_filtered (stream, "struct ");
+
+	/* Print the tag if it exists.  The HP aCC compiler emits a
+	   spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed
+	   enum}" tag for unnamed struct/union/enum's, which we don't
+	   want to print.  */
+	if (TYPE_TAG_NAME (type) != NULL
+	    && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
+	  {
+	    /* When printing the tag name, we are still effectively
+	       printing in the outer context, hence the use of FLAGS
+	       here.  */
+	    print_name_maybe_canonical (TYPE_TAG_NAME (type), flags, stream);
+	    if (show > 0)
+	      fputs_filtered (" ", stream);
+	  }
+
+	if (show < 0)
+	  {
+	    /* If we just printed a tag name, no need to print anything
+	       else.  */
+	    if (TYPE_TAG_NAME (type) == NULL)
+	      fprintf_filtered (stream, "{...}");
+	  }
+	else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
+	  {
+	    struct type *basetype;
+	    int vptr_fieldno;
+
+	    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);
+	    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);
+
+	    /* Now add in the local typedefs.  */
+	    recursively_update_typedef_hash (local_flags.local_typedefs, type);
+
+	    fprintf_filtered (stream, "{\n");
+	    if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0
+		&& TYPE_TYPEDEF_FIELD_COUNT (type) == 0)
+	      {
+		if (TYPE_STUB (type))
+		  fprintfi_filtered (level + 4, stream,
+				     _("<incomplete type>\n"));
+		else
+		  fprintfi_filtered (level + 4, stream,
+				     _("<no data fields>\n"));
+	      }
+
+	    /* Start off with no specific section type, so we can print
+	       one for the first field we find, and use that section type
+	       thereafter until we find another type.  */
+
+	    section_type = s_none;
+
+	    /* For a class, if all members are private, there's no need
+	       for a "private:" label; similarly, for a struct or union
+	       masquerading as a class, if all members are public, there's
+	       no need for a "public:" label.  */
+
+	    if (TYPE_DECLARED_CLASS (type))
+	      {
+		QUIT;
+		len = TYPE_NFIELDS (type);
+		for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+		  if (!TYPE_FIELD_PRIVATE (type, i))
 		    {
-		      len = TYPE_FN_FIELDLIST_LENGTH (type, j);
-		      for (i = 0; i < len; i++)
-			if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
-									j), i))
-			  {
-			    need_access_label = 1;
-			    break;
-			  }
-		      if (need_access_label)
-			break;
+		      need_access_label = 1;
+		      break;
 		    }
-		}
-	    }
-	  else
-	    {
-	      QUIT;
-	      len = TYPE_NFIELDS (type);
-	      for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-		if (TYPE_FIELD_PRIVATE (type, i)
-		    || TYPE_FIELD_PROTECTED (type, i))
+		QUIT;
+		if (!need_access_label)
 		  {
-		    need_access_label = 1;
-		    break;
+		    len2 = TYPE_NFN_FIELDS (type);
+		    for (j = 0; j < len2; j++)
+		      {
+			len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+			for (i = 0; i < len; i++)
+			  if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
+									  j), i))
+			    {
+			      need_access_label = 1;
+			      break;
+			    }
+			if (need_access_label)
+			  break;
+		      }
 		  }
-	      QUIT;
-	      if (!need_access_label)
-		{
-		  len2 = TYPE_NFN_FIELDS (type);
-		  for (j = 0; j < len2; j++)
+	      }
+	    else
+	      {
+		QUIT;
+		len = TYPE_NFIELDS (type);
+		for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+		  if (TYPE_FIELD_PRIVATE (type, i)
+		      || TYPE_FIELD_PROTECTED (type, i))
 		    {
-		      QUIT;
-		      len = TYPE_FN_FIELDLIST_LENGTH (type, j);
-		      for (i = 0; i < len; i++)
-			if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type,
-									 j), i)
-			    || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
-									  j),
-						      i))
-			  {
-			    need_access_label = 1;
-			    break;
-			  }
-		      if (need_access_label)
-			break;
+		      need_access_label = 1;
+		      break;
 		    }
-		}
-	    }
+		QUIT;
+		if (!need_access_label)
+		  {
+		    len2 = TYPE_NFN_FIELDS (type);
+		    for (j = 0; j < len2; j++)
+		      {
+			QUIT;
+			len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+			for (i = 0; i < len; i++)
+			  if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type,
+									   j), i)
+			      || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
+									    j),
+							i))
+			    {
+			      need_access_label = 1;
+			      break;
+			    }
+			if (need_access_label)
+			  break;
+		      }
+		  }
+	      }
 
-	  /* If there is a base class for this type,
-	     do not print the field that it occupies.  */
+	    /* If there is a base class for this type,
+	       do not print the field that it occupies.  */
 
-	  len = TYPE_NFIELDS (type);
-	  vptr_fieldno = get_vptr_fieldno (type, &basetype);
-	  for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-	    {
-	      QUIT;
+	    len = TYPE_NFIELDS (type);
+	    vptr_fieldno = get_vptr_fieldno (type, &basetype);
+	    for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+	      {
+		QUIT;
 
-	      /* If we have a virtual table pointer, omit it.  Even if
-		 virtual table pointers are not specifically marked in
-		 the debug info, they should be artificial.  */
-	      if ((i == vptr_fieldno && type == basetype)
-		  || TYPE_FIELD_ARTIFICIAL (type, i))
-		continue;
+		/* If we have a virtual table pointer, omit it.  Even if
+		   virtual table pointers are not specifically marked in
+		   the debug info, they should be artificial.  */
+		if ((i == vptr_fieldno && type == basetype)
+		    || TYPE_FIELD_ARTIFICIAL (type, i))
+		  continue;
 
-	      if (need_access_label)
-		{
-		  if (TYPE_FIELD_PROTECTED (type, i))
-		    {
-		      if (section_type != s_protected)
-			{
-			  section_type = s_protected;
-			  fprintfi_filtered (level + 2, stream,
-					     "protected:\n");
-			}
-		    }
-		  else if (TYPE_FIELD_PRIVATE (type, i))
-		    {
-		      if (section_type != s_private)
-			{
-			  section_type = s_private;
-			  fprintfi_filtered (level + 2, stream,
-					     "private:\n");
-			}
-		    }
-		  else
-		    {
-		      if (section_type != s_public)
-			{
-			  section_type = s_public;
-			  fprintfi_filtered (level + 2, stream,
-					     "public:\n");
-			}
-		    }
-		}
+		if (need_access_label)
+		  {
+		    if (TYPE_FIELD_PROTECTED (type, i))
+		      {
+			if (section_type != s_protected)
+			  {
+			    section_type = s_protected;
+			    fprintfi_filtered (level + 2, stream,
+					       "protected:\n");
+			  }
+		      }
+		    else if (TYPE_FIELD_PRIVATE (type, i))
+		      {
+			if (section_type != s_private)
+			  {
+			    section_type = s_private;
+			    fprintfi_filtered (level + 2, stream,
+					       "private:\n");
+			  }
+		      }
+		    else
+		      {
+			if (section_type != s_public)
+			  {
+			    section_type = s_public;
+			    fprintfi_filtered (level + 2, stream,
+					       "public:\n");
+			  }
+		      }
+		  }
 
-	      print_spaces_filtered (level + 4, stream);
-	      if (field_is_static (&TYPE_FIELD (type, i)))
-		fprintf_filtered (stream, "static ");
-	      c_print_type (TYPE_FIELD_TYPE (type, i),
-			    TYPE_FIELD_NAME (type, i),
-			    stream, show - 1, level + 4, flags);
-	      if (!field_is_static (&TYPE_FIELD (type, i))
-		  && TYPE_FIELD_PACKED (type, i))
-		{
-		  /* It is a bitfield.  This code does not attempt
-		     to look at the bitpos and reconstruct filler,
-		     unnamed fields.  This would lead to misleading
-		     results if the compiler does not put out fields
-		     for such things (I don't know what it does).  */
-		  fprintf_filtered (stream, " : %d",
-				    TYPE_FIELD_BITSIZE (type, i));
-		}
-	      fprintf_filtered (stream, ";\n");
-	    }
+		print_spaces_filtered (level + 4, stream);
+		if (field_is_static (&TYPE_FIELD (type, i)))
+		  fprintf_filtered (stream, "static ");
+		c_print_type (TYPE_FIELD_TYPE (type, i),
+			      TYPE_FIELD_NAME (type, i),
+			      stream, show - 1, level + 4,
+			      &local_flags);
+		if (!field_is_static (&TYPE_FIELD (type, i))
+		    && TYPE_FIELD_PACKED (type, i))
+		  {
+		    /* It is a bitfield.  This code does not attempt
+		       to look at the bitpos and reconstruct filler,
+		       unnamed fields.  This would lead to misleading
+		       results if the compiler does not put out fields
+		       for such things (I don't know what it does).  */
+		    fprintf_filtered (stream, " : %d",
+				      TYPE_FIELD_BITSIZE (type, i));
+		  }
+		fprintf_filtered (stream, ";\n");
+	      }
 
 	  /* If there are both fields and methods, put a blank line
 	     between them.  Make sure to count only method that we
@@ -1061,7 +1201,8 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 			   && !is_type_conversion_operator (type, i, j))
 		    {
 		      c_print_type (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
-				    "", stream, -1, 0, flags);
+				    "", stream, -1, 0,
+				    &local_flags);
 		      fputs_filtered (" ", stream);
 		    }
 		  if (TYPE_FN_FIELD_STUB (f, j))
@@ -1082,10 +1223,10 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 		  if (demangled_name == NULL)
 		    {
 		      /* In some cases (for instance with the HP
-		         demangling), if a function has more than 10
-		         arguments, the demangling will fail.
-		         Let's try to reconstruct the function
-		         signature from the symbol information.  */
+			 demangling), if a function has more than 10
+			 arguments, the demangling will fail.
+			 Let's try to reconstruct the function
+			 signature from the symbol information.  */
 		      if (!TYPE_FN_FIELD_STUB (f, j))
 			{
 			  int staticp = TYPE_FN_FIELD_STATIC_P (f, j);
@@ -1095,7 +1236,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 						     "",
 						     method_name,
 						     staticp,
-						     stream, flags);
+						     stream, &local_flags);
 			}
 		      else
 			fprintf_filtered (stream,
@@ -1142,30 +1283,40 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 	      if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0)
 		fprintf_filtered (stream, "\n");
 
-	      for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
-		{
-		  struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i);
+		for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
+		  {
+		    struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i);
+		    struct typedef_hash_table *table2;
+
+		    /* Dereference the typedef declaration itself.  */
+		    gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
+		    target = TYPE_TARGET_TYPE (target);
+
+		    print_spaces_filtered (level + 4, stream);
+		    fprintf_filtered (stream, "typedef ");
+
+		    /* We want to print typedefs with substitutions
+		       from the template parameters or globally-known
+		       typedefs but not local typedefs.  */
+		    c_print_type (target,
+				  TYPE_TYPEDEF_FIELD_NAME (type, i),
+				  stream, show - 1, level + 4,
+				  &semi_local_flags);
+		    fprintf_filtered (stream, ";\n");
+		  }
+	      }
 
-		  /* Dereference the typedef declaration itself.  */
-		  gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
-		  target = TYPE_TARGET_TYPE (target);
+	    fprintfi_filtered (level, stream, "}");
 
-		  print_spaces_filtered (level + 4, stream);
-		  fprintf_filtered (stream, "typedef ");
-		  c_print_type (target, TYPE_TYPEDEF_FIELD_NAME (type, i),
-				stream, show - 1, level + 4, flags);
-		  fprintf_filtered (stream, ";\n");
-		}
-	    }
-
-	  fprintfi_filtered (level, stream, "}");
+	    if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
+	      fprintfi_filtered (level,
+				 stream, _(" (Local at %s:%d)\n"),
+				 TYPE_LOCALTYPE_FILE (type),
+				 TYPE_LOCALTYPE_LINE (type));
+	  }
 
-	  if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
-	    fprintfi_filtered (level,
-			       stream, _(" (Local at %s:%d)\n"),
-			       TYPE_LOCALTYPE_FILE (type),
-			       TYPE_LOCALTYPE_LINE (type));
-	}
+	do_cleanups (local_cleanups);
+      }
       break;
 
     case TYPE_CODE_ENUM:
@@ -1179,7 +1330,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       if (TYPE_TAG_NAME (type) != NULL
 	  && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
 	{
-	  fputs_filtered (TYPE_TAG_NAME (type), stream);
+	  print_name_maybe_canonical (TYPE_TAG_NAME (type), flags, stream);
 	  if (show > 0)
 	    fputs_filtered (" ", stream);
 	}
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 8ac8799..0bccf94 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -2406,7 +2406,7 @@ integer_types_same_name_p (const char *first, const char *second)
 /* Compares type A to type B returns 1 if the represent the same type
    0 otherwise.  */
 
-static int
+int
 types_equal (struct type *a, struct type *b)
 {
   /* Identical type pointers.  */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 73fcbb1..47b7c0e 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1657,4 +1657,6 @@ extern struct type *copy_type_recursive (struct objfile *objfile,
 
 extern struct type *copy_type (const struct type *type);
 
+extern int types_equal (struct type *, struct type *);
+
 #endif /* GDBTYPES_H */
diff --git a/gdb/testsuite/gdb.cp/ptype-flags.cc b/gdb/testsuite/gdb.cp/ptype-flags.cc
new file mode 100644
index 0000000..3077f73
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ptype-flags.cc
@@ -0,0 +1,47 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   */
+
+template<typename S>
+class Simple
+{
+  S val;
+};
+
+template<typename T>
+class Base
+{
+};
+
+template<typename T>
+class Holder : public Base<T>
+{
+public:
+  Simple<T> t;
+  Simple<T*> tstar;
+
+  typedef Simple< Simple<T> > Z;
+
+  Z z;
+
+  double method(void) { return 23.0; }
+};
+
+Holder<int> value;
+
+int main()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/ptype-flags.exp b/gdb/testsuite/gdb.cp/ptype-flags.exp
new file mode 100644
index 0000000..a992b9c
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ptype-flags.exp
@@ -0,0 +1,85 @@
+# Copyright 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set nl		"\[\r\n\]+"
+
+if { [skip_cplus_tests] } { continue }
+
+load_lib "cp-support.exp"
+
+standard_testfile .cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    return
+}
+
+gdb_test_no_output "set language c++" ""
+gdb_test_no_output "set width 0" ""
+
+proc do_check {name {flags ""} {show_typedefs 1} {show_methods 1} {raw 0}} {
+    set contents {
+	{ base "public Base<T>" }
+	{ field public "Simple<T> t;" }
+	{ field public "Simple<T*> tstar;" }
+    }
+
+    if {$raw} {
+	lappend contents { field public "Holder<int>::Z z;" }
+    } else {
+	lappend contents { field public "Z z;" }
+    }
+
+    if {$show_typedefs} {
+	lappend contents { typedef public "Simple<Simple<T> > Z;" }
+    }
+
+    if {$show_methods} {
+	lappend contents { method public "double method();" }
+    }
+
+    if {$raw} {
+	regsub -all -- "T" $contents "int" contents
+    }
+
+    cp_test_ptype_class value $name "class" "Holder<int>" $contents \
+	"" {} $flags
+}
+
+do_check "basic test"
+do_check "no methods" "/m" 1 0
+do_check "no typedefs" "/t" 0 1
+do_check "no methods or typedefs" "/mt" 0 0
+
+do_check "raw" "/r" 1 1 1
+do_check "raw no methods" "/rm" 1 0 1
+do_check "raw no typedefs" "/rt" 0 1 1
+do_check "raw no methods or typedefs" "/rmt" 0 0 1
+
+gdb_test_no_output "set print type methods off"
+do_check "basic test, default methods off" "" 1 0
+do_check "methods, default methods off" "/M" 1 1
+do_check "no typedefs, default methods off" "/t" 0 0
+do_check "methods, no typedefs, default methods off" "/Mt" 0 1
+
+gdb_test_no_output "set print type typedefs off"
+do_check "basic test, default methods+typedefs off" "" 0 0
+do_check "methods, default methods+typedefs off" "/M" 0 1
+do_check "typedefs, default methods+typedefs off" "/T" 1 0
+do_check "methods typedefs, default methods+typedefs off" "/MT" 1 1
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 47915b1..9ebb3bd 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -40,7 +40,7 @@ proc test_ptype_of_templates {} {
     global gdb_prompt
     global ws
 
-    gdb_test_multiple "ptype T5<int>" "ptype T5<int>" {
+    gdb_test_multiple "ptype/r T5<int>" "ptype T5<int>" {
 	-re "type = class T5<int> \{${ws}public:${ws}static int X;${ws}int x;${ws}int val;${ws}T5<int> & operator=\\(T5<int> const ?&\\);${ws}T5\\(int\\);${ws}T5\\((T5<int> const|const T5<int>) ?&\\);${ws}~T5\\((void|)\\);${ws}static void \\* operator new\\(unsigned( int| long)?\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\}\r\n$gdb_prompt $" {
 	    xfail "ptype T5<int> -- new without size_t"
 	}
@@ -63,7 +63,7 @@ proc test_ptype_of_templates {} {
 	}
     }
 
-    gdb_test_multiple "ptype t5i" "ptype t5i" {
+    gdb_test_multiple "ptype/r t5i" "ptype t5i" {
         -re "type = class T5<int> \\{${ws}public:${ws}static int X;${ws}int x;${ws}int val;\r\n${ws}T5\\(int\\);${ws}T5\\(T5<int> const ?&\\);${ws}~T5\\((void|)\\);${ws}static void \\* operator new\\(unsigned( int| long)?\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\\}\r\n$gdb_prompt $" {
 	    xfail "ptype T5<int> -- with several fixes from 4.17 -- without size_t"
 	}
@@ -226,11 +226,13 @@ proc test_template_typedef {} {
 proc test_template_args {} {
 
     set empty_re "Empty *<void *\\(FunctionArg *<int>\\)>"
-    gdb_test "ptype empty" \
-	"type = (struct|class) $empty_re {.*<no data fields>.*}"
+    gdb_test "ptype/r empty" \
+	"type = (struct|class) $empty_re {.*<no data fields>.*}" \
+	"ptype empty"
 
-    gdb_test "ptype arg" \
-	"type = (struct|class) FunctionArg<int> {.*int method\\($empty_re \\&\\);.*}"
+    gdb_test "ptype/r arg" \
+	"type = (struct|class) FunctionArg<int> {.*int method\\($empty_re \\&\\);.*}" \
+	"ptype arg"
 }
 
 proc do_tests {} {
@@ -291,7 +293,7 @@ gdb_test "print fvpchar" \
 # NOTE: carlton/2003-02-26: However, because of a bug in the way GDB
 # handles nested types, we don't get this right in the DWARF-2 case.
 
-gdb_test_multiple "ptype Foo" "ptype Foo" {
+gdb_test_multiple "ptype/r Foo" "ptype Foo" {
     -re "type = template <(class |)T> (class |)Foo \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Foo<volatile char \\*>\r\n\[ \t\]*(class |)Foo<char>\r\n\[ \t\]*(class |)Foo<int>\r\n$gdb_prompt $" {
 	pass "ptype Foo"
     }
@@ -312,7 +314,7 @@ gdb_test_multiple "ptype Foo" "ptype Foo" {
 
 # ptype Foo<int>
 
-gdb_test_multiple "ptype fint" "ptype fint" {
+gdb_test_multiple "ptype/r fint" "ptype fint" {
     -re "type = (class |)Foo<int> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int foo\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fint"
     }
@@ -323,7 +325,7 @@ gdb_test_multiple "ptype fint" "ptype fint" {
 
 # ptype Foo<char>
 
-gdb_test_multiple "ptype fchar" "ptype fchar" {
+gdb_test_multiple "ptype/r fchar" "ptype fchar" {
     -re "type = (class |)Foo<char> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*.*char foo\\(int, char\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fchar"
     }
@@ -334,7 +336,7 @@ gdb_test_multiple "ptype fchar" "ptype fchar" {
 
 # ptype Foo<volatile char *>
 
-gdb_test_multiple "ptype fvpchar" "ptype fvpchar" {
+gdb_test_multiple "ptype/r fvpchar" "ptype fvpchar" {
     -re "type = (class |)Foo<volatile char ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*char.*\\*t;\r\n\r\n\[ \t\]*.*char \\* foo\\(int,.*char.*\\*\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fvpchar"
     }
@@ -374,7 +376,7 @@ gdb_test_multiple "print Foo<volatile char*>::foo" "print Foo<volatile char*>::f
 # Template Bar<T, int>
 
 # same as Foo for g++
-gdb_test_multiple "ptype Bar" "ptype Bar" {
+gdb_test_multiple "ptype/r Bar" "ptype Bar" {
     -re "type = template <(class |)T, (class |)sz> (class |)Bar \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Bar<int,(\\(int\\)|)1>\r\n\[ \t\]*(class |)Bar<int,(\\(int\\)|)33>\r\n$gdb_prompt $" {
 	pass "ptype Bar"
     }
@@ -394,7 +396,7 @@ gdb_test_multiple "ptype Bar" "ptype Bar" {
 
 # ptype Bar<int,33>
 
-gdb_test_multiple "ptype bint" "ptype bint" {
+gdb_test_multiple "ptype/r bint" "ptype bint" {
     -re "type = (class |)Bar<int, ?(\\(int\\)|)33> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int bar\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bint"
     }
@@ -405,7 +407,7 @@ gdb_test_multiple "ptype bint" "ptype bint" {
 
 # ptype Bar<int, (4>3)>
 
-gdb_test_multiple "ptype bint2" "ptype bint2" {
+gdb_test_multiple "ptype/r bint2" "ptype bint2" {
     -re "type = (class |)Bar<int, ?(\\(int\\)|)1> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int bar\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bint2"
     }
@@ -417,7 +419,7 @@ gdb_test_multiple "ptype bint2" "ptype bint2" {
 # Template Baz<T, char>
 
 # Same as Foo, for g++
-gdb_test_multiple "ptype Baz" "ptype Baz" {
+gdb_test_multiple "ptype/r Baz" "ptype Baz" {
     -re "type = template <(class |)T, ?(class |)sz> (class |)Baz \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Baz<char,(\\(char\\)|)97>\r\n\[ \t\]*(class |)Baz<int,(\\(char\\)|)115>\r\n$gdb_prompt $" {
 	pass "ptype Baz"
     }
@@ -441,7 +443,7 @@ gdb_test_multiple "ptype Baz" "ptype Baz" {
 
 # ptype Baz<int, 's'>
 
-gdb_test_multiple "ptype bazint" "ptype bazint" {
+gdb_test_multiple "ptype/r bazint" "ptype bazint" {
     -re "type = (class |)Baz<int, ?(\\(char\\)|)(115|\\'s\\')> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int baz\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bazint"
     }
@@ -452,7 +454,7 @@ gdb_test_multiple "ptype bazint" "ptype bazint" {
 
 # ptype Baz<char, 'a'>
 
-gdb_test_multiple "ptype bazint2" "ptype bazint2" {
+gdb_test_multiple "ptype/r bazint2" "ptype bazint2" {
     -re "type = (class |)Baz<char, ?(\\(char\\)|)(97|\\'a\\')> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*.*char baz\\(int, char\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bazint2"
     }
@@ -463,7 +465,7 @@ gdb_test_multiple "ptype bazint2" "ptype bazint2" {
 
 # Template Qux<T, int (*f)(int) >
 # Same as Foo for g++
-gdb_test_multiple "ptype Qux" "ptype Qux" {
+gdb_test_multiple "ptype/r Qux" "ptype Qux" {
     -re "type = template <(class |)T, ?(class |)sz> (class |)Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Qux<int,&string>\r\n\[ \t\]*(class |)Qux<char,&string>\r\n$gdb_prompt $" {
 	pass "ptype Qux"
     }
@@ -486,7 +488,7 @@ gdb_test_multiple "ptype Qux" "ptype Qux" {
 
 # pt Qux<int,&string>
 
-gdb_test_multiple "ptype quxint" "ptype quxint" {
+gdb_test_multiple "ptype/r quxint" "ptype quxint" {
     -re "type = class Qux<int, ?& ?string> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int qux\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype quxint"
     }
@@ -505,7 +507,7 @@ gdb_test_multiple "ptype quxint" "ptype quxint" {
 # Template Spec<T1, T2>
 
 # Same as Foo for g++
-gdb_test_multiple "ptype Spec" "ptype Spec" {
+gdb_test_multiple "ptype/r Spec" "ptype Spec" {
     -re "type = template <(class |)T1, (class |)T2> (class |)Spec \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Spec<int,int \\*>\r\n\[ \t\]*(class |)Spec<int,char>\r\n$gdb_prompt $" {
 	pass "ptype Spec"
     }
@@ -524,7 +526,7 @@ gdb_test_multiple "ptype Spec" "ptype Spec" {
 
 # pt Spec<char,0>
 
-gdb_test_multiple "ptype siip" "ptype siip" {
+gdb_test_multiple "ptype/r siip" "ptype siip" {
     -re "type = class Spec<int, ?int ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\r\n\[ \t\]*.*int spec\\(int ?\\*\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype siip"
     }
@@ -535,7 +537,7 @@ gdb_test_multiple "ptype siip" "ptype siip" {
 
 # pt Garply<int>
 
-gdb_test_multiple "ptype Garply<int>" "ptype Garply<int>" {
+gdb_test_multiple "ptype/r Garply<int>" "ptype Garply<int>" {
     -re "type = class Garply<int> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int garply\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype Garply<int>"
     }
@@ -546,7 +548,7 @@ gdb_test_multiple "ptype Garply<int>" "ptype Garply<int>" {
 
 # ptype of nested template name
 
-gdb_test_multiple "ptype Garply<Garply<char> >" "ptype Garply<Garply<char> >" {
+gdb_test_multiple "ptype/r Garply<Garply<char> >" "ptype Garply<Garply<char> >" {
     -re "type = (class |)Garply<Garply<char> > \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*(class |)Garply<char> t;\r\n\r\n\[ \t\]*.*(class |)Garply<char> garply\\(int, (class |)Garply<char>\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype Garply<Garply<char> >"
     }
diff --git a/gdb/testsuite/gdb.mi/mi-var-child.exp b/gdb/testsuite/gdb.mi/mi-var-child.exp
index 1d72311..b536c22 100644
--- a/gdb/testsuite/gdb.mi/mi-var-child.exp
+++ b/gdb/testsuite/gdb.mi/mi-var-child.exp
@@ -64,14 +64,14 @@ mi_list_varobj_children "struct_declarations" {
     {struct_declarations.integer integer 0 int}
     {struct_declarations.character character 0 char}
     {struct_declarations.char_ptr char_ptr 1 "char \\*"}
-    {struct_declarations.long_int long_int 0 "long int"}
+    {struct_declarations.long_int long_int 0 "long( int)?"}
     {struct_declarations.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {struct_declarations.long_array long_array 12 "long int \\[12\\]"}
+    {struct_declarations.long_array long_array 12 "long( int)? \\[12\\]"}
     {struct_declarations.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {struct_declarations.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long( int)?\\))?"}
     {struct_declarations.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long( int)?)?\\)"}
     {struct_declarations.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {struct_declarations.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of struct_declarations"
@@ -150,7 +150,8 @@ mi_gdb_test "-var-info-num-children struct_declarations.int_ptr_ptr" \
 
 # Test: c_variable-4.15
 # Desc: children of struct_declarations.long_array
-mi_list_array_varobj_children "struct_declarations.long_array" 12 "long int" \
+mi_list_array_varobj_children "struct_declarations.long_array" 12 \
+    "long( int)?" \
     "get children of struct_declarations.long_array"
 
 # Test: c_variable-4.16
@@ -199,7 +200,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.func_ptr_ptr" \
 mi_list_varobj_children "struct_declarations.u1" {
     {struct_declarations.u1.a a 0 int}
     {struct_declarations.u1.b b 1 {char \*}}
-    {struct_declarations.u1.c c 0 {long int}}
+    {struct_declarations.u1.c c 0 {long( int)?}}
     {struct_declarations.u1.d d 0 {enum foo}}
 } "get children of struct_declarations.u1"
 
@@ -215,7 +216,7 @@ mi_list_varobj_children "struct_declarations.s2" {
     {struct_declarations.s2.u2 u2 3 {union \{\.\.\.\}}}
     {struct_declarations.s2.g g 0 int}
     {struct_declarations.s2.h h 0 char}
-    {struct_declarations.s2.i i 10 {long int \[10\]}}
+    {struct_declarations.s2.i i 10 {long( int)? \[10\]}}
 } "get children of struct_declarations.s2"
 
 #gdbtk_test c_variable-4.25 {children of struct_declarations.s2} {
@@ -289,7 +290,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.u1.d" \
 # Desc: children of struct_declarations.s2.u2
 mi_list_varobj_children "struct_declarations.s2.u2" {
     {"struct_declarations.s2.u2.u1s1" "u1s1" 4 {struct \{\.\.\.\}}}
-    {struct_declarations.s2.u2.f f 0 "long int"}
+    {struct_declarations.s2.u2.f f 0 "long( int)?"}
     {struct_declarations.s2.u2.u1s2 u1s2 2 {struct \{\.\.\.\}}}
 } "get children of struct_declarations.s2.u2"
 
@@ -327,7 +328,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.s2.h" \
 # Desc: children of struct_declarations.s2.i
 set t {}
 for {set i 0} {$i < 10} {incr i} {
-    lappend t [list struct_declarations.s2.i.$i $i 0 "long int"]
+    lappend t [list struct_declarations.s2.i.$i $i 0 "long( int)?"]
 }
 mi_list_varobj_children struct_declarations.s2.i $t \
 	"get children of struct_declarations.s2.i"
@@ -481,14 +482,14 @@ mi_list_varobj_children "weird" {
     {weird.integer integer 0 int}
     {weird.character character 0 char}
     {weird.char_ptr char_ptr 1 "char \\*"}
-    {weird.long_int long_int 0 "long int"}
+    {weird.long_int long_int 0 "long( int)?"}
     {weird.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {weird.long_array long_array 12 "long int \\[12\\]"}
+    {weird.long_array long_array 12 "long( int)? \\[12\\]"}
     {weird.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {weird.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long( int)?\\))?"}
     {weird.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long( int)?)?\\)"}
     {weird.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {weird.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of weird"
@@ -502,7 +503,7 @@ mi_gdb_test "-var-info-num-children weird" \
 
 # Test: c_variable-4.84
 # Desc: children of weird->long_array
-mi_list_array_varobj_children weird.long_array 12 "long int" \
+mi_list_array_varobj_children weird.long_array 12 "long( int)?" \
 	"get children of weird.long_array"
 #gdbtk_test c_variable-4.84 {children of weird->long_array} {
 #  get_children weird.long_array
@@ -783,18 +784,18 @@ mi_gdb_test "-var-update --all-values *" \
  "update all vars struct_declarations.long_array.11 changed, print values."
 
 mi_list_varobj_children {struct_declarations.long_array --all-values} {
-    {struct_declarations.long_array.0 0 0 "long int" 1234}
-    {struct_declarations.long_array.1 1 0 "long int" 2345}
-    {struct_declarations.long_array.2 2 0 "long int" 3456}
-    {struct_declarations.long_array.3 3 0 "long int" 4567}
-    {struct_declarations.long_array.4 4 0 "long int" 5678}
-    {struct_declarations.long_array.5 5 0 "long int" 6789}
-    {struct_declarations.long_array.6 6 0 "long int" 7890}
-    {struct_declarations.long_array.7 7 0 "long int" 8901}
-    {struct_declarations.long_array.8 8 0 "long int" 9012}
-    {struct_declarations.long_array.9 9 0 "long int" 1234}
-    {struct_declarations.long_array.10 10 0 "long int" 3456}
-    {struct_declarations.long_array.11 11 0 "long int" 5678}
+    {struct_declarations.long_array.0 0 0 "long( int)?" 1234}
+    {struct_declarations.long_array.1 1 0 "long( int)?" 2345}
+    {struct_declarations.long_array.2 2 0 "long( int)?" 3456}
+    {struct_declarations.long_array.3 3 0 "long( int)?" 4567}
+    {struct_declarations.long_array.4 4 0 "long( int)?" 5678}
+    {struct_declarations.long_array.5 5 0 "long( int)?" 6789}
+    {struct_declarations.long_array.6 6 0 "long( int)?" 7890}
+    {struct_declarations.long_array.7 7 0 "long( int)?" 8901}
+    {struct_declarations.long_array.8 8 0 "long( int)?" 9012}
+    {struct_declarations.long_array.9 9 0 "long( int)?" 1234}
+    {struct_declarations.long_array.10 10 0 "long( int)?" 3456}
+    {struct_declarations.long_array.11 11 0 "long( int)?" 5678}
 } "listing of names and values of children"
 
 mi_list_varobj_children {struct_declarations --simple-values} \
@@ -802,14 +803,14 @@ mi_list_varobj_children {struct_declarations --simple-values} \
          {struct_declarations.integer integer 0 int 123} \
          {struct_declarations.character character 0 char {0 '\\\\000'}} \
          [list struct_declarations.char_ptr char_ptr 1 "char \\*" "$hex \\\\\"hello\\\\\""] \
-         {struct_declarations.long_int long_int 0 "long int" 0} \
+         {struct_declarations.long_int long_int 0 "long( int)?" 0} \
          [list struct_declarations.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*" "$hex"] \
-         {struct_declarations.long_array long_array 12 "long int \\[12\\]"} \
+         {struct_declarations.long_array long_array 12 "long( int)? \\[12\\]"} \
          [list struct_declarations.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)" "(@$hex: |)$hex <nothing>"] \
          {struct_declarations.func_ptr_struct func_ptr_struct 0 \
-              "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?" 0x0} \
+              "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long( int)?\\))?" 0x0} \
          {struct_declarations.func_ptr_ptr func_ptr_ptr 0 \
-              "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)" 0x0} \
+              "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long( int)?)?\\)" 0x0} \
          {struct_declarations.u1 u1 4 "union \\{\\.\\.\\.\\}"} \
          {struct_declarations.s2 s2 4 "struct \\{\\.\\.\\.\\}"} \
 ] "listing of children, simple types: names, type and values, complex types: names and types"
@@ -913,7 +914,7 @@ mi_create_varobj "psnp->long_ptr" "psnp->long_ptr" \
 # Test: c_variable-5.20
 # Desc: children of psnp->long_ptr
 mi_list_varobj_children "psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long int \*\*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long( int)? \*\*\*}}
 } "get children of psnp->long_ptr"
 
 # Test: c_variable-5.21
@@ -925,7 +926,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr" \
 # Test: c_variable-5.22
 # Desc: children of *(psnp->long_ptr)
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long int \*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long( int)? \*\*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr"
 
 
@@ -939,7 +940,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr" \
 # Desc: children of *(*(psnp->long_ptr))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr} \
-         {\*\*\*psnp->long_ptr} 1 {long int \*}}
+         {\*\*\*psnp->long_ptr} 1 {long( int)? \*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr"
 
 # Test: c_variable-5.25
@@ -952,7 +953,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr.**psnp->long_
 # Desc: children of *(*(*(psnp->long_ptr)))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr.\*\*\*\*psnp->long_ptr}
-        {\*\*\*\*psnp->long_ptr} 0 {long int}}
+        {\*\*\*\*psnp->long_ptr} 0 {long( int)?}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr"
 
 # Test: c_variable-5.27
@@ -995,7 +996,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs" \
 # Desc: children of psnp->ptrs[0]
 mi_list_varobj_children "psnp->ptrs.0" {
     {psnp->ptrs.0.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.long_ptr long_ptr 1 {long( int)? \*\*\*\*}}
     {psnp->ptrs.0.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0"
@@ -1010,7 +1011,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0" \
 # Desc: children of psnp->ptrs[0]->next
 mi_list_varobj_children "psnp->ptrs.0.next" {
     {psnp->ptrs.0.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long( int)? \*\*\*\*}}
     {psnp->ptrs.0.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next"
@@ -1100,7 +1101,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0.next.char_ptr.*char_ptr.**char_
 # Desc: children of psnp->ptrs[0]->next->next
 mi_list_varobj_children "psnp->ptrs.0.next.next" {
     {psnp->ptrs.0.next.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long( int)? \*\*\*\*}}
     {psnp->ptrs.0.next.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next.next"
diff --git a/gdb/testsuite/gdb.mi/mi-var-cmd.exp b/gdb/testsuite/gdb.mi/mi-var-cmd.exp
index 4c560a7..f3e8601 100644
--- a/gdb/testsuite/gdb.mi/mi-var-cmd.exp
+++ b/gdb/testsuite/gdb.mi/mi-var-cmd.exp
@@ -83,9 +83,9 @@ mi_create_varobj_checked lcharacter lcharacter\[0\] char "create local variable
 
 mi_create_varobj_checked lpcharacter lpcharacter {char \*} "create local variable lpcharacter"
 
-mi_create_varobj_checked llong llong "long int" "create local variable llong"
+mi_create_varobj_checked llong llong "long( int)?" "create local variable llong"
 
-mi_create_varobj_checked lplong lplong {long int \*} "create local variable lplong"
+mi_create_varobj_checked lplong lplong {long( int)? \*} "create local variable lplong"
 
 mi_create_varobj_checked lfloat lfloat float "create local variable lfloat"
 
@@ -408,7 +408,7 @@ mi_continue_to subroutine1
 # Desc: create variable for locals i,l in subroutine1
 mi_create_varobj_checked i i int "create i"
 
-mi_create_varobj_checked l l {long int \*} "create l"
+mi_create_varobj_checked l l {long( int)? \*} "create l"
 
 # Test: c_variable-2.11
 # Desc: create do_locals_tests local in subroutine1
diff --git a/gdb/testsuite/gdb.mi/mi-var-display.exp b/gdb/testsuite/gdb.mi/mi-var-display.exp
index 5cb5f26..b16e7ee 100644
--- a/gdb/testsuite/gdb.mi/mi-var-display.exp
+++ b/gdb/testsuite/gdb.mi/mi-var-display.exp
@@ -215,14 +215,14 @@ mi_list_varobj_children weird {
         {weird.integer integer 0 int}
         {weird.character character 0 char}
         {weird.char_ptr char_ptr 1 "char \\*"}
-        {weird.long_int long_int 0 "long int"}
+        {weird.long_int long_int 0 "long( int)?"}
         {weird.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-        {weird.long_array long_array 10 "long int \\[10\\]"}
+        {weird.long_array long_array 10 "long( int)? \\[10\\]"}
         {weird.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
         {weird.func_ptr_struct func_ptr_struct 0 \
-                 "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+                 "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long( int)?\\))?"}
         {weird.func_ptr_ptr func_ptr_ptr 0 \
-                 "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+                 "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long( int)?)?\\)"}
         {weird.u1 u1 4 "union \\{\\.\\.\\.\\}"}
         {weird.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children local variable weird"
@@ -443,7 +443,7 @@ mi_gdb_test "-var-info-num-children anonu" \
 mi_list_varobj_children "anonu" {
         {anonu.a a 0 int}
         {anonu.b b 0 char}
-        {anonu.c c 0 "long int"}
+        {anonu.c c 0 "long( int)?"}
 } "get children of anonu"
 
 # Test: c_variable-7.30
@@ -520,7 +520,7 @@ mi_gdb_test "-var-info-num-children anons" \
 mi_list_varobj_children anons {
         {anons.a a 0 int}
         {anons.b b 0 char}
-        {anons.c c 0 "long int"}
+        {anons.c c 0 "long( int)?"}
 } "get children of anons"
 
 # Test: c_variable-7.50
diff --git a/gdb/testsuite/gdb.mi/mi2-var-child.exp b/gdb/testsuite/gdb.mi/mi2-var-child.exp
index fdf12f7..0ec5bfb 100644
--- a/gdb/testsuite/gdb.mi/mi2-var-child.exp
+++ b/gdb/testsuite/gdb.mi/mi2-var-child.exp
@@ -63,14 +63,14 @@ mi_list_varobj_children "struct_declarations" {
     {struct_declarations.integer integer 0 int}
     {struct_declarations.character character 0 char}
     {struct_declarations.char_ptr char_ptr 1 "char \\*"}
-    {struct_declarations.long_int long_int 0 "long int"}
+    {struct_declarations.long_int long_int 0 "long( int)?"}
     {struct_declarations.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {struct_declarations.long_array long_array 10 "long int \\[10\\]"}
+    {struct_declarations.long_array long_array 10 "long( int)? \\[10\\]"}
     {struct_declarations.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {struct_declarations.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long( int)?\\))?"}
     {struct_declarations.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long( int)?)?\\)"}
     {struct_declarations.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {struct_declarations.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of struct_declarations"
@@ -150,7 +150,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.int_ptr_ptr" \
 
 # Test: c_variable-4.15
 # Desc: children of struct_declarations.long_array
-mi_list_array_varobj_children "struct_declarations.long_array" 10 "long int" \
+mi_list_array_varobj_children "struct_declarations.long_array" 10 "long( int)?" \
     "get children of struct_declarations.long_array"
 
 # Test: c_variable-4.16
@@ -199,7 +199,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.func_ptr_ptr" \
 mi_list_varobj_children "struct_declarations.u1" {
     {struct_declarations.u1.a a 0 int}
     {struct_declarations.u1.b b 1 {char \*}}
-    {struct_declarations.u1.c c 0 {long int}}
+    {struct_declarations.u1.c c 0 {long( int)?}}
     {struct_declarations.u1.d d 0 {enum foo}}
 } "get children of struct_declarations.u1"
 
@@ -215,7 +215,7 @@ mi_list_varobj_children "struct_declarations.s2" {
     {struct_declarations.s2.u2 u2 3 {union \{\.\.\.\}}}
     {struct_declarations.s2.g g 0 int}
     {struct_declarations.s2.h h 0 char}
-    {struct_declarations.s2.i i 10 {long int \[10\]}}
+    {struct_declarations.s2.i i 10 {long( int)? \[10\]}}
 } "get children of struct_declarations.s2"
 
 #gdbtk_test c_variable-4.25 {children of struct_declarations.s2} {
@@ -289,7 +289,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.u1.d" \
 # Desc: children of struct_declarations.s2.u2
 mi_list_varobj_children "struct_declarations.s2.u2" {
     {"struct_declarations.s2.u2.u1s1" "u1s1" 4 {struct \{\.\.\.\}}}
-    {struct_declarations.s2.u2.f f 0 "long int"}
+    {struct_declarations.s2.u2.f f 0 "long( int)?"}
     {struct_declarations.s2.u2.u1s2 u1s2 2 {struct \{\.\.\.\}}}
 } "get children of struct_declarations.s2.u2"
 
@@ -327,7 +327,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.s2.h" \
 # Desc: children of struct_declarations.s2.i
 set t {}
 for {set i 0} {$i < 10} {incr i} {
-    lappend t [list struct_declarations.s2.i.$i $i 0 "long int"]
+    lappend t [list struct_declarations.s2.i.$i $i 0 "long( int)?"]
 }
 mi_list_varobj_children struct_declarations.s2.i $t \
 	"get children of struct_declarations.s2.i"
@@ -481,14 +481,14 @@ mi_list_varobj_children "weird" {
     {weird.integer integer 0 int}
     {weird.character character 0 char}
     {weird.char_ptr char_ptr 1 "char \\*"}
-    {weird.long_int long_int 0 "long int"}
+    {weird.long_int long_int 0 "long( int)?"}
     {weird.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {weird.long_array long_array 10 "long int \\[10\\]"}
+    {weird.long_array long_array 10 "long( int)? \\[10\\]"}
     {weird.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {weird.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long( int)?\\))?"}
     {weird.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long( int)?)?\\)"}
     {weird.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {weird.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of weird"
@@ -502,7 +502,7 @@ mi_gdb_test "-var-info-num-children weird" \
 
 # Test: c_variable-4.84
 # Desc: children of weird->long_array
-mi_list_array_varobj_children weird.long_array 10 "long int" \
+mi_list_array_varobj_children weird.long_array 10 "long( int)?" \
 	"get children of weird.long_array"
 #gdbtk_test c_variable-4.84 {children of weird->long_array} {
 #  get_children weird.long_array
@@ -865,7 +865,7 @@ mi_create_varobj "psnp->long_ptr" "psnp->long_ptr" \
 # Test: c_variable-5.20
 # Desc: children of psnp->long_ptr
 mi_list_varobj_children "psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long int \*\*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long( int)? \*\*\*}}
 } "get children of psnp->long_ptr"
 
 # Test: c_variable-5.21
@@ -877,7 +877,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr" \
 # Test: c_variable-5.22
 # Desc: children of *(psnp->long_ptr)
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long int \*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long( int)? \*\*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr"
 
 
@@ -891,7 +891,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr" \
 # Desc: children of *(*(psnp->long_ptr))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr} \
-         {\*\*\*psnp->long_ptr} 1 {long int \*}}
+         {\*\*\*psnp->long_ptr} 1 {long( int)? \*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr"
 
 # Test: c_variable-5.25
@@ -904,7 +904,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr.**psnp->long_
 # Desc: children of *(*(*(psnp->long_ptr)))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr.\*\*\*\*psnp->long_ptr}
-        {\*\*\*\*psnp->long_ptr} 0 {long int}}
+        {\*\*\*\*psnp->long_ptr} 0 {long( int)?}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr"
 
 # Test: c_variable-5.27
@@ -948,7 +948,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs" \
 # Desc: children of psnp->ptrs[0]
 mi_list_varobj_children "psnp->ptrs.0" {
     {psnp->ptrs.0.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.long_ptr long_ptr 1 {long( int)? \*\*\*\*}}
     {psnp->ptrs.0.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0"
@@ -963,7 +963,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0" \
 # Desc: children of psnp->ptrs[0]->next
 mi_list_varobj_children "psnp->ptrs.0.next" {
     {psnp->ptrs.0.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long( int)? \*\*\*\*}}
     {psnp->ptrs.0.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next"
@@ -1053,7 +1053,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0.next.char_ptr.*char_ptr.**char_
 # Desc: children of psnp->ptrs[0]->next->next
 mi_list_varobj_children "psnp->ptrs.0.next.next" {
     {psnp->ptrs.0.next.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long( int)? \*\*\*\*}}
     {psnp->ptrs.0.next.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next.next"
diff --git a/gdb/testsuite/gdb.mi/mi2-var-cmd.exp b/gdb/testsuite/gdb.mi/mi2-var-cmd.exp
index 5af2af8..78bd5b7 100644
--- a/gdb/testsuite/gdb.mi/mi2-var-cmd.exp
+++ b/gdb/testsuite/gdb.mi/mi2-var-cmd.exp
@@ -82,9 +82,9 @@ mi_create_varobj_checked lcharacter lcharacter\[0\] char "create local variable
 
 mi_create_varobj_checked lpcharacter lpcharacter {char \*} "create local variable lpcharacter"
 
-mi_create_varobj_checked llong llong "long int" "create local variable llong"
+mi_create_varobj_checked llong llong "long( int)?" "create local variable llong"
 
-mi_create_varobj_checked lplong lplong {long int \*} "create local variable lplong"
+mi_create_varobj_checked lplong lplong {long( int)? \*} "create local variable lplong"
 
 mi_create_varobj_checked lfloat lfloat float "create local variable lfloat"
 
@@ -370,7 +370,7 @@ mi_continue_to "subroutine1"
 # Desc: create variable for locals i,l in subroutine1
 mi_create_varobj_checked i i int "create i"
 
-mi_create_varobj_checked l l {long int \*} "create l"
+mi_create_varobj_checked l l {long( int)? \*} "create l"
 
 # Test: c_variable-2.11
 # Desc: create do_locals_tests local in subroutine1
diff --git a/gdb/testsuite/gdb.mi/mi2-var-display.exp b/gdb/testsuite/gdb.mi/mi2-var-display.exp
index 4bb1cd8..9e79d3e 100644
--- a/gdb/testsuite/gdb.mi/mi2-var-display.exp
+++ b/gdb/testsuite/gdb.mi/mi2-var-display.exp
@@ -214,14 +214,14 @@ mi_list_varobj_children weird {
         {weird.integer integer 0 int}
         {weird.character character 0 char}
         {weird.char_ptr char_ptr 1 "char \\*"}
-        {weird.long_int long_int 0 "long int"}
+        {weird.long_int long_int 0 "long( int)?"}
         {weird.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-        {weird.long_array long_array 10 "long int \\[10\\]"}
+        {weird.long_array long_array 10 "long( int)? \\[10\\]"}
         {weird.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
         {weird.func_ptr_struct func_ptr_struct 0 \
-                 "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+                 "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long( int)?\\))?"}
         {weird.func_ptr_ptr func_ptr_ptr 0 \
-                 "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+                 "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long( int)?)?\\)"}
         {weird.u1 u1 4 "union \\{\\.\\.\\.\\}"}
         {weird.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children local variable weird"
@@ -442,7 +442,7 @@ mi_gdb_test "-var-info-num-children anonu" \
 mi_list_varobj_children "anonu" {
         {anonu.a a 0 int}
         {anonu.b b 0 char}
-        {anonu.c c 0 "long int"}
+        {anonu.c c 0 "long( int)?"}
 } "get children of anonu"
 
 # Test: c_variable-7.30
@@ -519,7 +519,7 @@ mi_gdb_test "-var-info-num-children anons" \
 mi_list_varobj_children anons {
         {anons.a a 0 int}
         {anons.b b 0 char}
-        {anons.c c 0 "long int"}
+        {anons.c c 0 "long( int)?"}
 } "get children of anons"
 
 # Test: c_variable-7.50
diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp
index b984f4d..827fda8 100644
--- a/gdb/testsuite/lib/cp-support.exp
+++ b/gdb/testsuite/lib/cp-support.exp
@@ -101,6 +101,8 @@ proc cp_check_errata { expected_string actual_string errata_table } {
 # demangler syntax adjustment, so you have to make a bigger table
 # with lines for each output variation.
 # 
+# IN_PTYPE_ARG are arguments to pass to ptype.  The default is "/r".
+#
 # gdb can vary the output of ptype in several ways:
 #
 # . CLASS/STRUCT
@@ -179,15 +181,16 @@ proc cp_check_errata { expected_string actual_string errata_table } {
 #
 # -- chastain 2004-08-07
 
-proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } } {
+proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } { in_ptype_arg /r } } {
     global gdb_prompt
     set wsopt "\[\r\n\t \]*"
 
-    # The test name defaults to the command.
+    # The test name defaults to the command, but without the
+    # arguments, for historical reasons.
 
     if { "$in_testname" == "" } then { set in_testname "ptype $in_exp" }
 
-    set in_command "ptype $in_exp"
+    set in_command "ptype${in_ptype_arg} $in_exp"
 
     # Save class tables in a history array for reuse.
 
@@ -233,13 +236,13 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
 
     set parse_okay 0
     gdb_test_multiple "$in_command" "$in_testname // parse failed" {
-	-re "type = (struct|class)${wsopt}(\[A-Za-z0-9_\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" {
+	-re "type = (struct|class)${wsopt}(\[^ \t\]*)${wsopt}(\\\[with .*\\\]${wsopt})?((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" {
 	    set parse_okay          1
 	    set actual_key          $expect_out(1,string)
 	    set actual_tag          $expect_out(2,string)
-	    set actual_base_string  $expect_out(3,string)
-	    set actual_body         $expect_out(5,string)
-	    set actual_tail         $expect_out(6,string)
+	    set actual_base_string  $expect_out(4,string)
+	    set actual_body         $expect_out(6,string)
+	    set actual_tail         $expect_out(7,string)
 	}
     }
     if { ! $parse_okay } then { return }
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 509b3ee..0e1c93c 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -51,7 +51,8 @@ const struct type_print_options type_print_raw_options =
 {
   1,				/* raw */
   1,				/* print_methods */
-  1				/* print_typedefs */
+  1,				/* print_typedefs */
+  NULL				/* local_typedefs */
 };
 
 /* The default flags for 'ptype' and 'whatis'.  */
@@ -60,11 +61,202 @@ static struct type_print_options default_ptype_flags =
 {
   0,				/* raw */
   1,				/* print_methods */
-  1				/* print_typedefs */
+  1,				/* print_typedefs */
+  NULL				/* local_typedefs */
 };
 
 \f
 
+/* 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
+hash_typedef_field (const void *p)
+{
+  const struct typedef_field *tf = p;
+  struct type *t = check_typedef (tf->type);
+
+  return htab_hash_string (TYPE_SAFE_NAME (t));
+}
+
+/* An equality function for a typedef field.  */
+
+static int
+eq_typedef_field (const void *a, const void *b)
+{
+  const struct typedef_field *tfa = a;
+  const struct typedef_field *tfb = b;
+
+  return types_equal (tfa->type, tfb->type);
+}
+
+/* Add typedefs from T to the hash table TABLE.  */
+
+void
+recursively_update_typedef_hash (struct typedef_hash_table *table,
+				 struct type *t)
+{
+  int i;
+
+  if (table == NULL)
+    return;
+
+  for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
+    {
+      struct typedef_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
+      void **slot;
+
+      slot = htab_find_slot (table->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.  */
+      if (*slot == NULL)
+	*slot = tdef;
+    }
+
+  /* Recurse into superclasses.  */
+  for (i = 0; i < TYPE_N_BASECLASSES (t); ++i)
+    recursively_update_typedef_hash (table, TYPE_BASECLASS (t, i));
+}
+
+/* Add template parameters from T to the typedef hash TABLE.  */
+
+void
+add_template_parameters (struct typedef_hash_table *table, struct type *t)
+{
+  int i;
+
+  if (table == NULL)
+    return;
+
+  for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
+    {
+      struct typedef_field *tf;
+      void **slot;
+
+      /* We only want type-valued template parameters in the hash.  */
+      if (SYMBOL_CLASS (TYPE_TEMPLATE_ARGUMENT (t, i)) != LOC_TYPEDEF)
+	continue;
+
+      tf = XOBNEW (&table->storage, struct typedef_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);
+      if (*slot == NULL)
+	*slot = tf;
+    }
+}
+
+/* Create a new typedef-lookup hash table.  */
+
+struct typedef_hash_table *
+create_typedef_hash (void)
+{
+  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;
+}
+
+/* Free a typedef field table.  */
+
+void
+free_typedef_hash (struct typedef_hash_table *table)
+{
+  if (table != NULL)
+    {
+      htab_delete (table->table);
+      obstack_free (&table->storage, NULL);
+      xfree (table);
+    }
+}
+
+/* A cleanup for freeing a typedef_hash_table.  */
+
+static void
+do_free_typedef_hash (void *arg)
+{
+  free_typedef_hash (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.  */
+
+static int
+copy_typedef_hash_element (void **slot, void *nt)
+{
+  htab_t new_table = nt;
+  void **new_slot;
+
+  new_slot = htab_find_slot (new_table, *slot, INSERT);
+  if (*new_slot == NULL)
+    *new_slot = *slot;
+
+  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;
+}
+
+/* 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.  */
+
+const char *
+find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
+{
+  struct typedef_field tf, *found;
+
+  if (flags->local_typedefs == NULL)
+    return NULL;
+
+  tf.name = NULL;
+  tf.type = t;
+  found = htab_find (flags->local_typedefs->table, &tf);
+
+  return found == NULL ? NULL : found->name;
+}
+
+\f
+
 /* Print a description of a type in the format of a 
    typedef for the current language.
    NEW is the new name for a type TYPE.  */
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 1e15097..71bac01 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -22,6 +22,7 @@
 
 enum language;
 struct ui_file;
+struct typedef_hash_table;
 
 struct type_print_options
 {
@@ -33,10 +34,30 @@ struct type_print_options
 
   /* True means print typedefs in a class.  */
   unsigned int print_typedefs : 1;
+
+  /* If not NULL, a local typedef hash table used when printing a
+     type.  */
+  struct typedef_hash_table *local_typedefs;
 };
 
 extern const struct type_print_options type_print_raw_options;
 
+void recursively_update_typedef_hash (struct typedef_hash_table *,
+				      struct type *);
+
+void add_template_parameters (struct typedef_hash_table *, struct type *);
+
+struct typedef_hash_table *create_typedef_hash (void);
+
+void free_typedef_hash (struct typedef_hash_table *);
+
+struct cleanup *make_cleanup_free_typedef_hash (struct typedef_hash_table *);
+
+struct typedef_hash_table *copy_typedef_hash (struct typedef_hash_table *);
+
+const char *find_typedef_in_hash (const struct type_print_options *,
+				  struct type *);
+
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
 void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-09-21 19:32 ` Tom Tromey
@ 2012-10-31 19:18   ` Pedro Alves
  2012-11-01 21:01     ` Tom Tromey
  0 siblings, 1 reply; 9+ messages in thread
From: Pedro Alves @ 2012-10-31 19:18 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 09/21/2012 08:31 PM, Tom Tromey wrote:
> Tom> This patch implements class-local typedef substitutions for the C++
> Tom> type printer.  That is, when printing a type, gdb will now look at
> Tom> template argument names (if any) and typedefs defined in the class
> Tom> body, and substitute those names when printing type names.
> 
> More testing revealed an oddity in this code (a latent bug exposed by
> the subsequent Python patch); and the fix I chose required some changes
> to some MI test cases as well.  The particular change was that
> previously gdb could emit "long int" but now it will emit just "long" --
> I consider this to be an ok (perhaps even preferable) change.

I'm confused and curious at why such a change would be necessary.  I
couldn't find it from a quick look over the patch.
Can you expand a little?  Does this also affect the CLI?

Why expect both long and "long int"?  Is this compiler / debug format
dependent, perhaps?

>  mi_list_varobj_children {struct_declarations.long_array --all-values} {
> -    {struct_declarations.long_array.0 0 0 "long int" 1234}
> -    {struct_declarations.long_array.1 1 0 "long int" 2345}
> -    {struct_declarations.long_array.2 2 0 "long int" 3456}
> -    {struct_declarations.long_array.3 3 0 "long int" 4567}
> -    {struct_declarations.long_array.4 4 0 "long int" 5678}
> -    {struct_declarations.long_array.5 5 0 "long int" 6789}
> -    {struct_declarations.long_array.6 6 0 "long int" 7890}
> -    {struct_declarations.long_array.7 7 0 "long int" 8901}
> -    {struct_declarations.long_array.8 8 0 "long int" 9012}
> -    {struct_declarations.long_array.9 9 0 "long int" 1234}
> -    {struct_declarations.long_array.10 10 0 "long int" 3456}
> -    {struct_declarations.long_array.11 11 0 "long int" 5678}
> +    {struct_declarations.long_array.0 0 0 "long( int)?" 1234}
> +    {struct_declarations.long_array.1 1 0 "long( int)?" 2345}
> +    {struct_declarations.long_array.2 2 0 "long( int)?" 3456}
> +    {struct_declarations.long_array.3 3 0 "long( int)?" 4567}
> +    {struct_declarations.long_array.4 4 0 "long( int)?" 5678}
> +    {struct_declarations.long_array.5 5 0 "long( int)?" 6789}
> +    {struct_declarations.long_array.6 6 0 "long( int)?" 7890}
> +    {struct_declarations.long_array.7 7 0 "long( int)?" 8901}
> +    {struct_declarations.long_array.8 8 0 "long( int)?" 9012}
> +    {struct_declarations.long_array.9 9 0 "long( int)?" 1234}
> +    {struct_declarations.long_array.10 10 0 "long( int)?" 3456}
> +    {struct_declarations.long_array.11 11 0 "long( int)?" 5678}
>  } "listing of names and values of children"

>  mi_list_varobj_children "psnp->long_ptr" {
> -    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long int \*\*\*}}
> +    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long( int)? \*\*\*}}
>  } "get children of psnp->long_ptr"
>  

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-10-31 19:18   ` Pedro Alves
@ 2012-11-01 21:01     ` Tom Tromey
  2012-11-02 20:52       ` Tom Tromey
  0 siblings, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2012-11-01 21:01 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

Tom> More testing revealed an oddity in this code (a latent bug exposed by
Tom> the subsequent Python patch); and the fix I chose required some changes
Tom> to some MI test cases as well.  The particular change was that
Tom> previously gdb could emit "long int" but now it will emit just "long" --
Tom> I consider this to be an ok (perhaps even preferable) change.

Pedro> I'm confused and curious at why such a change would be necessary.  I
Pedro> couldn't find it from a quick look over the patch.
Pedro> Can you expand a little?  Does this also affect the CLI?

It has been a while, but I think the difference depends on whether the
type name is sent through canonicalization or not.

Pedro> Why expect both long and "long int"?  Is this compiler / debug format
Pedro> dependent, perhaps?

I will take another look and figure it out.

Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-11-01 21:01     ` Tom Tromey
@ 2012-11-02 20:52       ` Tom Tromey
  2012-11-05 20:26         ` Tom Tromey
  0 siblings, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2012-11-02 20:52 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Pedro> I'm confused and curious at why such a change would be necessary.  I
Pedro> couldn't find it from a quick look over the patch.
Pedro> Can you expand a little?  Does this also affect the CLI?

Tom> It has been a while, but I think the difference depends on whether the
Tom> type name is sent through canonicalization or not.

Yes, it is due to C++ name canonicalization.

It may be possible to avoid this in some cases, but I can't think of a
situation where the current approach would make the output worse.

It does affect the CLI in some cases, but I see now that I missed the
'default' case in c_type_print_base.  I will update that and see what
happens.

Pedro> Why expect both long and "long int"?  Is this compiler / debug format
Pedro> dependent, perhaps?

Tom> I will take another look and figure it out.

I think it is safe to just expect "long".
I'll change the patch.

Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-11-02 20:52       ` Tom Tromey
@ 2012-11-05 20:26         ` Tom Tromey
  2012-11-05 20:52           ` Eli Zaretskii
  0 siblings, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2012-11-05 20:26 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> It does affect the CLI in some cases, but I see now that I missed the
Tom> 'default' case in c_type_print_base.  I will update that and see what
Tom> happens.

Changing the default case here had surprisingly little fallout.
I changed call-sc.exp to use "ptype/r" to make the test names consistent
before and after my patch series, and I changed one test in volatile.exp
to drop the "int".

Here's the new patch.

Tom

Built and regtested on x86-64 F16.

	* NEWS: Update.
	* c-typeprint.c (find_typedef_for_canonicalize,
	print_name_maybe_canonical): New functions.
	(c_print_type): Look up type name.
	(cp_type_print_derivation_info): Add flags argument.  Use
	print_name_maybe_canonical.
	(cp_type_print_method_args): Add wrapping.
	(c_type_print_varspec_prefix): Use print_name_maybe_canonical.
	(c_type_print_template_args): New function.
	(c_type_print_base): Change wrapping.  Use
	print_name_maybe_canonical.
	<TYPE_CODE_STRUCT>: Possibly create a typedef hash, and do
	type name lookups.
	* gdbtypes.c (types_equal): No longer static.
	* gdbtypes.h (types_equal): Declare.
	* typeprint.c (type_print_raw_options, default_ptype_flags):
	Update.
	(struct typedef_hash_table): New.
	(hash_typedef_field, eq_typedef_field,
	recursively_update_typedef_hash, add_template_parameters,
	create_typedef_hash, free_typedef_hash, do_free_typedef_hash,
	make_cleanup_free_typedef_hash, copy_typedef_hash_element,
	copy_typedef_hash, find_typedef_in_hash): New functions.
	* typeprint.h (struct type_print_options) <local_typedefs>:
	New field.
	(recursively_update_typedef_hash, add_template_parameters,
	create_typedef_hash, free_typedef_hash,
	make_cleanup_free_typedef_hash, copy_typedef_hash,
	find_typedef_in_hash): Declare.

	* gdb.base/call-sc.exp: Use "ptype/r".
	* gdb.base/volatile.exp: Don't expect "int".
	* gdb.cp/ptype-flags.cc: New file.
	* gdb.cp/ptype-flags.exp: New file.
	* gdb.cp/templates.exp: Use ptype/r.
	(test_ptype_of_templates, test_template_typedef): Likewise.
	* lib/cp-support.exp (cp_test_ptype_class): Add in_ptype_arg
	argument.  Handle template names and template parameters.
	* gdb.mi/mi-var-cmd.exp: Accept "long".
	* gdb.mi/mi-var-child.exp: Accept "long".
	* gdb.mi/mi-var-display.exp: Accept "long".
	* gdb.mi/mi2-var-child.exp: Accept "long".
---
 gdb/NEWS                                |   15 +
 gdb/c-typeprint.c                       |  617 +++++++++++++++++++------------
 gdb/gdbtypes.c                          |    2 +-
 gdb/gdbtypes.h                          |    2 +
 gdb/testsuite/gdb.base/call-sc.exp      |    4 +-
 gdb/testsuite/gdb.base/volatile.exp     |    2 +-
 gdb/testsuite/gdb.cp/ptype-flags.cc     |   47 +++
 gdb/testsuite/gdb.cp/ptype-flags.exp    |   85 +++++
 gdb/testsuite/gdb.cp/templates.exp      |   46 ++--
 gdb/testsuite/gdb.mi/mi-var-child.exp   |   75 ++--
 gdb/testsuite/gdb.mi/mi-var-cmd.exp     |    6 +-
 gdb/testsuite/gdb.mi/mi-var-display.exp |   12 +-
 gdb/testsuite/gdb.mi/mi2-var-child.exp  |   42 +-
 gdb/testsuite/lib/cp-support.exp        |   17 +-
 gdb/typeprint.c                         |  196 ++++++++++-
 gdb/typeprint.h                         |   21 +
 16 files changed, 854 insertions(+), 335 deletions(-)
 create mode 100644 gdb/testsuite/gdb.cp/ptype-flags.cc
 create mode 100644 gdb/testsuite/gdb.cp/ptype-flags.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 069b84f..618bdf1 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -8,6 +8,9 @@
 -nh   Disables auto-loading of ~/.gdbinit, but still executes all the
       other initialization files, unlike -nx which disables all of them.
 
+* The 'ptype' and 'whatis' commands now accept an argument to control
+  type formatting.
+
 * Python scripting
 
   ** Vectors can be created with gdb.Type.vector.
@@ -52,6 +55,18 @@ py [command]
      (has been deprecated in GDB 7.5), and "info all-registers" should be used
      instead.
 
+* New options
+
+set print type methods (on|off)
+show print type methods
+  Control whether method declarations are displayed by "ptype".
+  The default is to show them.
+
+set print type typedefs (on|off)
+show print type typedefs
+  Control whether typedef definitions are displayed by "ptype".
+  The default is to show them.
+
 * MI changes
 
   ** Command parameter changes are now notified using new async record
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 6c47376..c6f8bb2 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -34,6 +34,7 @@
 #include "jv-lang.h"
 #include "gdb_string.h"
 #include <errno.h>
+#include "cp-support.h"
 
 static void c_type_print_varspec_prefix (struct type *,
 					 struct ui_file *,
@@ -45,6 +46,37 @@ static void c_type_print_modifier (struct type *,
 				   struct ui_file *,
 				   int, int);
 \f
+
+/* A callback function for cp_canonicalize_string_full that uses
+   find_typedef_in_hash.  */
+
+static const char *
+find_typedef_for_canonicalize (struct type *t, void *data)
+{
+  return find_typedef_in_hash (data, t);
+}
+
+/* Print NAME on STREAM.  If the 'raw' field of FLAGS is not set,
+   canonicalize NAME using the local typedefs first.  */
+
+static void
+print_name_maybe_canonical (const char *name,
+			    const struct type_print_options *flags,
+			    struct ui_file *stream)
+{
+  char *s = NULL;
+
+  if (!flags->raw)
+    s = cp_canonicalize_string_full (name,
+				     find_typedef_for_canonicalize,
+				     (void *) flags);
+
+  fputs_filtered (s ? s : name, stream);
+  xfree (s);
+}
+
+\f
+
 /* LEVEL is the depth to indent lines by.  */
 
 void
@@ -57,27 +89,38 @@ c_print_type (struct type *type,
   enum type_code code;
   int demangled_args;
   int need_post_space;
+  const char *local_name;
 
   if (show > 0)
     CHECK_TYPEDEF (type);
 
-  c_type_print_base (type, stream, show, level, flags);
-  code = TYPE_CODE (type);
-  if ((varstring != NULL && *varstring != '\0')
-  /* Need a space if going to print stars or brackets;
-     but not if we will print just a type name.  */
-      || ((show > 0 || TYPE_NAME (type) == 0)
-	  && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
-	      || code == TYPE_CODE_METHOD
-	      || (code == TYPE_CODE_ARRAY
-		  && !TYPE_VECTOR (type))
-	      || code == TYPE_CODE_MEMBERPTR
-	      || code == TYPE_CODE_METHODPTR
-	      || code == TYPE_CODE_REF)))
-    fputs_filtered (" ", stream);
-  need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
-  c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
-			       flags);
+  local_name = find_typedef_in_hash (flags, type);
+  if (local_name != NULL)
+    {
+      fputs_filtered (local_name, stream);
+      if (varstring != NULL && *varstring != '\0')
+	fputs_filtered (" ", stream);
+    }
+  else
+    {
+      c_type_print_base (type, stream, show, level, flags);
+      code = TYPE_CODE (type);
+      if ((varstring != NULL && *varstring != '\0')
+	  /* Need a space if going to print stars or brackets;
+	     but not if we will print just a type name.  */
+	  || ((show > 0 || TYPE_NAME (type) == 0)
+	      && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
+		  || code == TYPE_CODE_METHOD
+		  || (code == TYPE_CODE_ARRAY
+		      && !TYPE_VECTOR (type))
+		  || code == TYPE_CODE_MEMBERPTR
+		  || code == TYPE_CODE_METHODPTR
+		  || code == TYPE_CODE_REF)))
+	fputs_filtered (" ", stream);
+      need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
+      c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
+				   flags);
+    }
 
   if (varstring != NULL)
     {
@@ -85,10 +128,13 @@ c_print_type (struct type *type,
 
       /* For demangled function names, we have the arglist as part of
          the name, so don't print an additional pair of ()'s.  */
-
-      demangled_args = strchr (varstring, '(') != NULL;
-      c_type_print_varspec_suffix (type, stream, show,
-				   0, demangled_args, flags);
+      if (local_name == NULL)
+	{
+	  demangled_args = strchr (varstring, '(') != NULL;
+	  c_type_print_varspec_suffix (type, stream, show,
+				       0, demangled_args,
+				       flags);
+	}
     }
 }
 
@@ -139,13 +185,15 @@ c_print_typedef (struct type *type,
 
 static void
 cp_type_print_derivation_info (struct ui_file *stream,
-			       struct type *type)
+			       struct type *type,
+			       const struct type_print_options *flags)
 {
   const char *name;
   int i;
 
   for (i = 0; i < TYPE_N_BASECLASSES (type); i++)
     {
+      wrap_here ("        ");
       fputs_filtered (i == 0 ? ": " : ", ", stream);
       fprintf_filtered (stream, "%s%s ",
 			BASETYPE_VIA_PUBLIC (type, i)
@@ -153,7 +201,10 @@ cp_type_print_derivation_info (struct ui_file *stream,
 				      ? "protected" : "private"),
 			BASETYPE_VIA_VIRTUAL (type, i) ? " virtual" : "");
       name = type_name_no_tag (TYPE_BASECLASS (type, i));
-      fprintf_filtered (stream, "%s", name ? name : "(null)");
+      if (name)
+	print_name_maybe_canonical (name, flags, stream);
+      else
+	fprintf_filtered (stream, "(null)");
     }
   if (i > 0)
     {
@@ -191,7 +242,10 @@ cp_type_print_method_args (struct type *mtype, const char *prefix,
 	  if (i == nargs && varargs)
 	    fprintf_filtered (stream, ", ...");
 	  else if (i < nargs)
-	    fprintf_filtered (stream, ", ");
+	    {
+	      fprintf_filtered (stream, ", ");
+	      wrap_here ("        ");
+	    }
 	}
     }
   else if (varargs)
@@ -263,7 +317,7 @@ c_type_print_varspec_prefix (struct type *type,
 				   stream, show, 0, 0, flags);
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
-	fputs_filtered (name, stream);
+	print_name_maybe_canonical (name, flags, stream);
       else
 	c_type_print_base (TYPE_DOMAIN_TYPE (type),
 			   stream, -1, passed_a_ptr, flags);
@@ -276,7 +330,7 @@ c_type_print_varspec_prefix (struct type *type,
       fprintf_filtered (stream, "(");
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
-	fputs_filtered (name, stream);
+	print_name_maybe_canonical (name, flags, stream);
       else
 	c_type_print_base (TYPE_DOMAIN_TYPE (type),
 			   stream, -1, passed_a_ptr, flags);
@@ -697,6 +751,56 @@ c_type_print_varspec_suffix (struct type *type,
     }
 }
 
+/* A helper for c_type_print_base that displays template
+   parameters and their bindings, if needed.
+
+   TABLE is the local bindings table to use.  If NULL, no printing is
+   done.  Note that, at this point, TABLE won't have any useful
+   information in it -- but it is also used as a flag to
+   print_name_maybe_canonical to activate searching the global typedef
+   table.
+
+   TYPE is the type whose template arguments are being displayed.
+
+   STREAM is the stream on which to print.  */
+
+static void
+c_type_print_template_args (const struct type_print_options *flags,
+			    struct type *type, struct ui_file *stream)
+{
+  int first = 1, i;
+
+  if (flags->raw)
+    return;
+
+  for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (type); ++i)
+    {
+      struct symbol *sym = TYPE_TEMPLATE_ARGUMENT (type, i);
+
+      if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
+	continue;
+
+      if (first)
+	{
+	  wrap_here ("    ");
+	  fprintf_filtered (stream, _("[with %s = "),
+			    SYMBOL_LINKAGE_NAME (sym));
+	  first = 0;
+	}
+      else
+	{
+	  fputs_filtered (", ", stream);
+	  wrap_here ("         ");
+	  fprintf_filtered (stream, "%s = ", SYMBOL_LINKAGE_NAME (sym));
+	}
+
+      c_print_type (SYMBOL_TYPE (sym), "", stream, -1, 0, flags);
+    }
+
+  if (!first)
+    fputs_filtered (_("] "), stream);
+}
+
 /* Print the name of the type (or the ultimate pointer target,
    function value or array element), or the description of a structure
    or union.
@@ -731,7 +835,6 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 
   QUIT;
 
-  wrap_here ("    ");
   if (type == NULL)
     {
       fputs_filtered (_("<type unknown>"), stream);
@@ -749,7 +852,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       && TYPE_NAME (type) != NULL)
     {
       c_type_print_modifier (type, stream, 0, 1);
-      fputs_filtered (TYPE_NAME (type), stream);
+      print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
       return;
     }
 
@@ -778,193 +881,230 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
-      c_type_print_modifier (type, stream, 0, 1);
-      if (TYPE_CODE (type) == TYPE_CODE_UNION)
-	fprintf_filtered (stream, "union ");
-      else if (TYPE_DECLARED_CLASS (type))
-	fprintf_filtered (stream, "class ");
-      else
-	fprintf_filtered (stream, "struct ");
-
-      /* Print the tag if it exists.  The HP aCC compiler emits a
-         spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed
-         enum}" tag for unnamed struct/union/enum's, which we don't
-         want to print.  */
-      if (TYPE_TAG_NAME (type) != NULL
-	  && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
-	{
-	  fputs_filtered (TYPE_TAG_NAME (type), stream);
-	  if (show > 0)
-	    fputs_filtered (" ", stream);
-	}
-      wrap_here ("    ");
-      if (show < 0)
-	{
-	  /* If we just printed a tag name, no need to print anything
-	     else.  */
-	  if (TYPE_TAG_NAME (type) == NULL)
-	    fprintf_filtered (stream, "{...}");
-	}
-      else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
-	{
-	  struct type *basetype;
-	  int vptr_fieldno;
-
-	  cp_type_print_derivation_info (stream, type);
-
-	  fprintf_filtered (stream, "{\n");
-	  if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0
-	      && TYPE_TYPEDEF_FIELD_COUNT (type) == 0)
-	    {
-	      if (TYPE_STUB (type))
-		fprintfi_filtered (level + 4, stream,
-				   _("<incomplete type>\n"));
-	      else
-		fprintfi_filtered (level + 4, stream,
-				   _("<no data fields>\n"));
-	    }
-
-	  /* Start off with no specific section type, so we can print
-	     one for the first field we find, and use that section type
-	     thereafter until we find another type.  */
-
-	  section_type = s_none;
-
-	  /* For a class, if all members are private, there's no need
-	     for a "private:" label; similarly, for a struct or union
-	     masquerading as a class, if all members are public, there's
-	     no need for a "public:" label.  */
-
-	  if (TYPE_DECLARED_CLASS (type))
-	    {
-	      QUIT;
-	      len = TYPE_NFIELDS (type);
-	      for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-		if (!TYPE_FIELD_PRIVATE (type, i))
-		  {
-		    need_access_label = 1;
-		    break;
-		  }
-	      QUIT;
-	      if (!need_access_label)
-		{
-		  len2 = TYPE_NFN_FIELDS (type);
-		  for (j = 0; j < len2; j++)
+      {
+	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;
+
+	if (!flags->raw)
+	  {
+	    if (flags->local_typedefs)
+	      local_flags.local_typedefs
+		= copy_typedef_hash (flags->local_typedefs);
+	    else
+	      local_flags.local_typedefs = create_typedef_hash ();
+
+	    make_cleanup_free_typedef_hash (local_flags.local_typedefs);
+	  }
+
+	c_type_print_modifier (type, stream, 0, 1);
+	if (TYPE_CODE (type) == TYPE_CODE_UNION)
+	  fprintf_filtered (stream, "union ");
+	else if (TYPE_DECLARED_CLASS (type))
+	  fprintf_filtered (stream, "class ");
+	else
+	  fprintf_filtered (stream, "struct ");
+
+	/* Print the tag if it exists.  The HP aCC compiler emits a
+	   spurious "{unnamed struct}"/"{unnamed union}"/"{unnamed
+	   enum}" tag for unnamed struct/union/enum's, which we don't
+	   want to print.  */
+	if (TYPE_TAG_NAME (type) != NULL
+	    && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
+	  {
+	    /* When printing the tag name, we are still effectively
+	       printing in the outer context, hence the use of FLAGS
+	       here.  */
+	    print_name_maybe_canonical (TYPE_TAG_NAME (type), flags, stream);
+	    if (show > 0)
+	      fputs_filtered (" ", stream);
+	  }
+
+	if (show < 0)
+	  {
+	    /* If we just printed a tag name, no need to print anything
+	       else.  */
+	    if (TYPE_TAG_NAME (type) == NULL)
+	      fprintf_filtered (stream, "{...}");
+	  }
+	else if (show > 0 || TYPE_TAG_NAME (type) == NULL)
+	  {
+	    struct type *basetype;
+	    int vptr_fieldno;
+
+	    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);
+	    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);
+
+	    /* Now add in the local typedefs.  */
+	    recursively_update_typedef_hash (local_flags.local_typedefs, type);
+
+	    fprintf_filtered (stream, "{\n");
+	    if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0
+		&& TYPE_TYPEDEF_FIELD_COUNT (type) == 0)
+	      {
+		if (TYPE_STUB (type))
+		  fprintfi_filtered (level + 4, stream,
+				     _("<incomplete type>\n"));
+		else
+		  fprintfi_filtered (level + 4, stream,
+				     _("<no data fields>\n"));
+	      }
+
+	    /* Start off with no specific section type, so we can print
+	       one for the first field we find, and use that section type
+	       thereafter until we find another type.  */
+
+	    section_type = s_none;
+
+	    /* For a class, if all members are private, there's no need
+	       for a "private:" label; similarly, for a struct or union
+	       masquerading as a class, if all members are public, there's
+	       no need for a "public:" label.  */
+
+	    if (TYPE_DECLARED_CLASS (type))
+	      {
+		QUIT;
+		len = TYPE_NFIELDS (type);
+		for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+		  if (!TYPE_FIELD_PRIVATE (type, i))
 		    {
-		      len = TYPE_FN_FIELDLIST_LENGTH (type, j);
-		      for (i = 0; i < len; i++)
-			if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
-									j), i))
-			  {
-			    need_access_label = 1;
-			    break;
-			  }
-		      if (need_access_label)
-			break;
+		      need_access_label = 1;
+		      break;
 		    }
-		}
-	    }
-	  else
-	    {
-	      QUIT;
-	      len = TYPE_NFIELDS (type);
-	      for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-		if (TYPE_FIELD_PRIVATE (type, i)
-		    || TYPE_FIELD_PROTECTED (type, i))
+		QUIT;
+		if (!need_access_label)
 		  {
-		    need_access_label = 1;
-		    break;
+		    len2 = TYPE_NFN_FIELDS (type);
+		    for (j = 0; j < len2; j++)
+		      {
+			len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+			for (i = 0; i < len; i++)
+			  if (!TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
+									  j), i))
+			    {
+			      need_access_label = 1;
+			      break;
+			    }
+			if (need_access_label)
+			  break;
+		      }
 		  }
-	      QUIT;
-	      if (!need_access_label)
-		{
-		  len2 = TYPE_NFN_FIELDS (type);
-		  for (j = 0; j < len2; j++)
+	      }
+	    else
+	      {
+		QUIT;
+		len = TYPE_NFIELDS (type);
+		for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+		  if (TYPE_FIELD_PRIVATE (type, i)
+		      || TYPE_FIELD_PROTECTED (type, i))
 		    {
-		      QUIT;
-		      len = TYPE_FN_FIELDLIST_LENGTH (type, j);
-		      for (i = 0; i < len; i++)
-			if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type,
-									 j), i)
-			    || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
-									  j),
-						      i))
-			  {
-			    need_access_label = 1;
-			    break;
-			  }
-		      if (need_access_label)
-			break;
+		      need_access_label = 1;
+		      break;
 		    }
-		}
-	    }
+		QUIT;
+		if (!need_access_label)
+		  {
+		    len2 = TYPE_NFN_FIELDS (type);
+		    for (j = 0; j < len2; j++)
+		      {
+			QUIT;
+			len = TYPE_FN_FIELDLIST_LENGTH (type, j);
+			for (i = 0; i < len; i++)
+			  if (TYPE_FN_FIELD_PROTECTED (TYPE_FN_FIELDLIST1 (type,
+									   j), i)
+			      || TYPE_FN_FIELD_PRIVATE (TYPE_FN_FIELDLIST1 (type,
+									    j),
+							i))
+			    {
+			      need_access_label = 1;
+			      break;
+			    }
+			if (need_access_label)
+			  break;
+		      }
+		  }
+	      }
 
-	  /* If there is a base class for this type,
-	     do not print the field that it occupies.  */
+	    /* If there is a base class for this type,
+	       do not print the field that it occupies.  */
 
-	  len = TYPE_NFIELDS (type);
-	  vptr_fieldno = get_vptr_fieldno (type, &basetype);
-	  for (i = TYPE_N_BASECLASSES (type); i < len; i++)
-	    {
-	      QUIT;
+	    len = TYPE_NFIELDS (type);
+	    vptr_fieldno = get_vptr_fieldno (type, &basetype);
+	    for (i = TYPE_N_BASECLASSES (type); i < len; i++)
+	      {
+		QUIT;
 
-	      /* If we have a virtual table pointer, omit it.  Even if
-		 virtual table pointers are not specifically marked in
-		 the debug info, they should be artificial.  */
-	      if ((i == vptr_fieldno && type == basetype)
-		  || TYPE_FIELD_ARTIFICIAL (type, i))
-		continue;
+		/* If we have a virtual table pointer, omit it.  Even if
+		   virtual table pointers are not specifically marked in
+		   the debug info, they should be artificial.  */
+		if ((i == vptr_fieldno && type == basetype)
+		    || TYPE_FIELD_ARTIFICIAL (type, i))
+		  continue;
 
-	      if (need_access_label)
-		{
-		  if (TYPE_FIELD_PROTECTED (type, i))
-		    {
-		      if (section_type != s_protected)
-			{
-			  section_type = s_protected;
-			  fprintfi_filtered (level + 2, stream,
-					     "protected:\n");
-			}
-		    }
-		  else if (TYPE_FIELD_PRIVATE (type, i))
-		    {
-		      if (section_type != s_private)
-			{
-			  section_type = s_private;
-			  fprintfi_filtered (level + 2, stream,
-					     "private:\n");
-			}
-		    }
-		  else
-		    {
-		      if (section_type != s_public)
-			{
-			  section_type = s_public;
-			  fprintfi_filtered (level + 2, stream,
-					     "public:\n");
-			}
-		    }
-		}
+		if (need_access_label)
+		  {
+		    if (TYPE_FIELD_PROTECTED (type, i))
+		      {
+			if (section_type != s_protected)
+			  {
+			    section_type = s_protected;
+			    fprintfi_filtered (level + 2, stream,
+					       "protected:\n");
+			  }
+		      }
+		    else if (TYPE_FIELD_PRIVATE (type, i))
+		      {
+			if (section_type != s_private)
+			  {
+			    section_type = s_private;
+			    fprintfi_filtered (level + 2, stream,
+					       "private:\n");
+			  }
+		      }
+		    else
+		      {
+			if (section_type != s_public)
+			  {
+			    section_type = s_public;
+			    fprintfi_filtered (level + 2, stream,
+					       "public:\n");
+			  }
+		      }
+		  }
 
-	      print_spaces_filtered (level + 4, stream);
-	      if (field_is_static (&TYPE_FIELD (type, i)))
-		fprintf_filtered (stream, "static ");
-	      c_print_type (TYPE_FIELD_TYPE (type, i),
-			    TYPE_FIELD_NAME (type, i),
-			    stream, show - 1, level + 4, flags);
-	      if (!field_is_static (&TYPE_FIELD (type, i))
-		  && TYPE_FIELD_PACKED (type, i))
-		{
-		  /* It is a bitfield.  This code does not attempt
-		     to look at the bitpos and reconstruct filler,
-		     unnamed fields.  This would lead to misleading
-		     results if the compiler does not put out fields
-		     for such things (I don't know what it does).  */
-		  fprintf_filtered (stream, " : %d",
-				    TYPE_FIELD_BITSIZE (type, i));
-		}
-	      fprintf_filtered (stream, ";\n");
-	    }
+		print_spaces_filtered (level + 4, stream);
+		if (field_is_static (&TYPE_FIELD (type, i)))
+		  fprintf_filtered (stream, "static ");
+		c_print_type (TYPE_FIELD_TYPE (type, i),
+			      TYPE_FIELD_NAME (type, i),
+			      stream, show - 1, level + 4,
+			      &local_flags);
+		if (!field_is_static (&TYPE_FIELD (type, i))
+		    && TYPE_FIELD_PACKED (type, i))
+		  {
+		    /* It is a bitfield.  This code does not attempt
+		       to look at the bitpos and reconstruct filler,
+		       unnamed fields.  This would lead to misleading
+		       results if the compiler does not put out fields
+		       for such things (I don't know what it does).  */
+		    fprintf_filtered (stream, " : %d",
+				      TYPE_FIELD_BITSIZE (type, i));
+		  }
+		fprintf_filtered (stream, ";\n");
+	      }
 
 	  /* If there are both fields and methods, put a blank line
 	     between them.  Make sure to count only method that we
@@ -1062,7 +1202,8 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 			   && !is_type_conversion_operator (type, i, j))
 		    {
 		      c_print_type (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)),
-				    "", stream, -1, 0, flags);
+				    "", stream, -1, 0,
+				    &local_flags);
 		      fputs_filtered (" ", stream);
 		    }
 		  if (TYPE_FN_FIELD_STUB (f, j))
@@ -1083,10 +1224,10 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 		  if (demangled_name == NULL)
 		    {
 		      /* In some cases (for instance with the HP
-		         demangling), if a function has more than 10
-		         arguments, the demangling will fail.
-		         Let's try to reconstruct the function
-		         signature from the symbol information.  */
+			 demangling), if a function has more than 10
+			 arguments, the demangling will fail.
+			 Let's try to reconstruct the function
+			 signature from the symbol information.  */
 		      if (!TYPE_FN_FIELD_STUB (f, j))
 			{
 			  int staticp = TYPE_FN_FIELD_STATIC_P (f, j);
@@ -1096,7 +1237,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 						     "",
 						     method_name,
 						     staticp,
-						     stream, flags);
+						     stream, &local_flags);
 			}
 		      else
 			fprintf_filtered (stream,
@@ -1143,30 +1284,40 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 	      if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0)
 		fprintf_filtered (stream, "\n");
 
-	      for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
-		{
-		  struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i);
+		for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
+		  {
+		    struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i);
+		    struct typedef_hash_table *table2;
+
+		    /* Dereference the typedef declaration itself.  */
+		    gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
+		    target = TYPE_TARGET_TYPE (target);
+
+		    print_spaces_filtered (level + 4, stream);
+		    fprintf_filtered (stream, "typedef ");
+
+		    /* We want to print typedefs with substitutions
+		       from the template parameters or globally-known
+		       typedefs but not local typedefs.  */
+		    c_print_type (target,
+				  TYPE_TYPEDEF_FIELD_NAME (type, i),
+				  stream, show - 1, level + 4,
+				  &semi_local_flags);
+		    fprintf_filtered (stream, ";\n");
+		  }
+	      }
 
-		  /* Dereference the typedef declaration itself.  */
-		  gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
-		  target = TYPE_TARGET_TYPE (target);
+	    fprintfi_filtered (level, stream, "}");
 
-		  print_spaces_filtered (level + 4, stream);
-		  fprintf_filtered (stream, "typedef ");
-		  c_print_type (target, TYPE_TYPEDEF_FIELD_NAME (type, i),
-				stream, show - 1, level + 4, flags);
-		  fprintf_filtered (stream, ";\n");
-		}
-	    }
-
-	  fprintfi_filtered (level, stream, "}");
+	    if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
+	      fprintfi_filtered (level,
+				 stream, _(" (Local at %s:%d)\n"),
+				 TYPE_LOCALTYPE_FILE (type),
+				 TYPE_LOCALTYPE_LINE (type));
+	  }
 
-	  if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
-	    fprintfi_filtered (level,
-			       stream, _(" (Local at %s:%d)\n"),
-			       TYPE_LOCALTYPE_FILE (type),
-			       TYPE_LOCALTYPE_LINE (type));
-	}
+	do_cleanups (local_cleanups);
+      }
       break;
 
     case TYPE_CODE_ENUM:
@@ -1180,7 +1331,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       if (TYPE_TAG_NAME (type) != NULL
 	  && strncmp (TYPE_TAG_NAME (type), "{unnamed", 8))
 	{
-	  fputs_filtered (TYPE_TAG_NAME (type), stream);
+	  print_name_maybe_canonical (TYPE_TAG_NAME (type), flags, stream);
 	  if (show > 0)
 	    fputs_filtered (" ", stream);
 	}
@@ -1248,7 +1399,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       if (TYPE_NAME (type) != NULL)
 	{
 	  c_type_print_modifier (type, stream, 0, 1);
-	  fputs_filtered (TYPE_NAME (type), stream);
+	  print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
 	}
       else
 	{
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 149d31f..d322004 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -2406,7 +2406,7 @@ integer_types_same_name_p (const char *first, const char *second)
 /* Compares type A to type B returns 1 if the represent the same type
    0 otherwise.  */
 
-static int
+int
 types_equal (struct type *a, struct type *b)
 {
   /* Identical type pointers.  */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 59a6a65..d5a7cf5 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1657,4 +1657,6 @@ extern struct type *copy_type_recursive (struct objfile *objfile,
 
 extern struct type *copy_type (const struct type *type);
 
+extern int types_equal (struct type *, struct type *);
+
 #endif /* GDBTYPES_H */
diff --git a/gdb/testsuite/gdb.base/call-sc.exp b/gdb/testsuite/gdb.base/call-sc.exp
index 1b2a495..703b37f 100644
--- a/gdb/testsuite/gdb.base/call-sc.exp
+++ b/gdb/testsuite/gdb.base/call-sc.exp
@@ -89,13 +89,13 @@ proc start_scalars_test { type } {
     # check that type matches what was passed in
     set test "ptype; ${testfile}"
     set foo_t "xxx"
-    gdb_test_multiple "ptype ${type}" "${test}" {
+    gdb_test_multiple "ptype/r ${type}" "${test}" {
 	-re "type = (\[^\r\n\]*)\r\n$gdb_prompt $" {
 	    set foo_t "$expect_out(1,string)"
 	    pass "$test (${foo_t})"
 	}
     }
-    gdb_test "ptype foo" "type = ${foo_t}" "ptype foo; ${testfile} $expect_out(1,string)"
+    gdb_test "ptype/r foo" "type = ${foo_t}" "ptype foo; ${testfile} $expect_out(1,string)"
 }
 
 
diff --git a/gdb/testsuite/gdb.base/volatile.exp b/gdb/testsuite/gdb.base/volatile.exp
index ade9d66..1f34b83 100644
--- a/gdb/testsuite/gdb.base/volatile.exp
+++ b/gdb/testsuite/gdb.base/volatile.exp
@@ -156,7 +156,7 @@ local_compiler_xfail_check
 gdb_test "ptype veneer" "type = volatile short( int)? \\* volatile.*"
 
 local_compiler_xfail_check
-gdb_test "ptype video" "type = volatile (unsigned short|short unsigned)( int) \\* volatile.*"
+gdb_test "ptype video" "type = volatile (unsigned short|short unsigned) \\* volatile.*"
 
 local_compiler_xfail_check
 gdb_test "ptype vacuum" "type = volatile long( int)? \\* volatile.*"
diff --git a/gdb/testsuite/gdb.cp/ptype-flags.cc b/gdb/testsuite/gdb.cp/ptype-flags.cc
new file mode 100644
index 0000000..3077f73
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ptype-flags.cc
@@ -0,0 +1,47 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   */
+
+template<typename S>
+class Simple
+{
+  S val;
+};
+
+template<typename T>
+class Base
+{
+};
+
+template<typename T>
+class Holder : public Base<T>
+{
+public:
+  Simple<T> t;
+  Simple<T*> tstar;
+
+  typedef Simple< Simple<T> > Z;
+
+  Z z;
+
+  double method(void) { return 23.0; }
+};
+
+Holder<int> value;
+
+int main()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/ptype-flags.exp b/gdb/testsuite/gdb.cp/ptype-flags.exp
new file mode 100644
index 0000000..f544807
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/ptype-flags.exp
@@ -0,0 +1,85 @@
+# Copyright 2012 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+set nl		"\[\r\n\]+"
+
+if { [skip_cplus_tests] } { continue }
+
+load_lib "cp-support.exp"
+
+standard_testfile .cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    return
+}
+
+gdb_test_no_output "set language c++" ""
+gdb_test_no_output "set width 0" ""
+
+proc do_check {name {flags ""} {show_typedefs 1} {show_methods 1} {raw 0}} {
+    set contents {
+	{ base "public Base<T>" }
+	{ field public "Simple<T> t;" }
+	{ field public "Simple<T*> tstar;" }
+    }
+
+    if {$raw} {
+	lappend contents { field public "Holder<int>::Z z;" }
+    } else {
+	lappend contents { field public "Z z;" }
+    }
+
+    if {$show_typedefs} {
+	lappend contents { typedef public "typedef Simple<Simple<T> > Z;" }
+    }
+
+    if {$show_methods} {
+	lappend contents { method public "double method();" }
+    }
+
+    if {$raw} {
+	regsub -all -- "T" $contents "int" contents
+    }
+
+    cp_test_ptype_class value $name "class" "Holder<int>" $contents \
+	"" {} $flags
+}
+
+do_check "basic test"
+do_check "no methods" "/m" 1 0
+do_check "no typedefs" "/t" 0 1
+do_check "no methods or typedefs" "/mt" 0 0
+
+do_check "raw" "/r" 1 1 1
+do_check "raw no methods" "/rm" 1 0 1
+do_check "raw no typedefs" "/rt" 0 1 1
+do_check "raw no methods or typedefs" "/rmt" 0 0 1
+
+gdb_test_no_output "set print type methods off"
+do_check "basic test, default methods off" "" 1 0
+do_check "methods, default methods off" "/M" 1 1
+do_check "no typedefs, default methods off" "/t" 0 0
+do_check "methods, no typedefs, default methods off" "/Mt" 0 1
+
+gdb_test_no_output "set print type typedefs off"
+do_check "basic test, default methods+typedefs off" "" 0 0
+do_check "methods, default methods+typedefs off" "/M" 0 1
+do_check "typedefs, default methods+typedefs off" "/T" 1 0
+do_check "methods typedefs, default methods+typedefs off" "/MT" 1 1
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 47915b1..9ebb3bd 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -40,7 +40,7 @@ proc test_ptype_of_templates {} {
     global gdb_prompt
     global ws
 
-    gdb_test_multiple "ptype T5<int>" "ptype T5<int>" {
+    gdb_test_multiple "ptype/r T5<int>" "ptype T5<int>" {
 	-re "type = class T5<int> \{${ws}public:${ws}static int X;${ws}int x;${ws}int val;${ws}T5<int> & operator=\\(T5<int> const ?&\\);${ws}T5\\(int\\);${ws}T5\\((T5<int> const|const T5<int>) ?&\\);${ws}~T5\\((void|)\\);${ws}static void \\* operator new\\(unsigned( int| long)?\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\}\r\n$gdb_prompt $" {
 	    xfail "ptype T5<int> -- new without size_t"
 	}
@@ -63,7 +63,7 @@ proc test_ptype_of_templates {} {
 	}
     }
 
-    gdb_test_multiple "ptype t5i" "ptype t5i" {
+    gdb_test_multiple "ptype/r t5i" "ptype t5i" {
         -re "type = class T5<int> \\{${ws}public:${ws}static int X;${ws}int x;${ws}int val;\r\n${ws}T5\\(int\\);${ws}T5\\(T5<int> const ?&\\);${ws}~T5\\((void|)\\);${ws}static void \\* operator new\\(unsigned( int| long)?\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\\}\r\n$gdb_prompt $" {
 	    xfail "ptype T5<int> -- with several fixes from 4.17 -- without size_t"
 	}
@@ -226,11 +226,13 @@ proc test_template_typedef {} {
 proc test_template_args {} {
 
     set empty_re "Empty *<void *\\(FunctionArg *<int>\\)>"
-    gdb_test "ptype empty" \
-	"type = (struct|class) $empty_re {.*<no data fields>.*}"
+    gdb_test "ptype/r empty" \
+	"type = (struct|class) $empty_re {.*<no data fields>.*}" \
+	"ptype empty"
 
-    gdb_test "ptype arg" \
-	"type = (struct|class) FunctionArg<int> {.*int method\\($empty_re \\&\\);.*}"
+    gdb_test "ptype/r arg" \
+	"type = (struct|class) FunctionArg<int> {.*int method\\($empty_re \\&\\);.*}" \
+	"ptype arg"
 }
 
 proc do_tests {} {
@@ -291,7 +293,7 @@ gdb_test "print fvpchar" \
 # NOTE: carlton/2003-02-26: However, because of a bug in the way GDB
 # handles nested types, we don't get this right in the DWARF-2 case.
 
-gdb_test_multiple "ptype Foo" "ptype Foo" {
+gdb_test_multiple "ptype/r Foo" "ptype Foo" {
     -re "type = template <(class |)T> (class |)Foo \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Foo<volatile char \\*>\r\n\[ \t\]*(class |)Foo<char>\r\n\[ \t\]*(class |)Foo<int>\r\n$gdb_prompt $" {
 	pass "ptype Foo"
     }
@@ -312,7 +314,7 @@ gdb_test_multiple "ptype Foo" "ptype Foo" {
 
 # ptype Foo<int>
 
-gdb_test_multiple "ptype fint" "ptype fint" {
+gdb_test_multiple "ptype/r fint" "ptype fint" {
     -re "type = (class |)Foo<int> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int foo\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fint"
     }
@@ -323,7 +325,7 @@ gdb_test_multiple "ptype fint" "ptype fint" {
 
 # ptype Foo<char>
 
-gdb_test_multiple "ptype fchar" "ptype fchar" {
+gdb_test_multiple "ptype/r fchar" "ptype fchar" {
     -re "type = (class |)Foo<char> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*.*char foo\\(int, char\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fchar"
     }
@@ -334,7 +336,7 @@ gdb_test_multiple "ptype fchar" "ptype fchar" {
 
 # ptype Foo<volatile char *>
 
-gdb_test_multiple "ptype fvpchar" "ptype fvpchar" {
+gdb_test_multiple "ptype/r fvpchar" "ptype fvpchar" {
     -re "type = (class |)Foo<volatile char ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*char.*\\*t;\r\n\r\n\[ \t\]*.*char \\* foo\\(int,.*char.*\\*\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype fvpchar"
     }
@@ -374,7 +376,7 @@ gdb_test_multiple "print Foo<volatile char*>::foo" "print Foo<volatile char*>::f
 # Template Bar<T, int>
 
 # same as Foo for g++
-gdb_test_multiple "ptype Bar" "ptype Bar" {
+gdb_test_multiple "ptype/r Bar" "ptype Bar" {
     -re "type = template <(class |)T, (class |)sz> (class |)Bar \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Bar<int,(\\(int\\)|)1>\r\n\[ \t\]*(class |)Bar<int,(\\(int\\)|)33>\r\n$gdb_prompt $" {
 	pass "ptype Bar"
     }
@@ -394,7 +396,7 @@ gdb_test_multiple "ptype Bar" "ptype Bar" {
 
 # ptype Bar<int,33>
 
-gdb_test_multiple "ptype bint" "ptype bint" {
+gdb_test_multiple "ptype/r bint" "ptype bint" {
     -re "type = (class |)Bar<int, ?(\\(int\\)|)33> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int bar\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bint"
     }
@@ -405,7 +407,7 @@ gdb_test_multiple "ptype bint" "ptype bint" {
 
 # ptype Bar<int, (4>3)>
 
-gdb_test_multiple "ptype bint2" "ptype bint2" {
+gdb_test_multiple "ptype/r bint2" "ptype bint2" {
     -re "type = (class |)Bar<int, ?(\\(int\\)|)1> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int bar\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bint2"
     }
@@ -417,7 +419,7 @@ gdb_test_multiple "ptype bint2" "ptype bint2" {
 # Template Baz<T, char>
 
 # Same as Foo, for g++
-gdb_test_multiple "ptype Baz" "ptype Baz" {
+gdb_test_multiple "ptype/r Baz" "ptype Baz" {
     -re "type = template <(class |)T, ?(class |)sz> (class |)Baz \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Baz<char,(\\(char\\)|)97>\r\n\[ \t\]*(class |)Baz<int,(\\(char\\)|)115>\r\n$gdb_prompt $" {
 	pass "ptype Baz"
     }
@@ -441,7 +443,7 @@ gdb_test_multiple "ptype Baz" "ptype Baz" {
 
 # ptype Baz<int, 's'>
 
-gdb_test_multiple "ptype bazint" "ptype bazint" {
+gdb_test_multiple "ptype/r bazint" "ptype bazint" {
     -re "type = (class |)Baz<int, ?(\\(char\\)|)(115|\\'s\\')> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int baz\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bazint"
     }
@@ -452,7 +454,7 @@ gdb_test_multiple "ptype bazint" "ptype bazint" {
 
 # ptype Baz<char, 'a'>
 
-gdb_test_multiple "ptype bazint2" "ptype bazint2" {
+gdb_test_multiple "ptype/r bazint2" "ptype bazint2" {
     -re "type = (class |)Baz<char, ?(\\(char\\)|)(97|\\'a\\')> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*char t;\r\n\r\n\[ \t\]*.*char baz\\(int, char\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype bazint2"
     }
@@ -463,7 +465,7 @@ gdb_test_multiple "ptype bazint2" "ptype bazint2" {
 
 # Template Qux<T, int (*f)(int) >
 # Same as Foo for g++
-gdb_test_multiple "ptype Qux" "ptype Qux" {
+gdb_test_multiple "ptype/r Qux" "ptype Qux" {
     -re "type = template <(class |)T, ?(class |)sz> (class |)Qux \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*T t;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Qux<int,&string>\r\n\[ \t\]*(class |)Qux<char,&string>\r\n$gdb_prompt $" {
 	pass "ptype Qux"
     }
@@ -486,7 +488,7 @@ gdb_test_multiple "ptype Qux" "ptype Qux" {
 
 # pt Qux<int,&string>
 
-gdb_test_multiple "ptype quxint" "ptype quxint" {
+gdb_test_multiple "ptype/r quxint" "ptype quxint" {
     -re "type = class Qux<int, ?& ?string> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int qux\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype quxint"
     }
@@ -505,7 +507,7 @@ gdb_test_multiple "ptype quxint" "ptype quxint" {
 # Template Spec<T1, T2>
 
 # Same as Foo for g++
-gdb_test_multiple "ptype Spec" "ptype Spec" {
+gdb_test_multiple "ptype/r Spec" "ptype Spec" {
     -re "type = template <(class |)T1, (class |)T2> (class |)Spec \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\\}\r\ntemplate instantiations:\r\n\[ \t\]*(class |)Spec<int,int \\*>\r\n\[ \t\]*(class |)Spec<int,char>\r\n$gdb_prompt $" {
 	pass "ptype Spec"
     }
@@ -524,7 +526,7 @@ gdb_test_multiple "ptype Spec" "ptype Spec" {
 
 # pt Spec<char,0>
 
-gdb_test_multiple "ptype siip" "ptype siip" {
+gdb_test_multiple "ptype/r siip" "ptype siip" {
     -re "type = class Spec<int, ?int ?\\*> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\r\n\[ \t\]*.*int spec\\(int ?\\*\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype siip"
     }
@@ -535,7 +537,7 @@ gdb_test_multiple "ptype siip" "ptype siip" {
 
 # pt Garply<int>
 
-gdb_test_multiple "ptype Garply<int>" "ptype Garply<int>" {
+gdb_test_multiple "ptype/r Garply<int>" "ptype Garply<int>" {
     -re "type = class Garply<int> \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*int t;\r\n\r\n\[ \t\]*.*int garply\\(int, int\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype Garply<int>"
     }
@@ -546,7 +548,7 @@ gdb_test_multiple "ptype Garply<int>" "ptype Garply<int>" {
 
 # ptype of nested template name
 
-gdb_test_multiple "ptype Garply<Garply<char> >" "ptype Garply<Garply<char> >" {
+gdb_test_multiple "ptype/r Garply<Garply<char> >" "ptype Garply<Garply<char> >" {
     -re "type = (class |)Garply<Garply<char> > \\{\r\n\[ \t\]*public:\r\n\[ \t\]*int x;\r\n\[ \t\]*.*(class |)Garply<char> t;\r\n\r\n\[ \t\]*.*(class |)Garply<char> garply\\(int, (class |)Garply<char>\\);\r\n\\}\r\n$gdb_prompt $" {
 	pass "ptype Garply<Garply<char> >"
     }
diff --git a/gdb/testsuite/gdb.mi/mi-var-child.exp b/gdb/testsuite/gdb.mi/mi-var-child.exp
index 1d72311..7e61684 100644
--- a/gdb/testsuite/gdb.mi/mi-var-child.exp
+++ b/gdb/testsuite/gdb.mi/mi-var-child.exp
@@ -64,14 +64,14 @@ mi_list_varobj_children "struct_declarations" {
     {struct_declarations.integer integer 0 int}
     {struct_declarations.character character 0 char}
     {struct_declarations.char_ptr char_ptr 1 "char \\*"}
-    {struct_declarations.long_int long_int 0 "long int"}
+    {struct_declarations.long_int long_int 0 "long"}
     {struct_declarations.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {struct_declarations.long_array long_array 12 "long int \\[12\\]"}
+    {struct_declarations.long_array long_array 12 "long \\[12\\]"}
     {struct_declarations.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {struct_declarations.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long\\))?"}
     {struct_declarations.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long)?\\)"}
     {struct_declarations.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {struct_declarations.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of struct_declarations"
@@ -150,7 +150,8 @@ mi_gdb_test "-var-info-num-children struct_declarations.int_ptr_ptr" \
 
 # Test: c_variable-4.15
 # Desc: children of struct_declarations.long_array
-mi_list_array_varobj_children "struct_declarations.long_array" 12 "long int" \
+mi_list_array_varobj_children "struct_declarations.long_array" 12 \
+    "long" \
     "get children of struct_declarations.long_array"
 
 # Test: c_variable-4.16
@@ -199,7 +200,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.func_ptr_ptr" \
 mi_list_varobj_children "struct_declarations.u1" {
     {struct_declarations.u1.a a 0 int}
     {struct_declarations.u1.b b 1 {char \*}}
-    {struct_declarations.u1.c c 0 {long int}}
+    {struct_declarations.u1.c c 0 {long}}
     {struct_declarations.u1.d d 0 {enum foo}}
 } "get children of struct_declarations.u1"
 
@@ -215,7 +216,7 @@ mi_list_varobj_children "struct_declarations.s2" {
     {struct_declarations.s2.u2 u2 3 {union \{\.\.\.\}}}
     {struct_declarations.s2.g g 0 int}
     {struct_declarations.s2.h h 0 char}
-    {struct_declarations.s2.i i 10 {long int \[10\]}}
+    {struct_declarations.s2.i i 10 {long \[10\]}}
 } "get children of struct_declarations.s2"
 
 #gdbtk_test c_variable-4.25 {children of struct_declarations.s2} {
@@ -289,7 +290,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.u1.d" \
 # Desc: children of struct_declarations.s2.u2
 mi_list_varobj_children "struct_declarations.s2.u2" {
     {"struct_declarations.s2.u2.u1s1" "u1s1" 4 {struct \{\.\.\.\}}}
-    {struct_declarations.s2.u2.f f 0 "long int"}
+    {struct_declarations.s2.u2.f f 0 "long"}
     {struct_declarations.s2.u2.u1s2 u1s2 2 {struct \{\.\.\.\}}}
 } "get children of struct_declarations.s2.u2"
 
@@ -327,7 +328,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.s2.h" \
 # Desc: children of struct_declarations.s2.i
 set t {}
 for {set i 0} {$i < 10} {incr i} {
-    lappend t [list struct_declarations.s2.i.$i $i 0 "long int"]
+    lappend t [list struct_declarations.s2.i.$i $i 0 "long"]
 }
 mi_list_varobj_children struct_declarations.s2.i $t \
 	"get children of struct_declarations.s2.i"
@@ -481,14 +482,14 @@ mi_list_varobj_children "weird" {
     {weird.integer integer 0 int}
     {weird.character character 0 char}
     {weird.char_ptr char_ptr 1 "char \\*"}
-    {weird.long_int long_int 0 "long int"}
+    {weird.long_int long_int 0 "long"}
     {weird.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {weird.long_array long_array 12 "long int \\[12\\]"}
+    {weird.long_array long_array 12 "long \\[12\\]"}
     {weird.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {weird.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long\\))?"}
     {weird.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long)?\\)"}
     {weird.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {weird.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of weird"
@@ -502,7 +503,7 @@ mi_gdb_test "-var-info-num-children weird" \
 
 # Test: c_variable-4.84
 # Desc: children of weird->long_array
-mi_list_array_varobj_children weird.long_array 12 "long int" \
+mi_list_array_varobj_children weird.long_array 12 "long" \
 	"get children of weird.long_array"
 #gdbtk_test c_variable-4.84 {children of weird->long_array} {
 #  get_children weird.long_array
@@ -783,18 +784,18 @@ mi_gdb_test "-var-update --all-values *" \
  "update all vars struct_declarations.long_array.11 changed, print values."
 
 mi_list_varobj_children {struct_declarations.long_array --all-values} {
-    {struct_declarations.long_array.0 0 0 "long int" 1234}
-    {struct_declarations.long_array.1 1 0 "long int" 2345}
-    {struct_declarations.long_array.2 2 0 "long int" 3456}
-    {struct_declarations.long_array.3 3 0 "long int" 4567}
-    {struct_declarations.long_array.4 4 0 "long int" 5678}
-    {struct_declarations.long_array.5 5 0 "long int" 6789}
-    {struct_declarations.long_array.6 6 0 "long int" 7890}
-    {struct_declarations.long_array.7 7 0 "long int" 8901}
-    {struct_declarations.long_array.8 8 0 "long int" 9012}
-    {struct_declarations.long_array.9 9 0 "long int" 1234}
-    {struct_declarations.long_array.10 10 0 "long int" 3456}
-    {struct_declarations.long_array.11 11 0 "long int" 5678}
+    {struct_declarations.long_array.0 0 0 "long" 1234}
+    {struct_declarations.long_array.1 1 0 "long" 2345}
+    {struct_declarations.long_array.2 2 0 "long" 3456}
+    {struct_declarations.long_array.3 3 0 "long" 4567}
+    {struct_declarations.long_array.4 4 0 "long" 5678}
+    {struct_declarations.long_array.5 5 0 "long" 6789}
+    {struct_declarations.long_array.6 6 0 "long" 7890}
+    {struct_declarations.long_array.7 7 0 "long" 8901}
+    {struct_declarations.long_array.8 8 0 "long" 9012}
+    {struct_declarations.long_array.9 9 0 "long" 1234}
+    {struct_declarations.long_array.10 10 0 "long" 3456}
+    {struct_declarations.long_array.11 11 0 "long" 5678}
 } "listing of names and values of children"
 
 mi_list_varobj_children {struct_declarations --simple-values} \
@@ -802,14 +803,14 @@ mi_list_varobj_children {struct_declarations --simple-values} \
          {struct_declarations.integer integer 0 int 123} \
          {struct_declarations.character character 0 char {0 '\\\\000'}} \
          [list struct_declarations.char_ptr char_ptr 1 "char \\*" "$hex \\\\\"hello\\\\\""] \
-         {struct_declarations.long_int long_int 0 "long int" 0} \
+         {struct_declarations.long_int long_int 0 "long" 0} \
          [list struct_declarations.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*" "$hex"] \
-         {struct_declarations.long_array long_array 12 "long int \\[12\\]"} \
+         {struct_declarations.long_array long_array 12 "long \\[12\\]"} \
          [list struct_declarations.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)" "(@$hex: |)$hex <nothing>"] \
          {struct_declarations.func_ptr_struct func_ptr_struct 0 \
-              "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?" 0x0} \
+              "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long\\))?" 0x0} \
          {struct_declarations.func_ptr_ptr func_ptr_ptr 0 \
-              "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)" 0x0} \
+              "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long)?\\)" 0x0} \
          {struct_declarations.u1 u1 4 "union \\{\\.\\.\\.\\}"} \
          {struct_declarations.s2 s2 4 "struct \\{\\.\\.\\.\\}"} \
 ] "listing of children, simple types: names, type and values, complex types: names and types"
@@ -913,7 +914,7 @@ mi_create_varobj "psnp->long_ptr" "psnp->long_ptr" \
 # Test: c_variable-5.20
 # Desc: children of psnp->long_ptr
 mi_list_varobj_children "psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long int \*\*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long \*\*\*}}
 } "get children of psnp->long_ptr"
 
 # Test: c_variable-5.21
@@ -925,7 +926,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr" \
 # Test: c_variable-5.22
 # Desc: children of *(psnp->long_ptr)
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long int \*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long \*\*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr"
 
 
@@ -939,7 +940,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr" \
 # Desc: children of *(*(psnp->long_ptr))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr} \
-         {\*\*\*psnp->long_ptr} 1 {long int \*}}
+         {\*\*\*psnp->long_ptr} 1 {long \*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr"
 
 # Test: c_variable-5.25
@@ -952,7 +953,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr.**psnp->long_
 # Desc: children of *(*(*(psnp->long_ptr)))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr.\*\*\*\*psnp->long_ptr}
-        {\*\*\*\*psnp->long_ptr} 0 {long int}}
+        {\*\*\*\*psnp->long_ptr} 0 {long}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr"
 
 # Test: c_variable-5.27
@@ -995,7 +996,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs" \
 # Desc: children of psnp->ptrs[0]
 mi_list_varobj_children "psnp->ptrs.0" {
     {psnp->ptrs.0.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.long_ptr long_ptr 1 {long \*\*\*\*}}
     {psnp->ptrs.0.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0"
@@ -1010,7 +1011,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0" \
 # Desc: children of psnp->ptrs[0]->next
 mi_list_varobj_children "psnp->ptrs.0.next" {
     {psnp->ptrs.0.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long \*\*\*\*}}
     {psnp->ptrs.0.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next"
@@ -1100,7 +1101,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0.next.char_ptr.*char_ptr.**char_
 # Desc: children of psnp->ptrs[0]->next->next
 mi_list_varobj_children "psnp->ptrs.0.next.next" {
     {psnp->ptrs.0.next.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long \*\*\*\*}}
     {psnp->ptrs.0.next.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next.next"
diff --git a/gdb/testsuite/gdb.mi/mi-var-cmd.exp b/gdb/testsuite/gdb.mi/mi-var-cmd.exp
index 4c560a7..345e94b 100644
--- a/gdb/testsuite/gdb.mi/mi-var-cmd.exp
+++ b/gdb/testsuite/gdb.mi/mi-var-cmd.exp
@@ -83,9 +83,9 @@ mi_create_varobj_checked lcharacter lcharacter\[0\] char "create local variable
 
 mi_create_varobj_checked lpcharacter lpcharacter {char \*} "create local variable lpcharacter"
 
-mi_create_varobj_checked llong llong "long int" "create local variable llong"
+mi_create_varobj_checked llong llong "long" "create local variable llong"
 
-mi_create_varobj_checked lplong lplong {long int \*} "create local variable lplong"
+mi_create_varobj_checked lplong lplong {long \*} "create local variable lplong"
 
 mi_create_varobj_checked lfloat lfloat float "create local variable lfloat"
 
@@ -408,7 +408,7 @@ mi_continue_to subroutine1
 # Desc: create variable for locals i,l in subroutine1
 mi_create_varobj_checked i i int "create i"
 
-mi_create_varobj_checked l l {long int \*} "create l"
+mi_create_varobj_checked l l {long \*} "create l"
 
 # Test: c_variable-2.11
 # Desc: create do_locals_tests local in subroutine1
diff --git a/gdb/testsuite/gdb.mi/mi-var-display.exp b/gdb/testsuite/gdb.mi/mi-var-display.exp
index 5cb5f26..251f948 100644
--- a/gdb/testsuite/gdb.mi/mi-var-display.exp
+++ b/gdb/testsuite/gdb.mi/mi-var-display.exp
@@ -215,14 +215,14 @@ mi_list_varobj_children weird {
         {weird.integer integer 0 int}
         {weird.character character 0 char}
         {weird.char_ptr char_ptr 1 "char \\*"}
-        {weird.long_int long_int 0 "long int"}
+        {weird.long_int long_int 0 "long"}
         {weird.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-        {weird.long_array long_array 10 "long int \\[10\\]"}
+        {weird.long_array long_array 10 "long \\[10\\]"}
         {weird.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
         {weird.func_ptr_struct func_ptr_struct 0 \
-                 "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+                 "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long\\))?"}
         {weird.func_ptr_ptr func_ptr_ptr 0 \
-                 "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+                 "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long)?\\)"}
         {weird.u1 u1 4 "union \\{\\.\\.\\.\\}"}
         {weird.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children local variable weird"
@@ -443,7 +443,7 @@ mi_gdb_test "-var-info-num-children anonu" \
 mi_list_varobj_children "anonu" {
         {anonu.a a 0 int}
         {anonu.b b 0 char}
-        {anonu.c c 0 "long int"}
+        {anonu.c c 0 "long"}
 } "get children of anonu"
 
 # Test: c_variable-7.30
@@ -520,7 +520,7 @@ mi_gdb_test "-var-info-num-children anons" \
 mi_list_varobj_children anons {
         {anons.a a 0 int}
         {anons.b b 0 char}
-        {anons.c c 0 "long int"}
+        {anons.c c 0 "long"}
 } "get children of anons"
 
 # Test: c_variable-7.50
diff --git a/gdb/testsuite/gdb.mi/mi2-var-child.exp b/gdb/testsuite/gdb.mi/mi2-var-child.exp
index fdf12f7..6a3823f 100644
--- a/gdb/testsuite/gdb.mi/mi2-var-child.exp
+++ b/gdb/testsuite/gdb.mi/mi2-var-child.exp
@@ -63,14 +63,14 @@ mi_list_varobj_children "struct_declarations" {
     {struct_declarations.integer integer 0 int}
     {struct_declarations.character character 0 char}
     {struct_declarations.char_ptr char_ptr 1 "char \\*"}
-    {struct_declarations.long_int long_int 0 "long int"}
+    {struct_declarations.long_int long_int 0 "long"}
     {struct_declarations.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {struct_declarations.long_array long_array 10 "long int \\[10\\]"}
+    {struct_declarations.long_array long_array 10 "long \\[10\\]"}
     {struct_declarations.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {struct_declarations.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long\\))?"}
     {struct_declarations.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long)?\\)"}
     {struct_declarations.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {struct_declarations.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of struct_declarations"
@@ -150,7 +150,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.int_ptr_ptr" \
 
 # Test: c_variable-4.15
 # Desc: children of struct_declarations.long_array
-mi_list_array_varobj_children "struct_declarations.long_array" 10 "long int" \
+mi_list_array_varobj_children "struct_declarations.long_array" 10 "long" \
     "get children of struct_declarations.long_array"
 
 # Test: c_variable-4.16
@@ -199,7 +199,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.func_ptr_ptr" \
 mi_list_varobj_children "struct_declarations.u1" {
     {struct_declarations.u1.a a 0 int}
     {struct_declarations.u1.b b 1 {char \*}}
-    {struct_declarations.u1.c c 0 {long int}}
+    {struct_declarations.u1.c c 0 {long}}
     {struct_declarations.u1.d d 0 {enum foo}}
 } "get children of struct_declarations.u1"
 
@@ -215,7 +215,7 @@ mi_list_varobj_children "struct_declarations.s2" {
     {struct_declarations.s2.u2 u2 3 {union \{\.\.\.\}}}
     {struct_declarations.s2.g g 0 int}
     {struct_declarations.s2.h h 0 char}
-    {struct_declarations.s2.i i 10 {long int \[10\]}}
+    {struct_declarations.s2.i i 10 {long \[10\]}}
 } "get children of struct_declarations.s2"
 
 #gdbtk_test c_variable-4.25 {children of struct_declarations.s2} {
@@ -289,7 +289,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.u1.d" \
 # Desc: children of struct_declarations.s2.u2
 mi_list_varobj_children "struct_declarations.s2.u2" {
     {"struct_declarations.s2.u2.u1s1" "u1s1" 4 {struct \{\.\.\.\}}}
-    {struct_declarations.s2.u2.f f 0 "long int"}
+    {struct_declarations.s2.u2.f f 0 "long"}
     {struct_declarations.s2.u2.u1s2 u1s2 2 {struct \{\.\.\.\}}}
 } "get children of struct_declarations.s2.u2"
 
@@ -327,7 +327,7 @@ mi_gdb_test "-var-info-num-children struct_declarations.s2.h" \
 # Desc: children of struct_declarations.s2.i
 set t {}
 for {set i 0} {$i < 10} {incr i} {
-    lappend t [list struct_declarations.s2.i.$i $i 0 "long int"]
+    lappend t [list struct_declarations.s2.i.$i $i 0 "long"]
 }
 mi_list_varobj_children struct_declarations.s2.i $t \
 	"get children of struct_declarations.s2.i"
@@ -481,14 +481,14 @@ mi_list_varobj_children "weird" {
     {weird.integer integer 0 int}
     {weird.character character 0 char}
     {weird.char_ptr char_ptr 1 "char \\*"}
-    {weird.long_int long_int 0 "long int"}
+    {weird.long_int long_int 0 "long"}
     {weird.int_ptr_ptr int_ptr_ptr 1 "int \\*\\*"}
-    {weird.long_array long_array 10 "long int \\[10\\]"}
+    {weird.long_array long_array 10 "long \\[10\\]"}
     {weird.func_ptr func_ptr 0 "void \\(\\*\\)\\((void)?\\)"}
     {weird.func_ptr_struct func_ptr_struct 0 \
-         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long int\\))?"}
+         "struct _struct_decl \\(\\*\\)(\\(int, char \\*, long\\))?"}
     {weird.func_ptr_ptr func_ptr_ptr 0 \
-        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long int)?\\)"}
+        "struct _struct_decl \\*\\(\\*\\)\\((int, char \\*, long)?\\)"}
     {weird.u1 u1 4 "union \\{\\.\\.\\.\\}"}
     {weird.s2 s2 4 "struct \\{\\.\\.\\.\\}"}
 } "get children of weird"
@@ -502,7 +502,7 @@ mi_gdb_test "-var-info-num-children weird" \
 
 # Test: c_variable-4.84
 # Desc: children of weird->long_array
-mi_list_array_varobj_children weird.long_array 10 "long int" \
+mi_list_array_varobj_children weird.long_array 10 "long" \
 	"get children of weird.long_array"
 #gdbtk_test c_variable-4.84 {children of weird->long_array} {
 #  get_children weird.long_array
@@ -865,7 +865,7 @@ mi_create_varobj "psnp->long_ptr" "psnp->long_ptr" \
 # Test: c_variable-5.20
 # Desc: children of psnp->long_ptr
 mi_list_varobj_children "psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long int \*\*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr} {\*psnp->long_ptr} 1 {long \*\*\*}}
 } "get children of psnp->long_ptr"
 
 # Test: c_variable-5.21
@@ -877,7 +877,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr" \
 # Test: c_variable-5.22
 # Desc: children of *(psnp->long_ptr)
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr" {
-    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long int \*\*}}
+    {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr} {\*\*psnp->long_ptr} 1 {long \*\*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr"
 
 
@@ -891,7 +891,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr" \
 # Desc: children of *(*(psnp->long_ptr))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr} \
-         {\*\*\*psnp->long_ptr} 1 {long int \*}}
+         {\*\*\*psnp->long_ptr} 1 {long \*}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr"
 
 # Test: c_variable-5.25
@@ -904,7 +904,7 @@ mi_gdb_test "-var-info-num-children psnp->long_ptr.*psnp->long_ptr.**psnp->long_
 # Desc: children of *(*(*(psnp->long_ptr)))
 mi_list_varobj_children "psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr" {
     {{psnp->long_ptr.\*psnp->long_ptr.\*\*psnp->long_ptr.\*\*\*psnp->long_ptr.\*\*\*\*psnp->long_ptr}
-        {\*\*\*\*psnp->long_ptr} 0 {long int}}
+        {\*\*\*\*psnp->long_ptr} 0 {long}}
 } "get children of psnp->long_ptr.*psnp->long_ptr.**psnp->long_ptr.***psnp->long_ptr"
 
 # Test: c_variable-5.27
@@ -948,7 +948,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs" \
 # Desc: children of psnp->ptrs[0]
 mi_list_varobj_children "psnp->ptrs.0" {
     {psnp->ptrs.0.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.long_ptr long_ptr 1 {long \*\*\*\*}}
     {psnp->ptrs.0.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0"
@@ -963,7 +963,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0" \
 # Desc: children of psnp->ptrs[0]->next
 mi_list_varobj_children "psnp->ptrs.0.next" {
     {psnp->ptrs.0.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.long_ptr long_ptr 1 {long \*\*\*\*}}
     {psnp->ptrs.0.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next"
@@ -1053,7 +1053,7 @@ mi_gdb_test "-var-info-num-children psnp->ptrs.0.next.char_ptr.*char_ptr.**char_
 # Desc: children of psnp->ptrs[0]->next->next
 mi_list_varobj_children "psnp->ptrs.0.next.next" {
     {psnp->ptrs.0.next.next.char_ptr char_ptr 1 {char \*\*\*\*}}
-    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long int \*\*\*\*}}
+    {psnp->ptrs.0.next.next.long_ptr long_ptr 1 {long \*\*\*\*}}
     {psnp->ptrs.0.next.next.ptrs ptrs 3 {struct _struct_n_pointer \*\[3\]}}
     {psnp->ptrs.0.next.next.next next 4 {struct _struct_n_pointer \*}}
 } "get children of psnp->ptrs.0.next.next"
diff --git a/gdb/testsuite/lib/cp-support.exp b/gdb/testsuite/lib/cp-support.exp
index 1414ffc..173fc08 100644
--- a/gdb/testsuite/lib/cp-support.exp
+++ b/gdb/testsuite/lib/cp-support.exp
@@ -100,6 +100,8 @@ proc cp_check_errata { expected_string actual_string errata_table } {
 # demangler syntax adjustment, so you have to make a bigger table
 # with lines for each output variation.
 # 
+# IN_PTYPE_ARG are arguments to pass to ptype.  The default is "/r".
+#
 # gdb can vary the output of ptype in several ways:
 #
 # . CLASS/STRUCT
@@ -178,15 +180,16 @@ proc cp_check_errata { expected_string actual_string errata_table } {
 #
 # -- chastain 2004-08-07
 
-proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } } {
+proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } { in_ptype_arg /r } } {
     global gdb_prompt
     set wsopt "\[\r\n\t \]*"
 
-    # The test name defaults to the command.
+    # The test name defaults to the command, but without the
+    # arguments, for historical reasons.
 
     if { "$in_testname" == "" } then { set in_testname "ptype $in_exp" }
 
-    set in_command "ptype $in_exp"
+    set in_command "ptype${in_ptype_arg} $in_exp"
 
     # Save class tables in a history array for reuse.
 
@@ -232,13 +235,13 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
 
     set parse_okay 0
     gdb_test_multiple "$in_command" "$in_testname // parse failed" {
-	-re "type = (struct|class)${wsopt}(\[A-Za-z0-9_\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" {
+	-re "type = (struct|class)${wsopt}(\[^ \t\]*)${wsopt}(\\\[with .*\\\]${wsopt})?((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" {
 	    set parse_okay          1
 	    set actual_key          $expect_out(1,string)
 	    set actual_tag          $expect_out(2,string)
-	    set actual_base_string  $expect_out(3,string)
-	    set actual_body         $expect_out(5,string)
-	    set actual_tail         $expect_out(6,string)
+	    set actual_base_string  $expect_out(4,string)
+	    set actual_body         $expect_out(6,string)
+	    set actual_tail         $expect_out(7,string)
 	}
     }
     if { ! $parse_okay } then { return }
diff --git a/gdb/typeprint.c b/gdb/typeprint.c
index 509b3ee..0e1c93c 100644
--- a/gdb/typeprint.c
+++ b/gdb/typeprint.c
@@ -51,7 +51,8 @@ const struct type_print_options type_print_raw_options =
 {
   1,				/* raw */
   1,				/* print_methods */
-  1				/* print_typedefs */
+  1,				/* print_typedefs */
+  NULL				/* local_typedefs */
 };
 
 /* The default flags for 'ptype' and 'whatis'.  */
@@ -60,11 +61,202 @@ static struct type_print_options default_ptype_flags =
 {
   0,				/* raw */
   1,				/* print_methods */
-  1				/* print_typedefs */
+  1,				/* print_typedefs */
+  NULL				/* local_typedefs */
 };
 
 \f
 
+/* 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
+hash_typedef_field (const void *p)
+{
+  const struct typedef_field *tf = p;
+  struct type *t = check_typedef (tf->type);
+
+  return htab_hash_string (TYPE_SAFE_NAME (t));
+}
+
+/* An equality function for a typedef field.  */
+
+static int
+eq_typedef_field (const void *a, const void *b)
+{
+  const struct typedef_field *tfa = a;
+  const struct typedef_field *tfb = b;
+
+  return types_equal (tfa->type, tfb->type);
+}
+
+/* Add typedefs from T to the hash table TABLE.  */
+
+void
+recursively_update_typedef_hash (struct typedef_hash_table *table,
+				 struct type *t)
+{
+  int i;
+
+  if (table == NULL)
+    return;
+
+  for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
+    {
+      struct typedef_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
+      void **slot;
+
+      slot = htab_find_slot (table->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.  */
+      if (*slot == NULL)
+	*slot = tdef;
+    }
+
+  /* Recurse into superclasses.  */
+  for (i = 0; i < TYPE_N_BASECLASSES (t); ++i)
+    recursively_update_typedef_hash (table, TYPE_BASECLASS (t, i));
+}
+
+/* Add template parameters from T to the typedef hash TABLE.  */
+
+void
+add_template_parameters (struct typedef_hash_table *table, struct type *t)
+{
+  int i;
+
+  if (table == NULL)
+    return;
+
+  for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
+    {
+      struct typedef_field *tf;
+      void **slot;
+
+      /* We only want type-valued template parameters in the hash.  */
+      if (SYMBOL_CLASS (TYPE_TEMPLATE_ARGUMENT (t, i)) != LOC_TYPEDEF)
+	continue;
+
+      tf = XOBNEW (&table->storage, struct typedef_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);
+      if (*slot == NULL)
+	*slot = tf;
+    }
+}
+
+/* Create a new typedef-lookup hash table.  */
+
+struct typedef_hash_table *
+create_typedef_hash (void)
+{
+  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;
+}
+
+/* Free a typedef field table.  */
+
+void
+free_typedef_hash (struct typedef_hash_table *table)
+{
+  if (table != NULL)
+    {
+      htab_delete (table->table);
+      obstack_free (&table->storage, NULL);
+      xfree (table);
+    }
+}
+
+/* A cleanup for freeing a typedef_hash_table.  */
+
+static void
+do_free_typedef_hash (void *arg)
+{
+  free_typedef_hash (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.  */
+
+static int
+copy_typedef_hash_element (void **slot, void *nt)
+{
+  htab_t new_table = nt;
+  void **new_slot;
+
+  new_slot = htab_find_slot (new_table, *slot, INSERT);
+  if (*new_slot == NULL)
+    *new_slot = *slot;
+
+  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;
+}
+
+/* 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.  */
+
+const char *
+find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
+{
+  struct typedef_field tf, *found;
+
+  if (flags->local_typedefs == NULL)
+    return NULL;
+
+  tf.name = NULL;
+  tf.type = t;
+  found = htab_find (flags->local_typedefs->table, &tf);
+
+  return found == NULL ? NULL : found->name;
+}
+
+\f
+
 /* Print a description of a type in the format of a 
    typedef for the current language.
    NEW is the new name for a type TYPE.  */
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 1e15097..71bac01 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -22,6 +22,7 @@
 
 enum language;
 struct ui_file;
+struct typedef_hash_table;
 
 struct type_print_options
 {
@@ -33,10 +34,30 @@ struct type_print_options
 
   /* True means print typedefs in a class.  */
   unsigned int print_typedefs : 1;
+
+  /* If not NULL, a local typedef hash table used when printing a
+     type.  */
+  struct typedef_hash_table *local_typedefs;
 };
 
 extern const struct type_print_options type_print_raw_options;
 
+void recursively_update_typedef_hash (struct typedef_hash_table *,
+				      struct type *);
+
+void add_template_parameters (struct typedef_hash_table *, struct type *);
+
+struct typedef_hash_table *create_typedef_hash (void);
+
+void free_typedef_hash (struct typedef_hash_table *);
+
+struct cleanup *make_cleanup_free_typedef_hash (struct typedef_hash_table *);
+
+struct typedef_hash_table *copy_typedef_hash (struct typedef_hash_table *);
+
+const char *find_typedef_in_hash (const struct type_print_options *,
+				  struct type *);
+
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
 void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
-- 
1.7.7.6

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-11-05 20:26         ` Tom Tromey
@ 2012-11-05 20:52           ` Eli Zaretskii
  2012-11-06 15:14             ` Tom Tromey
  0 siblings, 1 reply; 9+ messages in thread
From: Eli Zaretskii @ 2012-11-05 20:52 UTC (permalink / raw)
  To: Tom Tromey; +Cc: palves, gdb-patches

> From: Tom Tromey <tromey@redhat.com>
> Cc: gdb-patches@sourceware.org
> Date: Mon, 05 Nov 2012 13:26:09 -0700
> 
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -8,6 +8,9 @@
>  -nh   Disables auto-loading of ~/.gdbinit, but still executes all the
>        other initialization files, unlike -nx which disables all of them.
>  
> +* The 'ptype' and 'whatis' commands now accept an argument to control
> +  type formatting.
> +
>  * Python scripting
>  
>    ** Vectors can be created with gdb.Type.vector.
> @@ -52,6 +55,18 @@ py [command]
>       (has been deprecated in GDB 7.5), and "info all-registers" should be used
>       instead.
>  
> +* New options
> +
> +set print type methods (on|off)
> +show print type methods
> +  Control whether method declarations are displayed by "ptype".
> +  The default is to show them.
> +
> +set print type typedefs (on|off)
> +show print type typedefs
> +  Control whether typedef definitions are displayed by "ptype".
> +  The default is to show them.
> +

This part is OK, but shouldn't there be a patch for the manual to
match it?  Or did I miss something?

Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 8/9] class-local typedef substitutions
  2012-11-05 20:52           ` Eli Zaretskii
@ 2012-11-06 15:14             ` Tom Tromey
  0 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2012-11-06 15:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: palves, gdb-patches

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

>> +set print type methods (on|off)
>> +show print type methods
>> +  Control whether method declarations are displayed by "ptype".
>> +  The default is to show them.
>> +
>> +set print type typedefs (on|off)
>> +show print type typedefs
>> +  Control whether typedef definitions are displayed by "ptype".
>> +  The default is to show them.
>> +

Eli> This part is OK, but shouldn't there be a patch for the manual to
Eli> match it?  Or did I miss something?

Somehow the doc parts were in patch #6 ("add ptype/r to the cli").
You approved it conditionally -- thanks for bringing this up, I didn't
make those changes yet.  I'll make the updates now and I'll see whether
one of the changes should go into a different patch in the series.

Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-11-06 15:14 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-07 18:51 [PATCH 8/9] class-local typedef substitutions Tom Tromey
2012-09-08  8:00 ` Eli Zaretskii
2012-09-21 19:32 ` Tom Tromey
2012-10-31 19:18   ` Pedro Alves
2012-11-01 21:01     ` Tom Tromey
2012-11-02 20:52       ` Tom Tromey
2012-11-05 20:26         ` Tom Tromey
2012-11-05 20:52           ` Eli Zaretskii
2012-11-06 15:14             ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).