[RFA] 12266 (typedef'd parameters) revisited again

Keith Seitz
2011-06-03T23:34:16Z

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

Hi,

I've updated my patches for 12266, and I *think* I have finally stamped
out most of the bugs, nearly doubling the number of tests. Of course, it
is still possible that I've neglected something along the line.

I've attached the "whole" patch again (this is what will actually be
committed -- it is definitive). I have /not/ included separate patches
for the "printname" and "cp_demangle_name_parse_free" patches from last
go around, since those have not changed.

I am attaching, though, the cp_canonicalize_string_no_typedef and tests
patches, since those have changed non-trivially.

This patchset has been tested on the buildbot.

Keith

PS. Link to previous submission:
http://sourceware.org/ml/gdb-patches/2011-04/msg00405.html
http://sourceware.org/ml/gdb-patches/2011-04/msg00408.html
http://sourceware.org/ml/gdb-patches/2011-04/msg00407.html
http://sourceware.org/ml/gdb-patches/2011-04/msg00406.html
http://sourceware.org/ml/gdb-patches/2011-04/msg00409.html

PPS. ChangeLogs are nearly identical -- one addition:

* cp-support.c (replace_typedefs_qualified_name): New function.

[-- Attachment #2: cp_canonicalize_no_typedefs-3.patch --]
[-- Type: text/plain, Size: 13628 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..10335ee 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,247 @@ 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)
+ {
+ long len;
+ 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, &len);
+ 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 = len;
+ }
+ }
+ }
+}
+
+/* Replace any typdefs appearing in the qualified name
+ (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+ given in INFO. Store any transient memory in FREE_LIST. */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ VEC (namep) *free_list)
+{
+ struct ui_file *buf = mem_fileopen ();
+ struct demangle_component *comp = ret_comp;
+
+ /* Qualified names come in pieces -- the left subtree
+ points at the current qualifier's name and the right
+ subtree points to either the next qualifier or the final
+ name component. Smash all these components back together
+ to make a single DEMANGLE_COMPONENT_NAME node again
+ which can be looked up by inspect_type. */
+
+ while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+ {
+ ui_file_write (buf, d_left (comp)->u.s_name.s,
+ d_left (comp)->u.s_name.len);
+ ui_file_write (buf, "::", 2);
+ comp = d_right (comp);
+ }
+
+ /* If the next component is DEMANGLE_COMPONENT_NAME, the user
+ may have entered a typedef, e.g., "std::string". In this case,
+ save the qualified name assembled above and append the
+ name given by COMP. Then use this reassembled name to check
+ for a typedef. */
+
+ if (comp->type == DEMANGLE_COMPONENT_NAME)
+ {
+ long len;
+ char *name;
+
+ ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
+ name = ui_file_xstrdup (buf, &len);
+ VEC_safe_push (namep, free_list, name);
+
+ /* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node
+ with a DEMANGLE_COMPONENT_NAME node containing the whole
+ name. */
+ ret_comp->type = DEMANGLE_COMPONENT_NAME;
+ ret_comp->u.s_name.s = name;
+ ret_comp->u.s_name.len = len;
+ inspect_type (info, ret_comp, free_list);
+ }
+ else
+ replace_typedefs (info, comp, free_list);
+
+ ui_file_delete (buf);
+}
+
+/* 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));
+ }
+ /* Fall through */
+
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ 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_QUAL_NAME:
+ replace_typedefs_qualified_name (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:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ replace_typedefs (info, d_right (ret_comp), free_list);
+ break;
+
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ 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 4e90d0c..c570a1e 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -119,6 +119,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);
@@ -205,6 +207,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 c820539..b2edc83 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -249,7 +249,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;
@@ -1357,7 +1357,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;
@@ -1366,6 +1366,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. */
@@ -1633,7 +1634,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
@@ -1776,7 +1791,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);
@@ -2118,11 +2133,26 @@ 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, get_search_block (file_symtab),
- 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_search_block (file_symtab), VAR_DOMAIN, 0);
+ do_cleanups (cleanup);

if (sym != NULL)
return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);
diff --git a/gdb/typeprint.h b/gdb/typeprint.h
index b271bcc..49cd122 100644
--- a/gdb/typeprint.h
+++ b/gdb/typeprint.h
@@ -23,7 +23,7 @@
enum language;
struct ui_file;

