diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index f745a31..f7060fa 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -1979,6 +1979,27 @@ cp_demangled_name_parse_free (struct demangle_parse_info *parse_info) free (parse_info); } +/* Merge the two parse trees given by DEST and SRC. The parse tree + in SRC is attached to DEST at the node represented by TARGET. + SRC is then freed. */ + +void +cp_merge_demangle_parse_infos (struct demangle_parse_info *dest, + struct demangle_component *target, + struct demangle_parse_info *src) + +{ + struct demangle_info *di; + + memcpy (target, src->tree, sizeof (struct demangle_component)); + di = dest->info; + while (di->next != NULL) + di = di->next; + di->next = src->info; + src->info = NULL; + cp_demangled_name_parse_free (src); +} + /* A cleanup wrapper for cp_demangled_name_parse_free. */ static void diff --git a/gdb/cp-support.c b/gdb/cp-support.c index b67dedc..10335ee 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -86,6 +86,17 @@ static const char *operator_tokens[] = /* new[] and delete[] require special whitespace handling */ }; +/* A vector used to define a free list for typedef replacement + (replace_typedefs/inspect_type). See cp_canonicalize_string_no_typdefs + and inspect_type for more information. */ +typedef char *namep; +DEF_VEC_P (namep); + +static void +replace_typedefs (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + VEC (namep) *free_list); + /* Return 1 if STRING is clearly already in canonical form. This function is conservative; things which it does not recognize are assumed to be non-canonical, and the parser will sort them out @@ -117,6 +128,247 @@ cp_already_canonical (const char *string) return 0; } +/* Inspect the given RET_COMP for its type. If it is a typedef, + replace the node with the typedef's tree, storing any memory allocations + on the FREE_LIST. */ + +static void +inspect_type (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + VEC (namep) *free_list) +{ + char *name; + struct symbol *sym; + + /* Copy the symbol's name from RET_COMP and look it up + in the symbol table. */ + name = (char *) alloca (ret_comp->u.s_name.len + 1); + memcpy (name, ret_comp->u.s_name.s, ret_comp->u.s_name.len); + name[ret_comp->u.s_name.len] = '\0'; + sym = lookup_symbol (name, 0, VAR_DOMAIN, 0); + if (sym != NULL) + { + struct type *type = SYMBOL_TYPE (sym); + + /* If the type is a typedef, replace it. */ + if (TYPE_CODE (type) == TYPE_CODE_TYPEDEF) + { + long len; + struct demangle_parse_info *i; + struct ui_file *buf = mem_fileopen (); + struct cleanup *cleanup = make_cleanup_ui_file_delete (buf); + + CHECK_TYPEDEF (type); + type_print (type, "", buf, -1); + name = ui_file_xstrdup (buf, &len); + VEC_safe_push (namep, free_list, name); + do_cleanups (cleanup); + + /* Turn the result into a new tree. Note that this + tree will contain pointers into NAME, so NAME cannot + be free'd until all typedef conversion is done and + the final result is converted into a string. */ + i = cp_demangled_name_to_comp (name, NULL); + if (i != NULL) + { + /* Merge the two trees. */ + cp_merge_demangle_parse_infos (info, ret_comp, i); + + /* Replace any newly introduced typedefs. */ + replace_typedefs (info, ret_comp, free_list); + } + else + { + /* This shouldn't happen unless the type printer has + output something that the name parser cannot grok. + Nonetheless, an ounce of prevention... + + Canonicalize the name again, and store it in the + current node (RET_COMP). */ + char *canon = cp_canonicalize_string_no_typedefs (name); + + if (canon != NULL) + { + xfree (name); + name = canon; + } + + ret_comp->u.s_name.s = name; + ret_comp->u.s_name.len = len; + } + } + } +} + +/* Replace any typdefs appearing in the qualified name + (DEMANGLE_COMPONENT_QUAL_NAME) represented in RET_COMP for the name parse + given in INFO. Store any transient memory in FREE_LIST. */ + +static void +replace_typedefs_qualified_name (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + VEC (namep) *free_list) +{ + struct ui_file *buf = mem_fileopen (); + struct demangle_component *comp = ret_comp; + + /* Qualified names come in pieces -- the left subtree + points at the current qualifier's name and the right + subtree points to either the next qualifier or the final + name component. Smash all these components back together + to make a single DEMANGLE_COMPONENT_NAME node again + which can be looked up by inspect_type. */ + + while (comp->type == DEMANGLE_COMPONENT_QUAL_NAME) + { + ui_file_write (buf, d_left (comp)->u.s_name.s, + d_left (comp)->u.s_name.len); + ui_file_write (buf, "::", 2); + comp = d_right (comp); + } + + /* If the next component is DEMANGLE_COMPONENT_NAME, the user + may have entered a typedef, e.g., "std::string". In this case, + save the qualified name assembled above and append the + name given by COMP. Then use this reassembled name to check + for a typedef. */ + + if (comp->type == DEMANGLE_COMPONENT_NAME) + { + long len; + char *name; + + ui_file_write (buf, comp->u.s_name.s, comp->u.s_name.len); + name = ui_file_xstrdup (buf, &len); + VEC_safe_push (namep, free_list, name); + + /* Replace the top (DEMANGLE_COMPONENT_QUAL_NAME) node + with a DEMANGLE_COMPONENT_NAME node containing the whole + name. */ + ret_comp->type = DEMANGLE_COMPONENT_NAME; + ret_comp->u.s_name.s = name; + ret_comp->u.s_name.len = len; + inspect_type (info, ret_comp, free_list); + } + else + replace_typedefs (info, comp, free_list); + + ui_file_delete (buf); +} + +/* Walk the parse tree given by RET_COMP, replacing any typedefs with + their basic types. Any required memory allocations are added + to the FREE_LIST, which must be free'd by a caller. */ + +static void +replace_typedefs (struct demangle_parse_info *info, + struct demangle_component *ret_comp, + VEC (namep) *free_list) +{ + if (ret_comp) + { + switch (ret_comp->type) + { + case DEMANGLE_COMPONENT_ARGLIST: + /* "Parameter declarations that differ only in the presence + or absence of `const' and/or `volatile' are equivalent." + C++ Standard N3290, clause 13.1.3 #4. */ + while (d_left (ret_comp) != NULL + && (d_left (ret_comp)->type == DEMANGLE_COMPONENT_CONST + || d_left (ret_comp)->type == DEMANGLE_COMPONENT_VOLATILE)) + { + d_left (ret_comp) = d_left (d_left (ret_comp)); + } + /* Fall through */ + + case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: + replace_typedefs (info, d_left (ret_comp), free_list); + replace_typedefs (info, d_right (ret_comp), free_list); + break; + + case DEMANGLE_COMPONENT_NAME: + inspect_type (info, ret_comp, free_list); + break; + + case DEMANGLE_COMPONENT_QUAL_NAME: + replace_typedefs_qualified_name (info, ret_comp, free_list); + break; + + case DEMANGLE_COMPONENT_FUNCTION_TYPE: + case DEMANGLE_COMPONENT_LOCAL_NAME: + case DEMANGLE_COMPONENT_TYPED_NAME: + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_ARRAY_TYPE: + case DEMANGLE_COMPONENT_PTRMEM_TYPE: + case DEMANGLE_COMPONENT_TEMPLATE: + replace_typedefs (info, d_right (ret_comp), free_list); + break; + + case DEMANGLE_COMPONENT_POINTER: + case DEMANGLE_COMPONENT_REFERENCE: + replace_typedefs (info, d_left (ret_comp), free_list); + break; + + default: + break; + } + } +} + +/* Parse STRING and convert it to canonical form, resolving any typedefs. + If parsing fails, or if STRING is already canonical, return NULL. + Otherwise return the canonical form. The return value is allocated via + xmalloc. */ + +char * +cp_canonicalize_string_no_typedefs (const char *string) +{ + char *ret; + unsigned int estimated_len; + struct demangle_parse_info *info; + VEC (namep) *free_list; + + ret = NULL; + free_list = VEC_alloc (namep, 10); + estimated_len = strlen (string) * 2; + info = cp_demangled_name_to_comp (string, NULL); + if (info != NULL) + { + /* Replace all the typedefs in the tree. */ + replace_typedefs (info, info->tree, free_list); + + /* Convert the tree back into a string. */ + ret = cp_comp_to_string (info->tree, estimated_len); + gdb_assert (ret != NULL); + + /* Free the parse information. */ + cp_demangled_name_parse_free (info); + + /* Free any memory allocated during typedef replacement. */ + if (!VEC_empty (namep, free_list)) + { + int i; + char *iter; + + for (i = 0; VEC_iterate (namep, free_list, i, iter); ++i) + xfree (iter); + } + + /* Free the vector used for the free list. */ + VEC_free (namep, free_list); + + /* Finally, compare the original string with the computed + name, returning NULL if they are the same. */ + if (strcmp (string, ret) == 0) + { + xfree (ret); + return NULL; + } + } + + return ret; +} + /* Parse STRING and convert it to canonical form. If parsing fails, or if STRING is already canonical, return NULL. Otherwise return the canonical form. The return value is allocated via xmalloc. */ diff --git a/gdb/cp-support.h b/gdb/cp-support.h index 4e90d0c..c570a1e 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -119,6 +119,8 @@ struct using_direct extern char *cp_canonicalize_string (const char *string); +extern char *cp_canonicalize_string_no_typedefs (const char *string); + extern char *cp_class_name_from_physname (const char *physname); extern char *method_name_from_physname (const char *physname); @@ -205,6 +207,9 @@ extern char *cp_comp_to_string (struct demangle_component *result, extern void cp_demangled_name_parse_free (struct demangle_parse_info *); extern struct cleanup *make_cleanup_cp_demangled_name_parse_free (struct demangle_parse_info *); +extern void cp_merge_demangle_parse_infos (struct demangle_parse_info *, + struct demangle_component *, + struct demangle_parse_info *); /* The list of "maint cplus" commands. */ diff --git a/gdb/linespec.c b/gdb/linespec.c index c820539..b2edc83 100644 --- a/gdb/linespec.c +++ b/gdb/linespec.c @@ -249,7 +249,7 @@ find_methods (struct type *t, char *name, enum language language, /* NAME is typed by the user: it needs to be canonicalized before passing to lookup_symbol. */ - canon = cp_canonicalize_string (name); + canon = cp_canonicalize_string_no_typedefs (name); if (canon != NULL) { name = canon; @@ -1357,7 +1357,7 @@ decode_compound (char **argptr, int funfirstline, char *the_real_saved_arg, char *p) { struct symtabs_and_lines values; - char *p2; + char *p2, *name; char *saved_arg2 = *argptr; char *temp_end; struct symbol *sym; @@ -1366,6 +1366,7 @@ decode_compound (char **argptr, int funfirstline, struct type *t; char *saved_java_argptr = NULL; char *saved_arg; + struct cleanup *cleanup; /* If the user specified any completer quote characters in the input, strip them. They are superfluous. */ @@ -1633,7 +1634,21 @@ decode_compound (char **argptr, int funfirstline, *argptr = (*p == '\'') ? p + 1 : p; /* Look up entire name. */ - sym = lookup_symbol (copy, get_selected_block (0), VAR_DOMAIN, 0); + name = copy; + + cleanup = make_cleanup (null_cleanup, NULL); + if (current_language->la_language == language_cplus) + { + char *canon = cp_canonicalize_string_no_typedefs (copy); + if (canon != NULL) + { + name = canon; + make_cleanup (xfree, name); + } + } + + sym = lookup_symbol (name, get_selected_block (0), VAR_DOMAIN, 0); + do_cleanups (cleanup); if (sym) return symbol_found (funfirstline, canonical, copy, sym, NULL, NULL); else @@ -1776,7 +1791,7 @@ find_method (int funfirstline, struct linespec_result *canonical, strcpy (name, SYMBOL_NATURAL_NAME (sym_class)); strcat (name, "::"); strcat (name, copy); - canon = cp_canonicalize_string (name); + canon = cp_canonicalize_string_no_typedefs (name); if (canon != NULL) { xfree (name); @@ -2118,11 +2133,26 @@ decode_variable (char *copy, int funfirstline, struct linespec_result *canonical, struct symtab *file_symtab) { + char *name; struct symbol *sym; + struct cleanup *cleanup; struct minimal_symbol *msymbol; - sym = lookup_symbol (copy, get_search_block (file_symtab), - VAR_DOMAIN, 0); + name = copy; + cleanup = make_cleanup (null_cleanup, NULL); + if (current_language->la_language == language_cplus) + { + char *canon = cp_canonicalize_string_no_typedefs (copy); + + if (canon != NULL) + { + name = canon; + make_cleanup (xfree, name); + } + } + + sym = lookup_symbol (name, get_search_block (file_symtab), VAR_DOMAIN, 0); + do_cleanups (cleanup); if (sym != NULL) return symbol_found (funfirstline, canonical, copy, sym, file_symtab, NULL); diff --git a/gdb/typeprint.h b/gdb/typeprint.h index b271bcc..49cd122 100644 --- a/gdb/typeprint.h +++ b/gdb/typeprint.h @@ -23,7 +23,7 @@ enum language; struct ui_file; -/* An enumeration for specifying the type of a computed symobl name. */ +/* An enumeration for specifying the type of a computed symbol name. */ enum name_kind { NAME_KIND_FULL, /* The fullname (methods do not