Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFA] Typedef'd method parameters [0/4]
@ 2011-04-21 21:15 Keith Seitz
  2011-04-25 20:53 ` Tom Tromey
  2011-05-12 21:28 ` Keith Seitz
  0 siblings, 2 replies; 9+ messages in thread
From: Keith Seitz @ 2011-04-21 21:15 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 3907 bytes --]

Hi,

I've been working on fixing c++/12266 and c++/12506 in which users are 
unable to specify linespecs for class methods which have typedef'd 
parameters, e.g., klass:method(my_typedef). This is an attempt to fix 
this shortcoming. [This is not a dwarf2_physname regression.]

I've attempted to split this up into four different patches to help 
facilitate review, but to be honest, I'm not sure how helpful this split 
is going to be, but I'll leave it to maintainers to ask for whatever 
would help them digest this easiest.

Back to the problem. Physnames (similar to linkage names) are used to 
store symbols in the symbol tables -- this is the whole dwarf2_physname 
patchset from last year. These physnames should represent the most basic 
"name" of a symbol.

The inability to use typedef'd parameter types arises from the fact that 
we do fairly literal lookups in the symbol table from decode_line_1 et 
al. So for example, if the user types "break klass::method(my_typedef)", 
decode_compound will attempt to look for a method of "klass" with the 
parameter type "my_typedef". Alas, as I've already mentioned, the symbol 
tables do not contain this information -- the contain whatever the 
typedef resolves to (klass::method(int), for example).

The proposed solution in this patchset is to use the C++ name parser to 
find these method parameter types, look them up, and if they are 
typedefs, change the name in the tree to physname of the typedef.

A note on the test suite: I propose to get these all approved and commit 
in one go. If done this way, no test suite regressions should occur. Or 
at least they don't show up here. :-)

There are several (mechanical) problems that arise from this approach 
that need to be dealt with first. First of all, 
cp_demangled_name_to_comp can not be called recursively because the 
storage for the resulting parse tree is rewritten with every call.

This can happen before debuginfo is read and the user attempts to 
specify a linespec; when the typedef is looked up, the dwarf reader will 
call cp_canonicalize_string, destroying the result. So the first of 
these patches addresses this. It is pretty much orthogonal to the other 
patches.

Second, c_type_print_args (and several functions in c-typeprint.c) 
needed to be taught the difference between linkage names and print 
names. [Reminder: Both skip artificial parameters; linkage names always 
resolve typedefs.] This is addressed in the second patch.

The third patch is actually the "guts" of the patch, which walks the 
name parse tree and converts typedefs. The main function of interest 
here is cp_canonicalize_string_no_typedefs, which is largely a clone of 
cp_canonicalize_string, except that it resolves any typedefs found in 
the name (as if you couldn't guess that).

The final/fourth patch is test cases for this. I have really tried to 
hit a bunch of corner cases, but it is likely that users have thought of 
some way to express something in C++ that I have not.

Just a side note for maintainers, since I know this is going to come up: 
I have tried my best to consolidate name canonicalization, but there are 
a bunch of problems that arise from attempting to do this. I believe the 
solution proposed here is the most consistent from an API perspective -- 
everything still acts the way it should (and has). The alternative is to 
canonicalize_no_typedefs before anyone calls lookup_symbol or 
lookup_symbol_in_language. I rejected this approach.

In one specific case, we have no choice but to re-canonicalize the input 
anyway, and this isn't particularly time-critical code, since it is only 
called from decode_line_1, i.e., from user input. It does not get called 
from dwarf2read.c.

Keith

PS. I've attached the whole patch as a single large piece for those 
interested in skipping the piecemeal evaluation of the patchset. [See 
ChangeLogs in subsequent messages.]

[-- Attachment #2: 12266-whole.patch --]
[-- Type: text/plain, Size: 44299 bytes --]

Index: c-typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/c-typeprint.c,v
retrieving revision 1.70
diff -u -p -r1.70 c-typeprint.c
--- c-typeprint.c	22 Mar 2011 17:35:22 -0000	1.70
+++ c-typeprint.c	21 Apr 2011 17:59:14 -0000
@@ -44,14 +44,22 @@ static void c_type_print_varspec_prefix 
 static void c_type_print_modifier (struct type *,
 				   struct ui_file *,
 				   int, int);
+
+static void c_type_print_base_internal (struct type *, struct ui_file *,
+					int, int, int);
+
 \f
-/* LEVEL is the depth to indent lines by.  */
+/* The real c_print_type.  See c_print_type below for a description
+   of parameters and usage.
 
-void
-c_print_type (struct type *type,
-	      const char *varstring,
-	      struct ui_file *stream,
-	      int show, int level)
+   LINKAGE_NAME should be non-zero if we are printing a linkage name
+   on the stream.  */
+
+static void
+c_print_type_internal (struct type *type,
+		       const char *varstring,
+		       struct ui_file *stream,
+		       int show, int level, int linkage_name)
 {
   enum type_code code;
   int demangled_args;
@@ -60,7 +68,7 @@ c_print_type (struct type *type,
   if (show > 0)
     CHECK_TYPEDEF (type);
 
-  c_type_print_base (type, stream, show, level);
+  c_type_print_base_internal (type, stream, show, level, linkage_name);
   code = TYPE_CODE (type);
   if ((varstring != NULL && *varstring != '\0')
   /* Need a space if going to print stars or brackets;
@@ -85,10 +93,25 @@ c_print_type (struct type *type,
 
       demangled_args = strchr (varstring, '(') != NULL;
       c_type_print_varspec_suffix (type, stream, show,
-				   0, demangled_args);
+				   0, demangled_args, linkage_name);
     }
 }
 
+/* Print TYPE to the STREAM.
+   VARSTRING (optional) is the name of the field being printed.
+   If SHOW is greater than zero,  print the details of the type.  Otherwise
+   simply print the type name.
+   LEVEL is the depth to indent lines by.  */
+
+void
+c_print_type (struct type *type,
+	      const char *varstring,
+	      struct ui_file *stream,
+	      int show, int level)
+{
+  c_print_type_internal (type, varstring, stream, show, level, 0);
+}
+
 /* Print a typedef using C syntax.  TYPE is the underlying type.
    NEW_SYMBOL is the symbol naming the type.  STREAM is the stream on
    which to print.  */
@@ -166,17 +189,14 @@ cp_type_print_derivation_info (struct ui
 /* Print the C++ method arguments ARGS to the file STREAM.  */
 
 static void
-cp_type_print_method_args (struct type *mtype, char *prefix,
-			   char *varstring, int staticp,
-			   struct ui_file *stream)
+cp_type_print_method_args (struct type *mtype, char *varstring,
+			   int staticp, struct ui_file *stream)
 {
   struct field *args = TYPE_FIELDS (mtype);
   int nargs = TYPE_NFIELDS (mtype);
   int varargs = TYPE_VARARGS (mtype);
   int i;
 
-  fprintf_symbol_filtered (stream, prefix,
-			   language_cplus, DMGL_ANSI);
   fprintf_symbol_filtered (stream, varstring,
 			   language_cplus, DMGL_ANSI);
   fputs_filtered ("(", stream);
@@ -386,17 +406,25 @@ c_type_print_modifier (struct type *type
 
 
 /* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD
-   or TYPE_CODE_FUNC, to STREAM.  Artificial arguments, such as "this"
-   in non-static methods, are displayed if LINKAGE_NAME is zero.  If
-   LINKAGE_NAME is non-zero and LANGUAGE is language_cplus the topmost
-   parameter types get removed their possible const and volatile qualifiers to
+   or TYPE_CODE_FUNC, to STREAM.
+
+   LINKAGE_NAME is non-zero when the SYMBOL_LINKAGE_NAME of TYPE
+   (a function or method) is printed.  Artifical parameters such as "this"
+   in non-static methods are skipped and all typedefs will be removed/expanded.
+   Additionally if LANGUAGE is language_cplus, topmost parameter types
+   may have any possible const and volatile qualifiers removed to
    match demangled linkage name parameters part of such function type.
+
+   PRINT_NAME is non-zero when the SYMBOL_PRINT_NAME of TYPE is
+   printed.  In this case, artificial parameters are skipped, but
+   any typedef'd parameter types are left intact.
+
    LANGUAGE is the language in which TYPE was defined.  This is a necessary
    evil since this code is used by the C, C++, and Java backends.  */
 
 void
 c_type_print_args (struct type *type, struct ui_file *stream,
-		   int linkage_name, enum language language)
+		   int linkage_name, int print_name, enum language language)
 {
   int i, len;
   struct field *args;
@@ -410,7 +438,7 @@ c_type_print_args (struct type *type, st
     {
       struct type *param_type;
 
-      if (TYPE_FIELD_ARTIFICIAL (type, i) && linkage_name)
+      if (TYPE_FIELD_ARTIFICIAL (type, i) && (linkage_name || print_name))
 	continue;
 
       if (printed_any)
@@ -433,10 +461,13 @@ c_type_print_args (struct type *type, st
 	  param_type = make_cv_type (0, 0, param_type, NULL);
 	}
 
+      if (linkage_name)
+	CHECK_TYPEDEF (param_type);
+
       if (language == language_java)
 	java_print_type (param_type, "", stream, -1, 0);
       else
-	c_print_type (param_type, "", stream, -1, 0);
+	c_print_type_internal (param_type, "", stream, -1, 0, linkage_name);
       printed_any = 1;
     }
 
@@ -599,13 +630,16 @@ remove_qualifiers (char *qid)
 
 /* Print any array sizes, function arguments or close parentheses
    needed after the variable name (to describe its type).
-   Args work like c_type_print_varspec_prefix.  */
+   Args work like c_type_print_varspec_prefix.
+
+   LINKAGE_NAME is non-zero when printing the linkage name of a
+   function or method.  */
 
 void
 c_type_print_varspec_suffix (struct type *type,
 			     struct ui_file *stream,
 			     int show, int passed_a_ptr,
-			     int demangled_args)
+			     int demangled_args, int linkage_name)
 {
   if (type == 0)
     return;
@@ -631,25 +665,25 @@ c_type_print_varspec_suffix (struct type
 	fprintf_filtered (stream, "]");
 
 	c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				     show, 0, 0);
+				     show, 0, 0, linkage_name);
       }
       break;
 
     case TYPE_CODE_MEMBERPTR:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 0, 0);
+				   show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_METHODPTR:
       fprintf_filtered (stream, ")");
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 0, 0);
+				   show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 1, 0);
+				   show, 1, 0, linkage_name);
       break;
 
     case TYPE_CODE_METHOD:
@@ -657,14 +691,17 @@ c_type_print_varspec_suffix (struct type
       if (passed_a_ptr)
 	fprintf_filtered (stream, ")");
       if (!demangled_args)
-	c_type_print_args (type, stream, 0, current_language->la_language);
+	{
+	  c_type_print_args (type, stream, linkage_name, 0,
+			     current_language->la_language);
+	}
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, passed_a_ptr, 0);
+				   show, passed_a_ptr, 0, linkage_name);
       break;
 
     case TYPE_CODE_TYPEDEF:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, passed_a_ptr, 0);
+				   show, passed_a_ptr, 0, linkage_name);
       break;
 
     case TYPE_CODE_UNDEF:
@@ -694,27 +731,14 @@ c_type_print_varspec_suffix (struct type
     }
 }
 
-/* Print the name of the type (or the ultimate pointer target,
-   function value or array element), or the description of a structure
-   or union.
-
-   SHOW positive means print details about the type (e.g. enum
-   values), and print structure elements passing SHOW - 1 for show.
-
-   SHOW negative means just print the type name or struct tag if there
-   is one.  If there is no name, print something sensible but concise
-   like "struct {...}".
+/* The real c_type_print_base_internal.  This function takes an
+   additional argument over the API function c_type_print_base:
+   LINKAGE_NAME, which is non-zero when the linkage name is being
+   printed to the STREAM.  */
 
-   SHOW zero means just print the type name or struct tag if there is
-   one.  If there is no name, print something sensible but not as
-   concise like "struct {int x; int y;}".
-
-   LEVEL is the number of spaces to indent by.
-   We increase it for some recursive calls.  */
-
-void
-c_type_print_base (struct type *type, struct ui_file *stream,
-		   int show, int level)
+static void
+c_type_print_base_internal (struct type *type, struct ui_file *stream,
+			    int show, int level, int linkage_name)
 {
   int i;
   int len, real_len;
@@ -773,8 +797,8 @@ c_type_print_base (struct type *type, st
     case TYPE_CODE_FUNC:
     case TYPE_CODE_METHOD:
     case TYPE_CODE_METHODPTR:
-      c_type_print_base (TYPE_TARGET_TYPE (type),
-			 stream, show, level);
+      c_type_print_base_internal (TYPE_TARGET_TYPE (type),
+				  stream, show, level, linkage_name);
       break;
 
     case TYPE_CODE_STRUCT:
@@ -954,9 +978,10 @@ c_type_print_base (struct type *type, st
 	      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);
+	      c_print_type_internal (TYPE_FIELD_TYPE (type, i),
+				     TYPE_FIELD_NAME (type, i),
+				     stream, show - 1, level + 4,
+				     linkage_name);
 	      if (!field_is_static (&TYPE_FIELD (type, i))
 		  && TYPE_FIELD_PACKED (type, i))
 		{
@@ -1085,7 +1110,6 @@ c_type_print_base (struct type *type, st
 			  struct type *mtype = TYPE_FN_FIELD_TYPE (f, j);
 
 			  cp_type_print_method_args (mtype,
-						     "",
 						     method_name,
 						     staticp,
 						     stream);
@@ -1145,8 +1169,10 @@ c_type_print_base (struct type *type, st
 
 		  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);
+		  c_print_type_internal (target,
+					 TYPE_TYPEDEF_FIELD_NAME (type, i),
+					 stream, show - 1, level + 4,
+					 linkage_name);
 		  fprintf_filtered (stream, ";\n");
 		}
 	    }
@@ -1251,3 +1277,28 @@ c_type_print_base (struct type *type, st
       break;
     }
 }
+
+/* Print the name of the type (or the ultimate pointer target,
+   function value or array element), or the description of a structure
+   or union.
+
+   SHOW positive means print details about the type (e.g. enum
+   values), and print structure elements passing SHOW - 1 for show.
+
+   SHOW negative means just print the type name or struct tag if there
+   is one.  If there is no name, print something sensible but concise
+   like "struct {...}".
+
+   SHOW zero means just print the type name or struct tag if there is
+   one.  If there is no name, print something sensible but not as
+   concise like "struct {int x; int y;}".
+
+   LEVEL is the number of spaces to indent by.
+   We increase it for some recursive calls.  */
+
+void
+c_type_print_base (struct type *type, struct ui_file *stream,
+		   int show, int level)
+{
+  c_type_print_base_internal (type, stream, show, level, 0);
+}
Index: cp-name-parser.y
===================================================================
RCS file: /cvs/src/src/gdb/cp-name-parser.y,v
retrieving revision 1.20
diff -u -p -r1.20 cp-name-parser.y
--- cp-name-parser.y	18 Mar 2011 13:51:41 -0000	1.20
+++ cp-name-parser.y	21 Apr 2011 17:59:14 -0000
@@ -1935,20 +1935,15 @@ yyerror (char *msg)
    generally allocate too many components, but the extra memory usage
    doesn't hurt because the trees are temporary and the storage is
    reused.  More may be allocated later, by d_grab.  */
-static void
+static struct demangle_info *
 allocate_info (void)
 {
-  if (demangle_info == NULL)
-    {
-      demangle_info = malloc (sizeof (struct demangle_info));
-      demangle_info->prev = NULL;
-      demangle_info->next = NULL;
-    }
-  else
-    while (demangle_info->prev)
-      demangle_info = demangle_info->prev;
+  struct demangle_info *info = malloc (sizeof (struct demangle_info));
 
-  demangle_info->used = 0;
+  info->prev = NULL;
+  info->next = NULL;
+  info->used = 0;
+  return info;
 }
 
 /* Convert RESULT to a string.  The return value is allocated
@@ -1966,23 +1961,46 @@ cp_comp_to_string (struct demangle_compo
 			       &err);
 }
 
+/* Free any memory associated with the given PARSE_INFO.  */
+
+void
+cp_demangled_name_parse_free (struct demangle_parse_info *parse_info)
+{
+  struct demangle_info *info = parse_info->info;
+
+  /* Free any allocated chunks of memory for the parse.  */
+  while (info != NULL)
+    {
+      struct demangle_info *next = info->next;
+      free (info);
+      info = next;
+    }
+
+  /* Free the parser info.  */
+  free (parse_info);
+}
+
 /* Convert a demangled name to a demangle_component tree.  On success,
-   the root of the new tree is returned; it is valid until the next
-   call to this function and should not be freed.  On error, NULL is
+   a structure containing the root of the new tree is returned; it must
+   be freed by calling cp_demangled_name_parse_free. On error, NULL is
    returned, and an error message will be set in *ERRMSG (which does
    not need to be freed).  */
 
-struct demangle_component *
+struct demangle_parse_info *
 cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
 {
   static char errbuf[60];
-  struct demangle_component *result;
+  struct demangle_parse_info *result;
 
   prev_lexptr = lexptr = demangled_name;
   error_lexptr = NULL;
   global_errmsg = NULL;
 
-  allocate_info ();
+  demangle_info = allocate_info ();
+
+  result = ((struct demangle_parse_info *)
+	    malloc (sizeof (struct demangle_parse_info)));
+  result->info = demangle_info;
 
   if (yyparse ())
     {
@@ -1993,10 +2011,11 @@ cp_demangled_name_to_comp (const char *d
 	  strcat (errbuf, "'");
 	  *errmsg = errbuf;
 	}
+      cp_demangled_name_parse_free (result);
       return NULL;
     }
 
-  result = global_result;
+  result->tree = global_result;
   global_result = NULL;
 
   return result;
@@ -2052,7 +2071,7 @@ main (int argc, char **argv)
   char buf[65536];
   int arg;
   const char *errmsg;
-  struct demangle_component *result;
+  struct demangle_parse_info *result;
 
   arg = 1;
   if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
@@ -2086,7 +2105,8 @@ main (int argc, char **argv)
 	    continue;
 	  }
 
-	cp_print (result);
+	cp_print (result->tree);
+	cp_demangled_name_parse_free (result);
 
 	free (str2);
 	if (c)
@@ -2105,7 +2125,8 @@ main (int argc, char **argv)
 	  fputc ('\n', stderr);
 	  return 0;
 	}
-      cp_print (result);
+      cp_print (result->tree);
+      cp_demangled_name_parse_free (result);
       putchar ('\n');
     }
   return 0;
Index: cp-support.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.c,v
retrieving revision 1.49
diff -u -p -r1.49 cp-support.c
--- cp-support.c	26 Feb 2011 02:07:07 -0000	1.49
+++ cp-support.c	21 Apr 2011 17:59:15 -0000
@@ -117,6 +117,115 @@ cp_already_canonical (const char *string
     return 0;
 }
 
+/* Insepct the given RET_COMP for its type.  If it is a typedef,
+   replace the name stored in the tree with the typedef's fully resolved
+   type.  If no changes have been made to the tree, set CHANGED to 0;
+   otherwise set it to 1.  FREE_LIST contains any temprorary storage
+   that was used to revise the tree.  It should be freed by the caller. */
+
+static void
+inspect_type (struct demangle_component *ret_comp)
+{
+  char *name;
+  struct symbol *sym;
+
+  name = (char *) alloca (ret_comp->u.s_name.len + 1);
+  strncpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len);
+  name[ret_comp->u.s_name.len] = '\0';
+  sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+  if (sym != NULL)
+    {
+      struct type *type = SYMBOL_TYPE (sym);
+
+      if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+	{
+	  char *canon;
+	  struct ui_file *buf = mem_fileopen ();
+
+	  CHECK_TYPEDEF (type);
+	  type_print (type, "", buf, -1);
+	  name = ui_file_xstrdup (buf, NULL);
+	  ui_file_delete (buf);
+	  canon = cp_canonicalize_string_no_typedefs (name);
+	  if (canon != NULL)
+	    {
+	      xfree (name);
+	      name = canon;
+	    }
+	  ret_comp->u.s_name.s = name;
+	  ret_comp->u.s_name.len = strlen (name);
+	}
+    }
+}
+
+/* Walk the parse tree given by RET_COMP, replacing any typedefs with
+   their basic types.  CHANGED is set to indicate whether any changes
+   to the tree were made, and FREE_LIST will contain any memory used
+   for this purpose.  It must be freed by the caller.  */
+
+static void
+replace_typedefs (struct demangle_component *ret_comp)
+{
+  if (ret_comp)
+    {
+      switch (ret_comp->type)
+	{
+	case DEMANGLE_COMPONENT_ARGLIST:
+	  replace_typedefs (d_left (ret_comp));
+	  replace_typedefs (d_right (ret_comp));
+	  break;
+
+	case DEMANGLE_COMPONENT_NAME:
+	  inspect_type (ret_comp);
+	  break;
+
+	case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+	  replace_typedefs (d_right (ret_comp));
+	  break;
+
+	case DEMANGLE_COMPONENT_QUAL_NAME:
+	case DEMANGLE_COMPONENT_POINTER:
+	  replace_typedefs (d_left (ret_comp));
+	  break;
+
+	default:
+	  break;
+	}
+    }
+}
+
+/* Parse STRING and convert it to canonical form, resolving any typedefs. 
+   If parsing fails, or if STRING is already canonical, return NULL. 
+   Otherwise return the canonical form.  The return value is allocated via
+   xmalloc.  */
+
+char *
+cp_canonicalize_string_no_typedefs (const char *string)
+{
+  char *ret;
+  unsigned int estimated_len;
+  struct demangle_parse_info *info;
+
+  ret = NULL;
+  estimated_len = strlen (string) * 2;
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info != NULL)
+    {
+      replace_typedefs (info->tree);
+      ret = cp_comp_to_string (info->tree, estimated_len);
+      cp_demangled_name_parse_free (info);
+      if (strcmp (string, ret) == 0)
+	{
+	  xfree (ret);
+	  return NULL;
+	}
+    }
+
+  return ret;
+}
+
 /* Parse STRING and convert it to canonical form.  If parsing fails,
    or if STRING is already canonical, return NULL.  Otherwise return
    the canonical form.  The return value is allocated via xmalloc.  */