-/* An enumeration for specifying the type of a computed symobl name. */
+/* An enumeration for specifying the type of a computed symbol name. */
enum name_kind
{
NAME_KIND_FULL, /* The fullname (methods do not

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

diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 0212232..d48a9b2 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 {...}".
+/* 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;
@@ -744,7 +784,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);
@@ -770,16 +811,21 @@ 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 ");
- else
- fprintf_filtered (stream, "struct ");
+ if (!linkage_name)
+ {
+ if (TYPE_DECLARED_CLASS (type))
+ {
+ fprintf_filtered (stream, "class ");
+ }
+ else
+ fprintf_filtered (stream, "struct ");
+ }
goto struct_union;

case TYPE_CODE_UNION:
@@ -951,9 +997,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))
{
@@ -1093,7 +1140,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);
@@ -1153,8 +1199,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");
}
}
@@ -1259,3 +1307,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..10335ee 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,247 @@ 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)
+ {
+ long len;
+ 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, &len);
+ 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 = len;
+ }
+ }
+ }
+}
+
+/* Replace any typdefs appearing in the qualified name
+ (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+ given in INFO. Store any transient memory in FREE_LIST. */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ VEC (namep) *free_list)
+{
+ struct ui_file *buf = mem_fileopen ();
+ struct demangle_component *comp = ret_comp;
+
+ /* Qualified names come in pieces -- the left subtree
+ points at the current qualifier's name and the right
+ subtree points to either the next qualifier or the final
+ name component. Smash all these components back together
+ to make a single DEMANGLE_COMPONENT_NAME node again
+ which can be looked up by inspect_type. */
+
+ while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+ {
+ ui_file_write (buf, d_left (comp)->u.s_name.s,
+ d_left (comp)->u.s_name.len);
+ ui_file_write (buf, "::", 2);
+ comp = d_right (comp);
+ }
+
+ /* If the next component is DEMANGLE_COMPONENT_NAME, the user
+ may have entered a typedef, e.g., "std::string". In this case,
+ save the qualified name assembled above and append the
+ name given by COMP. Then use this reassembled name to check
+ for a typedef. */
+
+ if (comp->type == DEMANGLE_COMPONENT_NAME)
+ {
+ long len;
+ char *name;
+
+ ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
+ name = ui_file_xstrdup (buf, &len);
+ VEC_safe_push (namep, free_list, name);
+
+ /* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node
+ with a DEMANGLE_COMPONENT_NAME node containing the whole
+ name. */
+ ret_comp->type = DEMANGLE_COMPONENT_NAME;
+ ret_comp->u.s_name.s = name;
+ ret_comp->u.s_name.len = len;
+ inspect_type (info, ret_comp, free_list);
+ }
+ else
+ replace_typedefs (info, comp, free_list);
+
+ ui_file_delete (buf);
+}
+
+/* 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));
+ }
+ /* Fall through */
+
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ 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_QUAL_NAME:
+ replace_typedefs_qualified_name (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:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ replace_typedefs (info, d_right (ret_comp), free_list);
+ break;
+
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ 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. */
@@ -124,19 +376,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 +406,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 +440,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 +460,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 +538,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 +609,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 +625,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 +641,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 +666,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 +699,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 52d4cb7..f9fa062 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -44,6 +44,17 @@ struct demangle_component;

#define CP_ANONYMOUS_NAMESPACE_LEN 21

+/* 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
@@ -108,6 +119,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);
@@ -185,12 +198,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 29ca473..cdc46e3 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4918,7 +4918,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);
@@ -4926,7 +4926,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
@@ -4958,7 +4958,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);
@@ -5095,13 +5096,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)
{
@@ -5157,7 +5159,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
@@ -5170,7 +5172,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. */
@@ -11104,6 +11112,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 8d9ebfd..6c9ace0 100644
--- a/gdb/jv-typeprint.c
+++ b/gdb/jv-typeprint.c
@@ -329,9 +329,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)
@@ -350,5 +347,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 c820539..b2edc83 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -249,7 +249,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;
@@ -1357,7 +1357,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;
@@ -1366,6 +1366,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. */
@@ -1633,7 +1634,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
@@ -1776,7 +1791,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);
@@ -2118,11 +2133,26 @@ 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, get_search_block (file_symtab),
- 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_search_block (file_symtab), 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 8879ddf..ac9fa1c 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -755,17 +755,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..bf84882
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,115 @@
+/* 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)
+};
+
+namespace a
+{
+ namespace b
+ {
+ namespace c
+ {
+ namespace d
+ {
+ class bar { };
+ }
+ }
+
+ typedef c::d::bar BAR;
+ }
+}
+
+typedef a::b::BAR _BAR_;
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (_BAR_ &b) { } // test(_BAR_&)
+
+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..0d2b673
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,137 @@
+# 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" }
+ "_BAR_" { "_BAR_" "a::b::BAR" "a::b::c::d::bar" }
+}
+
+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
+ }
+ }
+ }
+}
+
+# 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
+ }
+ }
+}
+
+# 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
+ }
+}
+
+foreach t $typedefs(_BAR_) {
+ add methods "test" "$t&" {_BAR_&}
+}
+
+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..49cd122 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 symbol 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: typedef-params-tests-3.patch --]
[-- Type: text/plain, Size: 7675 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..bf84882
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,115 @@
+/* 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)
+};
+
+namespace a
+{
+ namespace b
+ {
+ namespace c
+ {
+ namespace d
+ {
+ class bar { };
+ }
+ }
+
+ typedef c::d::bar BAR;
+ }
+}
+
+typedef a::b::BAR _BAR_;
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (_BAR_ &b) { } // test(_BAR_&)
+
+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..0d2b673
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,137 @@
+# 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" }
+ "_BAR_" { "_BAR_" "a::b::BAR" "a::b::c::d::bar" }
+}
+
+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
+ }
+ }
+ }
+}
+
+# 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
+ }
+ }
+}
+
+# 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
+ }
+}
+
+foreach t $typedefs(_BAR_) {
+ add methods "test" "$t&" {_BAR_&}
+}
+
+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