This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


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

Re: [PATCH 8/9] class-local typedef substitutions


>>>>> "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);
 
+
+/* 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);
+}
+
+
+
 /* 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 */
 };
 
 
 
+/* 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;
+}
+
+
+
 /* 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


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