@@ -124,20 +233,21 @@ cp_already_canonical (const char *string
 char *
 cp_canonicalize_string (const char *string)
 {
-  struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   unsigned int estimated_len;
   char *ret;
 
   if (cp_already_canonical (string))
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (string, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info == NULL)
     return NULL;
 
   estimated_len = strlen (string) * 2;
-  ret = cp_comp_to_string (ret_comp, estimated_len);
-
+  ret = cp_comp_to_string (info->tree, estimated_len);
+  cp_demangled_name_parse_free (info);
+  
   if (strcmp (string, ret) == 0)
     {
       xfree (ret);
@@ -153,23 +263,28 @@ cp_canonicalize_string (const char *stri
    freed when finished with the tree, or NULL if none was needed.
    OPTIONS will be passed to the demangler.  */
 
-static struct demangle_component *
+static struct demangle_parse_info *
 mangled_name_to_comp (const char *mangled_name, int options,
 		      void **memory, char **demangled_p)
 {
-  struct demangle_component *ret;
   char *demangled_name;
+  struct demangle_parse_info *info;
 
   /* If it looks like a v3 mangled name, then try to go directly
      to trees.  */
   if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
     {
+      struct demangle_component *ret;
       ret = cplus_demangle_v3_components (mangled_name,
 					  options, memory);
       if (ret)
 	{
+	  info = ((struct demangle_parse_info *)
+		  xmalloc (sizeof (struct demangle_parse_info)));
+	  info->info = NULL;
+	  info->tree = ret;
 	  *demangled_p = NULL;
-	  return ret;
+	  return info;
 	}
     }
 
@@ -181,16 +296,16 @@ mangled_name_to_comp (const char *mangle
   
   /* If we could demangle the name, parse it to build the component
      tree.  */
-  ret = cp_demangled_name_to_comp (demangled_name, NULL);
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
 
-  if (ret == NULL)
+  if (info == NULL)
     {
       xfree (demangled_name);
       return NULL;
     }
 
   *demangled_p = demangled_name;
-  return ret;
+  return info;
 }
 
 /* Return the name of the class containing method PHYSNAME.  */
@@ -201,14 +316,16 @@ cp_class_name_from_physname (const char 
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp, *prev_comp, *cur_comp;
+  struct demangle_parse_info *info;
   int done;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-				   &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+			       &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
   done = 0;
+  ret_comp = info->tree;
 
   /* First strip off any qualifiers, if we have a function or
      method.  */
@@ -277,8 +394,8 @@ cp_class_name_from_physname (const char 
     }
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -348,13 +465,14 @@ method_name_from_physname (const char *p
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-				   &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+			       &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
@@ -363,8 +481,8 @@ method_name_from_physname (const char *p
     ret = cp_comp_to_string (ret_comp, 10);
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -379,17 +497,19 @@ cp_func_name (const char *full_name)
 {
   char *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = cp_demangled_name_to_comp (full_name, NULL);
-  if (!ret_comp)
+  info = cp_demangled_name_to_comp (full_name, NULL);
+  if (!info)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
     ret = cp_comp_to_string (ret_comp, 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -402,16 +522,18 @@ cp_remove_params (const char *demangled_
 {
   int done = 0;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   char *ret = NULL;
 
   if (demangled_name == NULL)
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (demangled_name, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
+  if (info == NULL)
     return NULL;
 
   /* First strip off any qualifiers, if we have a function or method.  */
+  ret_comp = info->tree;
   while (!done)
     switch (ret_comp->type)
       {
@@ -433,6 +555,7 @@ cp_remove_params (const char *demangled_
   if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
     ret = cp_comp_to_string (d_left (ret_comp), 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
Index: cp-support.h
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.h,v
retrieving revision 1.42
diff -u -p -r1.42 cp-support.h
--- cp-support.h	4 Apr 2011 14:37:16 -0000	1.42
+++ cp-support.h	21 Apr 2011 17:59:15 -0000
@@ -36,6 +36,16 @@ struct objfile;
 struct type;
 struct demangle_component;
 
+/* The result of parsing a name.  */
+struct demangle_parse_info
+{
+  /* The memory used during the parse.  */
+  struct demangle_info *info;
+
+  /* The result of the parse.  */
+  struct demangle_component *tree;
+};
+
 /* This struct is designed to store data from using directives.  It
    says that names from namespace IMPORT_SRC should be visible within
    namespace IMPORT_DEST.  These form a linked list; NEXT is the next
@@ -100,6 +110,8 @@ struct using_direct
 
 extern char *cp_canonicalize_string (const char *string);
 
+extern char *cp_canonicalize_string_no_typedefs (const char *string);
+
 extern char *cp_class_name_from_physname (const char *physname);
 
 extern char *method_name_from_physname (const char *physname);
@@ -177,12 +189,14 @@ struct type *cp_lookup_transparent_type 
 
 /* Functions from cp-name-parser.y.  */
 
-extern struct demangle_component *cp_demangled_name_to_comp
+extern struct demangle_parse_info *cp_demangled_name_to_comp
   (const char *demangled_name, const char **errmsg);
 
 extern char *cp_comp_to_string (struct demangle_component *result,
 				int estimated_len);
 
+extern void cp_demangled_name_parse_free (struct demangle_parse_info *);
+
 /* The list of "maint cplus" commands.  */
 
 extern struct cmd_list_element *maint_cplus_cmd_list;
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.524
diff -u -p -r1.524 dwarf2read.c
--- dwarf2read.c	15 Apr 2011 15:05:04 -0000	1.524
+++ dwarf2read.c	21 Apr 2011 17:59:17 -0000
@@ -307,6 +307,16 @@ struct delayed_method_info
 typedef struct delayed_method_info delayed_method_info;
 DEF_VEC_O (delayed_method_info);
 
+/* An enumeration for specifying the type of name dwarf2_compute_name
+   generates.  */
+enum name_kind
+  {
+    NAME_KIND_FULL,	/* The fullname (methods do not
+			   contain any formal parameters).  */
+    NAME_KIND_PHYS,	/* The physname used to lookup symbols.  */
+    NAME_KIND_PRINT	/* The name used when printing the symbol.  */
+  };
+    
 /* Internal state when decoding a particular compilation unit.  */
 struct dwarf2_cu
 {
@@ -4835,7 +4845,7 @@ do_ui_file_peek_last (void *object, cons
 
 static const char *
 dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
-		     int physname)
+		     enum name_kind kind)
 {
   if (name == NULL)
     name = dwarf2_name (die, cu);
@@ -4843,7 +4853,7 @@ dwarf2_compute_name (char *name, struct 
   /* For Fortran GDB prefers DW_AT_*linkage_name if present but otherwise
      compute it by typename_concat inside GDB.  */
   if (cu->language == language_ada
-      || (cu->language == language_fortran && physname))
+      || (cu->language == language_fortran && kind == NAME_KIND_PHYS))
     {
       /* For Ada unit, we prefer the linkage name over the name, as
 	 the former contains the exported name, which the user expects
@@ -4875,7 +4885,8 @@ dwarf2_compute_name (char *name, struct 
 	  if (*prefix != '\0')
 	    {
 	      char *prefixed_name = typename_concat (NULL, prefix, name,
-						     physname, cu);
+						     (kind == NAME_KIND_PHYS),
+						     cu);
 
 	      fputs_unfiltered (prefixed_name, buf);
 	      xfree (prefixed_name);
@@ -5012,13 +5023,17 @@ dwarf2_compute_name (char *name, struct 
 	  /* For Java and C++ methods, append formal parameter type
 	     information, if PHYSNAME.  */
 
-	  if (physname && die->tag == DW_TAG_subprogram
+	  if ((kind == NAME_KIND_PHYS || kind == NAME_KIND_PRINT)
+	      && die->tag == DW_TAG_subprogram
 	      && (cu->language == language_cplus
 		  || cu->language == language_java))
 	    {
 	      struct type *type = read_type_die (die, cu);
 
-	      c_type_print_args (type, buf, 1, cu->language);
+	      c_type_print_args (type, buf,
+				 (kind == NAME_KIND_PHYS ? 1 : 0),
+				 (kind == NAME_KIND_PRINT ? 1 : 0),
+				 cu->language);
 
 	      if (cu->language == language_java)
 		{
@@ -5074,7 +5089,7 @@ dwarf2_compute_name (char *name, struct 
 static const char *
 dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, 0);
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_FULL);
 }
 
 /* Construct a physname for the given DIE in CU.  NAME may either be
@@ -5087,7 +5102,13 @@ dwarf2_full_name (char *name, struct die
 static const char *
 dwarf2_physname (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, 1);
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_PHYS);
+}
+
+static const char *
+dwarf2_print_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
+{
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_PRINT);
 }
 
 /* Read the import statement specified by the given die and record it.  */
@@ -11002,6 +11023,20 @@ new_symbol_full (struct die_info *die, s
       linkagename = dwarf2_physname (name, die, cu);
       SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), 0, objfile);
 
+      /* For C++ set the symbol's demangled name if it is different than
+	 the computed physname.  This can happen when the source defines
+	 a method with typedef'd parameters.  This is ultimately used by
+	 the type printer.  */
+      if (cu->language == language_cplus && die->tag == DW_TAG_subprogram)
+	{
+	  const char *print_name = dwarf2_print_name (name, die, cu);
+	  if (strcmp (print_name, linkagename))
+	    {
+	      symbol_set_demangled_name (&(sym->ginfo),
+					 (char *) print_name, NULL);
+	    }
+	}
+
       /* Fortran does not have mangling standard and the mangling does differ
 	 between gfortran, iFort etc.  */
       if (cu->language == language_fortran
Index: jv-typeprint.c
===================================================================
RCS file: /cvs/src/src/gdb/jv-typeprint.c,v
retrieving revision 1.22
diff -u -p -r1.22 jv-typeprint.c
--- jv-typeprint.c	9 Jan 2011 03:08:57 -0000	1.22
+++ jv-typeprint.c	21 Apr 2011 17:59:18 -0000
@@ -328,9 +328,6 @@ java_type_print_base (struct type *type,
 
 /* LEVEL is the depth to indent lines by.  */
 
-extern void c_type_print_varspec_suffix (struct type *, struct ui_file *,
-					 int, int, int);
-
 void
 java_print_type (struct type *type, const char *varstring,
 		 struct ui_file *stream, int show, int level)
@@ -349,5 +346,5 @@ java_print_type (struct type *type, cons
      so don't print an additional pair of ()'s.  */
 
   demangled_args = varstring != NULL && strchr (varstring, '(') != NULL;
-  c_type_print_varspec_suffix (type, stream, show, 0, demangled_args);
+  c_type_print_varspec_suffix (type, stream, show, 0, demangled_args, 0);
 }
Index: linespec.c
===================================================================
RCS file: /cvs/src/src/gdb/linespec.c,v
retrieving revision 1.118
diff -u -p -r1.118 linespec.c
--- linespec.c	4 Apr 2011 17:41:07 -0000	1.118
+++ linespec.c	21 Apr 2011 17:59:18 -0000
@@ -222,7 +222,7 @@ find_methods (struct type *t, char *name
 
   /* NAME is typed by the user: it needs to be canonicalized before
      passing to lookup_symbol.  */
-  canon = cp_canonicalize_string (name);
+  canon = cp_canonicalize_string_no_typedefs (name);
   if (canon != NULL)
     {
       name = canon;
@@ -1315,7 +1315,7 @@ decode_compound (char **argptr, int funf
 		 char *the_real_saved_arg, char *p)
 {
   struct symtabs_and_lines values;
-  char *p2;
+  char *p2, *name, *canon;
   char *saved_arg2 = *argptr;
   char *temp_end;
   struct symbol *sym;
@@ -1324,6 +1324,7 @@ decode_compound (char **argptr, int funf
   struct type *t;
   char *saved_java_argptr = NULL;
   char *saved_arg;
+  struct cleanup *cleanup;
 
   /* If the user specified any completer quote characters in the input,
      strip them.  They are superfluous.  */
@@ -1586,7 +1587,17 @@ decode_compound (char **argptr, int funf
   *argptr = (*p == '\'') ? p + 1 : p;
 
   /* Look up entire name.  */
-  sym = lookup_symbol (copy, get_selected_block (0), VAR_DOMAIN, 0);
+  name = copy;
+  canon = cp_canonicalize_string_no_typedefs (copy);
+  if (canon != NULL)
+    {
+      name = canon;
+      cleanup = make_cleanup (xfree, name);
+    }
+  else
+    cleanup = make_cleanup (null_cleanup, NULL);
+  sym = lookup_symbol (name, get_selected_block (0), VAR_DOMAIN, 0);
+  do_cleanups (cleanup);
   if (sym)
     return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL);
   else
@@ -1727,7 +1738,7 @@ find_method (int funfirstline, struct li
 	  strcpy (name, SYMBOL_NATURAL_NAME (sym_class));
 	  strcat (name, "::");
 	  strcat (name, copy);
-	  canon = cp_canonicalize_string (name);
+	  canon = cp_canonicalize_string_no_typedefs (name);
 	  if (canon != NULL)
 	    {
 	      xfree (name);
@@ -2069,15 +2080,27 @@ decode_variable (char *copy, int funfirs
 		 struct linespec_result *canonical,
 		 struct symtab *file_symtab)
 {
+  char *name;
   struct symbol *sym;
+  struct cleanup *cleanup;
   struct minimal_symbol *msymbol;
 
-  sym = lookup_symbol (copy,
+  name = cp_canonicalize_string_no_typedefs (copy);
+  if (name == NULL)
+    {
+      name = copy;
+      cleanup = make_cleanup (null_cleanup, NULL);
+    }
+  else
+    cleanup = make_cleanup (xfree, name);
+
+  sym = lookup_symbol (name,
 		       (file_symtab
 			? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
 					     STATIC_BLOCK)
 			: get_selected_block (0)),
 		       VAR_DOMAIN, 0);
+  do_cleanups (cleanup);
 
   if (sym != NULL)
     return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.266
diff -u -p -r1.266 symtab.c
--- symtab.c	19 Apr 2011 18:04:07 -0000	1.266
+++ symtab.c	21 Apr 2011 17:59:19 -0000
@@ -740,17 +740,21 @@ symbol_demangled_name (const struct gene
   return NULL;
 }
 
-/* Return the search name of a symbol---generally the demangled or
-   linkage name of the symbol, depending on how it will be searched for.
-   If there is no distinct demangled name, then returns the same value
-   (same pointer) as SYMBOL_LINKAGE_NAME.  */
+/* Return the search name of a symbol.  This is typically the smybol's 
+   physname (SYMBOL_LINKAGE_NAME). Symbols with mangled names
+   are special: return their SYMBOL_NATURAL_NAME instead.  */
 char *
 symbol_search_name (const struct general_symbol_info *gsymbol)
 {
   if (gsymbol->language == language_ada)
     return gsymbol->name;
   else
-    return symbol_natural_name (gsymbol);
+    {
+      if (gsymbol->name && gsymbol->name[0] == '_' && gsymbol->name[1] == 'Z')
+	return symbol_natural_name (gsymbol);
+      else
+	return gsymbol->name;
+    }
 }
 
 /* Initialize the structure fields to zero values.  */
@@ -2900,8 +2904,8 @@ compare_search_syms (const void *sa, con
   struct symbol_search **sym_a = (struct symbol_search **) sa;
   struct symbol_search **sym_b = (struct symbol_search **) sb;
 
-  return strcmp (SYMBOL_PRINT_NAME ((*sym_a)->symbol),
-		 SYMBOL_PRINT_NAME ((*sym_b)->symbol));
+  return strcmp (SYMBOL_SEARCH_NAME ((*sym_a)->symbol),
+		 SYMBOL_SEARCH_NAME ((*sym_b)->symbol));
 }
 
 /* Sort the ``nfound'' symbols in the list after prevtail.  Leave
Index: typeprint.h
===================================================================
RCS file: /cvs/src/src/gdb/typeprint.h,v
retrieving revision 1.11
diff -u -p -r1.11 typeprint.h
--- typeprint.h	1 Jan 2011 15:33:18 -0000	1.11
+++ typeprint.h	21 Apr 2011 17:59:19 -0000
@@ -26,7 +26,9 @@ struct ui_file;
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
 void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
-				  int, int);
+				  int, int, int);
+
+void c_type_print_args (struct type *, struct ui_file *,
+			int, int, enum language);
 
-void c_type_print_args (struct type *, struct ui_file *, int, enum language);
 #endif
Index: python/py-type.c
===================================================================
RCS file: /cvs/src/src/gdb/python/py-type.c,v
retrieving revision 1.18
diff -u -p -r1.18 py-type.c
--- python/py-type.c	26 Jan 2011 20:53:45 -0000	1.18
+++ python/py-type.c	21 Apr 2011 17:59:19 -0000
@@ -577,6 +577,7 @@ typy_legacy_template_argument (struct ty
 {
   int i;
   struct demangle_component *demangled;
+  struct demangle_parse_info *info;
   const char *err;
   struct type *argtype;
 
@@ -587,12 +588,13 @@ typy_legacy_template_argument (struct ty
     }
 
   /* Note -- this is not thread-safe.  */
-  demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
-  if (! demangled)
+  info = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
+  if (! info)
     {
       PyErr_SetString (PyExc_RuntimeError, err);
       return NULL;
     }
+  demangled = info->tree;
 
   /* Strip off component names.  */
   while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME
@@ -601,6 +603,7 @@ typy_legacy_template_argument (struct ty
 
   if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE)
     {
+      cp_demangled_name_parse_free (info);
       PyErr_SetString (PyExc_RuntimeError, _("Type is not a template."));
       return NULL;
     }
@@ -613,12 +616,14 @@ typy_legacy_template_argument (struct ty
 
   if (! demangled)
     {
+      cp_demangled_name_parse_free (info);
       PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
 		    argno);
       return NULL;
     }
 
   argtype = typy_lookup_type (demangled->u.s_binary.left, block);
+  cp_demangled_name_parse_free (info);
   if (! argtype)
     return NULL;
 
Index: testsuite/gdb.cp/meth-typedefs.cc
===================================================================
RCS file: testsuite/gdb.cp/meth-typedefs.cc
diff -N testsuite/gdb.cp/meth-typedefs.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.cp/meth-typedefs.cc	21 Apr 2011 17:59:19 -0000
@@ -0,0 +1,80 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.
+
+   Contributed by Red Hat, originally written by Keith Seitz.  */
+
+#include <stdlib.h>
+
+typedef const char* const* my_type;
+typedef int my_type_2;
+typedef my_type my_other_type;
+typedef my_type_2 my_other_type_2;
+
+typedef void (*fptr1) (my_other_type);
+typedef void (*fptr2) (fptr1, my_other_type_2);
+typedef void (*fptr3) (fptr2, my_other_type);
+
+namespace A
+{
+  class foo
+  {
+  public:
+    foo (void) { }
+    foo (my_other_type a) { } // A::foo::foo(my_other_type)
+    foo (my_other_type_2 a) { } // A::foo::foo(my_other_type_2)
+    foo (my_other_type_2 a, my_other_type b) { } // A::foo::foo(my_other_type_2, my_other_type)
+    foo (fptr3) { } // A::foo::foo(fptr3)
+    void test (my_other_type a) { } // A::foo::test(my_other_type)
+    void test (my_other_type_2 a) { } // A::foo::test(my_other_type_2)
+    void test (my_other_type_2 a, my_other_type b) { } // A::foo::test(my_other_type_2, my_other_type)
+    void test (fptr3 a) { } // A::foo::test(fptr3)
+  };
+};
+
+namespace B
+{
+  void
+  test (my_other_type foo) { } // B::test(my_other_type)
+
+  void
+  test (my_other_type foo, my_other_type_2) { } // B::test(my_other_type, my_other_type_2)
+};
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (my_other_type foo, my_other_type_2) { } // test(my_other_type, my_other_type_2)
+
+int
+main (void)
+{
+  A::foo f, a[3];
+  f.test (static_cast<my_other_type> (NULL));
+  f.test (0);
+  f.test (0, static_cast<my_type> (NULL));
+  f.test (static_cast<fptr3> (NULL));
+  B::test (static_cast<my_other_type> (NULL));
+  B::test (static_cast<my_other_type> (NULL), 0);
+  test (static_cast<my_other_type> (NULL));
+  test (static_cast<my_other_type> (NULL), 0);  
+  A::foo w (static_cast<my_other_type> (NULL));
+  A::foo x (0);
+  A::foo y (0, static_cast<my_other_type> (NULL));
+  A::foo z (static_cast<fptr3> (NULL));
+  return 0;
+}
Index: testsuite/gdb.cp/meth-typedefs.exp
===================================================================
RCS file: testsuite/gdb.cp/meth-typedefs.exp
diff -N testsuite/gdb.cp/meth-typedefs.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.cp/meth-typedefs.exp	21 Apr 2011 17:59:20 -0000
@@ -0,0 +1,112 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# Contributed by Red Hat, originally written by Keith Seitz.
+#
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+proc add {var name params expected} {
+    upvar $var result
+    set expect ".*// ${name}\\($expected\\)"
+    lappend result [list "${name}($params)" $expect]
+}
+ 
+if {[skip_cplus_tests]} { continue }
+
+# Tests for c++/12266 et al
+set testfile "meth-typedefs"
+set srcfile $testfile.cc
+
+if {[prepare_for_testing $testfile $testfile $srcfile {c++ debug}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+array set typedefs {
+    "my_other_type" {"my_other_type" "my_type" "const char* const*"}
+    "my_other_type_2" {"my_other_type_2" "my_type_2" "int"}
+}
+
+set methods {}
+
+# Add the simple, one-parameter methods
+foreach method {A::foo::test A::foo::foo} {
+    foreach type {my_other_type my_other_type_2} {
+	foreach t $typedefs($type)  {
+	    add methods $method $t $type
+	}
+    }
+}
+# Add two-parameter methods
+foreach method {A::foo::test A::foo::foo} {
+    set type "my_other_type_2, my_other_type"
+    foreach t1 $typedefs(my_other_type_2) {
+	foreach t2 $typedefs(my_other_type) {
+	    add methods $method "$t1, $t2" $type
+	}
+    }
+}
+
+# Add the function pointer methods
+set type "fptr3"
+foreach method {A::foo::test A::foo::foo} {
+    add methods $method "fptr3" $type
+
+    foreach t1 $typedefs(my_other_type) {
+	add methods $method "void (*)(fptr2, $t1)" $type
+	foreach t2 $typedefs(my_other_type_2) {
+	    add methods $method "void (*)(void (*)(fptr1, $t2), $t1)" $type
+	    foreach t3 $typedefs(my_other_type) {
+		add methods $method \
+		    "void (*)(void (*)(void (*) ($t3), $t2), $t1)" $type
+	    }
+	}
+    }
+}
+
+# Add non-method tests
+set type1 "my_other_type"
+set type2 "my_other_type, my_other_type_2"
+foreach method {"test" "B::test"} {
+    foreach t1 $typedefs(my_other_type) {
+	add methods $method $t1 $type1
+	foreach t2 $typedefs(my_other_type_2) {
+	    add methods $method "$t1, $t2" $type2
+	}
+    }
+}
+
+gdb_test_no_output "set listsize 1" ""
+
+# Finally, for each method in the list METHODS, check whether
+# the user can "list" it and "break" on it (both quoted and unquoted).
+foreach test $methods {
+    set func [lindex $test 0]
+    set result [lindex $test 1]
+    gdb_test "list $func" $result
+    if {[gdb_breakpoint $func]} {
+      pass "break $func"
+    }
+    if {[gdb_breakpoint '$func']} {
+      pass "break '$func'"
+    }
+}
+
+gdb_exit
+return 0

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

* Re: [RFA] Typedef'd method parameters [0/4]
  2011-04-21 21:15 [RFA] Typedef'd method parameters [0/4] Keith Seitz
@ 2011-04-25 20:53 ` Tom Tromey
  2011-05-12 21:28 ` Keith Seitz
  1 sibling, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2011-04-25 20:53 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:

Keith> I've attempted to split this up into four different patches to help
Keith> facilitate review, but to be honest, I'm not sure how helpful this
Keith> split is going to be, but I'll leave it to maintainers to ask for
Keith> whatever would help them digest this easiest.

I think this split was pretty good.
I didn't try to read the combined patch, so I can't actually say whether
it helped :-)

Keith> The inability to use typedef'd parameter types arises from the
Keith> fact that we do fairly literal lookups in the symbol table from
Keith> decode_line_1 et al.

I have often thought that maybe this is something we would want to fix.

Instead of storing `namesp::klass::method(int)' in the symbol table,
maybe we could just have an entry for "namesp", which would itself
contain a symbol table for the namespace, and so on, down to an entry
for "method" that would contain all the method overloads.

This would be a big change, though.  And I do have to wonder what
concrete benefits would arise from it, aside from "work the way
everybody expects".  Maybe it would let us make the DWARF reader lazier.

Keith> A note on the test suite: I propose to get these all approved and
Keith> commit in one go. If done this way, no test suite regressions should
Keith> occur. Or at least they don't show up here. :-)

I would not mind if the cp-name-parser.y patch were committed
separately.  I see it as a separate cleanup.  But, it is not very
important, and if you have a single patch ready, then don't bother.

Keith> Just a side note for maintainers, since I know this is going to
Keith> come up: I have tried my best to consolidate name
Keith> canonicalization, but there are a bunch of problems that arise
Keith> from attempting to do this. I believe the solution proposed here
Keith> is the most consistent from an API perspective -- everything
Keith> still acts the way it should (and has). The alternative is to
Keith> canonicalize_no_typedefs before anyone calls lookup_symbol or
Keith> lookup_symbol_in_language. I rejected this approach.

I think the approach you took is fine, but I am curious to know why you
rejected the other.

Tom


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

* Re: [RFA] Typedef'd method parameters [0/4]
  2011-04-21 21:15 [RFA] Typedef'd method parameters [0/4] Keith Seitz
  2011-04-25 20:53 ` Tom Tromey
@ 2011-05-12 21:28 ` Keith Seitz
  2011-05-16 15:49   ` [rfc] physname cross-check [Re: [RFA] Typedef'd method parameters [0/4]] Jan Kratochvil
  1 sibling, 1 reply; 9+ messages in thread
From: Keith Seitz @ 2011-05-12 21:28 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 332 bytes --]

On 04/21/2011 02:15 PM, Keith Seitz wrote:
> PS. I've attached the whole patch as a single large piece for those
> interested in skipping the piecemeal evaluation of the patchset. [See
> ChangeLogs in subsequent messages.]

I'm sending an updated set of all of the patches just in case something 
got foobar'd along the way.

Keith

[-- Attachment #2: cp_demangled_name_parse_free-2.patch --]
[-- Type: text/plain, Size: 13003 bytes --]

diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index 8736777..f745a31 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -60,7 +60,7 @@ static const char *lexptr, *prev_lexptr, *error_lexptr, *global_errmsg;
 
 struct demangle_info {
   int used;
-  struct demangle_info *prev, *next;
+  struct demangle_info *next;
   struct demangle_component comps[ALLOC_CHUNK];
 };
 
@@ -76,7 +76,6 @@ d_grab (void)
       if (demangle_info->next == NULL)
 	{
 	  more = malloc (sizeof (struct demangle_info));
-	  more->prev = demangle_info;
 	  more->next = NULL;
 	  demangle_info->next = more;
 	}
@@ -1935,20 +1934,14 @@ yyerror (char *msg)
    generally allocate too many components, but the extra memory usage
    doesn't hurt because the trees are temporary and the storage is
    reused.  More may be allocated later, by d_grab.  */
-static void
+static struct demangle_info *
 allocate_info (void)
 {
-  if (demangle_info == NULL)
-    {
-      demangle_info = malloc (sizeof (struct demangle_info));
-      demangle_info->prev = NULL;
-      demangle_info->next = NULL;
-    }
-  else
-    while (demangle_info->prev)
-      demangle_info = demangle_info->prev;
+  struct demangle_info *info = malloc (sizeof (struct demangle_info));
 
-  demangle_info->used = 0;
+  info->next = NULL;
+  info->used = 0;
+  return info;
 }
 
 /* Convert RESULT to a string.  The return value is allocated
@@ -1966,23 +1959,65 @@ cp_comp_to_string (struct demangle_component *result, int estimated_len)
 			       &err);
 }
 
+/* Free any memory associated with the given PARSE_INFO.  */
+
+void
+cp_demangled_name_parse_free (struct demangle_parse_info *parse_info)
+{
+  struct demangle_info *info = parse_info->info;
+
+  /* Free any allocated chunks of memory for the parse.  */
+  while (info != NULL)
+    {
+      struct demangle_info *next = info->next;
+
+      free (info);
+      info = next;
+    }
+
+  /* Free the parser info.  */
+  free (parse_info);
+}
+
+/* A cleanup wrapper for cp_demangled_name_parse_free.  */
+
+static void
+do_demangled_name_parse_free_cleanup (void *data)
+{
+  struct demangle_parse_info *info = (struct demangle_parse_info *) data;
+
+  cp_demangled_name_parse_free (info);
+}
+
+/* Create a cleanup for C++ name parsing.  */
+
+struct cleanup *
+make_cleanup_cp_demangled_name_parse_free (struct demangle_parse_info *info)
+{
+  return make_cleanup (do_demangled_name_parse_free_cleanup, info);
+}
+
 /* Convert a demangled name to a demangle_component tree.  On success,
-   the root of the new tree is returned; it is valid until the next
-   call to this function and should not be freed.  On error, NULL is
+   a structure containing the root of the new tree is returned; it must
+   be freed by calling cp_demangled_name_parse_free. On error, NULL is
    returned, and an error message will be set in *ERRMSG (which does
    not need to be freed).  */
 
-struct demangle_component *
+struct demangle_parse_info *
 cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
 {
   static char errbuf[60];
-  struct demangle_component *result;
+  struct demangle_parse_info *result;
 
   prev_lexptr = lexptr = demangled_name;
   error_lexptr = NULL;
   global_errmsg = NULL;
 
-  allocate_info ();
+  demangle_info = allocate_info ();
+
+  result = ((struct demangle_parse_info *)
+	    malloc (sizeof (struct demangle_parse_info)));
+  result->info = demangle_info;
 
   if (yyparse ())
     {
@@ -1993,10 +2028,11 @@ cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
 	  strcat (errbuf, "'");
 	  *errmsg = errbuf;
 	}
+      cp_demangled_name_parse_free (result);
       return NULL;
     }
 
-  result = global_result;
+  result->tree = global_result;
   global_result = NULL;
 
   return result;
@@ -2052,7 +2088,7 @@ main (int argc, char **argv)
   char buf[65536];
   int arg;
   const char *errmsg;
-  struct demangle_component *result;
+  struct demangle_parse_info *result;
 
   arg = 1;
   if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
@@ -2086,7 +2122,8 @@ main (int argc, char **argv)
 	    continue;
 	  }
 
-	cp_print (result);
+	cp_print (result->tree);
+	cp_demangled_name_parse_free (result);
 
 	free (str2);
 	if (c)
@@ -2105,7 +2142,8 @@ main (int argc, char **argv)
 	  fputc ('\n', stderr);
 	  return 0;
 	}
-      cp_print (result);
+      cp_print (result->tree);
+      cp_demangled_name_parse_free (result);
       putchar ('\n');
     }
   return 0;
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index a479067..b67dedc 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -124,19 +124,20 @@ cp_already_canonical (const char *string)
 char *
 cp_canonicalize_string (const char *string)
 {
-  struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   unsigned int estimated_len;
   char *ret;
 
   if (cp_already_canonical (string))
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (string, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info == NULL)
     return NULL;
 
   estimated_len = strlen (string) * 2;
-  ret = cp_comp_to_string (ret_comp, estimated_len);
+  ret = cp_comp_to_string (info->tree, estimated_len);
+  cp_demangled_name_parse_free (info);
 
   if (strcmp (string, ret) == 0)
     {
@@ -153,23 +154,29 @@ cp_canonicalize_string (const char *string)
    freed when finished with the tree, or NULL if none was needed.
    OPTIONS will be passed to the demangler.  */
 
-static struct demangle_component *
+static struct demangle_parse_info *
 mangled_name_to_comp (const char *mangled_name, int options,
 		      void **memory, char **demangled_p)
 {
-  struct demangle_component *ret;
   char *demangled_name;
+  struct demangle_parse_info *info;
 
   /* If it looks like a v3 mangled name, then try to go directly
      to trees.  */
   if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
     {
+      struct demangle_component *ret;
+
       ret = cplus_demangle_v3_components (mangled_name,
 					  options, memory);
       if (ret)
 	{
+	  info = ((struct demangle_parse_info *)
+		  xmalloc (sizeof (struct demangle_parse_info)));
+	  info->info = NULL;
+	  info->tree = ret;
 	  *demangled_p = NULL;
-	  return ret;
+	  return info;
 	}
     }
 
@@ -181,16 +188,16 @@ mangled_name_to_comp (const char *mangled_name, int options,
   
   /* If we could demangle the name, parse it to build the component
      tree.  */
-  ret = cp_demangled_name_to_comp (demangled_name, NULL);
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
 
-  if (ret == NULL)
+  if (info == NULL)
     {
       xfree (demangled_name);
       return NULL;
     }
 
   *demangled_p = demangled_name;
-  return ret;
+  return info;
 }
 
 /* Return the name of the class containing method PHYSNAME.  */
@@ -201,14 +208,16 @@ cp_class_name_from_physname (const char *physname)
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp, *prev_comp, *cur_comp;
+  struct demangle_parse_info *info;
   int done;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-				   &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+			       &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
   done = 0;
+  ret_comp = info->tree;
 
   /* First strip off any qualifiers, if we have a function or
      method.  */
@@ -277,8 +286,8 @@ cp_class_name_from_physname (const char *physname)
     }
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -348,13 +357,14 @@ method_name_from_physname (const char *physname)
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-				   &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+			       &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
@@ -363,8 +373,8 @@ method_name_from_physname (const char *physname)
     ret = cp_comp_to_string (ret_comp, 10);
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -379,17 +389,19 @@ cp_func_name (const char *full_name)
 {
   char *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = cp_demangled_name_to_comp (full_name, NULL);
-  if (!ret_comp)
+  info = cp_demangled_name_to_comp (full_name, NULL);
+  if (!info)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
     ret = cp_comp_to_string (ret_comp, 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -402,16 +414,18 @@ cp_remove_params (const char *demangled_name)
 {
   int done = 0;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   char *ret = NULL;
 
   if (demangled_name == NULL)
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (demangled_name, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
+  if (info == NULL)
     return NULL;
 
   /* First strip off any qualifiers, if we have a function or method.  */
+  ret_comp = info->tree;
   while (!done)
     switch (ret_comp->type)
       {
@@ -433,6 +447,7 @@ cp_remove_params (const char *demangled_name)
   if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
     ret = cp_comp_to_string (d_left (ret_comp), 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 57aa03a..12bb6cd 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -36,6 +36,16 @@ struct objfile;
 struct type;
 struct demangle_component;
 
+/* The result of parsing a name.  */
+struct demangle_parse_info
+{
+  /* The memory used during the parse.  */
+  struct demangle_info *info;
+
+  /* The result of the parse.  */
+  struct demangle_component *tree;
+};
+
 /* This struct is designed to store data from using directives.  It
    says that names from namespace IMPORT_SRC should be visible within
    namespace IMPORT_DEST.  These form a linked list; NEXT is the next
@@ -177,12 +187,16 @@ struct type *cp_lookup_transparent_type (const char *name);
 
 /* Functions from cp-name-parser.y.  */
 
-extern struct demangle_component *cp_demangled_name_to_comp
+extern struct demangle_parse_info *cp_demangled_name_to_comp
   (const char *demangled_name, const char **errmsg);
 
 extern char *cp_comp_to_string (struct demangle_component *result,
 				int estimated_len);
 
+extern void cp_demangled_name_parse_free (struct demangle_parse_info *);
+extern struct cleanup *make_cleanup_cp_demangled_name_parse_free
+     (struct demangle_parse_info *);
+
 /* The list of "maint cplus" commands.  */
 
 extern struct cmd_list_element *maint_cplus_cmd_list;
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index c010420..f4616c3 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -577,8 +577,10 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 {
   int i;
   struct demangle_component *demangled;
+  struct demangle_parse_info *info;
   const char *err;
   struct type *argtype;
+  struct cleanup *cleanup;
 
   if (TYPE_NAME (type) == NULL)
     {
@@ -587,12 +589,14 @@ typy_legacy_template_argument (struct type *type, struct block *block,
     }
 
   /* Note -- this is not thread-safe.  */
-  demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
-  if (! demangled)
+  info = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
+  if (! info)
     {
       PyErr_SetString (PyExc_RuntimeError, err);
       return NULL;
     }
+  demangled = info->tree;
+  cleanup = make_cleanup_cp_demangled_name_parse_free (info);
 
   /* Strip off component names.  */
   while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME
@@ -601,6 +605,7 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 
   if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE)
     {
+      do_cleanups (cleanup);
       PyErr_SetString (PyExc_RuntimeError, _("Type is not a template."));
       return NULL;
     }
@@ -613,12 +618,14 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 
   if (! demangled)
     {
+      do_cleanups (cleanup);
       PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
 		    argno);
       return NULL;
     }
 
   argtype = typy_lookup_type (demangled->u.s_binary.left, block);
+  do_cleanups (cleanup);
   if (! argtype)
     return NULL;
 

[-- Attachment #3: printname-2.patch --]
[-- Type: text/plain, Size: 24583 bytes --]

diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 2e23dd7..0120a4b 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -38,29 +38,37 @@
 
 static void c_type_print_varspec_prefix (struct type *,
 					 struct ui_file *,
-					 int, int, int);
+					 int, int, int, int);
 
 /* Print "const", "volatile", or address space modifiers.  */
 static void c_type_print_modifier (struct type *,
 				   struct ui_file *,
 				   int, int);
+
+static void c_type_print_base_internal (struct type *, struct ui_file *,
+					int, int, int);
+
 \f
-/* LEVEL is the depth to indent lines by.  */
+/* The real c_print_type.  See c_print_type below for a description
+   of parameters and usage.
 
-void
-c_print_type (struct type *type,
-	      const char *varstring,
-	      struct ui_file *stream,
-	      int show, int level)
+   LINKAGE_NAME should be non-zero if we are printing a linkage name
+   on the stream.  */
+
+static void
+c_print_type_internal (struct type *type,
+		       const char *varstring,
+		       struct ui_file *stream,
+		       int show, int level, int linkage_name)
 {
   enum type_code code;
   int demangled_args;
   int need_post_space;
 
-  if (show > 0)
+  if (show > 0 || linkage_name)
     CHECK_TYPEDEF (type);
 
-  c_type_print_base (type, stream, show, level);
+  c_type_print_base_internal (type, stream, show, level, linkage_name);
   code = TYPE_CODE (type);
   if ((varstring != NULL && *varstring != '\0')
   /* Need a space if going to print stars or brackets;
@@ -74,7 +82,8 @@ c_print_type (struct type *type,
 	      || 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);
+  c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
+			       linkage_name);
 
   if (varstring != NULL)
     {
@@ -85,10 +94,25 @@ c_print_type (struct type *type,
 
       demangled_args = strchr (varstring, '(') != NULL;
       c_type_print_varspec_suffix (type, stream, show,
-				   0, demangled_args);
+				   0, demangled_args, linkage_name);
     }
 }
 
+/* Print TYPE to the STREAM.
+   VARSTRING (optional) is the name of the field being printed.
+   If SHOW is greater than zero,  print the details of the type.  Otherwise
+   simply print the type name.
+   LEVEL is the depth to indent lines by.  */
+
+void
+c_print_type (struct type *type,
+	      const char *varstring,
+	      struct ui_file *stream,
+	      int show, int level)
+{
+  c_print_type_internal (type, varstring, stream, show, level, 0);
+}
+
 /* Print a typedef using C syntax.  TYPE is the underlying type.
    NEW_SYMBOL is the symbol naming the type.  STREAM is the stream on
    which to print.  */
@@ -166,17 +190,14 @@ cp_type_print_derivation_info (struct ui_file *stream,
 /* Print the C++ method arguments ARGS to the file STREAM.  */
 
 static void
-cp_type_print_method_args (struct type *mtype, char *prefix,
-			   char *varstring, int staticp,
-			   struct ui_file *stream)
+cp_type_print_method_args (struct type *mtype, char *varstring,
+			   int staticp, struct ui_file *stream)
 {
   struct field *args = TYPE_FIELDS (mtype);
   int nargs = TYPE_NFIELDS (mtype);
   int varargs = TYPE_VARARGS (mtype);
   int i;
 
-  fprintf_symbol_filtered (stream, prefix,
-			   language_cplus, DMGL_ANSI);
   fprintf_symbol_filtered (stream, varstring,
 			   language_cplus, DMGL_ANSI);
   fputs_filtered ("(", stream);
@@ -231,36 +252,42 @@ cp_type_print_method_args (struct type *mtype, char *prefix,
    
    NEED_POST_SPACE is non-zero when a space will be be needed
    between a trailing qualifier and a field, variable, or function
-   name.  */
+   name.
+
+   LINKAGE_NAME is non-zero when constructing the phsyname for the type.  */
 
 static void
 c_type_print_varspec_prefix (struct type *type,
 			     struct ui_file *stream,
 			     int show, int passed_a_ptr,
-			     int need_post_space)
+			     int need_post_space,
+			     int linkage_name)
 {
   char *name;
 
   if (type == 0)
     return;
 
-  if (TYPE_NAME (type) && show <= 0)
+  if (TYPE_NAME (type) && show <= 0 && !linkage_name)
     return;
 
   QUIT;
 
+  if (linkage_name)
+    CHECK_TYPEDEF (type);
+
   switch (TYPE_CODE (type))
     {
     case TYPE_CODE_PTR:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 1, 1);
+				   stream, show, 1, 1, linkage_name);
       fprintf_filtered (stream, "*");
       c_type_print_modifier (type, stream, 1, need_post_space);
       break;
 
     case TYPE_CODE_MEMBERPTR:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
 	fputs_filtered (name, stream);
@@ -272,7 +299,7 @@ c_type_print_varspec_prefix (struct type *type,
 
     case TYPE_CODE_METHODPTR:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       fprintf_filtered (stream, "(");
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
@@ -285,7 +312,7 @@ c_type_print_varspec_prefix (struct type *type,
 
     case TYPE_CODE_REF:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 1, 0);
+				   stream, show, 1, 0, linkage_name);
       fprintf_filtered (stream, "&");
       c_type_print_modifier (type, stream, 1, need_post_space);
       break;
@@ -293,21 +320,21 @@ c_type_print_varspec_prefix (struct type *type,
     case TYPE_CODE_METHOD:
     case TYPE_CODE_FUNC:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       if (passed_a_ptr)
 	fprintf_filtered (stream, "(");
       break;
 
     case TYPE_CODE_ARRAY:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       if (passed_a_ptr)
 	fprintf_filtered (stream, "(");
       break;
 
     case TYPE_CODE_TYPEDEF:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_UNDEF:
@@ -386,17 +413,27 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
 
 
 /* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD
-   or TYPE_CODE_FUNC, to STREAM.  Artificial arguments, such as "this"
-   in non-static methods, are displayed if LINKAGE_NAME is zero.  If
-   LINKAGE_NAME is non-zero and LANGUAGE is language_cplus the topmost
-   parameter types get removed their possible const and volatile qualifiers to
+   or TYPE_CODE_FUNC, to STREAM.
+
+   KIND describes the type of symbol to print to the stream.  If KIND
+   is NAME_KIND_PHYS (the SYMBOL_LINKAGE_NAME of TYPE is being printed),
+   artifical parameters such as "this" in non-static methods are skipped
+   and all typedefs will be removed/expanded.
+
+   Additionally if LANGUAGE is language_cplus, topmost parameter types
+   may have any possible const and volatile qualifiers removed to
    match demangled linkage name parameters part of such function type.
+
+   If KIND is NAME_KIND_PRINT (when the SYMBOL_PRINT_NAME of TYPE is
+   being printed),  artificial parameters are skipped, but any typedef'd
+   parameter types are left intact.
+
    LANGUAGE is the language in which TYPE was defined.  This is a necessary
    evil since this code is used by the C, C++, and Java backends.  */
 
 void
 c_type_print_args (struct type *type, struct ui_file *stream,
-		   int linkage_name, enum language language)
+		   enum name_kind kind, enum language language)
 {
   int i, len;
   struct field *args;
@@ -410,7 +447,8 @@ c_type_print_args (struct type *type, struct ui_file *stream,
     {
       struct type *param_type;
 
-      if (TYPE_FIELD_ARTIFICIAL (type, i) && linkage_name)
+      if (TYPE_FIELD_ARTIFICIAL (type, i)
+	  && (kind == NAME_KIND_PHYS || kind == NAME_KIND_PRINT))
 	continue;
 
       if (printed_any)
@@ -421,7 +459,7 @@ c_type_print_args (struct type *type, struct ui_file *stream,
 
       param_type = TYPE_FIELD_TYPE (type, i);
 
-      if (language == language_cplus && linkage_name)
+      if (language == language_cplus && kind == NAME_KIND_PHYS)
 	{
 	  /* C++ standard, 13.1 Overloadable declarations, point 3, item:
 	     - Parameter declarations that differ only in the presence or
@@ -433,10 +471,14 @@ c_type_print_args (struct type *type, struct ui_file *stream,
 	  param_type = make_cv_type (0, 0, param_type, NULL);
 	}
 
+      if (kind == NAME_KIND_PHYS)
+	CHECK_TYPEDEF (param_type);
+
       if (language == language_java)
 	java_print_type (param_type, "", stream, -1, 0);
       else
-	c_print_type (param_type, "", stream, -1, 0);
+	c_print_type_internal (param_type, "", stream, -1, 0,
+			       kind == NAME_KIND_PHYS ? 1 : 0);
       printed_any = 1;
     }
 
@@ -599,22 +641,28 @@ remove_qualifiers (char *qid)
 
 /* Print any array sizes, function arguments or close parentheses
    needed after the variable name (to describe its type).
-   Args work like c_type_print_varspec_prefix.  */
+   Args work like c_type_print_varspec_prefix.
+
+   LINKAGE_NAME is non-zero when printing the linkage name of a
+   function or method.  */
 
 void
 c_type_print_varspec_suffix (struct type *type,
 			     struct ui_file *stream,
 			     int show, int passed_a_ptr,
-			     int demangled_args)
+			     int demangled_args, int linkage_name)
 {
   if (type == 0)
     return;
 
-  if (TYPE_NAME (type) && show <= 0)
+  if (TYPE_NAME (type) && show <= 0 && !linkage_name)
     return;
 
   QUIT;
 
+  if (linkage_name)
+    CHECK_TYPEDEF (type);
+
   switch (TYPE_CODE (type))
     {
     case TYPE_CODE_ARRAY:
@@ -631,25 +679,25 @@ c_type_print_varspec_suffix (struct type *type,
 	fprintf_filtered (stream, "]");
 
 	c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				     show, 0, 0);
+				     show, 0, 0, linkage_name);
       }
       break;
 
     case TYPE_CODE_MEMBERPTR:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 0, 0);
+				   show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_METHODPTR:
       fprintf_filtered (stream, ")");
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 0, 0);
+				   show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 1, 0);
+				   show, 1, 0, linkage_name);
       break;
 
     case TYPE_CODE_METHOD:
@@ -657,14 +705,19 @@ c_type_print_varspec_suffix (struct type *type,
       if (passed_a_ptr)
 	fprintf_filtered (stream, ")");
       if (!demangled_args)
-	c_type_print_args (type, stream, 0, current_language->la_language);
+	{
+	  enum name_kind kind;
+
+	  kind = linkage_name ? NAME_KIND_PHYS : NAME_KIND_FULL;
+	  c_type_print_args (type, stream, kind, current_language->la_language);
+	}
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, passed_a_ptr, 0);
+				   show, passed_a_ptr, 0, linkage_name);
       break;
 
     case TYPE_CODE_TYPEDEF:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, passed_a_ptr, 0);
+				   show, passed_a_ptr, 0, linkage_name);
       break;
 
     case TYPE_CODE_UNDEF:
@@ -694,27 +747,14 @@ c_type_print_varspec_suffix (struct type *type,
     }
 }
 
-/* Print the name of the type (or the ultimate pointer target,
-   function value or array element), or the description of a structure
-   or union.
-
-   SHOW positive means print details about the type (e.g. enum
-   values), and print structure elements passing SHOW - 1 for show.
-
-   SHOW negative means just print the type name or struct tag if there
-   is one.  If there is no name, print something sensible but concise
-   like "struct {...}".
-
-   SHOW zero means just print the type name or struct tag if there is
-   one.  If there is no name, print something sensible but not as
-   concise like "struct {int x; int y;}".
-
-   LEVEL is the number of spaces to indent by.
-   We increase it for some recursive calls.  */
+/* The real c_type_print_base_internal.  This function takes an
+   additional argument over the API function c_type_print_base:
+   LINKAGE_NAME, which is non-zero when the linkage name is being
+   printed to the STREAM.  */
 
-void
-c_type_print_base (struct type *type, struct ui_file *stream,
-		   int show, int level)
+static void
+c_type_print_base_internal (struct type *type, struct ui_file *stream,
+			    int show, int level, int linkage_name)
 {
   int i;
   int len, real_len;
@@ -747,7 +787,8 @@ c_type_print_base (struct type *type, struct ui_file *stream,
      class5 *foo".  */
 
   if (show <= 0
-      && TYPE_NAME (type) != NULL)
+      && TYPE_NAME (type) != NULL
+      && !linkage_name)
     {
       c_type_print_modifier (type, stream, 0, 1);
       fputs_filtered (TYPE_NAME (type), stream);
@@ -773,14 +814,17 @@ c_type_print_base (struct type *type, struct ui_file *stream,
     case TYPE_CODE_FUNC:
     case TYPE_CODE_METHOD:
     case TYPE_CODE_METHODPTR:
-      c_type_print_base (TYPE_TARGET_TYPE (type),
-			 stream, show, level);
+      c_type_print_base_internal (TYPE_TARGET_TYPE (type),
+				  stream, show, level, linkage_name);
       break;
 
     case TYPE_CODE_STRUCT:
       c_type_print_modifier (type, stream, 0, 1);
       if (TYPE_DECLARED_CLASS (type))
-	fprintf_filtered (stream, "class ");
+	{
+	  if (!linkage_name)
+	    fprintf_filtered (stream, "class ");
+	}
       else
 	fprintf_filtered (stream, "struct ");
       goto struct_union;
@@ -954,9 +998,10 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 	      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);
+	      c_print_type_internal (TYPE_FIELD_TYPE (type, i),
+				     TYPE_FIELD_NAME (type, i),
+				     stream, show - 1, level + 4,
+				     linkage_name);
 	      if (!field_is_static (&TYPE_FIELD (type, i))
 		  && TYPE_FIELD_PACKED (type, i))
 		{
@@ -1085,7 +1130,6 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 			  struct type *mtype = TYPE_FN_FIELD_TYPE (f, j);
 
 			  cp_type_print_method_args (mtype,
-						     "",
 						     method_name,
 						     staticp,
 						     stream);
@@ -1145,8 +1189,10 @@ c_type_print_base (struct type *type, struct ui_file *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);
+		  c_print_type_internal (target,
+					 TYPE_TYPEDEF_FIELD_NAME (type, i),
+					 stream, show - 1, level + 4,
+					 linkage_name);
 		  fprintf_filtered (stream, ";\n");
 		}
 	    }
@@ -1251,3 +1297,28 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       break;
     }
 }
+
+/* Print the name of the type (or the ultimate pointer target,
+   function value or array element), or the description of a structure
+   or union.
+
+   SHOW positive means print details about the type (e.g. enum
+   values), and print structure elements passing SHOW - 1 for show.
+
+   SHOW negative means just print the type name or struct tag if there
+   is one.  If there is no name, print something sensible but concise
+   like "struct {...}".
+
+   SHOW zero means just print the type name or struct tag if there is
+   one.  If there is no name, print something sensible but not as
+   concise like "struct {int x; int y;}".
+
+   LEVEL is the number of spaces to indent by.
+   We increase it for some recursive calls.  */
+
+void
+c_type_print_base (struct type *type, struct ui_file *stream,
+		   int show, int level)
+{
+  c_type_print_base_internal (type, stream, show, level, 0);
+}
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 81b20c7..374b9d5 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4888,7 +4888,7 @@ do_ui_file_peek_last (void *object, const char *buffer, long length)
 
 static const char *
 dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
-		     int physname)
+		     enum name_kind kind)
 {
   if (name == NULL)
     name = dwarf2_name (die, cu);
@@ -4896,7 +4896,7 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
   /* For Fortran GDB prefers DW_AT_*linkage_name if present but otherwise
      compute it by typename_concat inside GDB.  */
   if (cu->language == language_ada
-      || (cu->language == language_fortran && physname))
+      || (cu->language == language_fortran && kind == NAME_KIND_PHYS))
     {
       /* For Ada unit, we prefer the linkage name over the name, as
 	 the former contains the exported name, which the user expects
@@ -4928,7 +4928,8 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
 	  if (*prefix != '\0')
 	    {
 	      char *prefixed_name = typename_concat (NULL, prefix, name,
-						     physname, cu);
+						     (kind == NAME_KIND_PHYS),
+						     cu);
 
 	      fputs_unfiltered (prefixed_name, buf);
 	      xfree (prefixed_name);
@@ -5065,13 +5066,14 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
 	  /* For Java and C++ methods, append formal parameter type
 	     information, if PHYSNAME.  */
 
-	  if (physname && die->tag == DW_TAG_subprogram
+	  if ((kind == NAME_KIND_PHYS || kind == NAME_KIND_PRINT)
+	      && die->tag == DW_TAG_subprogram
 	      && (cu->language == language_cplus
 		  || cu->language == language_java))
 	    {
 	      struct type *type = read_type_die (die, cu);
 
-	      c_type_print_args (type, buf, 1, cu->language);
+	      c_type_print_args (type, buf, kind, cu->language);
 
 	      if (cu->language == language_java)
 		{
@@ -5127,7 +5129,7 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
 static const char *
 dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, 0);
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_FULL);
 }
 
 /* Construct a physname for the given DIE in CU.  NAME may either be
@@ -5140,7 +5142,13 @@ dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
 static const char *
 dwarf2_physname (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, 1);
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_PHYS);
+}
+
+static const char *
+dwarf2_print_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
+{
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_PRINT);
 }
 
 /* Read the import statement specified by the given die and record it.  */
@@ -11072,6 +11080,20 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
       linkagename = dwarf2_physname (name, die, cu);
       SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), 0, objfile);
 
+      /* For C++ set the symbol's demangled name if it is different than
+	 the computed physname.  This can happen when the source defines
+	 a method with typedef'd parameters.  This is ultimately used by
+	 the type printer.  */
+      if (cu->language == language_cplus && die->tag == DW_TAG_subprogram)
+	{
+	  const char *print_name = dwarf2_print_name (name, die, cu);
+	  if (strcmp (print_name, linkagename))
+	    {
+	      symbol_set_demangled_name (&(sym->ginfo),
+					 (char *) print_name, NULL);
+	    }
+	}
+
       /* Fortran does not have mangling standard and the mangling does differ
 	 between gfortran, iFort etc.  */
       if (cu->language == language_fortran
diff --git a/gdb/jv-typeprint.c b/gdb/jv-typeprint.c
index 0a709e9..12743c7 100644
--- a/gdb/jv-typeprint.c
+++ b/gdb/jv-typeprint.c
@@ -328,9 +328,6 @@ java_type_print_base (struct type *type, struct ui_file *stream, int show,
 
 /* LEVEL is the depth to indent lines by.  */
 
-extern void c_type_print_varspec_suffix (struct type *, struct ui_file *,
-					 int, int, int);
-
 void
 java_print_type (struct type *type, const char *varstring,
 		 struct ui_file *stream, int show, int level)
@@ -349,5 +346,5 @@ java_print_type (struct type *type, const char *varstring,
      so don't print an additional pair of ()'s.  */
 
   demangled_args = varstring != NULL && strchr (varstring, '(') != NULL;
-  c_type_print_varspec_suffix (type, stream, show, 0, demangled_args);
+  c_type_print_varspec_suffix (type, stream, show, 0, demangled_args, 0);
 }
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 249675b..a906524 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -902,7 +902,7 @@ prim_record_minimal_symbol_full (const char *name, int name_len, int copy_name,
   msymbol = &msym_bunch->contents[msym_bunch_index];
   SYMBOL_SET_LANGUAGE (msymbol, language_auto);
   SYMBOL_SET_NAMES (msymbol, name, name_len, copy_name, objfile);
-
+  SYMBOL_FLAGS (msymbol) |= GSYMBOL_FLAG_MSYMBOL;
   SYMBOL_VALUE_ADDRESS (msymbol) = address;
   SYMBOL_SECTION (msymbol) = section;
   SYMBOL_OBJ_SECTION (msymbol) = NULL;
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 84e01a6..b7c42bd 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -740,17 +740,21 @@ symbol_demangled_name (const struct general_symbol_info *gsymbol)
   return NULL;
 }
 
-/* Return the search name of a symbol---generally the demangled or
-   linkage name of the symbol, depending on how it will be searched for.
-   If there is no distinct demangled name, then returns the same value
-   (same pointer) as SYMBOL_LINKAGE_NAME.  */
+/* Return the SYMBOL_SEARCH_NAME of GSYMBOL.  */
+
 char *
 symbol_search_name (const struct general_symbol_info *gsymbol)
 {
   if (gsymbol->language == language_ada)
     return gsymbol->name;
   else
-    return symbol_natural_name (gsymbol);
+    {
+      if (gsymbol->flags & GSYMBOL_FLAG_MSYMBOL
+	  || gsymbol->language != language_cplus)
+	return symbol_natural_name (gsymbol);
+      else
+	return gsymbol->name;
+    }
 }
 
 /* Initialize the structure fields to zero values.  */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 12f52a2..cc3ed96 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -34,6 +34,14 @@ struct axs_value;
 struct agent_expr;
 struct program_space;
 
+/* A set of flags to describe a general symbol.  */
+
+enum gsymbol_flags
+{
+  /* This general symbol is a minimal symbol.  */
+  GSYMBOL_FLAG_MSYMBOL = (1 << 0)
+};
+
 /* Some of the structures in this file are space critical.
    The space-critical structures are:
 
@@ -147,6 +155,10 @@ struct general_symbol_info
 
   ENUM_BITFIELD(language) language : 8;
 
+  /* Flags for this symbol.  */
+
+  ENUM_BITFIELD(gsymbol_flags) flags : 1;
+
   /* Which section is this symbol in?  This is an index into
      section_offsets for this objfile.  Negative means that the symbol
      does not get relocated relative to a section.
@@ -184,6 +196,7 @@ extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *);
 #define SYMBOL_LANGUAGE(symbol)		(symbol)->ginfo.language
 #define SYMBOL_SECTION(symbol)		(symbol)->ginfo.section
 #define SYMBOL_OBJ_SECTION(symbol)	(symbol)->ginfo.obj_section
+#define SYMBOL_FLAGS(symbol)            (symbol)->ginfo.flags
 
 /* Initializes the language dependent portion of a symbol
    depending upon the language for the symbol.  */
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 82cf61a..b271bcc 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -23,10 +23,21 @@
 enum language;
 struct ui_file;
 
+/* An enumeration for specifying the type of a computed symobl name.  */
+enum name_kind
+  {
+    NAME_KIND_FULL,	/* The fullname (methods do not
+			   contain any formal parameters).  */
+    NAME_KIND_PHYS,	/* The physname used to lookup symbols.  */
+    NAME_KIND_PRINT	/* The name used when printing the symbol.  */
+  };
+
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
 void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
-				  int, int);
+				  int, int, int);
+
+void c_type_print_args (struct type *, struct ui_file *,
+			enum name_kind, enum language);
 
-void c_type_print_args (struct type *, struct ui_file *, int, enum language);
 #endif

[-- Attachment #4: cp_canonicalize_no_typedefs-2.patch --]
[-- Type: text/plain, Size: 11054 bytes --]

diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index f745a31..f7060fa 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -1979,6 +1979,27 @@ cp_demangled_name_parse_free (struct demangle_parse_info *parse_info)
   free (parse_info);
 }
 
+/* Merge the two parse trees given by DEST and SRC.  The parse tree
+   in SRC is attached to DEST at the node represented by TARGET.
+   SRC is then freed.  */
+
+void
+cp_merge_demangle_parse_infos (struct demangle_parse_info *dest,
+			       struct demangle_component *target,
+			       struct demangle_parse_info *src)
+
+{
+  struct demangle_info *di;
+
+  memcpy (target, src->tree, sizeof (struct demangle_component));
+  di = dest->info;
+  while (di->next != NULL)
+    di = di->next;
+  di->next = src->info;
+  src->info = NULL;
+  cp_demangled_name_parse_free (src);
+}
+
 /* A cleanup wrapper for cp_demangled_name_parse_free.  */
 
 static void
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index b67dedc..fc94353 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -86,6 +86,17 @@ static const char *operator_tokens[] =
     /* new[] and delete[] require special whitespace handling */
   };
 
+/* A vector used to define a free list for typedef replacement
+   (replace_typedefs/inspect_type).  See cp_canonicalize_string_no_typdefs
+   and inspect_type for more information.  */
+typedef char *namep;
+DEF_VEC_P (namep);
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+		  struct demangle_component *ret_comp,
+		  VEC (namep) *free_list);
+
 /* Return 1 if STRING is clearly already in canonical form.  This
    function is conservative; things which it does not recognize are
    assumed to be non-canonical, and the parser will sort them out
@@ -117,6 +128,182 @@ cp_already_canonical (const char *string)
     return 0;
 }
 
+/* Inspect the given RET_COMP for its type.  If it is a typedef,
+   replace the node with the typedef's tree, storing any memory allocations
+   on the FREE_LIST.   */
+
+static void
+inspect_type (struct demangle_parse_info *info,
+	      struct demangle_component *ret_comp,
+	      VEC (namep) *free_list)
+{
+  char *name;
+  struct symbol *sym;
+
+  /* Copy the symbol's name from RET_COMP and look it up
+     in the symbol table.  */
+  name = (char *) alloca (ret_comp->u.s_name.len + 1);
+  memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len);
+  name[ret_comp->u.s_name.len] = '\0';
+  sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+  if (sym != NULL)
+    {
+      struct type *type = SYMBOL_TYPE (sym);
+
+      /* If the type is a typedef, replace it.  */
+      if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+	{
+	  struct demangle_parse_info *i;
+	  struct ui_file *buf = mem_fileopen ();
+	  struct cleanup *cleanup = make_cleanup_ui_file_delete (buf);
+
+	  CHECK_TYPEDEF (type);
+	  type_print (type, "", buf, -1);
+	  name = ui_file_xstrdup (buf, NULL);
+	  VEC_safe_push (namep, free_list, name);
+	  do_cleanups (cleanup);
+
+	  /* Turn the result into a new tree.  Note that this
+	     tree will contain pointers into NAME, so NAME cannot
+	     be free'd until all typedef conversion is done and
+	     the final result is converted into a string.  */
+	  i = cp_demangled_name_to_comp (name, NULL);
+	  if (i != NULL)
+	    {
+	      /* Merge the two trees.  */
+	      cp_merge_demangle_parse_infos (info, ret_comp, i);
+
+	      /* Replace any newly introduced typedefs.  */
+	      replace_typedefs (info, ret_comp, free_list);
+	    }
+	  else
+	    {
+	      /* This shouldn't happen unless the type printer has
+		 output something that the name parser cannot grok.
+		 Nonetheless, an ounce of prevention...
+
+		 Canonicalize the name again, and store it in the
+		 current node (RET_COMP).  */
+	      char *canon = cp_canonicalize_string_no_typedefs (name);
+
+	      if (canon != NULL)
+		{
+		  xfree (name);
+		  name = canon;
+		}
+
+	      ret_comp->u.s_name.s = name;
+	      ret_comp->u.s_name.len = strlen (name);
+	    }
+	}
+    }
+}
+
+/* Walk the parse tree given by RET_COMP, replacing any typedefs with
+   their basic types.  Any required memory allocations are added
+   to the FREE_LIST, which must be free'd by a caller.  */
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+		  struct demangle_component *ret_comp,
+		  VEC (namep) *free_list)
+{
+  if (ret_comp)
+    {
+      switch (ret_comp->type)
+	{
+	case DEMANGLE_COMPONENT_ARGLIST:
+	  /* "Parameter declarations that differ only in the presence
+	     or absence of `const' and/or `volatile' are equivalent."
+	     C++ Standard N3290, clause 13.1.3 #4.  */
+	  while (d_left (ret_comp) != NULL
+		 && (d_left (ret_comp)->type == DEMANGLE_COMPONENT_CONST
+		     || d_left (ret_comp)->type == DEMANGLE_COMPONENT_VOLATILE))
+	    {
+	      d_left (ret_comp) = d_left (d_left (ret_comp));
+	    }
+
+	  replace_typedefs (info, d_left (ret_comp), free_list);
+	  replace_typedefs (info, d_right (ret_comp), free_list);
+	  break;
+
+	case DEMANGLE_COMPONENT_NAME:
+	  inspect_type (info, ret_comp, free_list);
+	  break;
+
+	case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+	case DEMANGLE_COMPONENT_CTOR:
+	case DEMANGLE_COMPONENT_ARRAY_TYPE:
+	case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+	  replace_typedefs (info, d_right (ret_comp), free_list);
+	  break;
+
+	case DEMANGLE_COMPONENT_POINTER:
+	  replace_typedefs (info, d_left (ret_comp), free_list);
+	  break;
+
+	default:
+	  break;
+	}
+    }
+}
+
+/* Parse STRING and convert it to canonical form, resolving any typedefs.
+   If parsing fails, or if STRING is already canonical, return NULL.
+   Otherwise return the canonical form.  The return value is allocated via
+   xmalloc.  */
+
+char *
+cp_canonicalize_string_no_typedefs (const char *string)
+{
+  char *ret;
+  unsigned int estimated_len;
+  struct demangle_parse_info *info;
+  VEC (namep) *free_list;
+
+  ret = NULL;
+  free_list = VEC_alloc (namep, 10);
+  estimated_len = strlen (string) * 2;
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info != NULL)
+    {
+      /* Replace all the typedefs in the tree.  */
+      replace_typedefs (info, info->tree, free_list);
+
+      /* Convert the tree back into a string.  */
+      ret = cp_comp_to_string (info->tree, estimated_len);
+      gdb_assert (ret != NULL);
+
+      /* Free the parse information.  */
+      cp_demangled_name_parse_free (info);
+
+      /* Free any memory allocated during typedef replacement.  */
+      if (!VEC_empty (namep, free_list))
+	{
+	  int i;
+	  char *iter;
+
+	  for (i = 0; VEC_iterate (namep, free_list, i, iter); ++i)
+	    xfree (iter);
+	}
+
+      /* Free the vector used for the free list.  */
+      VEC_free (namep, free_list);
+
+      /* Finally, compare the original string with the computed
+	 name, returning NULL if they are the same.  */
+      if (strcmp (string, ret) == 0)
+	{
+	  xfree (ret);
+	  return NULL;
+	}
+    }
+
+  return ret;
+}
+
 /* Parse STRING and convert it to canonical form.  If parsing fails,
    or if STRING is already canonical, return NULL.  Otherwise return
    the canonical form.  The return value is allocated via xmalloc.  */
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 12bb6cd..ba2e2d2 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -110,6 +110,8 @@ struct using_direct
 
 extern char *cp_canonicalize_string (const char *string);
 
+extern char *cp_canonicalize_string_no_typedefs (const char *string);
+
 extern char *cp_class_name_from_physname (const char *physname);
 
 extern char *method_name_from_physname (const char *physname);
@@ -196,6 +198,9 @@ extern char *cp_comp_to_string (struct demangle_component *result,
 extern void cp_demangled_name_parse_free (struct demangle_parse_info *);
 extern struct cleanup *make_cleanup_cp_demangled_name_parse_free
      (struct demangle_parse_info *);
+extern void cp_merge_demangle_parse_infos (struct demangle_parse_info *,
+					   struct demangle_component *,
+					   struct demangle_parse_info *);
 
 /* The list of "maint cplus" commands.  */
 
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 94bb86f..a85c3d0 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -222,7 +222,7 @@ find_methods (struct type *t, char *name, enum language language,
 
   /* NAME is typed by the user: it needs to be canonicalized before
      passing to lookup_symbol.  */
-  canon = cp_canonicalize_string (name);
+  canon = cp_canonicalize_string_no_typedefs (name);
   if (canon != NULL)
     {
       name = canon;
@@ -1315,7 +1315,7 @@ decode_compound (char **argptr, int funfirstline,
 		 char *the_real_saved_arg, char *p)
 {
   struct symtabs_and_lines values;
-  char *p2;
+  char *p2, *name;
   char *saved_arg2 = *argptr;
   char *temp_end;
   struct symbol *sym;
@@ -1324,6 +1324,7 @@ decode_compound (char **argptr, int funfirstline,
   struct type *t;
   char *saved_java_argptr = NULL;
   char *saved_arg;
+  struct cleanup *cleanup;
 
   /* If the user specified any completer quote characters in the input,
      strip them.  They are superfluous.  */
@@ -1586,7 +1587,21 @@ decode_compound (char **argptr, int funfirstline,
   *argptr = (*p == '\'') ? p + 1 : p;
 
   /* Look up entire name.  */
-  sym = lookup_symbol (copy, get_selected_block (0), VAR_DOMAIN, 0);
+  name = copy;
+
+  cleanup = make_cleanup (null_cleanup, NULL);
+  if (current_language->la_language == language_cplus)
+    {
+      char *canon = cp_canonicalize_string_no_typedefs (copy);
+      if (canon != NULL)
+	{
+	  name = canon;
+	  make_cleanup (xfree, name);
+	}
+    }
+
+  sym = lookup_symbol (name, get_selected_block (0), VAR_DOMAIN, 0);
+  do_cleanups (cleanup);
   if (sym)
     return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL);
   else
@@ -1727,7 +1742,7 @@ find_method (int funfirstline, struct linespec_result *canonical,
 	  strcpy (name, SYMBOL_NATURAL_NAME (sym_class));
 	  strcat (name, "::");
 	  strcat (name, copy);
-	  canon = cp_canonicalize_string (name);
+	  canon = cp_canonicalize_string_no_typedefs (name);
 	  if (canon != NULL)
 	    {
 	      xfree (name);
@@ -2069,15 +2084,31 @@ decode_variable (char *copy, int funfirstline,
 		 struct linespec_result *canonical,
 		 struct symtab *file_symtab)
 {
+  char *name;
   struct symbol *sym;
+  struct cleanup *cleanup;
   struct minimal_symbol *msymbol;
 
-  sym = lookup_symbol (copy,
+  name = copy;
+  cleanup = make_cleanup (null_cleanup, NULL);
+  if (current_language->la_language == language_cplus)
+    {
+      char *canon = cp_canonicalize_string_no_typedefs (copy);
+
+      if (canon != NULL)
+	{
+	  name = canon;
+	  make_cleanup (xfree, name);
+	}
+    }
+
+  sym = lookup_symbol (name,
 		       (file_symtab
 			? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
 					     STATIC_BLOCK)
 			: get_selected_block (0)),
 		       VAR_DOMAIN, 0);
+  do_cleanups (cleanup);
 
   if (sym != NULL)
     return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);

[-- Attachment #5: typedef-params-tests-2.patch --]
[-- Type: text/plain, Size: 7311 bytes --]

diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.cc b/gdb/testsuite/gdb.cp/meth-typedefs.cc
new file mode 100644
index 0000000..4055382
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,94 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.
+
+   Contributed by Red Hat, originally written by Keith Seitz.  */
+
+#include <stdlib.h>
+
+typedef const char* const* my_type;
+typedef int my_type_2;
+typedef my_type my_other_type;
+typedef my_type_2 my_other_type_2;
+typedef unsigned long CORE_ADDR;
+
+typedef void (*fptr1) (my_other_type);
+typedef void (*fptr2) (fptr1, my_other_type_2);
+typedef void (*fptr3) (fptr2, my_other_type);
+
+namespace A
+{
+  class foo
+  {
+  public:
+    foo (void) { }
+    foo (my_other_type a) { } // A::foo::foo(my_other_type)
+    foo (my_other_type_2 a) { } // A::foo::foo(my_other_type_2)
+    foo (my_other_type_2 a, const my_other_type b) { } // A::foo::foo(my_other_type_2, const my_other_type)
+    foo (fptr3) { } // A::foo::foo(fptr3)
+    foo (fptr1 *a) { } // A::foo::foo(fptr1*)
+    foo (CORE_ADDR (*) [10]) { } // A::foo::foo(CORE_ADDR (*) [10])
+
+    void test (my_other_type a) { } // A::foo::test(my_other_type)
+    void test (my_other_type_2 a) { } // A::foo::test(my_other_type_2)
+    void test (my_other_type_2 a, const my_other_type b) { } // A::foo::test(my_other_type_2, const my_other_type)
+    void test (fptr3 a) { } // A::foo::test(fptr3)
+    void test (fptr1 *a) { } // A::foo::test(fptr1*)
+    void test (CORE_ADDR (*) [10]) { } // A::foo::test(CORE_ADDR (*) [10])
+  };
+};
+
+namespace B
+{
+  void
+  test (my_other_type foo) { } // B::test(my_other_type)
+
+  void
+  test (my_other_type foo, my_other_type_2) { } // B::test(my_other_type, my_other_type_2)
+};
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (my_other_type foo, my_other_type_2) { } // test(my_other_type, my_other_type_2)
+
+int
+main (void)
+{
+  A::foo f;
+  fptr1 fptr;
+
+  f.test (static_cast<my_other_type> (NULL));
+  f.test (0);
+  f.test (0, static_cast<my_type> (NULL));
+  f.test (static_cast<fptr3> (NULL));
+  f.test (&fptr);
+  f.test (static_cast<CORE_ADDR (*) [10]> (0));
+  B::test (static_cast<my_other_type> (NULL));
+  B::test (static_cast<my_other_type> (NULL), 0);
+  test (static_cast<my_other_type> (NULL));
+  test (static_cast<my_other_type> (NULL), 0);
+
+  A::foo w (static_cast<my_other_type> (NULL));
+  A::foo x (0);
+  A::foo y (0, static_cast<my_other_type> (NULL));
+  A::foo z (static_cast<fptr3> (NULL));
+  A::foo a (&fptr);
+  A::foo b (static_cast<CORE_ADDR (*) [10]> (0));
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.exp b/gdb/testsuite/gdb.cp/meth-typedefs.exp
new file mode 100644
index 0000000..bdeb8a5
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,132 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# Contributed by Red Hat, originally written by Keith Seitz.
+#
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+proc add {var name params expected} {
+    upvar $var result
+    set expect ".*// ${name}\\($expected\\)"
+    lappend result [list "${name}($params)" $expect]
+}
+
+if {[skip_cplus_tests]} { continue }
+
+# Tests for c++/12266 et al
+set testfile "meth-typedefs"
+set srcfile $testfile.cc
+
+if {[prepare_for_testing $testfile $testfile $srcfile {c++ debug}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+array set typedefs {
+    "my_other_type" {"my_other_type" "my_type" "const char* const*"}
+    "my_other_type_2" {"my_other_type_2" "my_type_2" "int"}
+    "CORE_ADDR" { "CORE_ADDR" "unsigned long" }
+}
+
+set methods {}
+
+# Add the simple, one-parameter methods
+foreach method {A::foo::test A::foo::foo} {
+    foreach type {my_other_type my_other_type_2} {
+	foreach t $typedefs($type)  {
+	    add methods $method $t $type
+	}
+    }
+}
+
+# Add two-parameter methods
+foreach method {A::foo::test A::foo::foo} {
+    set type "my_other_type_2, const my_other_type"
+    foreach t1 $typedefs(my_other_type_2) {
+	foreach t2 $typedefs(my_other_type) {
+	    add methods $method "$t1, const $t2" $type
+	    add methods $method "$t1, $t2" $type
+	}
+    }
+}
+
+# Add the array-of-function pointer methods
+set type "fptr1\\*"
+foreach method {A::foo::test A::foo::foo} {
+    add methods $method "fptr1*" $type
+    foreach t $typedefs(my_other_type) {
+	add methods $method "void (**) ($t)" $type
+    }
+}
+
+# Add the function pointer methods
+set type "fptr3"
+foreach method {A::foo::test A::foo::foo} {
+    add methods $method "fptr3" $type
+
+    foreach t1 $typedefs(my_other_type) {
+	add methods $method "void (*)(fptr2, $t1)" $type
+	foreach t2 $typedefs(my_other_type_2) {
+	    add methods $method "void (*)(void (*)(fptr1, $t2), $t1)" $type
+	    foreach t3 $typedefs(my_other_type) {
+		add methods $method \
+		    "void (*)(void (*)(void (*) ($t3), $t2), $t1)" $type
+	    }
+	}
+    }
+}
+
+# Miscellaneous tests
+set type {CORE_ADDR \(\*\) \[10\]}
+foreach method {A::foo::foo A::foo::test} {
+    foreach t $typedefs(CORE_ADDR) {
+	add methods $method "$t (*) \[10\]" $type
+    }
+}
+
+# Add non-method tests
+set type1 "my_other_type"
+set type2 "my_other_type, my_other_type_2"
+foreach method {"test" "B::test"} {
+    foreach t1 $typedefs(my_other_type) {
+	add methods $method $t1 $type1
+	foreach t2 $typedefs(my_other_type_2) {
+	    add methods $method "$t1, $t2" $type2
+	}
+    }
+}
+
+gdb_test_no_output "set listsize 1" ""
+
+# Finally, for each method in the list METHODS, check whether
+# the user can "list" it and "break" on it (both quoted and unquoted).
+foreach test $methods {
+    set func [lindex $test 0]
+    set result [lindex $test 1]
+    gdb_test "list $func" $result
+    if {[gdb_breakpoint $func]} {
+      pass "break $func"
+    }
+    if {[gdb_breakpoint '$func']} {
+      pass "break '$func'"
+    }
+}
+
+gdb_exit
+return 0

[-- Attachment #6: 12266-whole-2.patch --]
[-- Type: text/plain, Size: 55076 bytes --]

diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 2e23dd7..0120a4b 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -38,29 +38,37 @@
 
 static void c_type_print_varspec_prefix (struct type *,
 					 struct ui_file *,
-					 int, int, int);
+					 int, int, int, int);
 
 /* Print "const", "volatile", or address space modifiers.  */
 static void c_type_print_modifier (struct type *,
 				   struct ui_file *,
 				   int, int);
+
+static void c_type_print_base_internal (struct type *, struct ui_file *,
+					int, int, int);
+
 \f
-/* LEVEL is the depth to indent lines by.  */
+/* The real c_print_type.  See c_print_type below for a description
+   of parameters and usage.
 
-void
-c_print_type (struct type *type,
-	      const char *varstring,
-	      struct ui_file *stream,
-	      int show, int level)
+   LINKAGE_NAME should be non-zero if we are printing a linkage name
+   on the stream.  */
+
+static void
+c_print_type_internal (struct type *type,
+		       const char *varstring,
+		       struct ui_file *stream,
+		       int show, int level, int linkage_name)
 {
   enum type_code code;
   int demangled_args;
   int need_post_space;
 
-  if (show > 0)
+  if (show > 0 || linkage_name)
     CHECK_TYPEDEF (type);
 
-  c_type_print_base (type, stream, show, level);
+  c_type_print_base_internal (type, stream, show, level, linkage_name);
   code = TYPE_CODE (type);
   if ((varstring != NULL && *varstring != '\0')
   /* Need a space if going to print stars or brackets;
@@ -74,7 +82,8 @@ c_print_type (struct type *type,
 	      || 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);
+  c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
+			       linkage_name);
 
   if (varstring != NULL)
     {
@@ -85,10 +94,25 @@ c_print_type (struct type *type,
 
       demangled_args = strchr (varstring, '(') != NULL;
       c_type_print_varspec_suffix (type, stream, show,
-				   0, demangled_args);
+				   0, demangled_args, linkage_name);
     }
 }
 
+/* Print TYPE to the STREAM.
+   VARSTRING (optional) is the name of the field being printed.
+   If SHOW is greater than zero,  print the details of the type.  Otherwise
+   simply print the type name.
+   LEVEL is the depth to indent lines by.  */
+
+void
+c_print_type (struct type *type,
+	      const char *varstring,
+	      struct ui_file *stream,
+	      int show, int level)
+{
+  c_print_type_internal (type, varstring, stream, show, level, 0);
+}
+
 /* Print a typedef using C syntax.  TYPE is the underlying type.
    NEW_SYMBOL is the symbol naming the type.  STREAM is the stream on
    which to print.  */
@@ -166,17 +190,14 @@ cp_type_print_derivation_info (struct ui_file *stream,
 /* Print the C++ method arguments ARGS to the file STREAM.  */
 
 static void
-cp_type_print_method_args (struct type *mtype, char *prefix,
-			   char *varstring, int staticp,
-			   struct ui_file *stream)
+cp_type_print_method_args (struct type *mtype, char *varstring,
+			   int staticp, struct ui_file *stream)
 {
   struct field *args = TYPE_FIELDS (mtype);
   int nargs = TYPE_NFIELDS (mtype);
   int varargs = TYPE_VARARGS (mtype);
   int i;
 
-  fprintf_symbol_filtered (stream, prefix,
-			   language_cplus, DMGL_ANSI);
   fprintf_symbol_filtered (stream, varstring,
 			   language_cplus, DMGL_ANSI);
   fputs_filtered ("(", stream);
@@ -231,36 +252,42 @@ cp_type_print_method_args (struct type *mtype, char *prefix,
    
    NEED_POST_SPACE is non-zero when a space will be be needed
    between a trailing qualifier and a field, variable, or function
-   name.  */
+   name.
+
+   LINKAGE_NAME is non-zero when constructing the phsyname for the type.  */
 
 static void
 c_type_print_varspec_prefix (struct type *type,
 			     struct ui_file *stream,
 			     int show, int passed_a_ptr,
-			     int need_post_space)
+			     int need_post_space,
+			     int linkage_name)
 {
   char *name;
 
   if (type == 0)
     return;
 
-  if (TYPE_NAME (type) && show <= 0)
+  if (TYPE_NAME (type) && show <= 0 && !linkage_name)
     return;
 
   QUIT;
 
+  if (linkage_name)
+    CHECK_TYPEDEF (type);
+
   switch (TYPE_CODE (type))
     {
     case TYPE_CODE_PTR:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 1, 1);
+				   stream, show, 1, 1, linkage_name);
       fprintf_filtered (stream, "*");
       c_type_print_modifier (type, stream, 1, need_post_space);
       break;
 
     case TYPE_CODE_MEMBERPTR:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
 	fputs_filtered (name, stream);
@@ -272,7 +299,7 @@ c_type_print_varspec_prefix (struct type *type,
 
     case TYPE_CODE_METHODPTR:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       fprintf_filtered (stream, "(");
       name = type_name_no_tag (TYPE_DOMAIN_TYPE (type));
       if (name)
@@ -285,7 +312,7 @@ c_type_print_varspec_prefix (struct type *type,
 
     case TYPE_CODE_REF:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 1, 0);
+				   stream, show, 1, 0, linkage_name);
       fprintf_filtered (stream, "&");
       c_type_print_modifier (type, stream, 1, need_post_space);
       break;
@@ -293,21 +320,21 @@ c_type_print_varspec_prefix (struct type *type,
     case TYPE_CODE_METHOD:
     case TYPE_CODE_FUNC:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       if (passed_a_ptr)
 	fprintf_filtered (stream, "(");
       break;
 
     case TYPE_CODE_ARRAY:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       if (passed_a_ptr)
 	fprintf_filtered (stream, "(");
       break;
 
     case TYPE_CODE_TYPEDEF:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
-				   stream, show, 0, 0);
+				   stream, show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_UNDEF:
@@ -386,17 +413,27 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
 
 
 /* Print out the arguments of TYPE, which should have TYPE_CODE_METHOD
-   or TYPE_CODE_FUNC, to STREAM.  Artificial arguments, such as "this"
-   in non-static methods, are displayed if LINKAGE_NAME is zero.  If
-   LINKAGE_NAME is non-zero and LANGUAGE is language_cplus the topmost
-   parameter types get removed their possible const and volatile qualifiers to
+   or TYPE_CODE_FUNC, to STREAM.
+
+   KIND describes the type of symbol to print to the stream.  If KIND
+   is NAME_KIND_PHYS (the SYMBOL_LINKAGE_NAME of TYPE is being printed),
+   artifical parameters such as "this" in non-static methods are skipped
+   and all typedefs will be removed/expanded.
+
+   Additionally if LANGUAGE is language_cplus, topmost parameter types
+   may have any possible const and volatile qualifiers removed to
    match demangled linkage name parameters part of such function type.
+
+   If KIND is NAME_KIND_PRINT (when the SYMBOL_PRINT_NAME of TYPE is
+   being printed),  artificial parameters are skipped, but any typedef'd
+   parameter types are left intact.
+
    LANGUAGE is the language in which TYPE was defined.  This is a necessary
    evil since this code is used by the C, C++, and Java backends.  */
 
 void
 c_type_print_args (struct type *type, struct ui_file *stream,
-		   int linkage_name, enum language language)
+		   enum name_kind kind, enum language language)
 {
   int i, len;
   struct field *args;
@@ -410,7 +447,8 @@ c_type_print_args (struct type *type, struct ui_file *stream,
     {
       struct type *param_type;
 
-      if (TYPE_FIELD_ARTIFICIAL (type, i) && linkage_name)
+      if (TYPE_FIELD_ARTIFICIAL (type, i)
+	  && (kind == NAME_KIND_PHYS || kind == NAME_KIND_PRINT))
 	continue;
 
       if (printed_any)
@@ -421,7 +459,7 @@ c_type_print_args (struct type *type, struct ui_file *stream,
 
       param_type = TYPE_FIELD_TYPE (type, i);
 
-      if (language == language_cplus && linkage_name)
+      if (language == language_cplus && kind == NAME_KIND_PHYS)
 	{
 	  /* C++ standard, 13.1 Overloadable declarations, point 3, item:
 	     - Parameter declarations that differ only in the presence or
@@ -433,10 +471,14 @@ c_type_print_args (struct type *type, struct ui_file *stream,
 	  param_type = make_cv_type (0, 0, param_type, NULL);
 	}
 
+      if (kind == NAME_KIND_PHYS)
+	CHECK_TYPEDEF (param_type);
+
       if (language == language_java)
 	java_print_type (param_type, "", stream, -1, 0);
       else
-	c_print_type (param_type, "", stream, -1, 0);
+	c_print_type_internal (param_type, "", stream, -1, 0,
+			       kind == NAME_KIND_PHYS ? 1 : 0);
       printed_any = 1;
     }
 
@@ -599,22 +641,28 @@ remove_qualifiers (char *qid)
 
 /* Print any array sizes, function arguments or close parentheses
    needed after the variable name (to describe its type).
-   Args work like c_type_print_varspec_prefix.  */
+   Args work like c_type_print_varspec_prefix.
+
+   LINKAGE_NAME is non-zero when printing the linkage name of a
+   function or method.  */
 
 void
 c_type_print_varspec_suffix (struct type *type,
 			     struct ui_file *stream,
 			     int show, int passed_a_ptr,
-			     int demangled_args)
+			     int demangled_args, int linkage_name)
 {
   if (type == 0)
     return;
 
-  if (TYPE_NAME (type) && show <= 0)
+  if (TYPE_NAME (type) && show <= 0 && !linkage_name)
     return;
 
   QUIT;
 
+  if (linkage_name)
+    CHECK_TYPEDEF (type);
+
   switch (TYPE_CODE (type))
     {
     case TYPE_CODE_ARRAY:
@@ -631,25 +679,25 @@ c_type_print_varspec_suffix (struct type *type,
 	fprintf_filtered (stream, "]");
 
 	c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				     show, 0, 0);
+				     show, 0, 0, linkage_name);
       }
       break;
 
     case TYPE_CODE_MEMBERPTR:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 0, 0);
+				   show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_METHODPTR:
       fprintf_filtered (stream, ")");
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 0, 0);
+				   show, 0, 0, linkage_name);
       break;
 
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, 1, 0);
+				   show, 1, 0, linkage_name);
       break;
 
     case TYPE_CODE_METHOD:
@@ -657,14 +705,19 @@ c_type_print_varspec_suffix (struct type *type,
       if (passed_a_ptr)
 	fprintf_filtered (stream, ")");
       if (!demangled_args)
-	c_type_print_args (type, stream, 0, current_language->la_language);
+	{
+	  enum name_kind kind;
+
+	  kind = linkage_name ? NAME_KIND_PHYS : NAME_KIND_FULL;
+	  c_type_print_args (type, stream, kind, current_language->la_language);
+	}
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, passed_a_ptr, 0);
+				   show, passed_a_ptr, 0, linkage_name);
       break;
 
     case TYPE_CODE_TYPEDEF:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
-				   show, passed_a_ptr, 0);
+				   show, passed_a_ptr, 0, linkage_name);
       break;
 
     case TYPE_CODE_UNDEF:
@@ -694,27 +747,14 @@ c_type_print_varspec_suffix (struct type *type,
     }
 }
 
-/* Print the name of the type (or the ultimate pointer target,
-   function value or array element), or the description of a structure
-   or union.
-
-   SHOW positive means print details about the type (e.g. enum
-   values), and print structure elements passing SHOW - 1 for show.
-
-   SHOW negative means just print the type name or struct tag if there
-   is one.  If there is no name, print something sensible but concise
-   like "struct {...}".
-
-   SHOW zero means just print the type name or struct tag if there is
-   one.  If there is no name, print something sensible but not as
-   concise like "struct {int x; int y;}".
-
-   LEVEL is the number of spaces to indent by.
-   We increase it for some recursive calls.  */
+/* The real c_type_print_base_internal.  This function takes an
+   additional argument over the API function c_type_print_base:
+   LINKAGE_NAME, which is non-zero when the linkage name is being
+   printed to the STREAM.  */
 
-void
-c_type_print_base (struct type *type, struct ui_file *stream,
-		   int show, int level)
+static void
+c_type_print_base_internal (struct type *type, struct ui_file *stream,
+			    int show, int level, int linkage_name)
 {
   int i;
   int len, real_len;
@@ -747,7 +787,8 @@ c_type_print_base (struct type *type, struct ui_file *stream,
      class5 *foo".  */
 
   if (show <= 0
-      && TYPE_NAME (type) != NULL)
+      && TYPE_NAME (type) != NULL
+      && !linkage_name)
     {
       c_type_print_modifier (type, stream, 0, 1);
       fputs_filtered (TYPE_NAME (type), stream);
@@ -773,14 +814,17 @@ c_type_print_base (struct type *type, struct ui_file *stream,
     case TYPE_CODE_FUNC:
     case TYPE_CODE_METHOD:
     case TYPE_CODE_METHODPTR:
-      c_type_print_base (TYPE_TARGET_TYPE (type),
-			 stream, show, level);
+      c_type_print_base_internal (TYPE_TARGET_TYPE (type),
+				  stream, show, level, linkage_name);
       break;
 
     case TYPE_CODE_STRUCT:
       c_type_print_modifier (type, stream, 0, 1);
       if (TYPE_DECLARED_CLASS (type))
-	fprintf_filtered (stream, "class ");
+	{
+	  if (!linkage_name)
+	    fprintf_filtered (stream, "class ");
+	}
       else
 	fprintf_filtered (stream, "struct ");
       goto struct_union;
@@ -954,9 +998,10 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 	      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);
+	      c_print_type_internal (TYPE_FIELD_TYPE (type, i),
+				     TYPE_FIELD_NAME (type, i),
+				     stream, show - 1, level + 4,
+				     linkage_name);
 	      if (!field_is_static (&TYPE_FIELD (type, i))
 		  && TYPE_FIELD_PACKED (type, i))
 		{
@@ -1085,7 +1130,6 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 			  struct type *mtype = TYPE_FN_FIELD_TYPE (f, j);
 
 			  cp_type_print_method_args (mtype,
-						     "",
 						     method_name,
 						     staticp,
 						     stream);
@@ -1145,8 +1189,10 @@ c_type_print_base (struct type *type, struct ui_file *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);
+		  c_print_type_internal (target,
+					 TYPE_TYPEDEF_FIELD_NAME (type, i),
+					 stream, show - 1, level + 4,
+					 linkage_name);
 		  fprintf_filtered (stream, ";\n");
 		}
 	    }
@@ -1251,3 +1297,28 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       break;
     }
 }
+
+/* Print the name of the type (or the ultimate pointer target,
+   function value or array element), or the description of a structure
+   or union.
+
+   SHOW positive means print details about the type (e.g. enum
+   values), and print structure elements passing SHOW - 1 for show.
+
+   SHOW negative means just print the type name or struct tag if there
+   is one.  If there is no name, print something sensible but concise
+   like "struct {...}".
+
+   SHOW zero means just print the type name or struct tag if there is
+   one.  If there is no name, print something sensible but not as
+   concise like "struct {int x; int y;}".
+
+   LEVEL is the number of spaces to indent by.
+   We increase it for some recursive calls.  */
+
+void
+c_type_print_base (struct type *type, struct ui_file *stream,
+		   int show, int level)
+{
+  c_type_print_base_internal (type, stream, show, level, 0);
+}
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index 8736777..f7060fa 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -60,7 +60,7 @@ static const char *lexptr, *prev_lexptr, *error_lexptr, *global_errmsg;
 
 struct demangle_info {
   int used;
-  struct demangle_info *prev, *next;
+  struct demangle_info *next;
   struct demangle_component comps[ALLOC_CHUNK];
 };
 
@@ -76,7 +76,6 @@ d_grab (void)
       if (demangle_info->next == NULL)
 	{
 	  more = malloc (sizeof (struct demangle_info));
-	  more->prev = demangle_info;
 	  more->next = NULL;
 	  demangle_info->next = more;
 	}
@@ -1935,20 +1934,14 @@ yyerror (char *msg)
    generally allocate too many components, but the extra memory usage
    doesn't hurt because the trees are temporary and the storage is
    reused.  More may be allocated later, by d_grab.  */
-static void
+static struct demangle_info *
 allocate_info (void)
 {
-  if (demangle_info == NULL)
-    {
-      demangle_info = malloc (sizeof (struct demangle_info));
-      demangle_info->prev = NULL;
-      demangle_info->next = NULL;
-    }
-  else
-    while (demangle_info->prev)
-      demangle_info = demangle_info->prev;
+  struct demangle_info *info = malloc (sizeof (struct demangle_info));
 
-  demangle_info->used = 0;
+  info->next = NULL;
+  info->used = 0;
+  return info;
 }
 
 /* Convert RESULT to a string.  The return value is allocated
@@ -1966,23 +1959,86 @@ cp_comp_to_string (struct demangle_component *result, int estimated_len)
 			       &err);
 }
 
+/* Free any memory associated with the given PARSE_INFO.  */
+
+void
+cp_demangled_name_parse_free (struct demangle_parse_info *parse_info)
+{
+  struct demangle_info *info = parse_info->info;
+
+  /* Free any allocated chunks of memory for the parse.  */
+  while (info != NULL)
+    {
+      struct demangle_info *next = info->next;
+
+      free (info);
+      info = next;
+    }
+
+  /* Free the parser info.  */
+  free (parse_info);
+}
+
+/* Merge the two parse trees given by DEST and SRC.  The parse tree
+   in SRC is attached to DEST at the node represented by TARGET.
+   SRC is then freed.  */
+
+void
+cp_merge_demangle_parse_infos (struct demangle_parse_info *dest,
+			       struct demangle_component *target,
+			       struct demangle_parse_info *src)
+
+{
+  struct demangle_info *di;
+
+  memcpy (target, src->tree, sizeof (struct demangle_component));
+  di = dest->info;
+  while (di->next != NULL)
+    di = di->next;
+  di->next = src->info;
+  src->info = NULL;
+  cp_demangled_name_parse_free (src);
+}
+
+/* A cleanup wrapper for cp_demangled_name_parse_free.  */
+
+static void
+do_demangled_name_parse_free_cleanup (void *data)
+{
+  struct demangle_parse_info *info = (struct demangle_parse_info *) data;
+
+  cp_demangled_name_parse_free (info);
+}
+
+/* Create a cleanup for C++ name parsing.  */
+
+struct cleanup *
+make_cleanup_cp_demangled_name_parse_free (struct demangle_parse_info *info)
+{
+  return make_cleanup (do_demangled_name_parse_free_cleanup, info);
+}
+
 /* Convert a demangled name to a demangle_component tree.  On success,
-   the root of the new tree is returned; it is valid until the next
-   call to this function and should not be freed.  On error, NULL is
+   a structure containing the root of the new tree is returned; it must
+   be freed by calling cp_demangled_name_parse_free. On error, NULL is
    returned, and an error message will be set in *ERRMSG (which does
    not need to be freed).  */
 
-struct demangle_component *
+struct demangle_parse_info *
 cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
 {
   static char errbuf[60];
-  struct demangle_component *result;
+  struct demangle_parse_info *result;
 
   prev_lexptr = lexptr = demangled_name;
   error_lexptr = NULL;
   global_errmsg = NULL;
 
-  allocate_info ();
+  demangle_info = allocate_info ();
+
+  result = ((struct demangle_parse_info *)
+	    malloc (sizeof (struct demangle_parse_info)));
+  result->info = demangle_info;
 
   if (yyparse ())
     {
@@ -1993,10 +2049,11 @@ cp_demangled_name_to_comp (const char *demangled_name, const char **errmsg)
 	  strcat (errbuf, "'");
 	  *errmsg = errbuf;
 	}
+      cp_demangled_name_parse_free (result);
       return NULL;
     }
 
-  result = global_result;
+  result->tree = global_result;
   global_result = NULL;
 
   return result;
@@ -2052,7 +2109,7 @@ main (int argc, char **argv)
   char buf[65536];
   int arg;
   const char *errmsg;
-  struct demangle_component *result;
+  struct demangle_parse_info *result;
 
   arg = 1;
   if (argv[arg] && strcmp (argv[arg], "--debug") == 0)
@@ -2086,7 +2143,8 @@ main (int argc, char **argv)
 	    continue;
 	  }
 
-	cp_print (result);
+	cp_print (result->tree);
+	cp_demangled_name_parse_free (result);
 
 	free (str2);
 	if (c)
@@ -2105,7 +2163,8 @@ main (int argc, char **argv)
 	  fputc ('\n', stderr);
 	  return 0;
 	}
-      cp_print (result);
+      cp_print (result->tree);
+      cp_demangled_name_parse_free (result);
       putchar ('\n');
     }
   return 0;
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index a479067..a1083b6 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -86,6 +86,17 @@ static const char *operator_tokens[] =
     /* new[] and delete[] require special whitespace handling */
   };
 
+/* A vector used to define a free list for typedef replacement
+   (replace_typedefs/inspect_type).  See cp_canonicalize_string_no_typdefs
+   and inspect_type for more information.  */
+typedef char *namep;
+DEF_VEC_P (namep);
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+		  struct demangle_component *ret_comp,
+		  VEC (namep) *free_list);
+
 /* Return 1 if STRING is clearly already in canonical form.  This
    function is conservative; things which it does not recognize are
    assumed to be non-canonical, and the parser will sort them out
@@ -117,6 +128,181 @@ cp_already_canonical (const char *string)
     return 0;
 }
 
+/* Inspect the given RET_COMP for its type.  If it is a typedef,
+   replace the node with the typedef's tree, storing any memory allocations
+   on the FREE_LIST.   */
+
+static void
+inspect_type (struct demangle_parse_info *info,
+	      struct demangle_component *ret_comp,
+	      VEC (namep) *free_list)
+{
+  char *name;
+  struct symbol *sym;
+
+  /* Copy the symbol's name from RET_COMP and look it up
+     in the symbol table.  */
+  name = (char *) alloca (ret_comp->u.s_name.len + 1);
+  memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len);
+  name[ret_comp->u.s_name.len] = '\0';
+  sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+  if (sym != NULL)
+    {
+      struct type *type = SYMBOL_TYPE (sym);
+
+      /* If the type is a typedef, replace it.  */
+      if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF)
+	{
+	  struct demangle_parse_info *i;
+	  struct ui_file *buf = mem_fileopen ();
+	  struct cleanup *cleanup = make_cleanup_ui_file_delete (buf);
+
+	  CHECK_TYPEDEF (type);
+	  type_print (type, "", buf, -1);
+	  name = ui_file_xstrdup (buf, NULL);
+	  VEC_safe_push (namep, free_list, name);
+	  do_cleanups (cleanup);
+
+	  /* Turn the result into a new tree.  Note that this
+	     tree will contain pointers into NAME, so NAME cannot
+	     be free'd until all typedef conversion is done and
+	     the final result is converted into a string.  */
+	  i = cp_demangled_name_to_comp (name, NULL);
+	  if (i != NULL)
+	    {
+	      /* Merge the two trees.  */
+	      cp_merge_demangle_parse_infos (info, ret_comp, i);
+
+	      /* Replace any newly introduced typedefs.  */
+	      replace_typedefs (info, ret_comp, free_list);
+	    }
+	  else
+	    {
+	      /* This shouldn't happen unless the type printer has
+		 output something that the name parser cannot grok.
+		 Nonetheless, an ounce of prevention...
+
+		 Canonicalize the name again, and store it in the
+		 current node (RET_COMP).  */
+	      char *canon = cp_canonicalize_string_no_typedefs (name);
+
+	      if (canon != NULL)
+		{
+		  xfree (name);
+		  name = canon;
+		}
+
+	      ret_comp->u.s_name.s = name;
+	      ret_comp->u.s_name.len = strlen (name);
+	    }
+	}
+    }
+}
+
+/* Walk the parse tree given by RET_COMP, replacing any typedefs with
+   their basic types.  Any required memory allocations are added
+   to the FREE_LIST, which must be free'd by a caller.  */
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+		  struct demangle_component *ret_comp,
+		  VEC (namep) *free_list)
+{
+  if (ret_comp)
+    {
+      switch (ret_comp->type)
+	{
+	case DEMANGLE_COMPONENT_ARGLIST:
+	  /* "Parameter declarations that differ only in the presence
+	     or absence of `const' and/or `volatile' are equivalent."
+	     C++ Standard N3290, clause 13.1.3 #4.  */
+	  while (d_left (ret_comp) != NULL
+		 && (d_left (ret_comp)->type == DEMANGLE_COMPONENT_CONST
+		     || d_left (ret_comp)->type == DEMANGLE_COMPONENT_VOLATILE))
+	    {
+	      d_left (ret_comp) = d_left (d_left (ret_comp));
+	    }
+
+	  replace_typedefs (info, d_left (ret_comp), free_list);
+	  replace_typedefs (info, d_right (ret_comp), free_list);
+	  break;
+
+	case DEMANGLE_COMPONENT_NAME:
+	  inspect_type (info, ret_comp, free_list);
+	  break;
+
+	case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+	case DEMANGLE_COMPONENT_LOCAL_NAME:
+	case DEMANGLE_COMPONENT_TYPED_NAME:
+	case DEMANGLE_COMPONENT_CTOR:
+	case DEMANGLE_COMPONENT_ARRAY_TYPE:
+	case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+	  replace_typedefs (info, d_right (ret_comp), free_list);
+	  break;
+
+	case DEMANGLE_COMPONENT_POINTER:
+	  replace_typedefs (info, d_left (ret_comp), free_list);
+	  break;
+
+	default:
+	  break;
+	}
+    }
+}
+
+/* Parse STRING and convert it to canonical form, resolving any typedefs.
+   If parsing fails, or if STRING is already canonical, return NULL.
+   Otherwise return the canonical form.  The return value is allocated via
+   xmalloc.  */
+
+char *
+cp_canonicalize_string_no_typedefs (const char *string)
+{
+  char *ret;
+  unsigned int estimated_len;
+  struct demangle_parse_info *info;
+  VEC (namep) *free_list;
+
+  ret = NULL;
+  free_list = VEC_alloc (namep, 10);
+  estimated_len = strlen (string) * 2;
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info != NULL)
+    {
+      /* Replace all the typedefs in the tree.  */
+      replace_typedefs (info, info->tree, free_list);
+
+      /* Convert the tree back into a string.  */
+      ret = cp_comp_to_string (info->tree, estimated_len);
+
+      /* Free the parse information.  */
+      cp_demangled_name_parse_free (info);
+
+      /* Free any memory allocated during typedef replacement.  */
+      if (!VEC_empty (namep, free_list))
+	{
+	  int i;
+	  char *iter;
+
+	  for (i = 0; VEC_iterate (namep, free_list, i, iter); ++i)
+	    xfree (iter);
+	}
+
+      /* Free the vector used for the free list.  */
+      VEC_free (namep, free_list);
+
+      /* Finally, compare the original string with the computed
+	 name, returning NULL if they are the same.  */
+      if (strcmp (string, ret) == 0)
+	{
+	  xfree (ret);
+	  return NULL;
+	}
+    }
+
+  return ret;
+}
+
 /* Parse STRING and convert it to canonical form.  If parsing fails,
    or if STRING is already canonical, return NULL.  Otherwise return
    the canonical form.  The return value is allocated via xmalloc.  */
@@ -124,19 +310,20 @@ cp_already_canonical (const char *string)
 char *
 cp_canonicalize_string (const char *string)
 {
-  struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   unsigned int estimated_len;
   char *ret;
 
   if (cp_already_canonical (string))
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (string, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (string, NULL);
+  if (info == NULL)
     return NULL;
 
   estimated_len = strlen (string) * 2;
-  ret = cp_comp_to_string (ret_comp, estimated_len);
+  ret = cp_comp_to_string (info->tree, estimated_len);
+  cp_demangled_name_parse_free (info);
 
   if (strcmp (string, ret) == 0)
     {
@@ -153,23 +340,29 @@ cp_canonicalize_string (const char *string)
    freed when finished with the tree, or NULL if none was needed.
    OPTIONS will be passed to the demangler.  */
 
-static struct demangle_component *
+static struct demangle_parse_info *
 mangled_name_to_comp (const char *mangled_name, int options,
 		      void **memory, char **demangled_p)
 {
-  struct demangle_component *ret;
   char *demangled_name;
+  struct demangle_parse_info *info;
 
   /* If it looks like a v3 mangled name, then try to go directly
      to trees.  */
   if (mangled_name[0] == '_' && mangled_name[1] == 'Z')
     {
+      struct demangle_component *ret;
+
       ret = cplus_demangle_v3_components (mangled_name,
 					  options, memory);
       if (ret)
 	{
+	  info = ((struct demangle_parse_info *)
+		  xmalloc (sizeof (struct demangle_parse_info)));
+	  info->info = NULL;
+	  info->tree = ret;
 	  *demangled_p = NULL;
-	  return ret;
+	  return info;
 	}
     }
 
@@ -181,16 +374,16 @@ mangled_name_to_comp (const char *mangled_name, int options,
   
   /* If we could demangle the name, parse it to build the component
      tree.  */
-  ret = cp_demangled_name_to_comp (demangled_name, NULL);
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
 
-  if (ret == NULL)
+  if (info == NULL)
     {
       xfree (demangled_name);
       return NULL;
     }
 
   *demangled_p = demangled_name;
-  return ret;
+  return info;
 }
 
 /* Return the name of the class containing method PHYSNAME.  */
@@ -201,14 +394,16 @@ cp_class_name_from_physname (const char *physname)
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp, *prev_comp, *cur_comp;
+  struct demangle_parse_info *info;
   int done;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-				   &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+			       &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
   done = 0;
+  ret_comp = info->tree;
 
   /* First strip off any qualifiers, if we have a function or
      method.  */
@@ -277,8 +472,8 @@ cp_class_name_from_physname (const char *physname)
     }
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -348,13 +543,14 @@ method_name_from_physname (const char *physname)
   void *storage = NULL;
   char *demangled_name = NULL, *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = mangled_name_to_comp (physname, DMGL_ANSI,
-				   &storage, &demangled_name);
-  if (ret_comp == NULL)
+  info = mangled_name_to_comp (physname, DMGL_ANSI,
+			       &storage, &demangled_name);
+  if (info == NULL)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
@@ -363,8 +559,8 @@ method_name_from_physname (const char *physname)
     ret = cp_comp_to_string (ret_comp, 10);
 
   xfree (storage);
-  if (demangled_name)
-    xfree (demangled_name);
+  xfree (demangled_name);
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -379,17 +575,19 @@ cp_func_name (const char *full_name)
 {
   char *ret;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
 
-  ret_comp = cp_demangled_name_to_comp (full_name, NULL);
-  if (!ret_comp)
+  info = cp_demangled_name_to_comp (full_name, NULL);
+  if (!info)
     return NULL;
 
-  ret_comp = unqualified_name_from_comp (ret_comp);
+  ret_comp = unqualified_name_from_comp (info->tree);
 
   ret = NULL;
   if (ret_comp != NULL)
     ret = cp_comp_to_string (ret_comp, 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
@@ -402,16 +600,18 @@ cp_remove_params (const char *demangled_name)
 {
   int done = 0;
   struct demangle_component *ret_comp;
+  struct demangle_parse_info *info;
   char *ret = NULL;
 
   if (demangled_name == NULL)
     return NULL;
 
-  ret_comp = cp_demangled_name_to_comp (demangled_name, NULL);
-  if (ret_comp == NULL)
+  info = cp_demangled_name_to_comp (demangled_name, NULL);
+  if (info == NULL)
     return NULL;
 
   /* First strip off any qualifiers, if we have a function or method.  */
+  ret_comp = info->tree;
   while (!done)
     switch (ret_comp->type)
       {
@@ -433,6 +633,7 @@ cp_remove_params (const char *demangled_name)
   if (ret_comp->type == DEMANGLE_COMPONENT_TYPED_NAME)
     ret = cp_comp_to_string (d_left (ret_comp), 10);
 
+  cp_demangled_name_parse_free (info);
   return ret;
 }
 
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 57aa03a..1e71941 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -36,6 +36,16 @@ struct objfile;
 struct type;
 struct demangle_component;
 
+/* The result of parsing a name.  */
+struct demangle_parse_info
+{
+  /* The memory used during the parse.  */
+  struct demangle_info *info;
+
+  /* The result of the parse.  */
+  struct demangle_component *tree;
+};
+
 /* This struct is designed to store data from using directives.  It
    says that names from namespace IMPORT_SRC should be visible within
    namespace IMPORT_DEST.  These form a linked list; NEXT is the next
@@ -100,6 +110,8 @@ struct using_direct
 
 extern char *cp_canonicalize_string (const char *string);
 
+extern char *cp_canonicalize_string_no_typedefs (const char *string);
+
 extern char *cp_class_name_from_physname (const char *physname);
 
 extern char *method_name_from_physname (const char *physname);
@@ -177,12 +189,19 @@ struct type *cp_lookup_transparent_type (const char *name);
 
 /* Functions from cp-name-parser.y.  */
 
-extern struct demangle_component *cp_demangled_name_to_comp
-  (const char *demangled_name, const char **errmsg);
+extern struct demangle_parse_info *cp_demangled_name_to_comp
+     (const char *demangled_name, const char **errmsg);
 
 extern char *cp_comp_to_string (struct demangle_component *result,
 				int estimated_len);
 
+extern void cp_demangled_name_parse_free (struct demangle_parse_info *);
+extern struct cleanup *make_cleanup_cp_demangled_name_parse_free
+     (struct demangle_parse_info *);
+extern void cp_merge_demangle_parse_infos (struct demangle_parse_info *,
+					   struct demangle_component *,
+					   struct demangle_parse_info *);
+
 /* The list of "maint cplus" commands.  */
 
 extern struct cmd_list_element *maint_cplus_cmd_list;
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 81b20c7..374b9d5 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4888,7 +4888,7 @@ do_ui_file_peek_last (void *object, const char *buffer, long length)
 
 static const char *
 dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
-		     int physname)
+		     enum name_kind kind)
 {
   if (name == NULL)
     name = dwarf2_name (die, cu);
@@ -4896,7 +4896,7 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
   /* For Fortran GDB prefers DW_AT_*linkage_name if present but otherwise
      compute it by typename_concat inside GDB.  */
   if (cu->language == language_ada
-      || (cu->language == language_fortran && physname))
+      || (cu->language == language_fortran && kind == NAME_KIND_PHYS))
     {
       /* For Ada unit, we prefer the linkage name over the name, as
 	 the former contains the exported name, which the user expects
@@ -4928,7 +4928,8 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
 	  if (*prefix != '\0')
 	    {
 	      char *prefixed_name = typename_concat (NULL, prefix, name,
-						     physname, cu);
+						     (kind == NAME_KIND_PHYS),
+						     cu);
 
 	      fputs_unfiltered (prefixed_name, buf);
 	      xfree (prefixed_name);
@@ -5065,13 +5066,14 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
 	  /* For Java and C++ methods, append formal parameter type
 	     information, if PHYSNAME.  */
 
-	  if (physname && die->tag == DW_TAG_subprogram
+	  if ((kind == NAME_KIND_PHYS || kind == NAME_KIND_PRINT)
+	      && die->tag == DW_TAG_subprogram
 	      && (cu->language == language_cplus
 		  || cu->language == language_java))
 	    {
 	      struct type *type = read_type_die (die, cu);
 
-	      c_type_print_args (type, buf, 1, cu->language);
+	      c_type_print_args (type, buf, kind, cu->language);
 
 	      if (cu->language == language_java)
 		{
@@ -5127,7 +5129,7 @@ dwarf2_compute_name (char *name, struct die_info *die, struct dwarf2_cu *cu,
 static const char *
 dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, 0);
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_FULL);
 }
 
 /* Construct a physname for the given DIE in CU.  NAME may either be
@@ -5140,7 +5142,13 @@ dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
 static const char *
 dwarf2_physname (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, 1);
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_PHYS);
+}
+
+static const char *
+dwarf2_print_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
+{
+  return dwarf2_compute_name (name, die, cu, NAME_KIND_PRINT);
 }
 
 /* Read the import statement specified by the given die and record it.  */
@@ -11072,6 +11080,20 @@ new_symbol_full (struct die_info *die, struct type *type, struct dwarf2_cu *cu,
       linkagename = dwarf2_physname (name, die, cu);
       SYMBOL_SET_NAMES (sym, linkagename, strlen (linkagename), 0, objfile);
 
+      /* For C++ set the symbol's demangled name if it is different than
+	 the computed physname.  This can happen when the source defines
+	 a method with typedef'd parameters.  This is ultimately used by
+	 the type printer.  */
+      if (cu->language == language_cplus && die->tag == DW_TAG_subprogram)
+	{
+	  const char *print_name = dwarf2_print_name (name, die, cu);
+	  if (strcmp (print_name, linkagename))
+	    {
+	      symbol_set_demangled_name (&(sym->ginfo),
+					 (char *) print_name, NULL);
+	    }
+	}
+
       /* Fortran does not have mangling standard and the mangling does differ
 	 between gfortran, iFort etc.  */
       if (cu->language == language_fortran
diff --git a/gdb/jv-typeprint.c b/gdb/jv-typeprint.c
index 0a709e9..12743c7 100644
--- a/gdb/jv-typeprint.c
+++ b/gdb/jv-typeprint.c
@@ -328,9 +328,6 @@ java_type_print_base (struct type *type, struct ui_file *stream, int show,
 
 /* LEVEL is the depth to indent lines by.  */
 
-extern void c_type_print_varspec_suffix (struct type *, struct ui_file *,
-					 int, int, int);
-
 void
 java_print_type (struct type *type, const char *varstring,
 		 struct ui_file *stream, int show, int level)
@@ -349,5 +346,5 @@ java_print_type (struct type *type, const char *varstring,
      so don't print an additional pair of ()'s.  */
 
   demangled_args = varstring != NULL && strchr (varstring, '(') != NULL;
-  c_type_print_varspec_suffix (type, stream, show, 0, demangled_args);
+  c_type_print_varspec_suffix (type, stream, show, 0, demangled_args, 0);
 }
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 94bb86f..a85c3d0 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -222,7 +222,7 @@ find_methods (struct type *t, char *name, enum language language,
 
   /* NAME is typed by the user: it needs to be canonicalized before
      passing to lookup_symbol.  */
-  canon = cp_canonicalize_string (name);
+  canon = cp_canonicalize_string_no_typedefs (name);
   if (canon != NULL)
     {
       name = canon;
@@ -1315,7 +1315,7 @@ decode_compound (char **argptr, int funfirstline,
 		 char *the_real_saved_arg, char *p)
 {
   struct symtabs_and_lines values;
-  char *p2;
+  char *p2, *name;
   char *saved_arg2 = *argptr;
   char *temp_end;
   struct symbol *sym;
@@ -1324,6 +1324,7 @@ decode_compound (char **argptr, int funfirstline,
   struct type *t;
   char *saved_java_argptr = NULL;
   char *saved_arg;
+  struct cleanup *cleanup;
 
   /* If the user specified any completer quote characters in the input,
      strip them.  They are superfluous.  */
@@ -1586,7 +1587,21 @@ decode_compound (char **argptr, int funfirstline,
   *argptr = (*p == '\'') ? p + 1 : p;
 
   /* Look up entire name.  */
-  sym = lookup_symbol (copy, get_selected_block (0), VAR_DOMAIN, 0);
+  name = copy;
+
+  cleanup = make_cleanup (null_cleanup, NULL);
+  if (current_language->la_language == language_cplus)
+    {
+      char *canon = cp_canonicalize_string_no_typedefs (copy);
+      if (canon != NULL)
+	{
+	  name = canon;
+	  make_cleanup (xfree, name);
+	}
+    }
+
+  sym = lookup_symbol (name, get_selected_block (0), VAR_DOMAIN, 0);
+  do_cleanups (cleanup);
   if (sym)
     return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL);
   else
@@ -1727,7 +1742,7 @@ find_method (int funfirstline, struct linespec_result *canonical,
 	  strcpy (name, SYMBOL_NATURAL_NAME (sym_class));
 	  strcat (name, "::");
 	  strcat (name, copy);
-	  canon = cp_canonicalize_string (name);
+	  canon = cp_canonicalize_string_no_typedefs (name);
 	  if (canon != NULL)
 	    {
 	      xfree (name);
@@ -2069,15 +2084,31 @@ decode_variable (char *copy, int funfirstline,
 		 struct linespec_result *canonical,
 		 struct symtab *file_symtab)
 {
+  char *name;
   struct symbol *sym;
+  struct cleanup *cleanup;
   struct minimal_symbol *msymbol;
 
-  sym = lookup_symbol (copy,
+  name = copy;
+  cleanup = make_cleanup (null_cleanup, NULL);
+  if (current_language->la_language == language_cplus)
+    {
+      char *canon = cp_canonicalize_string_no_typedefs (copy);
+
+      if (canon != NULL)
+	{
+	  name = canon;
+	  make_cleanup (xfree, name);
+	}
+    }
+
+  sym = lookup_symbol (name,
 		       (file_symtab
 			? BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_symtab),
 					     STATIC_BLOCK)
 			: get_selected_block (0)),
 		       VAR_DOMAIN, 0);
+  do_cleanups (cleanup);
 
   if (sym != NULL)
     return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);
diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 249675b..a906524 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -902,7 +902,7 @@ prim_record_minimal_symbol_full (const char *name, int name_len, int copy_name,
   msymbol = &msym_bunch->contents[msym_bunch_index];
   SYMBOL_SET_LANGUAGE (msymbol, language_auto);
   SYMBOL_SET_NAMES (msymbol, name, name_len, copy_name, objfile);
-
+  SYMBOL_FLAGS (msymbol) |= GSYMBOL_FLAG_MSYMBOL;
   SYMBOL_VALUE_ADDRESS (msymbol) = address;
   SYMBOL_SECTION (msymbol) = section;
   SYMBOL_OBJ_SECTION (msymbol) = NULL;
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index c010420..f4616c3 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -577,8 +577,10 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 {
   int i;
   struct demangle_component *demangled;
+  struct demangle_parse_info *info;
   const char *err;
   struct type *argtype;
+  struct cleanup *cleanup;
 
   if (TYPE_NAME (type) == NULL)
     {
@@ -587,12 +589,14 @@ typy_legacy_template_argument (struct type *type, struct block *block,
     }
 
   /* Note -- this is not thread-safe.  */
-  demangled = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
-  if (! demangled)
+  info = cp_demangled_name_to_comp (TYPE_NAME (type), &err);
+  if (! info)
     {
       PyErr_SetString (PyExc_RuntimeError, err);
       return NULL;
     }
+  demangled = info->tree;
+  cleanup = make_cleanup_cp_demangled_name_parse_free (info);
 
   /* Strip off component names.  */
   while (demangled->type == DEMANGLE_COMPONENT_QUAL_NAME
@@ -601,6 +605,7 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 
   if (demangled->type != DEMANGLE_COMPONENT_TEMPLATE)
     {
+      do_cleanups (cleanup);
       PyErr_SetString (PyExc_RuntimeError, _("Type is not a template."));
       return NULL;
     }
@@ -613,12 +618,14 @@ typy_legacy_template_argument (struct type *type, struct block *block,
 
   if (! demangled)
     {
+      do_cleanups (cleanup);
       PyErr_Format (PyExc_RuntimeError, _("No argument %d in template."),
 		    argno);
       return NULL;
     }
 
   argtype = typy_lookup_type (demangled->u.s_binary.left, block);
+  do_cleanups (cleanup);
   if (! argtype)
     return NULL;
 
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 84e01a6..b7c42bd 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -740,17 +740,21 @@ symbol_demangled_name (const struct general_symbol_info *gsymbol)
   return NULL;
 }
 
-/* Return the search name of a symbol---generally the demangled or
-   linkage name of the symbol, depending on how it will be searched for.
-   If there is no distinct demangled name, then returns the same value
-   (same pointer) as SYMBOL_LINKAGE_NAME.  */
+/* Return the SYMBOL_SEARCH_NAME of GSYMBOL.  */
+
 char *
 symbol_search_name (const struct general_symbol_info *gsymbol)
 {
   if (gsymbol->language == language_ada)
     return gsymbol->name;
   else
-    return symbol_natural_name (gsymbol);
+    {
+      if (gsymbol->flags & GSYMBOL_FLAG_MSYMBOL
+	  || gsymbol->language != language_cplus)
+	return symbol_natural_name (gsymbol);
+      else
+	return gsymbol->name;
+    }
 }
 
 /* Initialize the structure fields to zero values.  */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 12f52a2..cc3ed96 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -34,6 +34,14 @@ struct axs_value;
 struct agent_expr;
 struct program_space;
 
+/* A set of flags to describe a general symbol.  */
+
+enum gsymbol_flags
+{
+  /* This general symbol is a minimal symbol.  */
+  GSYMBOL_FLAG_MSYMBOL = (1 << 0)
+};
+
 /* Some of the structures in this file are space critical.
    The space-critical structures are:
 
@@ -147,6 +155,10 @@ struct general_symbol_info
 
   ENUM_BITFIELD(language) language : 8;
 
+  /* Flags for this symbol.  */
+
+  ENUM_BITFIELD(gsymbol_flags) flags : 1;
+
   /* Which section is this symbol in?  This is an index into
      section_offsets for this objfile.  Negative means that the symbol
      does not get relocated relative to a section.
@@ -184,6 +196,7 @@ extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *);
 #define SYMBOL_LANGUAGE(symbol)		(symbol)->ginfo.language
 #define SYMBOL_SECTION(symbol)		(symbol)->ginfo.section
 #define SYMBOL_OBJ_SECTION(symbol)	(symbol)->ginfo.obj_section
+#define SYMBOL_FLAGS(symbol)            (symbol)->ginfo.flags
 
 /* Initializes the language dependent portion of a symbol
    depending upon the language for the symbol.  */
diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.cc b/gdb/testsuite/gdb.cp/meth-typedefs.cc
new file mode 100644
index 0000000..4055382
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,94 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.
+
+   Contributed by Red Hat, originally written by Keith Seitz.  */
+
+#include <stdlib.h>
+
+typedef const char* const* my_type;
+typedef int my_type_2;
+typedef my_type my_other_type;
+typedef my_type_2 my_other_type_2;
+typedef unsigned long CORE_ADDR;
+
+typedef void (*fptr1) (my_other_type);
+typedef void (*fptr2) (fptr1, my_other_type_2);
+typedef void (*fptr3) (fptr2, my_other_type);
+
+namespace A
+{
+  class foo
+  {
+  public:
+    foo (void) { }
+    foo (my_other_type a) { } // A::foo::foo(my_other_type)
+    foo (my_other_type_2 a) { } // A::foo::foo(my_other_type_2)
+    foo (my_other_type_2 a, const my_other_type b) { } // A::foo::foo(my_other_type_2, const my_other_type)
+    foo (fptr3) { } // A::foo::foo(fptr3)
+    foo (fptr1 *a) { } // A::foo::foo(fptr1*)
+    foo (CORE_ADDR (*) [10]) { } // A::foo::foo(CORE_ADDR (*) [10])
+
+    void test (my_other_type a) { } // A::foo::test(my_other_type)
+    void test (my_other_type_2 a) { } // A::foo::test(my_other_type_2)
+    void test (my_other_type_2 a, const my_other_type b) { } // A::foo::test(my_other_type_2, const my_other_type)
+    void test (fptr3 a) { } // A::foo::test(fptr3)
+    void test (fptr1 *a) { } // A::foo::test(fptr1*)
+    void test (CORE_ADDR (*) [10]) { } // A::foo::test(CORE_ADDR (*) [10])
+  };
+};
+
+namespace B
+{
+  void
+  test (my_other_type foo) { } // B::test(my_other_type)
+
+  void
+  test (my_other_type foo, my_other_type_2) { } // B::test(my_other_type, my_other_type_2)
+};
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (my_other_type foo, my_other_type_2) { } // test(my_other_type, my_other_type_2)
+
+int
+main (void)
+{
+  A::foo f;
+  fptr1 fptr;
+
+  f.test (static_cast<my_other_type> (NULL));
+  f.test (0);
+  f.test (0, static_cast<my_type> (NULL));
+  f.test (static_cast<fptr3> (NULL));
+  f.test (&fptr);
+  f.test (static_cast<CORE_ADDR (*) [10]> (0));
+  B::test (static_cast<my_other_type> (NULL));
+  B::test (static_cast<my_other_type> (NULL), 0);
+  test (static_cast<my_other_type> (NULL));
+  test (static_cast<my_other_type> (NULL), 0);
+
+  A::foo w (static_cast<my_other_type> (NULL));
+  A::foo x (0);
+  A::foo y (0, static_cast<my_other_type> (NULL));
+  A::foo z (static_cast<fptr3> (NULL));
+  A::foo a (&fptr);
+  A::foo b (static_cast<CORE_ADDR (*) [10]> (0));
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.exp b/gdb/testsuite/gdb.cp/meth-typedefs.exp
new file mode 100644
index 0000000..bdeb8a5
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,132 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# Contributed by Red Hat, originally written by Keith Seitz.
+#
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+proc add {var name params expected} {
+    upvar $var result
+    set expect ".*// ${name}\\($expected\\)"
+    lappend result [list "${name}($params)" $expect]
+}
+
+if {[skip_cplus_tests]} { continue }
+
+# Tests for c++/12266 et al
+set testfile "meth-typedefs"
+set srcfile $testfile.cc
+
+if {[prepare_for_testing $testfile $testfile $srcfile {c++ debug}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+array set typedefs {
+    "my_other_type" {"my_other_type" "my_type" "const char* const*"}
+    "my_other_type_2" {"my_other_type_2" "my_type_2" "int"}
+    "CORE_ADDR" { "CORE_ADDR" "unsigned long" }
+}
+
+set methods {}
+
+# Add the simple, one-parameter methods
+foreach method {A::foo::test A::foo::foo} {
+    foreach type {my_other_type my_other_type_2} {
+	foreach t $typedefs($type)  {
+	    add methods $method $t $type
+	}
+    }
+}
+
+# Add two-parameter methods
+foreach method {A::foo::test A::foo::foo} {
+    set type "my_other_type_2, const my_other_type"
+    foreach t1 $typedefs(my_other_type_2) {
+	foreach t2 $typedefs(my_other_type) {
+	    add methods $method "$t1, const $t2" $type
+	    add methods $method "$t1, $t2" $type
+	}
+    }
+}
+
+# Add the array-of-function pointer methods
+set type "fptr1\\*"
+foreach method {A::foo::test A::foo::foo} {
+    add methods $method "fptr1*" $type
+    foreach t $typedefs(my_other_type) {
+	add methods $method "void (**) ($t)" $type
+    }
+}
+
+# Add the function pointer methods
+set type "fptr3"
+foreach method {A::foo::test A::foo::foo} {
+    add methods $method "fptr3" $type
+
+    foreach t1 $typedefs(my_other_type) {
+	add methods $method "void (*)(fptr2, $t1)" $type
+	foreach t2 $typedefs(my_other_type_2) {
+	    add methods $method "void (*)(void (*)(fptr1, $t2), $t1)" $type
+	    foreach t3 $typedefs(my_other_type) {
+		add methods $method \
+		    "void (*)(void (*)(void (*) ($t3), $t2), $t1)" $type
+	    }
+	}
+    }
+}
+
+# Miscellaneous tests
+set type {CORE_ADDR \(\*\) \[10\]}
+foreach method {A::foo::foo A::foo::test} {
+    foreach t $typedefs(CORE_ADDR) {
+	add methods $method "$t (*) \[10\]" $type
+    }
+}
+
+# Add non-method tests
+set type1 "my_other_type"
+set type2 "my_other_type, my_other_type_2"
+foreach method {"test" "B::test"} {
+    foreach t1 $typedefs(my_other_type) {
+	add methods $method $t1 $type1
+	foreach t2 $typedefs(my_other_type_2) {
+	    add methods $method "$t1, $t2" $type2
+	}
+    }
+}
+
+gdb_test_no_output "set listsize 1" ""
+
+# Finally, for each method in the list METHODS, check whether
+# the user can "list" it and "break" on it (both quoted and unquoted).
+foreach test $methods {
+    set func [lindex $test 0]
+    set result [lindex $test 1]
+    gdb_test "list $func" $result
+    if {[gdb_breakpoint $func]} {
+      pass "break $func"
+    }
+    if {[gdb_breakpoint '$func']} {
+      pass "break '$func'"
+    }
+}
+
+gdb_exit
+return 0
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index 82cf61a..b271bcc 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -23,10 +23,21 @@
 enum language;
 struct ui_file;
 
+/* An enumeration for specifying the type of a computed symobl name.  */
+enum name_kind
+  {
+    NAME_KIND_FULL,	/* The fullname (methods do not
+			   contain any formal parameters).  */
+    NAME_KIND_PHYS,	/* The physname used to lookup symbols.  */
+    NAME_KIND_PRINT	/* The name used when printing the symbol.  */
+  };
+
 void print_type_scalar (struct type * type, LONGEST, struct ui_file *);
 
 void c_type_print_varspec_suffix (struct type *, struct ui_file *, int,
-				  int, int);
+				  int, int, int);
+
+void c_type_print_args (struct type *, struct ui_file *,
+			enum name_kind, enum language);
 
-void c_type_print_args (struct type *, struct ui_file *, int, enum language);
 #endif

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

* [rfc] physname cross-check  [Re: [RFA] Typedef'd method parameters [0/4]]
  2011-05-12 21:28 ` Keith Seitz
@ 2011-05-16 15:49   ` Jan Kratochvil
  2011-05-17 18:15     ` Keith Seitz
  0 siblings, 1 reply; 9+ messages in thread
From: Jan Kratochvil @ 2011-05-16 15:49 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

Hi Keith,

On Thu, 12 May 2011 23:27:52 +0200, Keith Seitz wrote:
> I'm sending an updated set of all of the patches just in case
> something got foobar'd along the way.

I wrote a cross-check of what GDB thinks is the physname (which is in
demangled canonical form) vs. what GCC thinkgs is the physname (which needs to
be converted from mangled form and canonicalized).

It reports for me 34524 unique failures on libwebkit.so.debug.  (Sure such
count is caused only by a few physname computation bugs.)

Therefore I would propose a sinful idea to temporarily just use
DW_AT_linkage_name if it is available to ever release gdb-7.3 and make
DW_AT_linkage_name-less GDB a feature for gdb-7.4.  After all such cross-check
should exist anyway for verifying both GCC and GDB bugs this way.

This patch preferring DW_AT_linkage_name fixes for example this regression:

cat >1.h <<EOH
struct x {};
class C { public: void m (x *xp); };
EOH
cat >1.C <<EOH
#include "1.h"
C c;
int main () { c.m(0); }
EOH
cat >1b.C <<EOH
#include "1.h"
void C::m (x *xp) {}
EOH

# gcc-c++-4.6.0-7.fc15.x86_64
g++ -c -o 1b.o -Wall 1b.C; g++ -o 1 1.C 1b.o -Wall -g; ./gdb -q -nx ./1 -ex 'set complaints 10' -ex 'p main' -ex 'set complaints 0' -ex start -ex 'p c.m' -ex c -ex q
During symbol reading, Computed physname <C::m(struct x *)> does not match demangled <C::m(x*)> (from linkage <_ZN1C1mEP1x>) - DIE at 0x3d [in module .../1].

pre-phyname:       $2 = {void (C *, x *)} 0x4004f0 <C::m(x*)>
FSF GDB HEAD:      $2 = {void (C * const, x *)} 0x4004f0 <C::m(x*)>
HEAD + your patch: Cannot take address of method m.
your+this patches: $2 = {void (C * const, x *)} 0x4004f0 <C::m(x*)>

This is a regression.

Just it has some other existing testsuite regressions:
	gdb.cp/bs15503.exp gdb.cp/cp-relocate.exp gdb.cp/cpexprs.exp
	gdb.java/jmisc.exp gdb.java/jprint.exp

From a quick loook they seem to me like bugs in GDB expecting the incompatibly
computed physname but I did not try to fix it yet.

What do you think?


Thanks,
Jan


gdb/
2011-05-16  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* dwarf2read.c (dwarf2_physname): New variables physname, attr,
	mangled, retval, demangled, canon and back_to.  Cross-check
	DW_AT_linkage_name and PHYS_NAME if both available, return
	DW_AT_linkage_name in such case.

--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -5142,7 +5142,74 @@ dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
 static const char *
 dwarf2_physname (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, NAME_KIND_PHYS);
+  const char *physname = dwarf2_compute_name (name, die, cu, NAME_KIND_PHYS);
+  struct attribute *attr;
+  const char *mangled, *retval;
+  char *demangled, *canon;
+  struct cleanup *back_to;
+
+  /* Do not check PHYSNAME if it never will be needed by GDB.  GDB does not
+     need to support something it has no use for.  */
+  if (!die_needs_namespace (die, cu))
+    return physname;
+
+  attr = dwarf2_attr (die, DW_AT_linkage_name, cu);
+  if (!attr)
+    attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu);
+  if (!attr || !DW_STRING (attr))
+    {
+      /* DW_AT_linkage_name is missing in some cases - depend on what GDB has
+	 computed.  */
+
+      return physname;
+    }
+  mangled = DW_STRING (attr);
+
+  /* As both DW_AT_linkage_name (MANGLED) and computed PHYSNAME are present
+     cross-check them.  */
+
+  back_to = make_cleanup (null_cleanup, 0);
+
+  demangled = cplus_demangle (mangled, DMGL_PARAMS | DMGL_ANSI);
+  if (demangled)
+    make_cleanup (xfree, demangled);
+  else
+    demangled = (char *) mangled;
+
+  if (cu->language == language_cplus)
+    {
+      canon = cp_canonicalize_string (demangled);
+      if (canon != NULL)
+	make_cleanup (xfree, canon);
+      else
+	canon = demangled;
+    }
+  else
+    canon = demangled;
+
+  if (strcmp (physname, canon) != 0)
+    {
+      /* It may not mean a bug in GDB.  The compiler could also compute
+	 DW_AT_linkage_name incorrectly.  But in such case GDB would need to be
+	 bug-to-bug compatible.  */
+
+      complaint (&symfile_complaints,
+		 _("Computed physname <%s> does not match demangled <%s> "
+		   "(from linkage <%s>) - DIE at 0x%x [in module %s]"),
+		 physname, canon, mangled, die->offset, cu->objfile->name);
+
+      /* Prefer DW_AT_linkage_name (in the CANON form) - when it is available
+	 here - over computed PHYSNAME.  It is safer against both buggy GDB and
+	 buggy compilers.  */
+
+      retval = obsavestring (canon, strlen (canon),
+			     &cu->objfile->objfile_obstack);
+    }
+  else
+    retval = physname;
+
+  do_cleanups (back_to);
+  return retval;
 }
 
 static const char *


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

* Re: [rfc] physname cross-check  [Re: [RFA] Typedef'd method parameters [0/4]]
  2011-05-16 15:49   ` [rfc] physname cross-check [Re: [RFA] Typedef'd method parameters [0/4]] Jan Kratochvil
@ 2011-05-17 18:15     ` Keith Seitz
  2011-05-17 18:33       ` Jan Kratochvil
                         ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Keith Seitz @ 2011-05-17 18:15 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On 05/16/2011 08:48 AM, Jan Kratochvil wrote:

> I wrote a cross-check of what GDB thinks is the physname (which is in
> demangled canonical form) vs. what GCC thinkgs is the physname (which needs to
> be converted from mangled form and canonicalized).

That's a great idea! "Why didn't I think of that?" (famous last words)

> It reports for me 34524 unique failures on libwebkit.so.debug.  (Sure such
> count is caused only by a few physname computation bugs.)

I will start looking into these and filing/fixing bugs when my plate 
opens up here in the next day or two.

> Therefore I would propose a sinful idea to temporarily just use
> DW_AT_linkage_name if it is available to ever release gdb-7.3 and make
> DW_AT_linkage_name-less GDB a feature for gdb-7.4.  After all such cross-check
> should exist anyway for verifying both GCC and GDB bugs this way.

For me, what really matters is what is best for users. Is reverting 
dwarf2_physname better or worse than DW_AT_MIPS_linkage_name? That's a 
difficult question to answer in a black-and-white way, really, but my 
instincts (which could be wrong, of course) tell me that 
MIPS_linkage_name is the greater of two evils.

> cat>1.h<<EOH
> struct x {};
> class C { public: void m (x *xp); };
> EOH
> cat>1.C<<EOH
> #include "1.h"
> C c;
> int main () { c.m(0); }
> EOH
> cat>1b.C<<EOH
> #include "1.h"
> void C::m (x *xp) {}
> EOH

I've fixed this bug. This was just introduced in this patchset because 
the typeprinter did not recognize that in C++, "struct" = "class". [To 
be clear, it was *my* patch which introduced this inequality.] I have 
fixed this my patchset, and I have added a test for it.

Unfortunately, I must reiterate that I am a slave to the test suite. 
While I try my best to test everything that comes to mind, ultimately, 
not everything comes to (my) mind.

> Just it has some other existing testsuite regressions:
> 	gdb.cp/bs15503.exp gdb.cp/cp-relocate.exp gdb.cp/cpexprs.exp
> 	gdb.java/jmisc.exp gdb.java/jprint.exp

Using DW_AT_MIPS_linkage_name will not pass cpexprs.exp without some 
hacking; the demangled name will need to be re-parsed (to remove 
typedefs -- that might be a bit easier with this patchset) and 
subsequently canonicalize the result.

I really see this as an even bigger risk than keeping the current code. 
And then there's constructors -- no version of GCC that I've seen 
outputs DW_AT_MIPS_linkage_name for ctors, so they would still have to 
be computed in some way.

> What do you think?

In the end, it probably doesn't really matter what I think. :-) IMO, 
this all boils down to risk management. Which path is least risky for 
users and most conducive to moving forward?

This is a decision for you and other maintainers to consider.

Keith


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

* Re: [rfc] physname cross-check  [Re: [RFA] Typedef'd method parameters [0/4]]
  2011-05-17 18:15     ` Keith Seitz
@ 2011-05-17 18:33       ` Jan Kratochvil
  2011-05-17 19:04         ` Keith Seitz
  2011-05-17 21:01       ` Tom Tromey
  2011-05-19 23:04       ` [rfc] physname cross-check #2 Jan Kratochvil
  2 siblings, 1 reply; 9+ messages in thread
From: Jan Kratochvil @ 2011-05-17 18:33 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

On Tue, 17 May 2011 20:15:18 +0200, Keith Seitz wrote:
> Is reverting dwarf2_physname better or worse than DW_AT_MIPS_linkage_name?

In which single case can be dwarf2_physname better than
DW_AT_MIPS_linkage_name?  That's the question.  dwarf2_physname is AFAIK to
give the linkage name and DW_AT_MIPS_linkage_name always matches that.

Apparently the testsuite has regressions with demangled + canonicalized
DW_AT_MIPS_linkage_name so I am wrong but I do not understand why.


> Using DW_AT_MIPS_linkage_name will not pass cpexprs.exp without some
> hacking; the demangled name will need to be re-parsed (to remove
> typedefs

DW_AT_MIPS_linkage_name already has all the typedefs removed - it is the
linkage name.


> I really see this as an even bigger risk than keeping the current
> code. And then there's constructors -- no version of GCC that I've
> seen outputs DW_AT_MIPS_linkage_name for ctors, so they would still
> have to be computed in some way.

Yes, I agree for ctors/dtors we should use the dwarf2_physname computation.


Thanks,
Jan


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

* Re: [rfc] physname cross-check  [Re: [RFA] Typedef'd method parameters [0/4]]
  2011-05-17 18:33       ` Jan Kratochvil
@ 2011-05-17 19:04         ` Keith Seitz
  0 siblings, 0 replies; 9+ messages in thread
From: Keith Seitz @ 2011-05-17 19:04 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On 05/17/2011 11:33 AM, Jan Kratochvil wrote:
> On Tue, 17 May 2011 20:15:18 +0200, Keith Seitz wrote:
>> Is reverting dwarf2_physname better or worse than DW_AT_MIPS_linkage_name?
>
> In which single case can be dwarf2_physname better than
> DW_AT_MIPS_linkage_name?  That's the question.  dwarf2_physname is AFAIK to
> give the linkage name and DW_AT_MIPS_linkage_name always matches that.

Ideally the two should be equivalent. I don't remember all the specifics 
any more, but there were problems with constructors (already mentioned) 
and templates. These might have simply been compiler bugs. Template bugs 
might now be fixed because of the new template attributes.

>> Using DW_AT_MIPS_linkage_name will not pass cpexprs.exp without some
>> hacking; the demangled name will need to be re-parsed (to remove
>> typedefs
>
> DW_AT_MIPS_linkage_name already has all the typedefs removed - it is the
> linkage name.

It should, but IIRC, I kept seeing, e.g., "std::string" show up in the 
demangled form of DW_AT_MIPS_linkage_name. Perhaps this was due to an 
older compiler I was using? I cannot seem to reproduce this today. [Or 
maybe I am just remembering something else?]

Sorry, my memory of this has bitrotted quite a bit.
Keith


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

* Re: [rfc] physname cross-check  [Re: [RFA] Typedef'd method parameters [0/4]]
  2011-05-17 18:15     ` Keith Seitz
  2011-05-17 18:33       ` Jan Kratochvil
@ 2011-05-17 21:01       ` Tom Tromey
  2011-05-19 23:04       ` [rfc] physname cross-check #2 Jan Kratochvil
  2 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2011-05-17 21:01 UTC (permalink / raw)
  To: Keith Seitz; +Cc: Jan Kratochvil, gdb-patches

Jan> It reports for me 34524 unique failures on libwebkit.so.debug.  (Sure such
Jan> count is caused only by a few physname computation bugs.)

Keith> I will start looking into these and filing/fixing bugs when my plate
Keith> opens up here in the next day or two.

I can put aside what I am doing and help out with this.  Can you push a
branch with your patches, and Jan's checking patch, to archer.git?  We
can split up the problems and work on them.

Jan> Therefore I would propose a sinful idea to temporarily just use
Jan> DW_AT_linkage_name if it is available to ever release gdb-7.3 and
Jan> make DW_AT_linkage_name-less GDB a feature for gdb-7.4.  After all
Jan> such cross-check should exist anyway for verifying both GCC and GDB
Jan> bugs this way.

Keith> For me, what really matters is what is best for users. Is reverting
Keith> dwarf2_physname better or worse than DW_AT_MIPS_linkage_name?

I think either answer has some bad qualities, even if you just consider
the 7.3 release.

With Jan's proposal we are basically going back to the state before
physname.  As Keith points out, this regresses a good chunk of the new
tests that went in with physname.

Keeping physname means further delaying 7.3 and probably accepting that
we will have more as-yet-unknown regressions.

I don't have a good basis on which to evaluate the evidence pro or con.
My default position is to try push forward, not back: fix the bugs in
physname.

If there is more evidence for or against either approach, I would love
to know it.

Jan> What do you think?

Keith> In the end, it probably doesn't really matter what I think. :-) IMO,
Keith> this all boils down to risk management. Which path is least risky for
Keith> users and most conducive to moving forward?

Keith> This is a decision for you and other maintainers to consider.

No fair trying to escape.  And, your opinion does matter.

Tom


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

* Re: [rfc] physname cross-check #2
  2011-05-17 18:15     ` Keith Seitz
  2011-05-17 18:33       ` Jan Kratochvil
  2011-05-17 21:01       ` Tom Tromey
@ 2011-05-19 23:04       ` Jan Kratochvil
  2 siblings, 0 replies; 9+ messages in thread
From: Jan Kratochvil @ 2011-05-19 23:04 UTC (permalink / raw)
  To: Keith Seitz; +Cc: gdb-patches

On Tue, 17 May 2011 20:15:18 +0200, Keith Seitz wrote:
> For me, what really matters is what is best for users. Is reverting
> dwarf2_physname better or worse than DW_AT_MIPS_linkage_name?

This patch has no regressions on {x86_64,x86_64-m32,i686}-fedora15-linux-gnu.
And it prefers DW_AT_linkage_name when available to solve the DWARF<->ELF
symbols discrepancies.

DMGL_VERBOSE was suggested by Keith.

The libiberty/ part needs more review and a post to GCC but it seems as
a correct fix idea anyway.


Thanks,
Jan


--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -5142,7 +5142,77 @@ dwarf2_full_name (char *name, struct die_info *die, struct dwarf2_cu *cu)
 static const char *
 dwarf2_physname (char *name, struct die_info *die, struct dwarf2_cu *cu)
 {
-  return dwarf2_compute_name (name, die, cu, NAME_KIND_PHYS);
+  const char *physname = dwarf2_compute_name (name, die, cu, NAME_KIND_PHYS);
+  struct attribute *attr;
+  const char *mangled, *retval;
+  char *demangled, *canon;
+  struct cleanup *back_to;
+
+  /* Do not check PHYSNAME if it never will be needed by GDB.  GDB does not
+     need to support something it has no use for.  */
+  if (!die_needs_namespace (die, cu))
+    return physname;
+
+  attr = dwarf2_attr (die, DW_AT_linkage_name, cu);
+  if (!attr)
+    attr = dwarf2_attr (die, DW_AT_MIPS_linkage_name, cu);
+  if (!attr || !DW_STRING (attr))
+    {
+      /* DW_AT_linkage_name is missing in some cases - depend on what GDB has
+	 computed.  */
+
+      return physname;
+    }
+  mangled = DW_STRING (attr);
+
+  /* As both DW_AT_linkage_name (MANGLED) and computed PHYSNAME are present
+     cross-check them.  */
+
+  back_to = make_cleanup (null_cleanup, 0);
+
+  demangled = cplus_demangle (mangled,
+			      (DMGL_PARAMS | DMGL_VERBOSE | DMGL_RET_POSTFIX
+			       | DMGL_ANSI | (cu->language == language_java
+					      ? DMGL_JAVA : 0)));
+  if (demangled)
+    make_cleanup (xfree, demangled);
+  else
+    demangled = (char *) mangled;
+
+  if (cu->language == language_cplus)
+    {
+      canon = cp_canonicalize_string (demangled);
+      if (canon != NULL)
+	make_cleanup (xfree, canon);
+      else
+	canon = demangled;
+    }
+  else
+    canon = demangled;
+
+  if (strcmp (physname, canon) != 0)
+    {
+      /* It may not mean a bug in GDB.  The compiler could also compute
+	 DW_AT_linkage_name incorrectly.  But in such case GDB would need to be
+	 bug-to-bug compatible.  */
+
+      complaint (&symfile_complaints,
+		 _("Computed physname <%s> does not match demangled <%s> "
+		   "(from linkage <%s>) - DIE at 0x%x [in module %s]\n"),
+		 physname, canon, mangled, die->offset, cu->objfile->name);
+
+      /* Prefer DW_AT_linkage_name (in the CANON form) - when it is available
+	 here - over computed PHYSNAME.  It is safer against both buggy GDB and
+	 buggy compilers.  */
+
+      retval = obsavestring (canon, strlen (canon),
+			     &cu->objfile->objfile_obstack);
+    }
+  else
+    retval = physname;
+
+  do_cleanups (back_to);
+  return retval;
 }
 
 static const char *
--- a/gdb/testsuite/gdb.base/break-interp.exp
+++ b/gdb/testsuite/gdb.base/break-interp.exp
@@ -140,14 +140,14 @@ proc reach_1 {func command displacement} {
 	    }
 	    exp_continue
 	}
-	-re "Breakpoint \[0-9\]+, \\.?$func \\(.*\\) at .*:\[0-9\]+\r\n.*$gdb_prompt $" {
+	-re "Breakpoint \[0-9\]+, \\.?(__GI_)?$func \\(.*\\) at .*:\[0-9\]+\r\n.*$gdb_prompt $" {
 	    if {$func == "_dl_debug_state"} {
 		fail $test
 	    } else {
 		pass $test
 	    }
 	}
-	-re "Breakpoint \[0-9\]+, \[0-9xa-f\]+ in \\.?$func \\(\\).*\r\n$gdb_prompt $" {
+	-re "Breakpoint \[0-9\]+, \[0-9xa-f\]+ in \\.?(__GI_)?$func \\(\\).*\r\n$gdb_prompt $" {
 	    if {$func == "_dl_debug_state"} {
 		fail $test
 	    } else {
@@ -403,7 +403,7 @@ proc test_ld {file ifmain trynosym displacement} {
 
     reach "_dl_debug_state" "run" $displacement
 
-    gdb_test "bt" "#0 +\[^\r\n\]*\\m_dl_debug_state\\M.*" "dl bt"
+    gdb_test "bt" "#0 +\[^\r\n\]*\\m(__GI_)?_dl_debug_state\\M.*" "dl bt"
 
     if $ifmain {
 	reach "main" continue "NONE"
--- a/include/demangle.h
+++ b/include/demangle.h
@@ -45,7 +45,8 @@ extern "C" {
 #define DMGL_VERBOSE	 (1 << 3)	/* Include implementation details.  */
 #define DMGL_TYPES	 (1 << 4)	/* Also try to demangle type encodings.  */
 #define DMGL_RET_POSTFIX (1 << 5)       /* Print function return types (when
-                                           present) after function signature */
+                                           present) after function signature.
+                                           It applies only for toplevel types.  */
 
 #define DMGL_AUTO	 (1 << 8)
 #define DMGL_GNU	 (1 << 9)
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -3557,6 +3557,8 @@ static void
 d_print_comp (struct d_print_info *dpi,
               const struct demangle_component *dc)
 {
+  int ret_postfix;
+
   if (dc == NULL)
     {
       d_print_error (dpi);
@@ -3565,6 +3567,9 @@ d_print_comp (struct d_print_info *dpi,
   if (d_print_saw_error (dpi))
     return;
 
+  ret_postfix = dpi->options & DMGL_RET_POSTFIX;
+  dpi->options &= ~DMGL_RET_POSTFIX;
+
   switch (dc->type)
     {
     case DEMANGLE_COMPONENT_NAME:
@@ -3576,6 +3581,7 @@ d_print_comp (struct d_print_info *dpi,
 
     case DEMANGLE_COMPONENT_QUAL_NAME:
     case DEMANGLE_COMPONENT_LOCAL_NAME:
+      dpi->options |= ret_postfix;
       d_print_comp (dpi, d_left (dc));
       if ((dpi->options & DMGL_JAVA) == 0)
 	d_append_string (dpi, "::");
@@ -3597,6 +3603,7 @@ d_print_comp (struct d_print_info *dpi,
 	   any CV-qualifiers, which apply to the this parameter.  */
 	hold_modifiers = dpi->modifiers;
 	dpi->modifiers = 0;
+	dpi->options |= ret_postfix;
 	i = 0;
 	typed_name = d_left (dc);
 	while (typed_name != NULL)
@@ -3919,7 +3926,7 @@ d_print_comp (struct d_print_info *dpi,
 
     case DEMANGLE_COMPONENT_FUNCTION_TYPE:
       {
-	if ((dpi->options & DMGL_RET_POSTFIX) != 0)
+	if (ret_postfix)
 	  d_print_function_type (dpi, dc, dpi->modifiers);
 
 	/* Print return type if present */
@@ -3944,11 +3951,11 @@ d_print_comp (struct d_print_info *dpi,
 
 	    /* In standard prefix notation, there is a space between the
 	       return type and the function signature.  */
-	    if ((dpi->options & DMGL_RET_POSTFIX) == 0)
+	    if (!ret_postfix)
 	      d_append_char (dpi, ' ');
 	  }
 
-	if ((dpi->options & DMGL_RET_POSTFIX) == 0) 
+	if (!ret_postfix)
 	  d_print_function_type (dpi, dc, dpi->modifiers);
 
 	return;


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

end of thread, other threads:[~2011-05-19 23:04 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-21 21:15 [RFA] Typedef'd method parameters [0/4] Keith Seitz
2011-04-25 20:53 ` Tom Tromey
2011-05-12 21:28 ` Keith Seitz
2011-05-16 15:49   ` [rfc] physname cross-check [Re: [RFA] Typedef'd method parameters [0/4]] Jan Kratochvil
2011-05-17 18:15     ` Keith Seitz
2011-05-17 18:33       ` Jan Kratochvil
2011-05-17 19:04         ` Keith Seitz
2011-05-17 21:01       ` Tom Tromey
2011-05-19 23:04       ` [rfc] physname cross-check #2 Jan Kratochvil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox