Create search_name and fixed template lookup 2010-07-15 Sami Wagiaalla * valops.c (find_overload_match): Use SYMBOL_SEARCH_NAME instead of SYMBOL_NATURAL_NAME. * symtab.h: Added new member search_name to cplus_specific. (symbol_set_cplus_search_name): New function prototype. (symbol_get_cplus_search_name): New function prototype. * symtab.c (symbol_set_cplus_search_name): New function. (symbol_get_cplus_search_name): New function. (symbol_search_name): Handle the C++ case. (symbol_matches_template_name): New function. * dwarf2read.c (new_symbol): Set search_name of C++ template symbols. * cp-support.H (cp_name_has_template_parameters): New function prototype. (cp_remove_template_params): New function ptototype. * cp-support.c (cp_name_has_template_parameters): New function. (cp_remove_template_params_component): New function. (cp_remove_template_params): New function. (overload_list_add_symbol): Use SYMBOL_SEARCH_NAME instead of SYMBOL_NATURAL_NAME. * cp-name-parser.y (cp_demangled_name_to_comp): Added more detail to comment. 2010-07-15 Sami Wagiaalla * gdb.cp/temp-op.exp: New test. * gdb.cp/temp-op.cc: New test. * gdb.cp/cp-relocate.exp: Set the language C++. diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y index 6d7b600..c9b5747 100644 --- a/gdb/cp-name-parser.y +++ b/gdb/cp-name-parser.y @@ -1966,9 +1966,12 @@ cp_comp_to_string (struct demangle_component *result, int estimated_len) &err); } -/* 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 +/* Convert a demangled name to a demangle_component tree. The structure + of the tree depends on the format of each node in the tree. For + information on the structure of a node see the comment corresponding + to its type in demangle_component_type. + 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 returned, and an error message will be set in *ERRMSG (which does not need to be freed). */ diff --git a/gdb/cp-support.c b/gdb/cp-support.c index 41af7ae..4ef1a0a 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -428,6 +428,72 @@ cp_remove_params (const char *demangled_name) return ret; } +/* Returns 1 if the given name contains template parameters; + otherwise return 0. + Used as a quick heuristic to avoid more expensive template + parsing when not necessary. */ + +int +cp_name_has_template_parameters (const char *name) +{ + char *c = strchr (name, '<'); + return c != NULL && strchr (c+1, '>') != NULL; +} + +/* Remove template parameters components from the give tree. */ + +static struct demangle_component * +cp_remove_template_params_component (struct demangle_component *comp) +{ + + gdb_assert (comp != NULL); + + switch (comp->type) + { + case DEMANGLE_COMPONENT_TEMPLATE: + /* If there is a template component remove this node by re-parenting the + the left child. */ + comp = d_left (comp); + break; + case DEMANGLE_COMPONENT_QUAL_NAME: + /* For a qualified name remove template components from the right + subtree. */ + d_right (comp) = cp_remove_template_params_component (d_right (comp)); + break; + case DEMANGLE_COMPONENT_TYPED_NAME: + /* Template components, if present, will be in the left subtree. Remove + them. */ + d_left (comp) = cp_remove_template_params_component (d_left (comp)); + break; + default: + break; + } + + return comp; +} + +/* Remove template parameters from the given name. The returned string is + malloc'ed and must be properly saved and freed. */ + +char * +cp_remove_template_params (const char *name) +{ + struct demangle_component *ret_comp; + char *ret = NULL; + + if (name == NULL) + return NULL; + + ret_comp = cp_demangled_name_to_comp (name, NULL); + if (ret_comp == NULL) + return NULL; + + ret_comp = cp_remove_template_params_component (ret_comp); + ret = cp_comp_to_string (ret_comp, 10); + + return ret; +} + /* Here are some random pieces of trivia to keep in mind while trying to take apart demangled names: @@ -661,7 +727,7 @@ overload_list_add_symbol (struct symbol *sym, const char *oload_name) return; /* Get the demangled name without parameters */ - sym_name = cp_remove_params (SYMBOL_NATURAL_NAME (sym)); + sym_name = cp_remove_params (SYMBOL_SEARCH_NAME (sym)); if (!sym_name) return; diff --git a/gdb/cp-support.h b/gdb/cp-support.h index ddc4c93..a2c8f7f 100644 --- a/gdb/cp-support.h +++ b/gdb/cp-support.h @@ -107,6 +107,10 @@ extern char *cp_func_name (const char *full_name); extern char *cp_remove_params (const char *demangled_name); +extern int cp_name_has_template_parameters (const char *name); + +extern char *cp_remove_template_params (const char *name); + extern struct symbol **make_symbol_overload_list (const char *, const char *); diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index a8692ea..e4abd23 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -8661,6 +8661,7 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) if (name) { const char *linkagename; + const char *search_name = NULL; sym = (struct symbol *) obstack_alloc (&objfile->objfile_obstack, sizeof (struct symbol)); @@ -8680,6 +8681,26 @@ new_symbol (struct die_info *die, struct type *type, struct dwarf2_cu *cu) (char *) dwarf2_full_name (name, die, cu), NULL); + /* For C++ if the name contains template parameters remove them, and set + the cleaned up name to be the search name. */ + if (cu->language == language_cplus && linkagename + && cp_name_has_template_parameters (linkagename)) + { + char *tmp = cp_remove_template_params (linkagename); + + if (tmp != NULL && strcmp (tmp, linkagename) != 0) + { + search_name = obsavestring (tmp, strlen (tmp), + &objfile->objfile_obstack); + + symbol_set_cplus_search_name (&sym->ginfo, + objfile, + search_name); + } + + xfree (tmp); + } + /* Default assumptions. Use the passed type or decode it from the die. */ SYMBOL_DOMAIN (sym) = VAR_DOMAIN; diff --git a/gdb/symtab.c b/gdb/symtab.c index 2232114..70feb62 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -389,6 +389,30 @@ symbol_get_demangled_name (const struct general_symbol_info *gsymbol) return gsymbol->language_specific.mangled_lang.demangled_name; } +/* Set the search name of the give GSYMBOL to name. */ +void +symbol_set_cplus_search_name (struct general_symbol_info *gsymbol, + struct objfile *objfile, + const char *name) +{ + if (gsymbol->language_specific.cplus_specific == NULL) + symbol_init_cplus_specific (gsymbol, objfile); + + gsymbol->language_specific.cplus_specific->search_name = (char *) name; +} + +/* Get the search name of the give GSYMBOL. */ + +char* +symbol_get_cplus_search_name (const struct general_symbol_info *gsymbol) +{ + if (gsymbol->language_specific.cplus_specific != NULL + && gsymbol->language_specific.cplus_specific->search_name != NULL) + return gsymbol->language_specific.cplus_specific->search_name; + + return symbol_natural_name (gsymbol); +} + /* Initialize the language dependent portion of a symbol depending upon the language for the symbol. */ @@ -753,6 +777,8 @@ symbol_search_name (const struct general_symbol_info *gsymbol) { if (gsymbol->language == language_ada) return gsymbol->name; + else if (gsymbol->language == language_cplus) + return symbol_get_cplus_search_name (gsymbol); else return symbol_natural_name (gsymbol); } @@ -1656,6 +1682,18 @@ find_main_filename (void) return (NULL); } +/* Return 1 if NAME matches SYM's template name. */ + +static int +symbol_matches_template_name (const char *name, struct symbol *sym) +{ + const char *template_name = SYMBOL_NATURAL_NAME(sym); + if (template_name == NULL) + return 0; + + return strcmp_iw (template_name, name) == 0; +} + /* Search BLOCK for symbol NAME in DOMAIN. Note that if NAME is the demangled form of a C++ symbol, we will fail @@ -1677,10 +1715,29 @@ lookup_block_symbol (const struct block *block, const char *name, if (!BLOCK_FUNCTION (block)) { + const char *template_name = NULL; + + if (current_language->la_language == language_cplus + && cp_name_has_template_parameters (name)) + { + template_name = name; + name = cp_remove_template_params (name); + + if (name == NULL) + /* Not a legal C++ name. */ + return NULL; + } + for (sym = dict_iter_name_first (BLOCK_DICT (block), name, &iter); sym != NULL; sym = dict_iter_name_next (name, &iter)) { + /* For C++ if the name being searched for contains template + parameters check the template name of the symbol. */ + if (template_name != NULL + && !symbol_matches_template_name (template_name, sym)) + continue; + if (symbol_matches_domain (SYMBOL_LANGUAGE (sym), SYMBOL_DOMAIN (sym), domain)) return sym; diff --git a/gdb/symtab.h b/gdb/symtab.h index e6ab26f..d3d85cf 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -80,6 +80,11 @@ struct program_space; struct cplus_specific { char *demangled_name; + + /* If the symbol name contains template parameters this is the name with + these parameters removed to be used during search. Otherwise this + should be NULL, and the regular symbol name should be used. */ + char *search_name; }; /* Define a structure for the information that is common to all symbol types, @@ -166,6 +171,13 @@ extern void symbol_set_demangled_name (struct general_symbol_info *, char *, extern char *symbol_get_demangled_name (const struct general_symbol_info *); +/* Set the template name of the give GSYMBOL to name. */ +extern void symbol_set_cplus_search_name (struct general_symbol_info *gsymbol, + struct objfile *objfile, + const char *name); + +extern char* symbol_get_cplus_search_name (const struct general_symbol_info *); + extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, struct obj_section *); /* Note that all the following SYMBOL_* macros are used with the @@ -273,6 +285,7 @@ extern char *symbol_demangled_name (const struct general_symbol_info *symbol); (symbol_search_name (&(symbol)->ginfo)) extern char *symbol_search_name (const struct general_symbol_info *); + /* Analogous to SYMBOL_MATCHES_NATURAL_NAME, but uses the search name. */ #define SYMBOL_MATCHES_SEARCH_NAME(symbol, name) \ diff --git a/gdb/testsuite/gdb.cp/cp-relocate.exp b/gdb/testsuite/gdb.cp/cp-relocate.exp index 30d362a..880ad38 100644 --- a/gdb/testsuite/gdb.cp/cp-relocate.exp +++ b/gdb/testsuite/gdb.cp/cp-relocate.exp @@ -52,6 +52,8 @@ gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_file_cmd ${binfile} +gdb_test_no_output "set language c++" "" + # Find the interesting functions. We go to a little effort to find # the right function names here, to work around PR c++/40. set func1_name "" @@ -123,6 +125,8 @@ gdb_exit gdb_start gdb_reinitialize_dir $srcdir/$subdir +gdb_test_no_output "set language c++" "" + gdb_test "add-symbol-file ${binfile} 0 -s ${func1_sec} 0x10000 -s ${func2_sec} 0x20000" \ "Reading symbols from .*${testfile}\\.o\\.\\.\\.done\\.(|\r\nUsing host libthread_db library .*libthread_db.so.*\\.)" \ "add-symbol-file ${testfile}.o" \ diff --git a/gdb/testsuite/gdb.cp/temp-op.cc b/gdb/testsuite/gdb.cp/temp-op.cc new file mode 100644 index 0000000..6d4b13d --- /dev/null +++ b/gdb/testsuite/gdb.cp/temp-op.cc @@ -0,0 +1,105 @@ +class A +{ +}; + +template +int foo (T, char) +{ + T t; + return 11; +} + +template +int foo2 (T, T2, char) +{ + T t; + return 11; +} + +namespace C +{ + namespace D { + template + int foo3 (T, T2, char) + { + T t; + return 11; + } + } +} +int operator<< (A, int) +{ + return 12; +} + +int operator< (A, int) +{ + return 13; +} + +int operator<= (A, int) +{ + return 14; +} + +template +int operator==(T, char) +{ + return 15; +} + +int operator==(A, int) +{ + return 16; +} + +template +class B{ + T t; +public: + int operator==(int) + { + return 17; + } +}; + +int operator== (B, char){ + return 18; +} + +template +class Outer{ + public: + template + class Inner{ + public: + template + class ReallyInner{}; + }; +}; + + +int main () +{ + A a; + + foo (a, 'a'); + foo (a, 1); + foo2 (a, a, 'a'); + C::D::foo3 (a, a, 'a'); + + a << 22; + a < 22; + a <= 22; + + a == 'a'; + a == 1; + + B b; + b == 1; + b == 'a'; + + Outer::Inner::ReallyInner<5> oir; + + return 0; +} diff --git a/gdb/testsuite/gdb.cp/temp-op.exp b/gdb/testsuite/gdb.cp/temp-op.exp new file mode 100644 index 0000000..f48582f --- /dev/null +++ b/gdb/testsuite/gdb.cp/temp-op.exp @@ -0,0 +1,68 @@ +# Copyright 2008 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 . + +if $tracelevel then { + strace $tracelevel +} + +set testfile temp-op +set srcfile ${testfile}.cc +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } { + untested "Couldn't compile test program" + return -1 +} + +# Get things started. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +############################################ + +if ![runto_main] then { + perror "couldn't run to breakpoint main" + continue +} + +# Test that a templated function can be found +# with out specification of template arguments +gdb_test "p foo(a, 'a')" "= 11" + +# Test that function names with '<' in their names +# are not mistaken for templates +gdb_test "p a << 22" "= 12" +gdb_test "p a < 22" "= 13" +gdb_test "p a <= 22" "= 14" + +# Test that a template operator can be correctly +# evaluated +gdb_test "p a == 'a'" "= 15" + +# Test that overload resolution is still correctly +# performed. +gdb_test "p a == 1" "= 16" + +# Test calling a member function of a template class +gdb_test "p b == 1" "= 17" +gdb_test "p b == 'a'" "= 18" + +# Test that printing the a template name without +# template parameters does not return an arbitrary match + +gdb_test "p foo" "No symbol \"foo\" in current context" +gdb_test "ptype B" "No symbol \"foo\" in current context" diff --git a/gdb/valops.c b/gdb/valops.c index 506d40e..59ec3ee 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -2458,7 +2458,7 @@ find_overload_match (struct type **arg_types, int nargs, if (fsym) { - qualified_name = SYMBOL_NATURAL_NAME (fsym); + qualified_name = SYMBOL_SEARCH_NAME (fsym); /* If we have a function with a C++ name, try to extract just the function part. Do not try this for non-functions (e.g.