* [RFA] c++/12266 (again)
@ 2011-07-29 13:16 Keith Seitz
2011-08-01 20:38 ` Tom Tromey
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Keith Seitz @ 2011-07-29 13:16 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 3982 bytes --]
Hi,
I know it has been some time since my last attempt at this, but I have
spent the last several weeks testing the living daylights out of this
code and fixing fallout. I've added almost 300 new tests (for a total of
almost 800 tests), and I've run the code through libstdc++ and some of
libwebkit.
I feel relatively confident that I've tackled most of the problems, but,
of course, C++ is big and complex, and people always manage to surprise
me with strange ways of using it...
A reminder about this bug/enhancement request: linespecs can't deal with
typedefs. So if a user types "break my_func(my_typedef)", gdb may not
necessarily find it. [That's not entirely true today because a patch was
committed while I was away that allows decode_compound to fallback to
looking up minsyms. I have tested this with that patch defeated (testing
against the output of "nm -C").]
I've pruned the original patchset down substantially: a lot of the
previous three (!) patches dealt with dwarf2_physname fixes which are
now no longer necessary for GCC. I will attempt to clean these up for
later submission for the benefit of other non-GNU compilers.
I've attached two patches:
1) cp_demangled_name_parse_free.patch
This patch simply massages cp_string_to_comp to be redundant. It is
almost exactly the same as in my previous submissions. This patch is
mechanical and may be applied independently of the other patch.
2) cp_canonicalize_string_no_typedefs.patch
This is the guts of the work, and has changed quite a bit compared to
previous submissions. Major changes include better qualified name
handling, dealing with anonymous types, more complete/correct handling
of CV types in parameters, templates, and a few other things.
Keith
ChangeLog for cp_demangled_name_parse_free
2011-07-28 Keith Seitz <keiths@redhat.com>
* cp-name-parser.y (struct demangle_info): Remove unused
member PREV.
(d_grab): Likewise.
(allocate_info): Change return type to struct demangle_info *.
Always allocate a new demangle_info.
Remove unused PREV pointer.
(cp_demangled_name_parse_free): New function.
(do_dmeangled_name_parse_free_cleanup): New function.
(make_cleanup_cp_demangled_name_parse_free): New function.
(cp_demangled_name_to_comp): Change return type to
struct demangle_parse_info *.
Allocate a new storage for each call.
(main): Update usage for cp_demangled_name_to_comp
API change.
* cp-support.h (struct demangle_parse_info): New structure.
(cp_demangled_name_to_comp): Update API change for
return type.
(make_cleanup_cp_demangled_name_parse_free): New declaration.
(cp_demangled_name_parse_free): Declare.
* cp-support.c (cp_canonicalize_string): Update API
change for cp_demangled_name_to_comp.
(mangled_name_to_comp): Likewise.
Return struct demangle_parse_info, too.
(cp_class_name_from_physname): Update mangled_name_to_comp
API change.
(method_name_from_physname): Likewise.
(cp_func_name): Update API change for cp_demangled_name_to_comp.
(cp_remove_params): Likewise.
* python/py-type.c (typy_legacy_template_argument): Likewise.
ChangeLogs for cp_canonicalize_string_no_typedefs.patch
2011-07-28 Keith Seitz <keiths@redhat.com>
* cp-support.h (cp_canonicalize_string_no_typedefs): Declare.
(cp_merge_demangle_parse_infos): Declare.
* cp-support.c (ignore_typedefs): New file global.
(inspect_type): New function.
(replace_typedefs): New function.
(replace_typedefs_qualified_name): New function.
(cp_canonicalize_string_no_typedefs): New function.
* cp-name-parser.y (cp_merge_demangle_parse_infos): New function.
* linespec.c (find_methods): Use cp_canonicalize_string_no_typedefs
instead of cp_canonicalize_string.
(find_method): Likewise.
(decode_compound): Before looking up the name, call
cp_canonicalize_string_no_typedefs.
(decode_variable): Likewise.
testsuite/ChangeLog
2011-07-28 Keith Seitz <keiths@redhat.com>
* gdb.cp/meth-typedefs.cc: New file.
* gdb.cp/meth-typedefs.exp: New file.
[-- Attachment #2: cp_demangled_name_parse_free-4.patch --]
[-- Type: text/plain, Size: 13072 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 d23f19e..1c8afdb 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -46,6 +46,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
@@ -214,12 +225,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
- (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 *);
+
/* 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 8ab18cf..335342e 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: cp_canonicalize_no_typedefs-4.patch --]
[-- Type: text/plain, Size: 26875 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..7156918 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -86,6 +86,23 @@ static const char *operator_tokens[] =
/* new[] and delete[] require special whitespace handling */
};
+/* A list of typedefs which should not be substituted by replace_typedefs. */
+static const char *ignore_typedefs[] =
+ {
+ "std::istream", "std::iostream", "std::ostream", "std::string"
+ };
+
+/* 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 +134,370 @@ 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.
+
+ Returns 1 if any typedef substitutions were made, 0 otherwise. */
+
+static int
+inspect_type (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ VEC (namep) **free_list)
+{
+ int i;
+ 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';
+
+ /* Ignore any typedefs that should not be substituted. */
+ for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
+ {
+ if (strcmp (name, ignore_typedefs[i]) == 0)
+ return 0;
+ }
+
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+ if (sym != NULL)
+ {
+ struct type *otype = SYMBOL_TYPE (sym);
+
+ /* If the type is a typedef, replace it. */
+ if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF)
+ {
+ long len;
+ int is_anon;
+ struct type *last, *type;
+ struct demangle_parse_info *i;
+ struct ui_file *buf = mem_fileopen ();
+ struct cleanup *cleanup = make_cleanup_ui_file_delete (buf);
+
+ /* If the final typedef points to an anonymous struct, union,
+ or enum, keep the (last) typedef. */
+
+ /* Find the last typedef for the type. */
+ last = otype;
+ while (TYPE_CODE (TYPE_TARGET_TYPE (last)) == TYPE_CODE_TYPEDEF)
+ last = TYPE_TARGET_TYPE (last);
+
+ /* Get the real type of the typedef. */
+ type = check_typedef (otype);
+
+ is_anon = (TYPE_TAG_NAME (type) == NULL
+ && (TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION));
+ if (is_anon)
+ {
+ /* If there is only one typedef for this anonymous type,
+ do not substitute it. */
+ if (type == otype)
+ {
+ do_cleanups (cleanup);
+ return 0;
+ }
+ else
+ /* Use the last typedef seen as the type for this
+ anonymous type. */
+ type = last;
+ }
+
+
+ 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 -- but not
+ if the type is anonymous (that would lead to infinite
+ looping). */
+ if (!is_anon)
+ 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;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Replace any typedefs appearing in the qualified name
+ (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+ given in INFO. Store any allocated memory in FREE_LIST. */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ VEC (namep) **free_list)
+{
+ long len;
+ char *name;
+ struct ui_file *buf = mem_fileopen ();
+ struct demangle_component *comp = ret_comp;
+
+ /* Walk each node of the qualified name, reconstructing the name of
+ this element. With every node, check for any typedef substitutions.
+ If a substitution has occurred, replace the qualified name node
+ with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
+ substituted name. */
+ while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+ {
+ if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
+ {
+ struct demangle_component new;
+
+ ui_file_write (buf, d_left (comp)->u.s_name.s,
+ d_left (comp)->u.s_name.len);
+ name = ui_file_xstrdup (buf, &len);
+ new.type = DEMANGLE_COMPONENT_NAME;
+ new.u.s_name.s = name;
+ new.u.s_name.len = len;
+ if (inspect_type (info, &new, free_list))
+ {
+ char *n;
+
+ /* A typedef was substituted in NEW. Convert it to a
+ string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
+ node. */
+ n = cp_comp_to_string (&new, 100);
+ xfree (name);
+ if (n != NULL)
+ {
+ ui_file_rewind (buf);
+ VEC_safe_push (namep, *free_list, n);
+
+ d_left (ret_comp)->u.s_name.s = n;
+ d_left (ret_comp)->u.s_name.len = strlen (n);
+ d_right (ret_comp) = d_right (comp);
+ comp = ret_comp;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ /* The current node is not a name, so simply replace any
+ typedefs in it. Then print it to the stream to continue
+ checking for more typedefs in the tree. */
+ replace_typedefs (info, d_left (comp), free_list);
+ name = cp_comp_to_string (d_left (comp), 100);
+ if (name != NULL)
+ {
+ fputs_unfiltered (name, buf);
+ xfree (name);
+ }
+ }
+ ui_file_write (buf, "::", 2);
+ comp = d_right (comp);
+ }
+
+ /* If the next component is DEMANGLE_COMPONENT_NAME, 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)
+ {
+ 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;
+ (void) inspect_type (info, ret_comp, free_list);
+ }
+ else
+ replace_typedefs (info, comp, free_list);
+
+ ui_file_delete (buf);
+}
+
+
+/* A function to check const and volatile qualifiers for argument types.
+
+ "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. */
+
+static void
+check_cv_qualifiers (struct demangle_component *ret_comp)
+{
+ 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));
+ }
+}
+
+/* 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:
+ check_cv_qualifiers (ret_comp);
+ /* Fall through */
+
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ 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_TYPED_NAME:
+ {
+ struct demangle_component *comp = d_right (ret_comp);
+
+ while (comp != NULL
+ && (comp->type == DEMANGLE_COMPONENT_VOLATILE
+ || comp->type == DEMANGLE_COMPONENT_RESTRICT
+ || comp->type == DEMANGLE_COMPONENT_CONST
+ || comp->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || comp->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || comp->type == DEMANGLE_COMPONENT_CONST_THIS))
+ comp = d_left (comp);
+
+ if (d_left (ret_comp)->type != DEMANGLE_COMPONENT_NAME
+ || comp->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ replace_typedefs (info, d_left (ret_comp), free_list);
+ replace_typedefs (info, d_right (ret_comp), free_list);
+ }
+ break;
+
+ case DEMANGLE_COMPONENT_NAME:
+ (void) 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_LOCAL_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_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ 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 1c8afdb..65e0c69 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -145,6 +145,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);
@@ -234,6 +236,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 137ef9c..949af86 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -245,7 +245,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;
@@ -1365,7 +1365,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;
@@ -1373,6 +1373,7 @@ decode_compound (char **argptr, int funfirstline,
struct symbol *sym_class;
struct type *t;
char *saved_arg;
+ struct cleanup *cleanup;
/* If the user specified any completer quote characters in the input,
strip them. They are superfluous. */
@@ -1597,7 +1598,22 @@ 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
@@ -1743,7 +1759,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);
@@ -2085,16 +2101,31 @@ decode_variable (char *copy, int funfirstline,
struct linespec_result *canonical,
struct symtab *file_symtab)
{
+ char *name, *canon;
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);
+ 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);
if (sym != NULL)
- return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);
+ {
+ do_cleanups (cleanup);
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, NULL);
+ }
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ msymbol = lookup_minimal_symbol (name, NULL, NULL);
+ do_cleanups (cleanup);
if (msymbol != NULL)
return minsym_found (funfirstline, msymbol);
diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.cc b/gdb/testsuite/gdb.cp/meth-typedefs.cc
new file mode 100644
index 0000000..b3c68cc
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,149 @@
+/* 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 enum {E_A, E_B, E_C} anon_enum;
+typedef struct {int a; char b;} anon_struct;
+typedef union {int a; char b;} anon_union;
+typedef anon_enum aenum;
+typedef anon_struct astruct;
+typedef anon_union aunion;
+
+typedef void (*fptr1) (my_other_type);
+typedef void (*fptr2) (fptr1, my_other_type_2);
+typedef void (*fptr3) (fptr2, my_other_type);
+typedef void (*fptr4) (anon_enum a, anon_struct const& b, anon_union const*** c);
+
+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])
+ foo (aenum a, astruct const& b, aunion const*** c) { } // A::foo::foo(aenum, astruct const&, aunion const***)
+
+ 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])
+ void test (aenum a, astruct const& b, aunion const*** c) { }; // A::foo::test(aenum, astruct const&, aunion const***)
+ };
+};
+
+namespace B
+{
+ void
+ test (my_other_type foo) { } // B::test(my_other_type)
+
+ void
+ test (aenum a, astruct const& b, aunion const*** c) { } // B::test(aenum, astruct const&, aunion const***)
+
+ template <typename T1, typename T2>
+ void test (T1 a, T2 b) { } // B::test (T1, T2)
+
+ template <>
+ void test (my_other_type foo, my_other_type_2) { } // B::test<my_other_type, my_other_type_2>(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_;
+
+template <typename T1, typename T2>
+void test (T1 a, T2 b) {} // test (T1, T2)
+
+template <>
+void test (my_other_type foo, my_other_type_2) { } // test<my_other_type, my_other_type_2>(my_other_type, my_other_type_2)
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (_BAR_ &b) { } // test(_BAR_&)
+
+void
+test (aenum a, astruct const& b, aunion const*** c) { } // test(aenum, astruct const&, aunion const***)
+
+int
+main (void)
+{
+ A::foo my_foo;
+ fptr1 fptr;
+ astruct as = { 0, 0 };
+ aunion const au = { 0 };
+ aunion const* aup = &au;
+ aunion const** aupp = &aup;
+ aunion const*** auppp = &aupp;
+
+ my_foo.test (static_cast<my_other_type> (NULL));
+ my_foo.test (0);
+ my_foo.test (0, static_cast<my_type> (NULL));
+ my_foo.test (static_cast<fptr3> (NULL));
+ my_foo.test (&fptr);
+ my_foo.test (static_cast<CORE_ADDR (*) [10]> (0));
+ my_foo.test (E_A, as, auppp);
+
+ B::test (static_cast<my_other_type> (NULL));
+ B::test (static_cast<my_other_type> (NULL), 0);
+ B::test (E_A, as, auppp);
+
+ test (static_cast<my_other_type> (NULL));
+ test<my_other_type, my_other_type_2> (static_cast<my_other_type> (NULL), 0);
+ test (E_A, as, auppp);
+
+ A::foo a (static_cast<my_other_type> (NULL));
+ A::foo b (0);
+ A::foo c (0, static_cast<my_other_type> (NULL));
+ A::foo d (static_cast<fptr3> (NULL));
+ A::foo e (&fptr);
+ A::foo f (static_cast<CORE_ADDR (*) [10]> (0));
+ A::foo g (E_A, as, auppp);
+
+ fptr4 f4;
+
+ 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..851ec02
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,160 @@
+# 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 {kind {func}}} {
+ upvar $var result
+
+ if {[string compare $kind "template"] == 0} {
+ set method_name "${name}<$expected>"
+ } else {
+ set method_name "$name"
+ }
+
+ set expect ".*// ${method_name}\\($expected\\)"
+ lappend result [list "${method_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" }
+ "aenum" { "aenum" "anon_enum" }
+ "astruct" { "astruct" "anon_struct" }
+ "aunion" { "aunion" "anon_union" }
+}
+
+set methods {}
+
+# Add the simple, one-parameter methods
+foreach meth {A::foo::test A::foo::foo} {
+ foreach type {my_other_type my_other_type_2} {
+ foreach t $typedefs($type) {
+ add methods $meth $t $type
+ }
+ }
+}
+
+# Add two-parameter methods
+foreach meth {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 $meth "$t1, const $t2" $type
+ add methods $meth "$t1, $t2" $type
+ }
+ }
+}
+
+# Add three-parameter methods/functions
+foreach meth {A::foo::test A::foo::foo B::test test} {
+ set type "aenum, astruct const&, aunion const\\*\\*\\*"
+ foreach t1 $typedefs(aenum) {
+ foreach t2 $typedefs(astruct) {
+ foreach t3 $typedefs(aunion) {
+ add methods $meth "$t1, $t2 const&, $t3 const***" $type
+ }
+ }
+ }
+}
+
+# Add the array-of-function pointer methods
+set type "fptr1\\*"
+foreach meth {A::foo::test A::foo::foo} {
+ add methods $meth "fptr1*" $type
+ foreach t $typedefs(my_other_type) {
+ add methods $meth "void (**) ($t)" $type
+ }
+}
+
+# Add the function pointer methods
+set type "fptr3"
+foreach meth {A::foo::test A::foo::foo} {
+ add methods $meth "fptr3" $type
+
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth "void (*)(fptr2, $t1)" $type
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "void (*)(void (*)(fptr1, $t2), $t1)" $type
+ foreach t3 $typedefs(my_other_type) {
+ add methods $meth \
+ "void (*)(void (*)(void (*) ($t3), $t2), $t1)" $type
+ }
+ }
+ }
+}
+
+set type1 "my_other_type"
+set type2 "my_other_type, my_other_type_2"
+foreach meth {"test" "B::test"} {
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth $t1 $type1
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "$t1, $t2" $type2 template
+ }
+ }
+}
+
+# Miscellaneous tests
+set type {CORE_ADDR \(\*\) \[10\]}
+foreach meth {A::foo::foo A::foo::test} {
+ foreach t $typedefs(CORE_ADDR) {
+ add methods $meth "$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
+ 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] 13+ messages in thread* Re: [RFA] c++/12266 (again)
2011-07-29 13:16 [RFA] c++/12266 (again) Keith Seitz
@ 2011-08-01 20:38 ` Tom Tromey
2011-08-02 16:08 ` Tom Tromey
` (2 subsequent siblings)
3 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2011-08-01 20:38 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
Keith> 1) cp_demangled_name_parse_free.patch
Keith> This patch simply massages cp_string_to_comp to be redundant. It is
Keith> almost exactly the same as in my previous submissions. This patch is
Keith> mechanical and may be applied independently of the other patch.
This one is ok (still reading the other).
Tom
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFA] c++/12266 (again)
2011-07-29 13:16 [RFA] c++/12266 (again) Keith Seitz
2011-08-01 20:38 ` Tom Tromey
@ 2011-08-02 16:08 ` Tom Tromey
2011-08-02 17:58 ` Keith Seitz
2011-08-02 20:28 ` [RFA] c++/12266 (again) [cp_demangled_name_parse_free-4.patch] Jan Kratochvil
2011-08-02 20:37 ` [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch] Jan Kratochvil
3 siblings, 1 reply; 13+ messages in thread
From: Tom Tromey @ 2011-08-02 16:08 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
>>>>> "Keith" == Keith Seitz <keiths@redhat.com> writes:
Keith> +static const char *ignore_typedefs[] =
Maybe 'static const char * const'?
Keith> +typedef char *namep;
defs.h already has 'char_ptr' for this purpose.
Keith> +static void
Keith> +replace_typedefs (struct demangle_parse_info *info,
Indent this line somehow.
Keith> + while (TYPE_CODE (TYPE_TARGET_TYPE (last)) == TYPE_CODE_TYPEDEF)
Keith> + last = TYPE_TARGET_TYPE (last);
It seems like you could construct a test case where the type is a stub
type, so TYPE_TARGET_TYPE == NULL, causing a crash.
Keith> + /* If there is only one typedef for this anonymous type,
Keith> + do not substitute it. */
I don't understand this comment.
How does this code check if this anonymous type only had one typedef?
Keith> + (void) inspect_type (info, ret_comp, free_list);
Don't cast to void.
Keith> + /* Free any memory allocated during typedef replacement. */
Keith> + if (!VEC_empty (namep, free_list))
Keith> + {
Keith> + int i;
Keith> + char *iter;
Keith> +
Keith> + for (i = 0; VEC_iterate (namep, free_list, i, iter); ++i)
Keith> + xfree (iter);
You don't need the VEC_empty check here; vec.h will do the right thing
if you try to iterate an empty (or NULL) VEC.
Keith> + cleanup = make_cleanup (null_cleanup, NULL);
Keith> + if (current_language->la_language == language_cplus)
Keith> + {
Keith> + char *canon = cp_canonicalize_string_no_typedefs (copy);
Keith> +
Keith> + if (canon != NULL)
Keith> + {
Keith> + name = canon;
Keith> + make_cleanup (xfree, name);
Keith> + }
This change in linespec checks current_language, but the other does not.
Why is that?
Tom
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFA] c++/12266 (again)
2011-08-02 16:08 ` Tom Tromey
@ 2011-08-02 17:58 ` Keith Seitz
0 siblings, 0 replies; 13+ messages in thread
From: Keith Seitz @ 2011-08-02 17:58 UTC (permalink / raw)
Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2912 bytes --]
On 08/02/2011 09:08 AM, Tom Tromey wrote:
> Maybe 'static const char * const'?
Sure. I've never seen this done before, so I just (blindly) followed suit.
> Keith> +typedef char *namep;
>
> defs.h already has 'char_ptr' for this purpose.
Thanks. Changed. [I even went looking for that!]
> Keith> +static void
> Keith> +replace_typedefs (struct demangle_parse_info *info,
>
> Indent this line somehow.
Yes, sorry, I missed that one.
> Keith> + while (TYPE_CODE (TYPE_TARGET_TYPE (last)) == TYPE_CODE_TYPEDEF)
> Keith> + last = TYPE_TARGET_TYPE (last);
>
> It seems like you could construct a test case where the type is a stub
> type, so TYPE_TARGET_TYPE == NULL, causing a crash.
I've added a check for this.
>
> Keith> + /* If there is only one typedef for this anonymous type,
> Keith> + do not substitute it. */
>
> I don't understand this comment.
> How does this code check if this anonymous type only had one typedef?
A little re-arranging of the code (pushing the while loop into the
is_anon clause) would be less confusing, I think. While that whole block
deals with this, that comment is probably best deleted in favor of
explanations closer to the actual code dealing with it.
As for determining if there is only one typedef for a type, the idea is
to iterate over all the typedefs for the type. If the original type
(otype) is the same as the "last" typedef seen (i.e.,
TYPE_CODE(TYPE_TARGET_TYPE (last)) != TYPE_CODE_TYPEDEF), then there is
only one typedef associated with this type (well, at least in this chain
of typedefs). meth-typedefs.exp does exactly this (defines typedefs of
typedefs).
If there is a better/easier way, I'm all eyes!
> Keith> + (void) inspect_type (info, ret_comp, free_list);
>
> Don't cast to void.
Changed.
> Keith> + /* Free any memory allocated during typedef replacement. */
> Keith> + if (!VEC_empty (namep, free_list))
>
> You don't need the VEC_empty check here; vec.h will do the right thing
> if you try to iterate an empty (or NULL) VEC.
Changed.
> Keith> + cleanup = make_cleanup (null_cleanup, NULL);
> Keith> + if (current_language->la_language == language_cplus)
> Keith> + {
> Keith> + char *canon = cp_canonicalize_string_no_typedefs (copy);
> Keith> +
> Keith> + if (canon != NULL)
> Keith> + {
> Keith> + name = canon;
> Keith> + make_cleanup (xfree, name);
> Keith> + }
>
> This change in linespec checks current_language, but the other does not.
> Why is that?
I originally had both checking the language, but while testing,
uncovered some problems with that. I removed the check around the
problematic one but did not/forgot to do so with this one. I have
removed it and verified that it does not impact test results. [And
besides, there is no reason for this not to work with C anyway!]
Updated patch attached. Thank you for looking at this.
Keith
[-- Attachment #2: cp_canonicalize_no_typedefs-5.patch --]
[-- Type: text/plain, Size: 38889 bytes --]
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..924fff4 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -86,6 +86,22 @@ static const char *operator_tokens[] =
/* new[] and delete[] require special whitespace handling */
};
+/* A list of typedefs which should not be substituted by replace_typedefs. */
+static const char * const ignore_typedefs[] =
+ {
+ "std::istream", "std::iostream", "std::ostream", "std::string"
+ };
+
+/* 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. */
+DEF_VEC_P (char_ptr);
+
+static void
+ replace_typedefs (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ VEC (char_ptr) **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 +133,365 @@ 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.
+
+ Returns 1 if any typedef substitutions were made, 0 otherwise. */
+
+static int
+inspect_type (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ VEC (char_ptr) **free_list)
+{
+ int i;
+ 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';
+
+ /* Ignore any typedefs that should not be substituted. */
+ for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
+ {
+ if (strcmp (name, ignore_typedefs[i]) == 0)
+ return 0;
+ }
+
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+ if (sym != NULL)
+ {
+ struct type *otype = SYMBOL_TYPE (sym);
+
+ /* If the type is a typedef, replace it. */
+ if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF)
+ {
+ long len;
+ int is_anon;
+ struct type *type;
+ struct demangle_parse_info *i;
+ struct ui_file *buf = mem_fileopen ();
+ struct cleanup *cleanup = make_cleanup_ui_file_delete (buf);
+
+ /* Get the real type of the typedef. */
+ type = check_typedef (otype);
+
+ is_anon = (TYPE_TAG_NAME (type) == NULL
+ && (TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION));
+ if (is_anon)
+ {
+ struct type *last = otype;
+
+ /* Find the last typedef for the type. */
+ while (TYPE_TARGET_TYPE (last) != NULL
+ && (TYPE_CODE (TYPE_TARGET_TYPE (last))
+ == TYPE_CODE_TYPEDEF))
+ last = TYPE_TARGET_TYPE (last);
+
+ /* If there is only one typedef for this anonymous type,
+ do not substitute it. */
+ if (type == otype)
+ {
+ do_cleanups (cleanup);
+ return 0;
+ }
+ else
+ /* Use the last typedef seen as the type for this
+ anonymous type. */
+ type = last;
+ }
+
+
+ type_print (type, "", buf, -1);
+ name = ui_file_xstrdup (buf, &len);
+ VEC_safe_push (char_ptr, *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 -- but not
+ if the type is anonymous (that would lead to infinite
+ looping). */
+ if (!is_anon)
+ 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;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Replace any typedefs appearing in the qualified name
+ (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+ given in INFO. Store any allocated memory in FREE_LIST. */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp,
+ VEC (char_ptr) **free_list)
+{
+ long len;
+ char *name;
+ struct ui_file *buf = mem_fileopen ();
+ struct demangle_component *comp = ret_comp;
+
+ /* Walk each node of the qualified name, reconstructing the name of
+ this element. With every node, check for any typedef substitutions.
+ If a substitution has occurred, replace the qualified name node
+ with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
+ substituted name. */
+ while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+ {
+ if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
+ {
+ struct demangle_component new;
+
+ ui_file_write (buf, d_left (comp)->u.s_name.s,
+ d_left (comp)->u.s_name.len);
+ name = ui_file_xstrdup (buf, &len);
+ new.type = DEMANGLE_COMPONENT_NAME;
+ new.u.s_name.s = name;
+ new.u.s_name.len = len;
+ if (inspect_type (info, &new, free_list))
+ {
+ char *n;
+
+ /* A typedef was substituted in NEW. Convert it to a
+ string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
+ node. */
+ n = cp_comp_to_string (&new, 100);
+ xfree (name);
+ if (n != NULL)
+ {
+ ui_file_rewind (buf);
+ VEC_safe_push (char_ptr, *free_list, n);
+
+ d_left (ret_comp)->u.s_name.s = n;
+ d_left (ret_comp)->u.s_name.len = strlen (n);
+ d_right (ret_comp) = d_right (comp);
+ comp = ret_comp;
+ continue;
+ }
+ }
+ }
+ else
+ {
+ /* The current node is not a name, so simply replace any
+ typedefs in it. Then print it to the stream to continue
+ checking for more typedefs in the tree. */
+ replace_typedefs (info, d_left (comp), free_list);
+ name = cp_comp_to_string (d_left (comp), 100);
+ if (name != NULL)
+ {
+ fputs_unfiltered (name, buf);
+ xfree (name);
+ }
+ }
+ ui_file_write (buf, "::", 2);
+ comp = d_right (comp);
+ }
+
+ /* If the next component is DEMANGLE_COMPONENT_NAME, 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)
+ {
+ ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
+ name = ui_file_xstrdup (buf, &len);
+ VEC_safe_push (char_ptr, *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);
+}
+
+
+/* A function to check const and volatile qualifiers for argument types.
+
+ "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. */
+
+static void
+check_cv_qualifiers (struct demangle_component *ret_comp)
+{
+ 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));
+ }
+}
+
+/* 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 (char_ptr) **free_list)
+{
+ if (ret_comp)
+ {
+ switch (ret_comp->type)
+ {
+ case DEMANGLE_COMPONENT_ARGLIST:
+ check_cv_qualifiers (ret_comp);
+ /* Fall through */
+
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ 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_TYPED_NAME:
+ {
+ struct demangle_component *comp = d_right (ret_comp);
+
+ while (comp != NULL
+ && (comp->type == DEMANGLE_COMPONENT_VOLATILE
+ || comp->type == DEMANGLE_COMPONENT_RESTRICT
+ || comp->type == DEMANGLE_COMPONENT_CONST
+ || comp->type == DEMANGLE_COMPONENT_VOLATILE_THIS
+ || comp->type == DEMANGLE_COMPONENT_RESTRICT_THIS
+ || comp->type == DEMANGLE_COMPONENT_CONST_THIS))
+ comp = d_left (comp);
+
+ if (d_left (ret_comp)->type != DEMANGLE_COMPONENT_NAME
+ || comp->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ 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_LOCAL_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_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ 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)
+{
+ int i;
+ char *ret, *iter;
+ unsigned int estimated_len;
+ struct demangle_parse_info *info;
+ VEC (char_ptr) *free_list;
+
+ ret = NULL;
+ free_list = VEC_alloc (char_ptr, 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. */
+ for (i = 0; VEC_iterate (char_ptr, free_list, i, iter); ++i)
+ xfree (iter);
+
+ /* Free the vector used for the free list. */
+ VEC_free (char_ptr, 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 +499,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 +529,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 +563,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 +583,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 +661,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 +732,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 +748,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 +764,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 +789,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 +822,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 d23f19e..65e0c69 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -46,6 +46,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
@@ -134,6 +145,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);
@@ -214,12 +227,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/linespec.c b/gdb/linespec.c
index 137ef9c..b96c79f 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -245,7 +245,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;
@@ -1365,7 +1365,7 @@ decode_compound (char **argptr, int funfirstline,
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;
@@ -1373,6 +1373,7 @@ decode_compound (char **argptr, int funfirstline,
struct symbol *sym_class;
struct type *t;
char *saved_arg;
+ struct cleanup *cleanup;
/* If the user specified any completer quote characters in the input,
strip them. They are superfluous. */
@@ -1597,7 +1598,18 @@ 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);
+ 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
@@ -1743,7 +1755,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);
@@ -2085,16 +2097,31 @@ decode_variable (char *copy, int funfirstline,
struct linespec_result *canonical,
struct symtab *file_symtab)
{
+ char *name, *canon;
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);
+ 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);
if (sym != NULL)
- return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);
+ {
+ do_cleanups (cleanup);
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, NULL);
+ }
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ msymbol = lookup_minimal_symbol (name, NULL, NULL);
+ do_cleanups (cleanup);
if (msymbol != NULL)
return minsym_found (funfirstline, msymbol);
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 8ab18cf..335342e 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/testsuite/gdb.cp/meth-typedefs.cc b/gdb/testsuite/gdb.cp/meth-typedefs.cc
new file mode 100644
index 0000000..b3c68cc
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,149 @@
+/* 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 enum {E_A, E_B, E_C} anon_enum;
+typedef struct {int a; char b;} anon_struct;
+typedef union {int a; char b;} anon_union;
+typedef anon_enum aenum;
+typedef anon_struct astruct;
+typedef anon_union aunion;
+
+typedef void (*fptr1) (my_other_type);
+typedef void (*fptr2) (fptr1, my_other_type_2);
+typedef void (*fptr3) (fptr2, my_other_type);
+typedef void (*fptr4) (anon_enum a, anon_struct const& b, anon_union const*** c);
+
+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])
+ foo (aenum a, astruct const& b, aunion const*** c) { } // A::foo::foo(aenum, astruct const&, aunion const***)
+
+ 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])
+ void test (aenum a, astruct const& b, aunion const*** c) { }; // A::foo::test(aenum, astruct const&, aunion const***)
+ };
+};
+
+namespace B
+{
+ void
+ test (my_other_type foo) { } // B::test(my_other_type)
+
+ void
+ test (aenum a, astruct const& b, aunion const*** c) { } // B::test(aenum, astruct const&, aunion const***)
+
+ template <typename T1, typename T2>
+ void test (T1 a, T2 b) { } // B::test (T1, T2)
+
+ template <>
+ void test (my_other_type foo, my_other_type_2) { } // B::test<my_other_type, my_other_type_2>(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_;
+
+template <typename T1, typename T2>
+void test (T1 a, T2 b) {} // test (T1, T2)
+
+template <>
+void test (my_other_type foo, my_other_type_2) { } // test<my_other_type, my_other_type_2>(my_other_type, my_other_type_2)
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (_BAR_ &b) { } // test(_BAR_&)
+
+void
+test (aenum a, astruct const& b, aunion const*** c) { } // test(aenum, astruct const&, aunion const***)
+
+int
+main (void)
+{
+ A::foo my_foo;
+ fptr1 fptr;
+ astruct as = { 0, 0 };
+ aunion const au = { 0 };
+ aunion const* aup = &au;
+ aunion const** aupp = &aup;
+ aunion const*** auppp = &aupp;
+
+ my_foo.test (static_cast<my_other_type> (NULL));
+ my_foo.test (0);
+ my_foo.test (0, static_cast<my_type> (NULL));
+ my_foo.test (static_cast<fptr3> (NULL));
+ my_foo.test (&fptr);
+ my_foo.test (static_cast<CORE_ADDR (*) [10]> (0));
+ my_foo.test (E_A, as, auppp);
+
+ B::test (static_cast<my_other_type> (NULL));
+ B::test (static_cast<my_other_type> (NULL), 0);
+ B::test (E_A, as, auppp);
+
+ test (static_cast<my_other_type> (NULL));
+ test<my_other_type, my_other_type_2> (static_cast<my_other_type> (NULL), 0);
+ test (E_A, as, auppp);
+
+ A::foo a (static_cast<my_other_type> (NULL));
+ A::foo b (0);
+ A::foo c (0, static_cast<my_other_type> (NULL));
+ A::foo d (static_cast<fptr3> (NULL));
+ A::foo e (&fptr);
+ A::foo f (static_cast<CORE_ADDR (*) [10]> (0));
+ A::foo g (E_A, as, auppp);
+
+ fptr4 f4;
+
+ 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..851ec02
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,160 @@
+# 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 {kind {func}}} {
+ upvar $var result
+
+ if {[string compare $kind "template"] == 0} {
+ set method_name "${name}<$expected>"
+ } else {
+ set method_name "$name"
+ }
+
+ set expect ".*// ${method_name}\\($expected\\)"
+ lappend result [list "${method_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" }
+ "aenum" { "aenum" "anon_enum" }
+ "astruct" { "astruct" "anon_struct" }
+ "aunion" { "aunion" "anon_union" }
+}
+
+set methods {}
+
+# Add the simple, one-parameter methods
+foreach meth {A::foo::test A::foo::foo} {
+ foreach type {my_other_type my_other_type_2} {
+ foreach t $typedefs($type) {
+ add methods $meth $t $type
+ }
+ }
+}
+
+# Add two-parameter methods
+foreach meth {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 $meth "$t1, const $t2" $type
+ add methods $meth "$t1, $t2" $type
+ }
+ }
+}
+
+# Add three-parameter methods/functions
+foreach meth {A::foo::test A::foo::foo B::test test} {
+ set type "aenum, astruct const&, aunion const\\*\\*\\*"
+ foreach t1 $typedefs(aenum) {
+ foreach t2 $typedefs(astruct) {
+ foreach t3 $typedefs(aunion) {
+ add methods $meth "$t1, $t2 const&, $t3 const***" $type
+ }
+ }
+ }
+}
+
+# Add the array-of-function pointer methods
+set type "fptr1\\*"
+foreach meth {A::foo::test A::foo::foo} {
+ add methods $meth "fptr1*" $type
+ foreach t $typedefs(my_other_type) {
+ add methods $meth "void (**) ($t)" $type
+ }
+}
+
+# Add the function pointer methods
+set type "fptr3"
+foreach meth {A::foo::test A::foo::foo} {
+ add methods $meth "fptr3" $type
+
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth "void (*)(fptr2, $t1)" $type
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "void (*)(void (*)(fptr1, $t2), $t1)" $type
+ foreach t3 $typedefs(my_other_type) {
+ add methods $meth \
+ "void (*)(void (*)(void (*) ($t3), $t2), $t1)" $type
+ }
+ }
+ }
+}
+
+set type1 "my_other_type"
+set type2 "my_other_type, my_other_type_2"
+foreach meth {"test" "B::test"} {
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth $t1 $type1
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "$t1, $t2" $type2 template
+ }
+ }
+}
+
+# Miscellaneous tests
+set type {CORE_ADDR \(\*\) \[10\]}
+foreach meth {A::foo::foo A::foo::test} {
+ foreach t $typedefs(CORE_ADDR) {
+ add methods $meth "$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
+ 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] 13+ messages in thread
* Re: [RFA] c++/12266 (again) [cp_demangled_name_parse_free-4.patch]
2011-07-29 13:16 [RFA] c++/12266 (again) Keith Seitz
2011-08-01 20:38 ` Tom Tromey
2011-08-02 16:08 ` Tom Tromey
@ 2011-08-02 20:28 ` Jan Kratochvil
2011-08-09 20:23 ` Keith Seitz
2011-08-02 20:37 ` [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch] Jan Kratochvil
3 siblings, 1 reply; 13+ messages in thread
From: Jan Kratochvil @ 2011-08-02 20:28 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
On Fri, 29 Jul 2011 01:17:46 +0200, Keith Seitz wrote:
> 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
[...]
> +/* 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);
> +}
$ make test-cp-name-parser
cp-name-parser.y:2018: undefined reference to `make_cleanup'
[...]
> -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)));
This cast seems redundant to me.
[...]
> @@ -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)));
Redundant cast.
[...]
> --- a/gdb/cp-support.h
> +++ b/gdb/cp-support.h
> @@ -46,6 +46,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;
> +};
I guess you have been considering it but anyway:
Its ->tree items can reference for s_name the original string being demangled,
as you even state in some comments. Due to it it also requires later explicit
handling of `free_list'. Could this struct already have the original string
duplicated and this struct would track its freeing?
cp_merge_demangle_parse_infos would then track all the source strings in the
merged destination demangle_parse_info.
Thanks,
Jan
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFA] c++/12266 (again) [cp_demangled_name_parse_free-4.patch]
2011-08-02 20:28 ` [RFA] c++/12266 (again) [cp_demangled_name_parse_free-4.patch] Jan Kratochvil
@ 2011-08-09 20:23 ` Keith Seitz
2011-08-13 16:51 ` Jan Kratochvil
0 siblings, 1 reply; 13+ messages in thread
From: Keith Seitz @ 2011-08-09 20:23 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2663 bytes --]
On 08/02/2011 01:28 PM, Jan Kratochvil wrote:
> $ make test-cp-name-parser
> cp-name-parser.y:2018: undefined reference to `make_cleanup'
Fixed.
>> + result = ((struct demangle_parse_info *)
>> + malloc (sizeof (struct demangle_parse_info)));
>
> This cast seems redundant to me.
Removed. GDB is a mish-mash of usage discrepancies like this. [Mind you,
a C++ compiler will complain about this.]
>> + info = ((struct demangle_parse_info *)
>> + xmalloc (sizeof (struct demangle_parse_info)));
>
> Redundant cast.
Removed.
> I guess you have been considering it but anyway:
>
> Its ->tree items can reference for s_name the original string being demangled,
> as you even state in some comments. Due to it it also requires later explicit
> handling of `free_list'. Could this struct already have the original string
> duplicated and this struct would track its freeing?
> cp_merge_demangle_parse_infos would then track all the source strings in the
> merged destination demangle_parse_info.
That is actually something that didn't occur to me for some reason, but
I've made the necessary changes to use an obstack. [This change can be
seen in the next patch, since it is not strictly necessary for this
cleanup/refactoring.]
New patch attached.
Keith
ChangeLog
2011-08-09 Keith Seitz <keiths@redhat.com>
* cp-name-parser.y (struct demangle_info): Remove unused
member PREV.
(d_grab): Likewise.
(allocate_info): Change return type to struct demangle_info *.
Always allocate a new demangle_info.
Remove unused PREV pointer.
(cp_new_demangle_parse_info): New function.
(cp_demangled_name_parse_free): New function.
(do_demangled_name_parse_free_cleanup): New function.
(make_cleanup_cp_demangled_name_parse_free): New function.
(cp_demangled_name_to_comp): Change return type to
struct demangle_parse_info *.
Allocate a new storage for each call.
(main): Update usage for cp_demangled_name_to_comp
API change.
* cp-support.h (struct demangle_parse_info): New structure.
(cp_demangled_name_to_comp): Update API change for
return type.
(cp_new_demangle_parse_info): Declare.
(make_cleanup_cp_demangled_name_parse_free): New declaration.
(cp_demangled_name_parse_free): Declare.
* cp-support.c (cp_canonicalize_string): Update API
change for cp_demangled_name_to_comp.
(mangled_name_to_comp): Likewise.
Return struct demangle_parse_info, too.
(cp_class_name_from_physname): Update mangled_name_to_comp
API change.
(method_name_from_physname): Likewise.
(cp_func_name): Update API change for cp_demangled_name_to_comp.
(cp_remove_params): Likewise.
* python/py-type.c (typy_legacy_template_argument): Likewise.
[-- Attachment #2: cp_demangled_name_parse_free-5.patch --]
[-- Type: text/plain, Size: 13678 bytes --]
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index 8736777..6d23c9d 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,60 @@ cp_comp_to_string (struct demangle_component *result, int estimated_len)
&err);
}
+/* A convenience function to allocate and initialize a new struct
+ demangled_parse_info. */
+
+struct demangle_parse_info *
+cp_new_demangle_parse_info (void)
+{
+ struct demangle_parse_info *info;
+
+ info = malloc (sizeof (struct demangle_parse_info));
+ info->info = NULL;
+ info->tree = NULL;
+ return info;
+}
+
+/* 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 = cp_new_demangle_parse_info ();
+ result->info = demangle_info;
if (yyparse ())
{
@@ -1993,10 +2023,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 +2083,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 +2117,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 +2137,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..8cda2b4 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -86,6 +86,25 @@ static const char *operator_tokens[] =
/* new[] and delete[] require special whitespace handling */
};
+
+/* 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);
+}
+
/* 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
@@ -124,19 +143,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 +173,27 @@ 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 = cp_new_demangle_parse_info ();
+ info->tree = ret;
*demangled_p = NULL;
- return ret;
+ return info;
}
}
@@ -181,16 +205,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 +225,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 +303,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 +374,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 +390,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 +406,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 +431,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 +464,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 d23f19e..f333ffa 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -46,6 +46,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
@@ -214,12 +225,18 @@ 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 struct demangle_parse_info *cp_new_demangle_parse_info (void);
+
/* 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 8ab18cf..335342e 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;
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFA] c++/12266 (again) [cp_demangled_name_parse_free-4.patch]
2011-08-09 20:23 ` Keith Seitz
@ 2011-08-13 16:51 ` Jan Kratochvil
2011-08-18 16:22 ` Keith Seitz
0 siblings, 1 reply; 13+ messages in thread
From: Jan Kratochvil @ 2011-08-13 16:51 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
On Tue, 09 Aug 2011 22:22:42 +0200, Keith Seitz wrote:
> ChangeLog
> 2011-08-09 Keith Seitz <keiths@redhat.com>
>
> * cp-name-parser.y (struct demangle_info): Remove unused
> member PREV.
> (d_grab): Likewise.
> (allocate_info): Change return type to struct demangle_info *.
> Always allocate a new demangle_info.
> Remove unused PREV pointer.
> (cp_new_demangle_parse_info): New function.
> (cp_demangled_name_parse_free): New function.
> (do_demangled_name_parse_free_cleanup): New function.
> (make_cleanup_cp_demangled_name_parse_free): New function.
> (cp_demangled_name_to_comp): Change return type to
> struct demangle_parse_info *.
> Allocate a new storage for each call.
> (main): Update usage for cp_demangled_name_to_comp
> API change.
> * cp-support.h (struct demangle_parse_info): New structure.
> (cp_demangled_name_to_comp): Update API change for
> return type.
> (cp_new_demangle_parse_info): Declare.
> (make_cleanup_cp_demangled_name_parse_free): New declaration.
> (cp_demangled_name_parse_free): Declare.
> * cp-support.c (cp_canonicalize_string): Update API
> change for cp_demangled_name_to_comp.
> (mangled_name_to_comp): Likewise.
> Return struct demangle_parse_info, too.
> (cp_class_name_from_physname): Update mangled_name_to_comp
> API change.
> (method_name_from_physname): Likewise.
> (cp_func_name): Update API change for cp_demangled_name_to_comp.
> (cp_remove_params): Likewise.
> * python/py-type.c (typy_legacy_template_argument): Likewise.
I find it OK now.
Thanks,
Jan
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch]
2011-07-29 13:16 [RFA] c++/12266 (again) Keith Seitz
` (2 preceding siblings ...)
2011-08-02 20:28 ` [RFA] c++/12266 (again) [cp_demangled_name_parse_free-4.patch] Jan Kratochvil
@ 2011-08-02 20:37 ` Jan Kratochvil
2011-08-09 20:48 ` Keith Seitz
3 siblings, 1 reply; 13+ messages in thread
From: Jan Kratochvil @ 2011-08-02 20:37 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
On Fri, 29 Jul 2011 01:17:46 +0200, Keith Seitz wrote:
> --- 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. */
It would need to state that DEST will then still possibly reference the
original string of SRC. Commented more at `struct demangle_parse_info'.
> +
> +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));
Why not just:
*target = *src->tree;
> + 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
[...]
> +static int
> +inspect_type (struct demangle_parse_info *info,
> + struct demangle_component *ret_comp,
> + VEC (namep) **free_list)
> +{
> + int i;
> + 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';
> +
> + /* Ignore any typedefs that should not be substituted. */
> + for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
> + {
> + if (strcmp (name, ignore_typedefs[i]) == 0)
> + return 0;
> + }
> +
> + sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
> + if (sym != NULL)
> + {
> + struct type *otype = SYMBOL_TYPE (sym);
> +
> + /* If the type is a typedef, replace it. */
> + if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF)
> + {
> + long len;
> + int is_anon;
> + struct type *last, *type;
> + struct demangle_parse_info *i;
> + struct ui_file *buf = mem_fileopen ();
> + struct cleanup *cleanup = make_cleanup_ui_file_delete (buf);
> +
> + /* If the final typedef points to an anonymous struct, union,
> + or enum, keep the (last) typedef. */
> +
> + /* Find the last typedef for the type. */
> + last = otype;
> + while (TYPE_CODE (TYPE_TARGET_TYPE (last)) == TYPE_CODE_TYPEDEF)
> + last = TYPE_TARGET_TYPE (last);
You can calculate LAST only if it gets used - move the code more down.
> +
> + /* Get the real type of the typedef. */
> + type = check_typedef (otype);
> +
> + is_anon = (TYPE_TAG_NAME (type) == NULL
> + && (TYPE_CODE (type) == TYPE_CODE_ENUM
> + || TYPE_CODE (type) == TYPE_CODE_STRUCT
> + || TYPE_CODE (type) == TYPE_CODE_UNION));
> + if (is_anon)
> + {
> + /* If there is only one typedef for this anonymous type,
> + do not substitute it. */
> + if (type == otype)
> + {
> + do_cleanups (cleanup);
> + return 0;
> + }
> + else
> + /* Use the last typedef seen as the type for this
> + anonymous type. */
> + type = last;
> + }
In some cases type == otype here, such as if there was only one typedef of
anonymous type or of typedef failed to be resolved. Here could be also just
return 0.
if (type == otype)
{
do_cleanups;
return 0;
}
> +
> +
> + 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 -- but not
> + if the type is anonymous (that would lead to infinite
> + looping). */
> + if (!is_anon)
> + 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);
double-free, NAME is already in FREE_LIST.
> + name = canon;
LEN is not set here for NAME. And CANON is leaked.
> + }
> +
> + ret_comp->u.s_name.s = name;
> + ret_comp->u.s_name.len = len;
> + }
> +
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* Replace any typedefs appearing in the qualified name
> + (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
> + given in INFO. Store any allocated memory in FREE_LIST. */
> +
> +static void
> +replace_typedefs_qualified_name (struct demangle_parse_info *info,
> + struct demangle_component *ret_comp,
> + VEC (namep) **free_list)
> +{
> + long len;
> + char *name;
> + struct ui_file *buf = mem_fileopen ();
> + struct demangle_component *comp = ret_comp;
> +
> + /* Walk each node of the qualified name, reconstructing the name of
> + this element. With every node, check for any typedef substitutions.
> + If a substitution has occurred, replace the qualified name node
> + with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
> + substituted name. */
> + while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
> + {
> + if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
> + {
> + struct demangle_component new;
> +
> + ui_file_write (buf, d_left (comp)->u.s_name.s,
> + d_left (comp)->u.s_name.len);
> + name = ui_file_xstrdup (buf, &len);
> + new.type = DEMANGLE_COMPONENT_NAME;
> + new.u.s_name.s = name;
> + new.u.s_name.len = len;
> + if (inspect_type (info, &new, free_list))
> + {
> + char *n;
> +
> + /* A typedef was substituted in NEW. Convert it to a
> + string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
> + node. */
> + n = cp_comp_to_string (&new, 100);
> + xfree (name);
> + if (n != NULL)
> + {
> + ui_file_rewind (buf);
ui_file_rewind should happen even if N is NULL, somehow probably to rather
abort the operation on NULL N.
> + VEC_safe_push (namep, *free_list, n);
> +
IMO here is missing:
ret_comp->type = DEMANGLE_COMPONENT_NAME;
> + d_left (ret_comp)->u.s_name.s = n;
> + d_left (ret_comp)->u.s_name.len = strlen (n);
> + d_right (ret_comp) = d_right (comp);
> + comp = ret_comp;
> + continue;
> + }
> + }
> + }
> + else
> + {
> + /* The current node is not a name, so simply replace any
> + typedefs in it. Then print it to the stream to continue
> + checking for more typedefs in the tree. */
> + replace_typedefs (info, d_left (comp), free_list);
> + name = cp_comp_to_string (d_left (comp), 100);
If it returns NULL I would prefer some sort of abort. It risks now to quietly
corrupt the name. The later operations will probably fail not modifying
anything but still it is a bit fragile.
> + if (name != NULL)
> + {
> + fputs_unfiltered (name, buf);
> + xfree (name);
> + }
> + }
> + ui_file_write (buf, "::", 2);
> + comp = d_right (comp);
> + }
> +
> + /* If the next component is DEMANGLE_COMPONENT_NAME, 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)
> + {
> + 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;
> + (void) inspect_type (info, ret_comp, free_list);
> + }
> + else
> + replace_typedefs (info, comp, free_list);
> +
> + ui_file_delete (buf);
> +}
[...]
> +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:
> + check_cv_qualifiers (ret_comp);
> + /* Fall through */
> +
> + case DEMANGLE_COMPONENT_FUNCTION_TYPE:
> + case DEMANGLE_COMPONENT_TEMPLATE:
> + 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_TYPED_NAME:
> + {
> + struct demangle_component *comp = d_right (ret_comp);
> +
> + while (comp != NULL
> + && (comp->type == DEMANGLE_COMPONENT_VOLATILE
> + || comp->type == DEMANGLE_COMPONENT_RESTRICT
> + || comp->type == DEMANGLE_COMPONENT_CONST
> + || comp->type == DEMANGLE_COMPONENT_VOLATILE_THIS
> + || comp->type == DEMANGLE_COMPONENT_RESTRICT_THIS
> + || comp->type == DEMANGLE_COMPONENT_CONST_THIS))
> + comp = d_left (comp);
> +
> + if (d_left (ret_comp)->type != DEMANGLE_COMPONENT_NAME
> + || comp->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
> + replace_typedefs (info, d_left (ret_comp), free_list);
I admit I do not understand the goal of the COMP computation and the
conditional. replace_typedefs unconditionally does not break
gdb.cp/meth-typedefs.exp. At least a comment of the purpose would be nice.
> + replace_typedefs (info, d_right (ret_comp), free_list);
> + }
> + break;
> +
> + case DEMANGLE_COMPONENT_NAME:
> + (void) 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_LOCAL_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_CONST:
> + case DEMANGLE_COMPONENT_RESTRICT:
> + case DEMANGLE_COMPONENT_VOLATILE:
> + case DEMANGLE_COMPONENT_VOLATILE_THIS:
> + case DEMANGLE_COMPONENT_CONST_THIS:
> + case DEMANGLE_COMPONENT_RESTRICT_THIS:
> + 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;
obstack is easier for the freeing but it may be rather moved to struct
demangle_parse_info.
> +
> + ret = NULL;
> + free_list = VEC_alloc (namep, 10);
> + estimated_len = strlen (string) * 2;
> + info = cp_demangled_name_to_comp (string, NULL);
I have tried to run some strings to it and for example
jsRegExpFree(struct JSRegExp *)
fails to parse by cp-name-parser.y. This is outside of scope of this patch,
it should cause no regressions. It reduces the PR 12266 functionality and it
is a blocker for the possible future drop of DW_AT_MIPS_linkage_name.
> + 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;
> +}
> +
[...]
> @@ -1365,7 +1365,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;
> @@ -1373,6 +1373,7 @@ decode_compound (char **argptr, int funfirstline,
> struct symbol *sym_class;
> struct type *t;
> char *saved_arg;
> + struct cleanup *cleanup;
>
> /* If the user specified any completer quote characters in the input,
> strip them. They are superfluous. */
> @@ -1597,7 +1598,22 @@ 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);
You are now using cp_canonicalize_string_no_typedefs at the consumers but it
is not used at the producer - at dwarf2_canonicalize_name. It is not needed
there as long as GDB depends on DW_AT_MIPS_linkage_name. But do you plan to
use it at dwarf2_canonicalize_name? That is it would fix
the `set debug check-physname yes' warnings. I guess you were referring to
the dwarf2_canonicalize_name application by your text:
# I've pruned the original patchset down substantially: a lot of the
# previous three (!) patches dealt with dwarf2_physname fixes which are
# now no longer necessary for GCC. I will attempt to clean these up for
# later submission for the benefit of other non-GNU compilers.
> +
> + 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
[...]
Thanks,
Jan
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch]
2011-08-02 20:37 ` [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch] Jan Kratochvil
@ 2011-08-09 20:48 ` Keith Seitz
2011-08-13 16:50 ` Jan Kratochvil
0 siblings, 1 reply; 13+ messages in thread
From: Keith Seitz @ 2011-08-09 20:48 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 4261 bytes --]
On 08/02/2011 01:36 PM, Jan Kratochvil wrote:
>> +/* 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. */
>
> It would need to state that DEST will then still possibly reference the
> original string of SRC. Commented more at `struct demangle_parse_info'.
I have updated the comments.
> Why not just:
> *target = *src->tree;
Changed.
> You can calculate LAST only if it gets used - move the code more down.
That block got moved around based on Tom's comments. And obstacks
cleaned a lot of it up, too.
> In some cases type == otype here, such as if there was only one typedef of
> anonymous type or of typedef failed to be resolved. Here could be also just
> return 0.
Done.
> double-free, NAME is already in FREE_LIST.
> LEN is not set here for NAME. And CANON is leaked.
Yup. Cleaned up with the move to an obstack.
> ui_file_rewind should happen even if N is NULL, somehow probably to rather
> abort the operation on NULL N.
Agreed.
> IMO here is missing:
> ret_comp->type = DEMANGLE_COMPONENT_NAME;
Indeed!
> If it returns NULL I would prefer some sort of abort. It risks now to quietly
> corrupt the name. The later operations will probably fail not modifying
> anything but still it is a bit fragile.
Done.
>> + case DEMANGLE_COMPONENT_TYPED_NAME:
>> + {
>> + struct demangle_component *comp = d_right (ret_comp);
>> +
>> + while (comp != NULL
>> + && (comp->type == DEMANGLE_COMPONENT_VOLATILE
>> + || comp->type == DEMANGLE_COMPONENT_RESTRICT
>> + || comp->type == DEMANGLE_COMPONENT_CONST
>> + || comp->type == DEMANGLE_COMPONENT_VOLATILE_THIS
>> + || comp->type == DEMANGLE_COMPONENT_RESTRICT_THIS
>> + || comp->type == DEMANGLE_COMPONENT_CONST_THIS))
>> + comp = d_left (comp);
>> +
>> + if (d_left (ret_comp)->type != DEMANGLE_COMPONENT_NAME
>> + || comp->type != DEMANGLE_COMPONENT_FUNCTION_TYPE)
>> + replace_typedefs (info, d_left (ret_comp), free_list);
>
> I admit I do not understand the goal of the COMP computation and the
> conditional. replace_typedefs unconditionally does not break
> gdb.cp/meth-typedefs.exp. At least a comment of the purpose would be nice.
I've removed this to unconditionally call replace_typedefs. IIRC, that
was needed for some reason that escapes me at the moment. The real need
for it is being hidden by the minsym fallback. I'll follow-up on this
after this patchset is finalized. [That entails a lot of fixes to
c-typeprint.c and whatnot called by dwarf2_physname when physnames are
computed.]
> You are now using cp_canonicalize_string_no_typedefs at the consumers but it
> is not used at the producer - at dwarf2_canonicalize_name. It is not needed
> there as long as GDB depends on DW_AT_MIPS_linkage_name. But do you plan to
> use it at dwarf2_canonicalize_name? That is it would fix
> the `set debug check-physname yes' warnings.
When physnames are computed, no typedefs should appear in them (although
apparently exceptions should exist for std::string and others that are
excepted in libiberty). This is a bunch of bugs which I will address
immediately after this is finalized.
Thank you for reviewing this (again)!
New patch attached.
Keith
ChangeLog
2011-08-09 Keith Seitz <keiths@redhat.com>
* cp-support.h (cp_canonicalize_string_no_typedefs): Declare.
(cp_merge_demangle_parse_infos): Declare.
* cp-support.c (ignore_typedefs): New file global.
(copy_string_to_obstack): New function.
(inspect_type): New function.
(replace_typedefs): New function.
(replace_typedefs_qualified_name): New function.
(cp_canonicalize_string_no_typedefs): New function.
* cp-name-parser.y (cp_merge_demangle_parse_infos): New function.
(cp_new_demangle__parse_info): Allocate and initialize the obstack.
* linespec.c (find_methods): Use cp_canonicalize_string_no_typedefs
instead of cp_canonicalize_string.
(find_method): Likewise.
(decode_compound): Before looking up the name, call
cp_canonicalize_string_no_typedefs.
(decode_variable): Likewise.
2011-08-09 Keith Seitz <keiths@redhat.com>
* gdb.cp/meth-typedefs.cc: New file.
* gdb.cp/meth-typedefs.exp: New file.
[-- Attachment #2: cp_canonicalize_no_typedefs-5.patch --]
[-- Type: text/plain, Size: 27468 bytes --]
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index 6d23c9d..e73017c 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -41,6 +41,8 @@
#include "libiberty.h"
#include "demangle.h"
#include "cp-support.h"
+#include "gdb_obstack.h"
+#include "gdb_assert.h"
/* Bison does not make it easy to create a parser without global
state, unfortunately. Here are all the global variables used
@@ -1970,6 +1972,9 @@ cp_new_demangle_parse_info (void)
info = malloc (sizeof (struct demangle_parse_info));
info->info = NULL;
info->tree = NULL;
+ info->obstack = malloc (sizeof (struct obstack));
+ obstack_init (info->obstack);
+
return info;
}
@@ -1989,10 +1994,51 @@ cp_demangled_name_parse_free (struct demangle_parse_info *parse_info)
info = next;
}
+ /* Free any memory allocated during typedef replacement. */
+ obstack_free (parse_info->obstack, NULL);
+ free (parse_info->obstack);
+
/* 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.
+
+ NOTE 1: Since there is no API to merge obstacks, this function does
+ even attempt to try it. Fortunately, we do not (yet?) need this ability.
+ The code will assert if SRC->obstack is not empty.
+
+ NOTE 2: The string from which SRC was parsed must not be freed, since
+ this function will place pointers to that string into DEST. */
+
+void
+cp_merge_demangle_parse_infos (struct demangle_parse_info *dest,
+ struct demangle_component *target,
+ struct demangle_parse_info *src)
+
+{
+ struct demangle_info *di;
+
+ /* Copy the SRC's parse data into DEST. */
+ *target = *src->tree;
+ di = dest->info;
+ while (di->next != NULL)
+ di = di->next;
+ di->next = src->info;
+
+ /* Clear the (pointer to) SRC's parse data so that it is not freed when
+ cp_demangled_parse_info_free is called. */
+ src->info = NULL;
+
+ /* Assert if the SRC obstack is not empty. */
+ gdb_assert (obstack_empty_p (src->obstack));
+
+ /* Free SRC. */
+ cp_demangled_name_parse_free (src);
+}
+
/* Convert a demangled name to a demangle_component tree. On success,
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
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 8cda2b4..2eff1d8 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -86,6 +86,32 @@ static const char *operator_tokens[] =
/* new[] and delete[] require special whitespace handling */
};
+/* A list of typedefs which should not be substituted by replace_typedefs. */
+static const char * const ignore_typedefs[] =
+ {
+ "std::istream", "std::iostream", "std::ostream", "std::string"
+ };
+
+static void
+ replace_typedefs (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp);
+
+/* A convenience function to copy STRING into OBSTACK, returning a pointer
+ to the newly allocated string and saving the number of bytes saved in LEN.
+
+ It does not copy the terminating '\0' byte! */
+
+static char *
+copy_string_to_obstack (struct obstack *obstack, const char *string,
+ size_t *len)
+{
+ char *s;
+
+ *len = strlen (string);
+ s = obstack_alloc (obstack, *len);
+ memcpy (s, string, *len);
+ return s;
+}
/* A cleanup wrapper for cp_demangled_name_parse_free. */
@@ -136,6 +162,341 @@ 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.
+
+ Returns 1 if any typedef substitutions were made, 0 otherwise. */
+
+static int
+inspect_type (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp)
+{
+ int i;
+ 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';
+
+ /* Ignore any typedefs that should not be substituted. */
+ for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
+ {
+ if (strcmp (name, ignore_typedefs[i]) == 0)
+ return 0;
+ }
+
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+ if (sym != NULL)
+ {
+ struct type *otype = SYMBOL_TYPE (sym);
+
+ /* If the type is a typedef, replace it. */
+ if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF)
+ {
+ long len;
+ int is_anon;
+ struct type *type;
+ struct demangle_parse_info *i;
+ struct ui_file *buf;
+ struct cleanup *cleanup;
+
+ /* Get the real type of the typedef. */
+ type = check_typedef (otype);
+
+ is_anon = (TYPE_TAG_NAME (type) == NULL
+ && (TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION));
+ if (is_anon)
+ {
+ struct type *last = otype;
+
+ /* Find the last typedef for the type. */
+ while (TYPE_TARGET_TYPE (last) != NULL
+ && (TYPE_CODE (TYPE_TARGET_TYPE (last))
+ == TYPE_CODE_TYPEDEF))
+ last = TYPE_TARGET_TYPE (last);
+
+ /* If there is only one typedef for this anonymous type,
+ do not substitute it. */
+ if (type == otype)
+ return 0;
+ else
+ /* Use the last typedef seen as the type for this
+ anonymous type. */
+ type = last;
+ }
+
+
+ buf = mem_fileopen ();
+ cleanup = make_cleanup_ui_file_delete (buf);
+
+ type_print (type, "", buf, -1);
+ name = ui_file_obsavestring (buf, info->obstack, &len);
+ 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 -- but not
+ if the type is anonymous (that would lead to infinite
+ looping). */
+ if (!is_anon)
+ replace_typedefs (info, ret_comp);
+ }
+ 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)
+ {
+ /* Copy the canonicalization into the obstack and
+ free CANON. */
+ name = copy_string_to_obstack (info->obstack, canon, &len);
+ xfree (canon);
+ }
+
+ ret_comp->u.s_name.s = name;
+ ret_comp->u.s_name.len = len;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Replace any typedefs appearing in the qualified name
+ (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+ given in INFO. */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp)
+{
+ long len;
+ char *name;
+ struct ui_file *buf = mem_fileopen ();
+ struct demangle_component *comp = ret_comp;
+
+ /* Walk each node of the qualified name, reconstructing the name of
+ this element. With every node, check for any typedef substitutions.
+ If a substitution has occurred, replace the qualified name node
+ with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
+ substituted name. */
+ while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+ {
+ if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
+ {
+ struct demangle_component new;
+
+ ui_file_write (buf, d_left (comp)->u.s_name.s,
+ d_left (comp)->u.s_name.len);
+ name = ui_file_obsavestring (buf, info->obstack, &len);
+ new.type = DEMANGLE_COMPONENT_NAME;
+ new.u.s_name.s = name;
+ new.u.s_name.len = len;
+ if (inspect_type (info, &new))
+ {
+ char *n, *s;
+ size_t slen;
+
+ /* A typedef was substituted in NEW. Convert it to a
+ string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
+ node. */
+
+ ui_file_rewind (buf);
+ n = cp_comp_to_string (&new, 100);
+ if (n == NULL)
+ {
+ /* If something went astray, abort typedef substitutions. */
+ ui_file_delete (buf);
+ return;
+ }
+
+ s = copy_string_to_obstack (info->obstack, n, &slen);
+ xfree (n);
+
+ ret_comp->type = DEMANGLE_COMPONENT_NAME;
+ d_left (ret_comp)->u.s_name.s = s;
+ d_left (ret_comp)->u.s_name.len = slen;
+ d_right (ret_comp) = d_right (comp);
+ comp = ret_comp;
+ continue;
+ }
+ }
+ else
+ {
+ /* The current node is not a name, so simply replace any
+ typedefs in it. Then print it to the stream to continue
+ checking for more typedefs in the tree. */
+ replace_typedefs (info, d_left (comp));
+ name = cp_comp_to_string (d_left (comp), 100);
+ if (name == NULL)
+ {
+ /* If something went astray, abort typedef substitutions. */
+ ui_file_delete (buf);
+ return;
+ }
+ fputs_unfiltered (name, buf);
+ xfree (name);
+ }
+ ui_file_write (buf, "::", 2);
+ comp = d_right (comp);
+ }
+
+ /* If the next component is DEMANGLE_COMPONENT_NAME, 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)
+ {
+ ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
+ name = ui_file_obsavestring (buf, info->obstack, &len);
+
+ /* 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);
+ }
+ else
+ replace_typedefs (info, comp);
+
+ ui_file_delete (buf);
+}
+
+
+/* A function to check const and volatile qualifiers for argument types.
+
+ "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. */
+
+static void
+check_cv_qualifiers (struct demangle_component *ret_comp)
+{
+ 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));
+ }
+}
+
+/* Walk the parse tree given by RET_COMP, replacing any typedefs with
+ their basic types. */
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp)
+{
+ if (ret_comp)
+ {
+ switch (ret_comp->type)
+ {
+ case DEMANGLE_COMPONENT_ARGLIST:
+ check_cv_qualifiers (ret_comp);
+ /* Fall through */
+
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ replace_typedefs (info, d_left (ret_comp));
+ replace_typedefs (info, d_right (ret_comp));
+ break;
+
+ case DEMANGLE_COMPONENT_NAME:
+ inspect_type (info, ret_comp);
+ break;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ replace_typedefs_qualified_name (info, ret_comp);
+ break;
+
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_CTOR:
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ replace_typedefs (info, d_right (ret_comp));
+ break;
+
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ replace_typedefs (info, 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 all the typedefs in the tree. */
+ replace_typedefs (info, info->tree);
+
+ /* 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);
+
+ /* 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 f333ffa..5c839fc 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -55,6 +55,9 @@ struct demangle_parse_info
/* The result of the parse. */
struct demangle_component *tree;
+
+ /* Any temporary memory used during typedef replacement. */
+ struct obstack *obstack;
};
/* This struct is designed to store data from using directives. It
@@ -145,6 +148,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);
@@ -234,6 +239,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 *);
extern struct demangle_parse_info *cp_new_demangle_parse_info (void);
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 137ef9c..b96c79f 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -245,7 +245,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;
@@ -1365,7 +1365,7 @@ decode_compound (char **argptr, int funfirstline,
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;
@@ -1373,6 +1373,7 @@ decode_compound (char **argptr, int funfirstline,
struct symbol *sym_class;
struct type *t;
char *saved_arg;
+ struct cleanup *cleanup;
/* If the user specified any completer quote characters in the input,
strip them. They are superfluous. */
@@ -1597,7 +1598,18 @@ 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);
+ 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
@@ -1743,7 +1755,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);
@@ -2085,16 +2097,31 @@ decode_variable (char *copy, int funfirstline,
struct linespec_result *canonical,
struct symtab *file_symtab)
{
+ char *name, *canon;
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);
+ 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);
if (sym != NULL)
- return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);
+ {
+ do_cleanups (cleanup);
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, NULL);
+ }
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ msymbol = lookup_minimal_symbol (name, NULL, NULL);
+ do_cleanups (cleanup);
if (msymbol != NULL)
return minsym_found (funfirstline, msymbol);
diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.cc b/gdb/testsuite/gdb.cp/meth-typedefs.cc
new file mode 100644
index 0000000..b3c68cc
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,149 @@
+/* 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 enum {E_A, E_B, E_C} anon_enum;
+typedef struct {int a; char b;} anon_struct;
+typedef union {int a; char b;} anon_union;
+typedef anon_enum aenum;
+typedef anon_struct astruct;
+typedef anon_union aunion;
+
+typedef void (*fptr1) (my_other_type);
+typedef void (*fptr2) (fptr1, my_other_type_2);
+typedef void (*fptr3) (fptr2, my_other_type);
+typedef void (*fptr4) (anon_enum a, anon_struct const& b, anon_union const*** c);
+
+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])
+ foo (aenum a, astruct const& b, aunion const*** c) { } // A::foo::foo(aenum, astruct const&, aunion const***)
+
+ 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])
+ void test (aenum a, astruct const& b, aunion const*** c) { }; // A::foo::test(aenum, astruct const&, aunion const***)
+ };
+};
+
+namespace B
+{
+ void
+ test (my_other_type foo) { } // B::test(my_other_type)
+
+ void
+ test (aenum a, astruct const& b, aunion const*** c) { } // B::test(aenum, astruct const&, aunion const***)
+
+ template <typename T1, typename T2>
+ void test (T1 a, T2 b) { } // B::test (T1, T2)
+
+ template <>
+ void test (my_other_type foo, my_other_type_2) { } // B::test<my_other_type, my_other_type_2>(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_;
+
+template <typename T1, typename T2>
+void test (T1 a, T2 b) {} // test (T1, T2)
+
+template <>
+void test (my_other_type foo, my_other_type_2) { } // test<my_other_type, my_other_type_2>(my_other_type, my_other_type_2)
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (_BAR_ &b) { } // test(_BAR_&)
+
+void
+test (aenum a, astruct const& b, aunion const*** c) { } // test(aenum, astruct const&, aunion const***)
+
+int
+main (void)
+{
+ A::foo my_foo;
+ fptr1 fptr;
+ astruct as = { 0, 0 };
+ aunion const au = { 0 };
+ aunion const* aup = &au;
+ aunion const** aupp = &aup;
+ aunion const*** auppp = &aupp;
+
+ my_foo.test (static_cast<my_other_type> (NULL));
+ my_foo.test (0);
+ my_foo.test (0, static_cast<my_type> (NULL));
+ my_foo.test (static_cast<fptr3> (NULL));
+ my_foo.test (&fptr);
+ my_foo.test (static_cast<CORE_ADDR (*) [10]> (0));
+ my_foo.test (E_A, as, auppp);
+
+ B::test (static_cast<my_other_type> (NULL));
+ B::test (static_cast<my_other_type> (NULL), 0);
+ B::test (E_A, as, auppp);
+
+ test (static_cast<my_other_type> (NULL));
+ test<my_other_type, my_other_type_2> (static_cast<my_other_type> (NULL), 0);
+ test (E_A, as, auppp);
+
+ A::foo a (static_cast<my_other_type> (NULL));
+ A::foo b (0);
+ A::foo c (0, static_cast<my_other_type> (NULL));
+ A::foo d (static_cast<fptr3> (NULL));
+ A::foo e (&fptr);
+ A::foo f (static_cast<CORE_ADDR (*) [10]> (0));
+ A::foo g (E_A, as, auppp);
+
+ fptr4 f4;
+
+ 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..851ec02
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,160 @@
+# 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 {kind {func}}} {
+ upvar $var result
+
+ if {[string compare $kind "template"] == 0} {
+ set method_name "${name}<$expected>"
+ } else {
+ set method_name "$name"
+ }
+
+ set expect ".*// ${method_name}\\($expected\\)"
+ lappend result [list "${method_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" }
+ "aenum" { "aenum" "anon_enum" }
+ "astruct" { "astruct" "anon_struct" }
+ "aunion" { "aunion" "anon_union" }
+}
+
+set methods {}
+
+# Add the simple, one-parameter methods
+foreach meth {A::foo::test A::foo::foo} {
+ foreach type {my_other_type my_other_type_2} {
+ foreach t $typedefs($type) {
+ add methods $meth $t $type
+ }
+ }
+}
+
+# Add two-parameter methods
+foreach meth {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 $meth "$t1, const $t2" $type
+ add methods $meth "$t1, $t2" $type
+ }
+ }
+}
+
+# Add three-parameter methods/functions
+foreach meth {A::foo::test A::foo::foo B::test test} {
+ set type "aenum, astruct const&, aunion const\\*\\*\\*"
+ foreach t1 $typedefs(aenum) {
+ foreach t2 $typedefs(astruct) {
+ foreach t3 $typedefs(aunion) {
+ add methods $meth "$t1, $t2 const&, $t3 const***" $type
+ }
+ }
+ }
+}
+
+# Add the array-of-function pointer methods
+set type "fptr1\\*"
+foreach meth {A::foo::test A::foo::foo} {
+ add methods $meth "fptr1*" $type
+ foreach t $typedefs(my_other_type) {
+ add methods $meth "void (**) ($t)" $type
+ }
+}
+
+# Add the function pointer methods
+set type "fptr3"
+foreach meth {A::foo::test A::foo::foo} {
+ add methods $meth "fptr3" $type
+
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth "void (*)(fptr2, $t1)" $type
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "void (*)(void (*)(fptr1, $t2), $t1)" $type
+ foreach t3 $typedefs(my_other_type) {
+ add methods $meth \
+ "void (*)(void (*)(void (*) ($t3), $t2), $t1)" $type
+ }
+ }
+ }
+}
+
+set type1 "my_other_type"
+set type2 "my_other_type, my_other_type_2"
+foreach meth {"test" "B::test"} {
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth $t1 $type1
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "$t1, $t2" $type2 template
+ }
+ }
+}
+
+# Miscellaneous tests
+set type {CORE_ADDR \(\*\) \[10\]}
+foreach meth {A::foo::foo A::foo::test} {
+ foreach t $typedefs(CORE_ADDR) {
+ add methods $meth "$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
+ 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] 13+ messages in thread* Re: [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch]
2011-08-09 20:48 ` Keith Seitz
@ 2011-08-13 16:50 ` Jan Kratochvil
2011-08-18 16:25 ` Keith Seitz
0 siblings, 1 reply; 13+ messages in thread
From: Jan Kratochvil @ 2011-08-13 16:50 UTC (permalink / raw)
To: Keith Seitz; +Cc: gdb-patches
On Tue, 09 Aug 2011 22:48:23 +0200, Keith Seitz wrote:
> On 08/02/2011 01:36 PM, Jan Kratochvil wrote:
> >>+/* 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. */
> >
> >It would need to state that DEST will then still possibly reference the
> >original string of SRC. Commented more at `struct demangle_parse_info'.
>
> I have updated the comments.
I have filed:
http://sourceware.org/bugzilla/show_bug.cgi?id=13087
as I find wrong to reference memory it does not own, but I see no easy
solution now, so one can fix it by that PR above in the future.
[...]
> --- a/gdb/cp-name-parser.y
> +++ b/gdb/cp-name-parser.y
[...]
> @@ -1970,6 +1972,9 @@ cp_new_demangle_parse_info (void)
> info = malloc (sizeof (struct demangle_parse_info));
> info->info = NULL;
> info->tree = NULL;
> + info->obstack = malloc (sizeof (struct obstack));
obstack could be "inlined", not being a pointer, you stated it needs #include
"gdb_obstack.h" from "cp-support.h" but I do not see it as a problem.
> + obstack_init (info->obstack);
> +
> return info;
> }
>
> @@ -1989,10 +1994,51 @@ cp_demangled_name_parse_free (struct demangle_parse_info *parse_info)
> info = next;
> }
>
> + /* Free any memory allocated during typedef replacement. */
> + obstack_free (parse_info->obstack, NULL);
> + free (parse_info->obstack);
> +
> /* Free the parser info. */
> free (parse_info);
> }
[...]
> +void
> +cp_merge_demangle_parse_infos (struct demangle_parse_info *dest,
> + struct demangle_component *target,
> + struct demangle_parse_info *src)
> +
> +{
[...]
> + /* Assert if the SRC obstack is not empty. */
> + gdb_assert (obstack_empty_p (src->obstack));
$ make test-cp-name-parser
test-cp-name-parser.o: In function `cp_merge_demangle_parse_infos':
.../gdb/cp-name-parser.y:2036: undefined reference to `internal_error'
> +
> + /* Free SRC. */
> + cp_demangled_name_parse_free (src);
> +}
> +
> /* Convert a demangled name to a demangle_component tree. On success,
> 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
> diff --git a/gdb/cp-support.c b/gdb/cp-support.c
> index 8cda2b4..2eff1d8 100644
> --- a/gdb/cp-support.c
> +++ b/gdb/cp-support.c
[...]
> +static char *
> +copy_string_to_obstack (struct obstack *obstack, const char *string,
> + size_t *len)
> +{
> + char *s;
> +
> + *len = strlen (string);
> + s = obstack_alloc (obstack, *len);
> + memcpy (s, string, *len);
obstack_copy is more appropriate here.
> + return s;
> +}
>
> /* A cleanup wrapper for cp_demangled_name_parse_free. */
>
> @@ -136,6 +162,341 @@ 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.
> +
> + Returns 1 if any typedef substitutions were made, 0 otherwise. */
> +
> +static int
> +inspect_type (struct demangle_parse_info *info,
> + struct demangle_component *ret_comp)
> +{
> + int i;
> + 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';
> +
> + /* Ignore any typedefs that should not be substituted. */
> + for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
> + {
> + if (strcmp (name, ignore_typedefs[i]) == 0)
> + return 0;
> + }
> +
> + sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
> + if (sym != NULL)
> + {
> + struct type *otype = SYMBOL_TYPE (sym);
> +
> + /* If the type is a typedef, replace it. */
> + if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF)
> + {
> + long len;
> + int is_anon;
> + struct type *type;
> + struct demangle_parse_info *i;
> + struct ui_file *buf;
> + struct cleanup *cleanup;
> +
> + /* Get the real type of the typedef. */
> + type = check_typedef (otype);
> +
> + is_anon = (TYPE_TAG_NAME (type) == NULL
> + && (TYPE_CODE (type) == TYPE_CODE_ENUM
> + || TYPE_CODE (type) == TYPE_CODE_STRUCT
> + || TYPE_CODE (type) == TYPE_CODE_UNION));
> + if (is_anon)
> + {
> + struct type *last = otype;
> +
> + /* Find the last typedef for the type. */
> + while (TYPE_TARGET_TYPE (last) != NULL
> + && (TYPE_CODE (TYPE_TARGET_TYPE (last))
> + == TYPE_CODE_TYPEDEF))
> + last = TYPE_TARGET_TYPE (last);
> +
> + /* If there is only one typedef for this anonymous type,
> + do not substitute it. */
> + if (type == otype)
> + return 0;
> + else
> + /* Use the last typedef seen as the type for this
> + anonymous type. */
> + type = last;
> + }
> +
> +
> + buf = mem_fileopen ();
> + cleanup = make_cleanup_ui_file_delete (buf);
> +
> + type_print (type, "", buf, -1);
> + name = ui_file_obsavestring (buf, info->obstack, &len);
> + 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 -- but not
> + if the type is anonymous (that would lead to infinite
> + looping). */
> + if (!is_anon)
> + replace_typedefs (info, ret_comp);
> + }
> + 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)
> + {
> + /* Copy the canonicalization into the obstack and
> + free CANON. */
> + name = copy_string_to_obstack (info->obstack, canon, &len);
> + xfree (canon);
> + }
> +
> + ret_comp->u.s_name.s = name;
> + ret_comp->u.s_name.len = len;
> + }
> +
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* Replace any typedefs appearing in the qualified name
> + (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
> + given in INFO. */
> +
> +static void
> +replace_typedefs_qualified_name (struct demangle_parse_info *info,
> + struct demangle_component *ret_comp)
> +{
> + long len;
> + char *name;
> + struct ui_file *buf = mem_fileopen ();
> + struct demangle_component *comp = ret_comp;
> +
> + /* Walk each node of the qualified name, reconstructing the name of
> + this element. With every node, check for any typedef substitutions.
> + If a substitution has occurred, replace the qualified name node
> + with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
> + substituted name. */
> + while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
> + {
> + if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
> + {
> + struct demangle_component new;
> +
> + ui_file_write (buf, d_left (comp)->u.s_name.s,
> + d_left (comp)->u.s_name.len);
> + name = ui_file_obsavestring (buf, info->obstack, &len);
> + new.type = DEMANGLE_COMPONENT_NAME;
> + new.u.s_name.s = name;
> + new.u.s_name.len = len;
> + if (inspect_type (info, &new))
I missed it before but inspect_type calls type_print which is already
protected for exceptions inside inspect_type but BUF here is not protected by
make_cleanup. It is just a negligible mem leak.
> + {
> + char *n, *s;
> + size_t slen;
> +
> + /* A typedef was substituted in NEW. Convert it to a
> + string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
> + node. */
> +
> + ui_file_rewind (buf);
> + n = cp_comp_to_string (&new, 100);
> + if (n == NULL)
> + {
> + /* If something went astray, abort typedef substitutions. */
> + ui_file_delete (buf);
> + return;
> + }
> +
> + s = copy_string_to_obstack (info->obstack, n, &slen);
> + xfree (n);
> +
> + ret_comp->type = DEMANGLE_COMPONENT_NAME;
> + d_left (ret_comp)->u.s_name.s = s;
> + d_left (ret_comp)->u.s_name.len = slen;
> + d_right (ret_comp) = d_right (comp);
> + comp = ret_comp;
> + continue;
> + }
> + }
> + else
> + {
> + /* The current node is not a name, so simply replace any
> + typedefs in it. Then print it to the stream to continue
> + checking for more typedefs in the tree. */
> + replace_typedefs (info, d_left (comp));
> + name = cp_comp_to_string (d_left (comp), 100);
> + if (name == NULL)
> + {
> + /* If something went astray, abort typedef substitutions. */
> + ui_file_delete (buf);
> + return;
> + }
> + fputs_unfiltered (name, buf);
> + xfree (name);
> + }
> + ui_file_write (buf, "::", 2);
> + comp = d_right (comp);
> + }
> +
> + /* If the next component is DEMANGLE_COMPONENT_NAME, 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)
> + {
> + ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
> + name = ui_file_obsavestring (buf, info->obstack, &len);
> +
> + /* 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);
> + }
> + else
> + replace_typedefs (info, comp);
The same BUF exceptions protection for inspect_type and replace_typedefs
> +
> + ui_file_delete (buf);
> +}
> +
> +
nitpick: Two empty lines, should be one.
I find it OK to check it in with the noted changes.
Thanks,
Jan
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch]
2011-08-13 16:50 ` Jan Kratochvil
@ 2011-08-18 16:25 ` Keith Seitz
2011-08-18 16:35 ` Keith Seitz
0 siblings, 1 reply; 13+ messages in thread
From: Keith Seitz @ 2011-08-18 16:25 UTC (permalink / raw)
To: gdb-patches
On 08/13/2011 09:50 AM, Jan Kratochvil wrote:
>
> I find it OK to check it in with the noted changes.
All fixed and committed.
I want to send both Jan and Tom a big thank you for their patience and
the time they've spent reviewing this patchset. Your reviews have been
invaluable.
Keith
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch]
2011-08-18 16:25 ` Keith Seitz
@ 2011-08-18 16:35 ` Keith Seitz
0 siblings, 0 replies; 13+ messages in thread
From: Keith Seitz @ 2011-08-18 16:35 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 268 bytes --]
On 08/18/2011 09:25 AM, Keith Seitz wrote:
> On 08/13/2011 09:50 AM, Jan Kratochvil wrote:
>>
>> I find it OK to check it in with the noted changes.
>
> All fixed and committed.
And for the truly dedicated, I've attached the final version that was
committed.
Keith
[-- Attachment #2: 12266-final.patch --]
[-- Type: text/plain, Size: 40361 bytes --]
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index 286bbb4..f257370 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -41,6 +41,7 @@
#include "libiberty.h"
#include "demangle.h"
#include "cp-support.h"
+#include "gdb_assert.h"
/* Bison does not make it easy to create a parser without global
state, unfortunately. Here are all the global variables used
@@ -60,7 +61,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 +77,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 +1935,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 +1960,102 @@ cp_comp_to_string (struct demangle_component *result, int estimated_len)
&err);
}
+/* A convenience function to allocate and initialize a new struct
+ demangled_parse_info. */
+
+struct demangle_parse_info *
+cp_new_demangle_parse_info (void)
+{
+ struct demangle_parse_info *info;
+
+ info = malloc (sizeof (struct demangle_parse_info));
+ info->info = NULL;
+ info->tree = NULL;
+ obstack_init (&info->obstack);
+
+ return info;
+}
+
+/* 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 any memory allocated during typedef replacement. */
+ obstack_free (&parse_info->obstack, NULL);
+
+ /* 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.
+
+ NOTE 1: Since there is no API to merge obstacks, this function does
+ even attempt to try it. Fortunately, we do not (yet?) need this ability.
+ The code will assert if SRC->obstack is not empty.
+
+ NOTE 2: The string from which SRC was parsed must not be freed, since
+ this function will place pointers to that string into DEST. */
+
+void
+cp_merge_demangle_parse_infos (struct demangle_parse_info *dest,
+ struct demangle_component *target,
+ struct demangle_parse_info *src)
+
+{
+ struct demangle_info *di;
+
+ /* Copy the SRC's parse data into DEST. */
+ *target = *src->tree;
+ di = dest->info;
+ while (di->next != NULL)
+ di = di->next;
+ di->next = src->info;
+
+ /* Clear the (pointer to) SRC's parse data so that it is not freed when
+ cp_demangled_parse_info_free is called. */
+ src->info = NULL;
+
+ /* Assert if the SRC obstack is not empty. */
+ gdb_assert (obstack_empty_p (&src->obstack));
+
+ /* Free SRC. */
+ cp_demangled_name_parse_free (src);
+}
+
/* 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 = cp_new_demangle_parse_info ();
+ result->info = demangle_info;
if (yyparse ())
{
@@ -1993,10 +2066,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;
@@ -2048,6 +2122,20 @@ xfree (void *ptr)
}
}
+/* GDB normally defines internal_error itself, but when this file is built
+ as a standalone program, we must also provide an implementation. */
+
+void
+internal_error (const char *file, int line, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ fprintf (stderr, "%s:%d: internal error: ", file, line);
+ vfprintf (stderr, fmt, ap);
+ exit (1);
+}
+
int
main (int argc, char **argv)
{
@@ -2055,7 +2143,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)
@@ -2089,7 +2177,8 @@ main (int argc, char **argv)
continue;
}
- cp_print (result);
+ cp_print (result->tree);
+ cp_demangled_name_parse_free (result);
free (str2);
if (c)
@@ -2108,7 +2197,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..9e001b2 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -86,6 +86,47 @@ static const char *operator_tokens[] =
/* new[] and delete[] require special whitespace handling */
};
+/* A list of typedefs which should not be substituted by replace_typedefs. */
+static const char * const ignore_typedefs[] =
+ {
+ "std::istream", "std::iostream", "std::ostream", "std::string"
+ };
+
+static void
+ replace_typedefs (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp);
+
+/* A convenience function to copy STRING into OBSTACK, returning a pointer
+ to the newly allocated string and saving the number of bytes saved in LEN.
+
+ It does not copy the terminating '\0' byte! */
+
+static char *
+copy_string_to_obstack (struct obstack *obstack, const char *string,
+ long *len)
+{
+ *len = strlen (string);
+ return obstack_copy (obstack, string, *len);
+}
+
+/* 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);
+}
+
/* 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 +158,355 @@ 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.
+
+ Returns 1 if any typedef substitutions were made, 0 otherwise. */
+
+static int
+inspect_type (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp)
+{
+ int i;
+ char *name;
+ struct symbol *sym;
+ volatile struct gdb_exception except;
+
+ /* 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';
+
+ /* Ignore any typedefs that should not be substituted. */
+ for (i = 0; i < ARRAY_SIZE (ignore_typedefs); ++i)
+ {
+ if (strcmp (name, ignore_typedefs[i]) == 0)
+ return 0;
+ }
+
+ sym = NULL;
+ TRY_CATCH (except, RETURN_MASK_ALL)
+ {
+ sym = lookup_symbol (name, 0, VAR_DOMAIN, 0);
+ }
+
+ if (except.reason >= 0 && sym != NULL)
+ {
+ struct type *otype = SYMBOL_TYPE (sym);
+
+ /* If the type is a typedef, replace it. */
+ if (TYPE_CODE (otype) == TYPE_CODE_TYPEDEF)
+ {
+ long len;
+ int is_anon;
+ struct type *type;
+ struct demangle_parse_info *i;
+ struct ui_file *buf;
+
+ /* Get the real type of the typedef. */
+ type = check_typedef (otype);
+
+ is_anon = (TYPE_TAG_NAME (type) == NULL
+ && (TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION));
+ if (is_anon)
+ {
+ struct type *last = otype;
+
+ /* Find the last typedef for the type. */
+ while (TYPE_TARGET_TYPE (last) != NULL
+ && (TYPE_CODE (TYPE_TARGET_TYPE (last))
+ == TYPE_CODE_TYPEDEF))
+ last = TYPE_TARGET_TYPE (last);
+
+ /* If there is only one typedef for this anonymous type,
+ do not substitute it. */
+ if (type == otype)
+ return 0;
+ else
+ /* Use the last typedef seen as the type for this
+ anonymous type. */
+ type = last;
+ }
+
+ buf = mem_fileopen ();
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ type_print (type, "", buf, -1);
+ }
+
+ /* If type_print threw an exception, there is little point
+ in continuing, so just bow out gracefully. */
+ if (except.reason < 0)
+ {
+ ui_file_delete (buf);
+ return 0;
+ }
+
+ name = ui_file_obsavestring (buf, &info->obstack, &len);
+ ui_file_delete (buf);
+
+ /* 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 -- but not
+ if the type is anonymous (that would lead to infinite
+ looping). */
+ if (!is_anon)
+ replace_typedefs (info, ret_comp);
+ }
+ 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)
+ {
+ /* Copy the canonicalization into the obstack and
+ free CANON. */
+ name = copy_string_to_obstack (&info->obstack, canon, &len);
+ xfree (canon);
+ }
+
+ ret_comp->u.s_name.s = name;
+ ret_comp->u.s_name.len = len;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Replace any typedefs appearing in the qualified name
+ (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse
+ given in INFO. */
+
+static void
+replace_typedefs_qualified_name (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp)
+{
+ long len;
+ char *name;
+ struct ui_file *buf = mem_fileopen ();
+ struct demangle_component *comp = ret_comp;
+
+ /* Walk each node of the qualified name, reconstructing the name of
+ this element. With every node, check for any typedef substitutions.
+ If a substitution has occurred, replace the qualified name node
+ with a DEMANGLE_COMPONENT_NAME node representing the new, typedef-
+ substituted name. */
+ while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME)
+ {
+ if (d_left (comp)->type == DEMANGLE_COMPONENT_NAME)
+ {
+ struct demangle_component new;
+
+ ui_file_write (buf, d_left (comp)->u.s_name.s,
+ d_left (comp)->u.s_name.len);
+ name = ui_file_obsavestring (buf, &info->obstack, &len);
+ new.type = DEMANGLE_COMPONENT_NAME;
+ new.u.s_name.s = name;
+ new.u.s_name.len = len;
+ if (inspect_type (info, &new))
+ {
+ char *n, *s;
+ long slen;
+
+ /* A typedef was substituted in NEW. Convert it to a
+ string and replace the top DEMANGLE_COMPONENT_QUAL_NAME
+ node. */
+
+ ui_file_rewind (buf);
+ n = cp_comp_to_string (&new, 100);
+ if (n == NULL)
+ {
+ /* If something went astray, abort typedef substitutions. */
+ ui_file_delete (buf);
+ return;
+ }
+
+ s = copy_string_to_obstack (&info->obstack, n, &slen);
+ xfree (n);
+
+ d_left (ret_comp)->type = DEMANGLE_COMPONENT_NAME;
+ d_left (ret_comp)->u.s_name.s = s;
+ d_left (ret_comp)->u.s_name.len = slen;
+ d_right (ret_comp) = d_right (comp);
+ comp = ret_comp;
+ continue;
+ }
+ }
+ else
+ {
+ /* The current node is not a name, so simply replace any
+ typedefs in it. Then print it to the stream to continue
+ checking for more typedefs in the tree. */
+ replace_typedefs (info, d_left (comp));
+ name = cp_comp_to_string (d_left (comp), 100);
+ if (name == NULL)
+ {
+ /* If something went astray, abort typedef substitutions. */
+ ui_file_delete (buf);
+ return;
+ }
+ fputs_unfiltered (name, buf);
+ xfree (name);
+ }
+ ui_file_write (buf, "::", 2);
+ comp = d_right (comp);
+ }
+
+ /* If the next component is DEMANGLE_COMPONENT_NAME, 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)
+ {
+ ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len);
+ name = ui_file_obsavestring (buf, &info->obstack, &len);
+
+ /* 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);
+ }
+ else
+ replace_typedefs (info, comp);
+
+ ui_file_delete (buf);
+}
+
+
+/* A function to check const and volatile qualifiers for argument types.
+
+ "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. */
+
+static void
+check_cv_qualifiers (struct demangle_component *ret_comp)
+{
+ 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));
+ }
+}
+
+/* Walk the parse tree given by RET_COMP, replacing any typedefs with
+ their basic types. */
+
+static void
+replace_typedefs (struct demangle_parse_info *info,
+ struct demangle_component *ret_comp)
+{
+ if (ret_comp)
+ {
+ switch (ret_comp->type)
+ {
+ case DEMANGLE_COMPONENT_ARGLIST:
+ check_cv_qualifiers (ret_comp);
+ /* Fall through */
+
+ case DEMANGLE_COMPONENT_FUNCTION_TYPE:
+ case DEMANGLE_COMPONENT_TEMPLATE:
+ case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST:
+ case DEMANGLE_COMPONENT_TYPED_NAME:
+ replace_typedefs (info, d_left (ret_comp));
+ replace_typedefs (info, d_right (ret_comp));
+ break;
+
+ case DEMANGLE_COMPONENT_NAME:
+ inspect_type (info, ret_comp);
+ break;
+
+ case DEMANGLE_COMPONENT_QUAL_NAME:
+ replace_typedefs_qualified_name (info, ret_comp);
+ break;
+
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ case DEMANGLE_COMPONENT_CTOR:
+ case DEMANGLE_COMPONENT_ARRAY_TYPE:
+ case DEMANGLE_COMPONENT_PTRMEM_TYPE:
+ replace_typedefs (info, d_right (ret_comp));
+ break;
+
+ case DEMANGLE_COMPONENT_CONST:
+ case DEMANGLE_COMPONENT_RESTRICT:
+ case DEMANGLE_COMPONENT_VOLATILE:
+ case DEMANGLE_COMPONENT_VOLATILE_THIS:
+ case DEMANGLE_COMPONENT_CONST_THIS:
+ case DEMANGLE_COMPONENT_RESTRICT_THIS:
+ case DEMANGLE_COMPONENT_POINTER:
+ case DEMANGLE_COMPONENT_REFERENCE:
+ replace_typedefs (info, 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 all the typedefs in the tree. */
+ replace_typedefs (info, info->tree);
+
+ /* 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);
+
+ /* 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 +514,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 +544,27 @@ 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 = cp_new_demangle_parse_info ();
+ info->tree = ret;
*demangled_p = NULL;
- return ret;
+ return info;
}
}
@@ -181,16 +576,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 +596,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 +674,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 +745,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 +761,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 +777,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 +802,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 +835,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 d23f19e..51f808f 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -26,13 +26,12 @@
/* We need this for 'domain_enum', alas... */
#include "symtab.h"
-
#include "vec.h"
+#include "gdb_obstack.h"
/* Opaque declarations. */
struct symbol;
-struct obstack;
struct block;
struct objfile;
struct type;
@@ -46,6 +45,20 @@ 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;
+
+ /* Any temporary memory used during typedef replacement. */
+ struct obstack obstack;
+};
+
/* 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
@@ -134,6 +147,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);
@@ -214,12 +229,21 @@ 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 *);
+
+extern struct demangle_parse_info *cp_new_demangle_parse_info (void);
+
/* The list of "maint cplus" commands. */
extern struct cmd_list_element *maint_cplus_cmd_list;
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 137ef9c..b96c79f 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -245,7 +245,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;
@@ -1365,7 +1365,7 @@ decode_compound (char **argptr, int funfirstline,
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;
@@ -1373,6 +1373,7 @@ decode_compound (char **argptr, int funfirstline,
struct symbol *sym_class;
struct type *t;
char *saved_arg;
+ struct cleanup *cleanup;
/* If the user specified any completer quote characters in the input,
strip them. They are superfluous. */
@@ -1597,7 +1598,18 @@ 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);
+ 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
@@ -1743,7 +1755,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);
@@ -2085,16 +2097,31 @@ decode_variable (char *copy, int funfirstline,
struct linespec_result *canonical,
struct symtab *file_symtab)
{
+ char *name, *canon;
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);
+ 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);
if (sym != NULL)
- return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL);
+ {
+ do_cleanups (cleanup);
+ return symbol_found (funfirstline, canonical, copy, sym,
+ file_symtab, NULL);
+ }
- msymbol = lookup_minimal_symbol (copy, NULL, NULL);
+ msymbol = lookup_minimal_symbol (name, NULL, NULL);
+ do_cleanups (cleanup);
if (msymbol != NULL)
return minsym_found (funfirstline, msymbol);
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 8ab18cf..335342e 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/testsuite/gdb.cp/meth-typedefs.cc b/gdb/testsuite/gdb.cp/meth-typedefs.cc
new file mode 100644
index 0000000..d1b7c7f
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.cc
@@ -0,0 +1,151 @@
+/* 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 enum {E_A, E_B, E_C} anon_enum;
+typedef struct {int a; char b;} anon_struct;
+typedef union {int a; char b;} anon_union;
+typedef anon_enum aenum;
+typedef anon_struct astruct;
+typedef anon_union aunion;
+
+typedef void (*fptr1) (my_other_type);
+typedef void (*fptr2) (fptr1, my_other_type_2);
+typedef void (*fptr3) (fptr2, my_other_type);
+typedef void (*fptr4) (anon_enum a, anon_struct const& b, anon_union const*** c);
+
+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])
+ foo (aenum a, astruct const& b, aunion const*** c) { } // A::FOO::foo(aenum, astruct const&, aunion const***)
+
+ 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])
+ void test (aenum a, astruct const& b, aunion const*** c) { }; // A::FOO::test(aenum, astruct const&, aunion const***)
+ };
+
+ typedef foo FOO;
+};
+
+namespace B
+{
+ void
+ test (my_other_type foo) { } // B::test(my_other_type)
+
+ void
+ test (aenum a, astruct const& b, aunion const*** c) { } // B::test(aenum, astruct const&, aunion const***)
+
+ template <typename T1, typename T2>
+ void test (T1 a, T2 b) { } // B::test (T1, T2)
+
+ template <>
+ void test (my_other_type foo, my_other_type_2) { } // B::test<my_other_type, my_other_type_2>(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_;
+
+template <typename T1, typename T2>
+void test (T1 a, T2 b) {} // test (T1, T2)
+
+template <>
+void test (my_other_type foo, my_other_type_2) { } // test<my_other_type, my_other_type_2>(my_other_type, my_other_type_2)
+
+void
+test (my_other_type foo) { } // test(my_other_type)
+
+void
+test (_BAR_ &b) { } // test(_BAR_&)
+
+void
+test (aenum a, astruct const& b, aunion const*** c) { } // test(aenum, astruct const&, aunion const***)
+
+int
+main (void)
+{
+ A::FOO my_foo;
+ fptr1 fptr;
+ astruct as = { 0, 0 };
+ aunion const au = { 0 };
+ aunion const* aup = &au;
+ aunion const** aupp = &aup;
+ aunion const*** auppp = &aupp;
+
+ my_foo.test (static_cast<my_other_type> (NULL));
+ my_foo.test (0);
+ my_foo.test (0, static_cast<my_type> (NULL));
+ my_foo.test (static_cast<fptr3> (NULL));
+ my_foo.test (&fptr);
+ my_foo.test (static_cast<CORE_ADDR (*) [10]> (0));
+ my_foo.test (E_A, as, auppp);
+
+ B::test (static_cast<my_other_type> (NULL));
+ B::test (static_cast<my_other_type> (NULL), 0);
+ B::test (E_A, as, auppp);
+
+ test (static_cast<my_other_type> (NULL));
+ test<my_other_type, my_other_type_2> (static_cast<my_other_type> (NULL), 0);
+ test (E_A, as, auppp);
+
+ A::foo a (static_cast<my_other_type> (NULL));
+ A::foo b (0);
+ A::foo c (0, static_cast<my_other_type> (NULL));
+ A::foo d (static_cast<fptr3> (NULL));
+ A::foo e (&fptr);
+ A::foo f (static_cast<CORE_ADDR (*) [10]> (0));
+ A::foo g (E_A, as, auppp);
+
+ fptr4 f4;
+
+ 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..f80a735
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -0,0 +1,160 @@
+# 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 {kind {func}}} {
+ upvar $var result
+
+ if {[string compare $kind "template"] == 0} {
+ set method_name "${name}<$expected>"
+ } else {
+ set method_name "$name"
+ }
+
+ set expect ".*// ${method_name}\\($expected\\)"
+ lappend result [list "${method_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" }
+ "aenum" { "aenum" "anon_enum" }
+ "astruct" { "astruct" "anon_struct" }
+ "aunion" { "aunion" "anon_union" }
+}
+
+set methods {}
+
+# Add the simple, one-parameter methods
+foreach meth {A::FOO::test A::FOO::foo} {
+ foreach type {my_other_type my_other_type_2} {
+ foreach t $typedefs($type) {
+ add methods $meth $t $type
+ }
+ }
+}
+
+# Add two-parameter methods
+foreach meth {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 $meth "$t1, const $t2" $type
+ add methods $meth "$t1, $t2" $type
+ }
+ }
+}
+
+# Add three-parameter methods/functions
+foreach meth {A::FOO::test A::FOO::foo B::test test} {
+ set type "aenum, astruct const&, aunion const\\*\\*\\*"
+ foreach t1 $typedefs(aenum) {
+ foreach t2 $typedefs(astruct) {
+ foreach t3 $typedefs(aunion) {
+ add methods $meth "$t1, $t2 const&, $t3 const***" $type
+ }
+ }
+ }
+}
+
+# Add the array-of-function pointer methods
+set type "fptr1\\*"
+foreach meth {A::FOO::test A::FOO::foo} {
+ add methods $meth "fptr1*" $type
+ foreach t $typedefs(my_other_type) {
+ add methods $meth "void (**) ($t)" $type
+ }
+}
+
+# Add the function pointer methods
+set type "fptr3"
+foreach meth {A::FOO::test A::FOO::foo} {
+ add methods $meth "fptr3" $type
+
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth "void (*)(fptr2, $t1)" $type
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "void (*)(void (*)(fptr1, $t2), $t1)" $type
+ foreach t3 $typedefs(my_other_type) {
+ add methods $meth \
+ "void (*)(void (*)(void (*) ($t3), $t2), $t1)" $type
+ }
+ }
+ }
+}
+
+set type1 "my_other_type"
+set type2 "my_other_type, my_other_type_2"
+foreach meth {"test" "B::test"} {
+ foreach t1 $typedefs(my_other_type) {
+ add methods $meth $t1 $type1
+ foreach t2 $typedefs(my_other_type_2) {
+ add methods $meth "$t1, $t2" $type2 template
+ }
+ }
+}
+
+# Miscellaneous tests
+set type {CORE_ADDR \(\*\) \[10\]}
+foreach meth {A::FOO::foo A::FOO::test} {
+ foreach t $typedefs(CORE_ADDR) {
+ add methods $meth "$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
+ 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] 13+ messages in thread
end of thread, other threads:[~2011-08-18 16:35 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-29 13:16 [RFA] c++/12266 (again) Keith Seitz
2011-08-01 20:38 ` Tom Tromey
2011-08-02 16:08 ` Tom Tromey
2011-08-02 17:58 ` Keith Seitz
2011-08-02 20:28 ` [RFA] c++/12266 (again) [cp_demangled_name_parse_free-4.patch] Jan Kratochvil
2011-08-09 20:23 ` Keith Seitz
2011-08-13 16:51 ` Jan Kratochvil
2011-08-18 16:22 ` Keith Seitz
2011-08-02 20:37 ` [RFA] c++/12266 (again) [cp_canonicalize_no_typedefs-4.patch] Jan Kratochvil
2011-08-09 20:48 ` Keith Seitz
2011-08-13 16:50 ` Jan Kratochvil
2011-08-18 16:25 ` Keith Seitz
2011-08-18 16:35 ` Keith Seitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox