diff options
-rw-r--r-- | gdb/NEWS | 4 | ||||
-rw-r--r-- | gdb/cp-support.c | 8 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 46 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/templates.cc | 47 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/templates.exp | 67 | ||||
-rw-r--r-- | gdb/testsuite/gdb.linespec/cpcompletion.exp | 437 | ||||
-rw-r--r-- | gdb/testsuite/gdb.linespec/cpls-ops.exp | 53 | ||||
-rw-r--r-- | gdb/testsuite/gdb.linespec/cpls.cc | 110 | ||||
-rw-r--r-- | gdb/utils.c | 82 | ||||
-rw-r--r-- | gdb/utils.h | 7 |
10 files changed, 821 insertions, 40 deletions
@@ -6,6 +6,10 @@ * 'info proc' now works on running processes on FreeBSD systems and core files created on FreeBSD systems. +* C++ developers may now ignore template parameter lists when specifying + locations, e.g., while setting breakpoints. This is analogous to how + completion and symbol lookup handles overloaded functions or ABI tags. + *** Changes in GDB 8.1 * GDB now supports dynamically creating arbitrary register groups specified diff --git a/gdb/cp-support.c b/gdb/cp-support.c index dde417b..e8b21c3 100644 --- a/gdb/cp-support.c +++ b/gdb/cp-support.c @@ -1643,6 +1643,12 @@ cp_search_name_hash (const char *search_name) && string[5] != ':') break; + /* Ignore template parameter lists. */ + if (string[0] == '<' + && string[1] != '(' && string[1] != '<' && string[1] != '=' + && string[1] != ' ' && string[1] != '\0') + break; + hash = SYMBOL_HASH_NEXT (hash, *string); } return hash; @@ -1696,7 +1702,7 @@ cp_symbol_name_matches_1 (const char *symbol_search_name, while (true) { if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len, - mode, language_cplus, match_for_lcd) == 0) + mode, language_cplus, match_for_lcd, true) == 0) { if (comp_match_res != NULL) { diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index ee7adc8..ba34019 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -15188,6 +15188,52 @@ also use the @value{GDBN} command-line word completion facilities to list the available choices, or to finish the type list for you. @xref{Completion,, Command Completion}, for details on how to do this. +@item @r{Breakpoints in template functions} + +Similar to overloaded symbols, @value{GDBN} will set breakpoints in all +template instantiations with the user-specified name. To set a breakpoint in +a specific template instantiation, include the template parameter list. + +@smallexample +(gdb) b mytemplate +Breakpoint 1 at 0x40085b: mytemplate. (2 locations) +(gdb) info breakpoints +Num Type Disp Enb Address What +1 breakpoint keep y <MULTIPLE> +1.1 y 0x40085b in mytemplate<int>(int) + at mytemplate.cc:8 +1.2 y 0x40087a in mytemplate<double>(double) + at mytemplate.cc:8 +@end smallexample + +@noindent +In the above example, @value{GDBN} searches all namespaces and types for +functions named @code{mytemplate}, ignoring template parameter lists and +function arguments. + +In the below example, a template parameter list is specified, and @value{GDBN} +searches all namespaces and types for the specific instantiation: + +@smallexample +(gdb) b mytemplate<int> +Breakpoint 2 at 0x40085b: file mytemplate.cc, line 8. +(gdb) info breakpoints +Num Type Disp Enb Address What +2 breakpoint keep y 0x40085b in mytemplate<int>(int) + at mytemplate.cc:8 +@end smallexample + +Just as with function overloads, the @kbd{-qualified} flag may be used to +override this behavior, causing @value{GDBN} to search for a specific +function without ignoring template parameter lists. + +@smallexample +(gdb) b mytemplate +Breakpoint 3 at 0x40085b: mytemplate. (2 locations) +(gdb) b -qualified mytemplate +Function "mytemplate" not defined. +@end smallexample + @item @r{Breakpoints in functions with ABI tags} The GNU C@t{++} compiler introduced the notion of ABI ``tags'', which diff --git a/gdb/testsuite/gdb.cp/templates.cc b/gdb/testsuite/gdb.cp/templates.cc index db2dfe8..1a0500d 100644 --- a/gdb/testsuite/gdb.cp/templates.cc +++ b/gdb/testsuite/gdb.cp/templates.cc @@ -747,6 +747,34 @@ template<class C> int FunctionArg<C>::method(Empty<void (FunctionArg<C>)> &arg) Empty<void(FunctionArg<int>)> empty; FunctionArg<int> arg; +template <typename T1> +struct Foozle +{ + int x; + T1 t; + template <typename T2> + T2 fogey (T2 plop); +}; + +template <typename T1> +template <typename T2> +T2 Foozle<T1>::fogey (T2 plop) +{ + return plop; +} + +template <typename T> +int operator< (T &lhs, T &rhs) +{ + return 0; +} + +template <typename T> +int operator<< (T &obj, T &val) +{ + return 1; +}; + int main() { int i; @@ -818,5 +846,24 @@ int main() arg.method(empty); + Empty<int> e; + Foozle<int> fzi; + x = fzi.fogey (0); + c = fzi.fogey<char> ('a'); + e = fzi.fogey<Empty<int>> (e); + Foozle<char> fzc; + c = fzc.fogey ('b'); + x = fzc.fogey<int> (0); + e = fzc.fogey<Empty<int>> (e); + Foozle<Empty<int>> fze; + e = fze.fogey (e); + c = fze.fogey<char> ('c'); + x = fze.fogey<int> (0); + + z = e < e; + z += e << e; + z += fzi < fzi; + z += fzi << fzi; + return 0; // break here } diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp index af72268..8b4c7d7 100644 --- a/gdb/testsuite/gdb.cp/templates.exp +++ b/gdb/testsuite/gdb.cp/templates.exp @@ -580,3 +580,70 @@ gdb_test "print Garply<Garply<char> >::garply" \ # Now should work fine gdb_test "break Garply<Garply<char> >::garply" \ "Breakpoint \[0-9\]* at $hex: file .*templates.cc, line.*" + +# +# Template wild-matching tests +# + +# Turn off "ask" when multiple symbols are seen. +gdb_test_no_output "set multiple-symbols all" + +# Test setting breakpoints in a method of all class template instantiations, +# including overloads. +gdb_test "break Foo::foo" "Breakpoint.*at.* \\(3 locations\\)" +foreach t [list "int" "char" "volatile char *"] { + gdb_breakpoint "Foo<$t>::foo (int, $t)" + gdb_breakpoint "Foo::foo (int, $t)" +} + +gdb_test "break Bar::bar" "Breakpoint.*at.* \\(2 locations\\)" +gdb_test "break Bar::bar (int, int)" "Breakpoint.*at.* \\(2 locations\\)" +foreach val [list 1 33] { + gdb_breakpoint "Bar<int, $val>::bar (int, int)" +} + +# Test setting breakpoints in a member function template of a class template, +# including overloads. +gdb_test "break Foozle::fogey" "Breakpoint.*at.* \\(9 locations\\)" \ + "break at template method fogey" +foreach t [list "int" "char" "Empty<int>"] { + gdb_test "break Foozle::fogey ($t)" "Breakpoint.*at.* \\(3 locations\\)" + gdb_test "break Foozle::fogey<$t>" "Breakpoint.*at.* \\(3 locations\\)" + foreach u [list "int" "char" "Empty<int>"] { + gdb_breakpoint "Foozle<$t>::fogey<$u>" message + gdb_breakpoint "Foozle<$t>::fogey<$u> ($u)" message + } +} + +# Test templated operators < and <<. Restrict results to only the test +# source file. +# operator<: +# 1. operator< (const T2&, const T2&) +# 2. operator< (const T2&, char) +# 3. operator< <Empty<int>> +# 4. operator< <Foozle<in>> +# +# operator<<: +# 1. operator<< <Empty<int>> +# 2. operator<< <Foozle<int>> +gdb_test "break -source $srcfile -func operator<" \ + "Breakpoint.*at.* \\(4 locations\\)" +gdb_test "break -source $srcfile -func operator<<" \ + "Breakpoint.*at.* \\(2 locations\\)" +foreach t [list "Empty" "Foozle"] { + set tt "$t<int>" + gdb_breakpoint "operator< <$tt>" message + gdb_breakpoint "operator<< <$tt>" message + + # Try a specific instance, both with and without whitespace + # after the template-template parameter. + gdb_breakpoint "operator< <$tt> ($tt&, $tt&)" message + gdb_breakpoint "operator< <$tt > ($tt&, $tt&)" message + gdb_breakpoint "operator<< <$tt> ($tt&, $tt&)" message + gdb_breakpoint "operator<< <$tt > ($tt&, $tt&)" message +} + +# Test that "-qualified" finds no matching locations. +gdb_test_no_output "set breakpoint pending off" +gdb_test "break -qualified Foozle::fogey" \ + "Function \"Foozle::fogey\" not defined." diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp index d8aa5b2..9846943 100644 --- a/gdb/testsuite/gdb.linespec/cpcompletion.exp +++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp @@ -16,6 +16,7 @@ # This file is part of the gdb testsuite. load_lib completion-support.exp +load_lib data-structures.exp standard_testfile cpls.cc cpls2.cc cpls-hyphen.cc @@ -24,6 +25,217 @@ if {[prepare_for_testing "failed to prepare" $testfile \ return -1 } +# +# Some convenience procedures for testing template parameter list +# completion. +# + +# For the variable named ARGLISTVAR, which should be the name of an +# argument list in the calling frame, "consume" the top-most token. +# [See comments for makefoo for description of arglist format.] + +proc consume {arglistvar} { + upvar $arglistvar arglist + + # ARGLIST is a string -- simply strip off the first character. + set arglist [string range $arglist 1 end] +} + +# Create a function template named NAME, using the given stack ID to grab +# NUM template parameters. The result is pushed back onto the +# stack. NUM may be "all," in which case we use the entire stack +# to create the function template, including function arguments. +# The resulting template function's arguments are taken from the test +# source code for the function "foo" and is not generalized. + +proc maket {sid name {num 1}} { + + # Set up a temporary stack of parameters. This will reverse + # the order in SID so that when they are popped again below, + # we get them in the correct order. This also takes into account + # how many levels of the result stack we want to consider. + + set paramstack [::Stack::new] + if {[string equal $num "all"]} { + while {![stack empty $sid]} { + stack push $paramstack [stack pop $sid] + } + } else { + for {set i 0} {$i < $num} {incr i} { + stack push $paramstack [stack pop $sid] + } + } + + # Construct the function template and push it back to the + # top of the stack given by SID. + set result "" + set first true + while {![stack empty $paramstack]} { + set top [stack pop $paramstack] + if {$first} { + set first false + } else { + append result ", " + } + append result $top + } + + # Save argument list. + set args $result + + # GDB outputs "> >" instead of ">>". + if {[string index $top end] == ">"} { + append result " " + } + set result "$name<$result>" + if {[string equal $num "all"]} { + append result "($args)" + } + stack push $sid $result + stack delete $paramstack +} + +# Given the stack SID and the name of a variable of the desired template +# parameters, construct the actual template parameter and push it to the +# top of the stack. + +proc makearg {sid arglistvar} { + upvar $arglistvar arglist + + set c [string index $arglist 0] + consume arglist + switch $c { + A - + B { + makearg $sid arglist + makearg $sid arglist + maket $sid $c 2 + } + + a - + b - + c - + d { + makearg $sid arglist + maket $sid $c + } + + i { + stack push $sid "int" + } + + n { + # These are not templates. + set c [string index $arglist 0] + stack push $sid "n::n$c" + consume arglist + } + + N { + set c [string index $arglist 0] + makearg $sid arglist + set top [stack pop $sid] + stack push $sid "n::N$top" + } + + default { error "unhandled arglist identifier: '$c'" } + } +} + +# Given ARGLIST, construct a class template for the type and return +# it as a string. + +proc maketype {arglist} { + set s [Stack::new] + makearg $s arglist + set result [stack pop $s] + stack delete $s + return $result +} + +# Returns a function template declaration for the function "foo" in the +# corresponding test source code. ARGLIST specifies the exact instantiation +# that is desired. +# +# Generically, this procedure returns a string of the form, +# "foo<parameter-list> (arg-list)", where ARGLIST describes the parameter(s). +# +# Valid specifiers for ARGLIST (must be kept in sync with source code): +# +# i: Creates an "int" type. +# a, b, c, d: Creates the struct template of the same name, taking a single +# template parameter. +# A, B: Creates the struct template of the same name, taking two template +# parameters. +# na, nb: Creates the non-template structs n::na and n::nb, respectively. +# NA, NB: Creates the struct templates n::NA and n::NB, respectively, which +# take two template parameters. +# +# Examples: +# makefoo i +# --> foo<int> (int) +# makefoo ii +# --> foo<int, int> (int, int) +# makefoo Aiabi +# --> foo<A<int, a<b<int> > > > (A<int, a<b<int> > >) +# makefoo NANAiaiNBbiabi +# --> foo<n::NA<n::NA<int, a<int> >, n::NB<b<int>, a<b<int> > > > > +# (n::NA<n::NA<int, a<int> >, n::NB<b<int>, a<b<int> > > >) + +proc makefoo {arglist} { + set s [::Stack::new] + while {[string length $arglist] > 0} { + makearg $s arglist + } + + maket $s "foo" all + set result [stack pop $s] + stack delete $s + return $result +} + +# Test wrapper for a single "makefoo" unit test. + +proc test_makefoo_1 {arglist expected} { + set exp "foo<$expected" + if {[string index $exp end] == ">"} { + append exp " " + } + append exp ">" + append exp "($expected)" + + set calc [makefoo $arglist] + send_log "makefoo $arglist = $calc\n" + send_log "expecting: $exp\n" + if {[string equal $exp $calc]} { + pass "makefoo unit test: $arglist" + } else { + fail "makefoo unit test: $arglist" + } +} + +# Test whether the procedure "makefoo" is functioning as expected. + +proc test_makefoo {} { + test_makefoo_1 "i" "int" + test_makefoo_1 "ai" "a<int>" + test_makefoo_1 "aai" "a<a<int> >" + test_makefoo_1 "ii" "int, int" + test_makefoo_1 "aaibi" "a<a<int> >, b<int>" + test_makefoo_1 \ + "ababiibababai" "a<b<a<b<int> > > >, int, b<a<b<a<b<a<int> > > > > >" + test_makefoo_1 "Aii" "A<int, int>" + test_makefoo_1 "ABaibibi" "A<B<a<int>, b<int> >, b<int> >" + test_makefoo_1 "na" "n::na" + test_makefoo_1 "nana" "n::na, n::na" + test_makefoo_1 "NAii" "n::NA<int, int>" + test_makefoo_1 "NANAiiNAii" "n::NA<n::NA<int, int>, n::NA<int, int> >" +} + +# +# Tests start here. +# + # Disable the completion limit for the whole testcase. gdb_test_no_output "set max-completions unlimited" @@ -377,12 +589,11 @@ proc_with_prefix template-ret-type {} { test_complete_prefix_range $complete_line $start } - # Setting a breakpoint without the template params doesn't work. - check_setting_bp_fails "$cmd_prefix template2_fn" - # However, setting a breakpoint with template params and without - # the method params does work, just like with non-template - # functions. It also works with or without return type. + # Setting a breakpoint with or without template params and without + # the method params works, just like with non-template functions. + # It also works with or without return type. foreach linespec [list \ + "template2_fn" \ "${method_name}" \ "${method_name}${param_list}" \ "${struct_type}::${method_name}" \ @@ -396,6 +607,218 @@ proc_with_prefix template-ret-type {} { } } +# Test completion of function template foo. + +proc_with_prefix template-function-foo {} { + + foreach cmd_prefix {"b" "b -function"} { + # "foo" is ambiguous, this will set many different breakpoints. + set completion_list \ + [list \ + [makefoo Aabiaai] \ + [makefoo Aabiabi] \ + [makefoo Aabicdi] \ + [makefoo AabicdiAabiaai] \ + [makefoo AabicdiAabiabi] \ + [makefoo AabicdiBabicdi] \ + [makefoo Babicdi] \ + [makefoo aai] \ + [makefoo aaiabi] \ + [makefoo aaicci] \ + [makefoo aaicdi] \ + [makefoo abi] \ + [makefoo anabnb] \ + [makefoo cci] \ + [makefoo cdi] \ + [makefoo NAnanbNBnanb] \ + [makefoo nanb]] + test_gdb_complete_multiple "$cmd_prefix " "foo" "<" $completion_list + check_bp_locations_match_list "$cmd_prefix foo" $completion_list + + # "foo<" should give the same result, but it should not set any + # breakpoints. + test_gdb_complete_multiple "$cmd_prefix " "foo<" "" $completion_list + check_setting_bp_fails "$cmd_prefix foo<" + + # "foo<A" should only give completions in COMPLETION_LIST that + # start with "A" but should set no breakpoints. + set completion_list \ + [list \ + [makefoo Aabiaai] \ + [makefoo Aabiabi] \ + [makefoo Aabicdi] \ + [makefoo AabicdiAabiaai] \ + [makefoo AabicdiAabiabi] \ + [makefoo AabicdiBabicdi]] + test_gdb_complete_multiple "$cmd_prefix " "foo<A" "<a<b<int> >, " \ + $completion_list + check_setting_bp_fails "$cmd_prefix foo<A" + + # "foo<A>" should give any function with one parameter of any type + # of A. While the parameter list in the template should be ignored, + # the function's argument list should not be ignored. + set completion_list \ + [list \ + [makefoo Aabiaai] \ + [makefoo Aabiabi] \ + [makefoo Aabicdi]] + test_gdb_complete_multiple "$cmd_prefix " "foo<A>" \ + "(A<a<b<int> >, " $completion_list + check_bp_locations_match_list "$cmd_prefix foo<A>" $completion_list + + # "foo<A," should complete to any function with more than one + # parameter where the first parameter is any type of A. Insufficient + # location to set breakpoints. + set completion_list \ + [list \ + [makefoo AabicdiAabiaai] \ + [makefoo AabicdiAabiabi] \ + [makefoo AabicdiBabicdi]] + test_gdb_complete_multiple "$cmd_prefix " "foo<A," " " \ + $completion_list + check_setting_bp_fails "$cmd_prefix foo<A," + + # "foo<A<a<b<int>, a" should give all completions starting with + # "Aabia" but it is insufficient to set breakpoints. + set completion_list \ + [list \ + [makefoo Aabiaai] \ + [makefoo Aabiabi]] + test_gdb_complete_multiple "$cmd_prefix " "foo<A<a<b<int> >, a" \ + "<" $completion_list + check_setting_bp_fails "$cmd_prefix foo<A<a<b<int> >, a" + + # "foo<A<a<b<int>, a<" should yield the same results as above. + test_gdb_complete_multiple "$cmd_prefix " "foo<A<a<b<int> >, a<" \ + "" $completion_list + check_setting_bp_fails "$cmd_prefix foo<A<a<b<int> >, a<" + + # "foo<A<a<b<int>, a<a" is unique but insufficient to set a + # breakpoint. This has an ignored template parameter list, so + # the completion will contain an ignored list ("a<a>") + test_gdb_complete_unique "$cmd_prefix foo<A<a<b<int> >, a<a" \ + "$cmd_prefix [makefoo Aabiaai]" + check_setting_bp_fails "$cmd_prefix foo<A<b<int> >, a<a" + + # "foo<A<a<b<int>, a<b" is also unique. Same parameter ignoring + # happens here, too (except "a<b>"). + test_gdb_complete_unique "$cmd_prefix foo<A<a<b<int> >, a<b" \ + "$cmd_prefix [makefoo Aabiabi]" + check_setting_bp_fails "$cmd_prefix foo<A<a<b<int> >, a<b" + + # "foo<B" is unique but insufficient to set a breakpoint. + test_gdb_complete_unique "$cmd_prefix foo<B" \ + "$cmd_prefix [makefoo Babicdi]" + check_setting_bp_fails "$cmd_prefix foo<B" + + # "foo<B>" yields the same unique result and sets a breakpoint. + # Since the input skips the parameter list, so does the completion. + test_gdb_complete_unique "$cmd_prefix foo<B>" \ + "$cmd_prefix foo<B>(B<a<b<int> >, c<d<int> > >)" + check_bp_locations_match_list "$cmd_prefix foo<B>" \ + [list [makefoo Babicdi]] + + # "foo<B," should return no completions and no breakpoints. + test_gdb_complete_none "$cmd_prefix foo<B," + check_setting_bp_fails "$cmd_prefix foo<B," + + # "foo<n::" should yield only the functions starting with + # "n" and "N" and no breakpoints. + set completion_list \ + [list \ + [makefoo NAnanbNBnanb] \ + [makefoo nanb]] + test_gdb_complete_multiple "$cmd_prefix " "foo<n::" "" \ + $completion_list + check_setting_bp_fails "$cmd_prefix foo<n::" + + # "foo<A<a, c> >" is unique and sets a breakpoint. + # Multiple template parameter lists are skipped, so GDB will ignore + # them in the completion. + test_gdb_complete_unique "$cmd_prefix foo<A<a, c> >" \ + "$cmd_prefix foo<A<a, c> >(A<a<b<int> >, c<d<int> > >)" + check_bp_locations_match_list "$cmd_prefix foo<A<a, c> >" \ + [list [makefoo Aabicdi]] + } +} + +# Helper for template-class-with-method to build completion lists. + +proc makem {arglist_list} { + set completion_list {} + foreach arglist $arglist_list { + lappend completion_list "[maketype $arglist]::method()" + } + return $completion_list +} + +# Returns a list of elements that look like +# void TYPE::method() +# where TYPE is derived from each arglist in ARGLIST_LIST. + +proc test_makem_1 {arglist_list expected_list} { + set result [makem $arglist_list] + send_log "makem $arglist = $result\n" + send_log "expecting $expected_list\n" + + # Do list equality via canonical strings. + if {[expr {[list {*}$expected_list] eq [list {*}$result]}]} { + pass "makem unit test: $arglist" + } else { + fail "makem unit test: $arglist" + } +} + +# Unit tests for makem. + +proc test_makem {} { + test_makem_1 ai {"a<int>::method()"} + test_makem_1 bi {"b<int>::method()"} + test_makem_1 {ai bi} {"a<int>::method()" "b<int>::method()"} + test_makem_1 {Aaiaai Bbibbi abi cdi} { + "A<a<int>, a<a<int> > >::method()" + "B<b<int>, b<b<int> > >::method()" + "a<b<int> >::method()" + "c<d<int> >::method()" + } +} + +# Test class template containing a (non-templated) method called "method." + +proc_with_prefix template-class-with-method {} { + + foreach {type type_list} \ + [list \ + "" {aai abi cci cdi Aabicdi Aabiaai Aabiabi Babicdi} \ + "a" {aai abi} \ + "b" {} \ + "c" {cci cdi} \ + "A" {Aabicdi Aabiaai Aabiabi} \ + "B" {Babicdi} \ + "A<a, a>" {Aabiaai Aabiabi} \ + "A<a<b>, c>" {Aabicdi}\ + "A<a, d>" {} \ + "B<a, a>" {} \ + "B<a, b>" {} \ + "B<a, c>" {Babicdi}] \ + { + foreach cmd_prefix {"b" "b -function"} { + set c "$cmd_prefix " + if {$type != ""} { + append c "${type}::" + } + append c "method" + + if {[llength $type_list] > 0} { + test_gdb_complete_unique $c "${c}()" + check_bp_locations_match_list $c [makem $type_list] + } else { + test_gdb_complete_none $c + } + } + } +} + # Test completion of a const-overloaded funtion (const-overload). # Note that "const" appears after the function/method parameters. @@ -935,6 +1358,10 @@ proc test_driver {} { overload-3 template-overload template-ret-type + #test_makefoo + template-function-foo + #test_makem + template-class-with-method const-overload const-overload-quoted append-end-quote-char-when-unambiguous diff --git a/gdb/testsuite/gdb.linespec/cpls-ops.exp b/gdb/testsuite/gdb.linespec/cpls-ops.exp index 355735e..dbcda29 100644 --- a/gdb/testsuite/gdb.linespec/cpls-ops.exp +++ b/gdb/testsuite/gdb.linespec/cpls-ops.exp @@ -240,20 +240,6 @@ proc test_operator_ambiguous {class_name opn cls} { test_gdb_complete_multiple \ "$cmd_prefix " "$linespec_noparams" "" $location_list - # Setting the breakpoint doesn't create a breakpoint location - # for the template, because immediately after - # "operator()/operator[]" we have the template parameters, not - # the parameter list. - set location_list \ - [list \ - "${class_name}::operator${opn}${cls}(int)" \ - "${class_name}::operator${opn}${cls}(long)"] - if {$opn == "("} { - set location_list \ - [concat \ - [list "${class_name}::operator${opn}${cls}()"] \ - $location_list] - } check_bp_locations_match_list "$cmd_prefix $linespec_noparams" \ $location_list check_bp_locations_match_list "$cmd_prefix $linespec_noparams<int>" \ @@ -261,26 +247,33 @@ proc test_operator_ambiguous {class_name opn cls} { # Test the template version. Test both with and without # return type. - test_gdb_complete_unique \ - "$cmd_prefix ${class_name}::operator${opn}${cls}<int>(in" \ - "$cmd_prefix ${class_name}::operator${opn}${cls}<int>(int*)" - check_bp_locations_match_list \ - "$cmd_prefix ${class_name}::operator${opn}${cls}<int>(int*)" \ - [list "${class_name}::operator${opn}${cls}<int>(int*)"] - test_gdb_complete_unique \ - "$cmd_prefix void ${class_name}::operator${opn}${cls}<int>(in" \ - "$cmd_prefix void ${class_name}::operator${opn}${cls}<int>(int*)" - check_bp_locations_match_list \ - "$cmd_prefix void ${class_name}::operator${opn}${cls}<int>(int*)" \ - [list "${class_name}::operator${opn}${cls}<int>(int*)"] + set f "${class_name}::operator" + foreach ws1 {"" " "} { + foreach ws2 {"" " "} { + foreach ws3 {"" " "} { + test_gdb_complete_unique \ + "$cmd_prefix ${f}${opn}${ws1}${cls}<${ws2}int${ws3}>(in" \ + "$cmd_prefix ${f}${opn}${ws1}${cls}<${ws2}int${ws3}>(int*)" + check_bp_locations_match_list \ + "$cmd_prefix ${f}${opn}${ws1}${cls}<${ws2}int${ws3}>(int*)" \ + [list "${f}${opn}${cls}<int>(int*)"] + test_gdb_complete_unique \ + "$cmd_prefix void ${f}${opn}${ws1}${cls}<${ws2}int${ws3}>(in" \ + "$cmd_prefix void ${f}${opn}${ws1}${cls}<${ws2}int${ws3}>(int*)" + check_bp_locations_match_list \ + "$cmd_prefix void ${f}${opn}${ws1}${cls}<${ws2}int${ws3}>(int*)" \ + [list "${f}${opn}${cls}<int>(int*)"] + } + } + } # Add extra spaces. test_gdb_complete_unique \ - "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( in" \ - "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( int)" + "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( lo" \ + "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( long)" check_bp_locations_match_list \ - "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( int )" \ - [list "${class_name}::operator${opn}${cls}(int)"] + "$cmd_prefix ${class_name}::operator ${opn} ${cls} ( long )" \ + [list "${class_name}::operator${opn}${cls}(long)"] } } diff --git a/gdb/testsuite/gdb.linespec/cpls.cc b/gdb/testsuite/gdb.linespec/cpls.cc index 332a8b5..fd39651 100644 --- a/gdb/testsuite/gdb.linespec/cpls.cc +++ b/gdb/testsuite/gdb.linespec/cpls.cc @@ -146,7 +146,7 @@ namespace ns_overload3_test } } -/* Code for the template-overload tests. */ +/* Code for the template-function_foo (template parameter completion) tests. */ template <typename T> struct template_struct @@ -163,6 +163,113 @@ T template_struct<T>::template_overload_fn (T t) template_struct<int> template_struct_int; template_struct<long> template_struct_long; +/* Code for the template-parameter-overload test. */ + +template <typename T> +void foo (T c) {} + +template <typename T1, typename T2> +void foo (T1 a, T2 b) {} + +template <typename T> +struct a +{ + void method () {} +}; + +template <typename T> +struct b +{ + void method () {} +}; + +template <typename T> +struct c +{ + void method () {} +}; + +template <typename T> +struct d +{ + void method () {}; +}; + +template <typename T1, typename T2> +struct A +{ + void method () {} +}; + +template <typename T1, typename T2> +struct B +{ + void method () {} +}; + +namespace n +{ + struct na {}; + struct nb {}; + + template <typename T1, typename T2> + struct NA {}; + + template <typename T1, typename T2> + struct NB {}; +}; + +static void +template_function_foo () +{ + a<a<int>> aa; + aa.method (); + a<b<int>> ab; + ab.method (); + c<c<int>> cc; + cc.method (); + c<d<int>> cd; + cd.method (); + foo (aa); + foo (ab); + foo (cc); + foo (cd); + foo (aa, ab); + foo (aa, cc); + foo (aa, cd); + + A<a<b<int>>, c<d<int>>> Aabcd; + Aabcd.method (); + foo (Aabcd); + + A<a<b<int>>, a<a<int>>> Aabaa; + Aabaa.method (); + foo (Aabaa); + + A<a<b<int>>, a<b<int>>> Aabab; + Aabab.method (); + foo (Aabab); + + B<a<b<int>>, c<d<int>>> Babcd; + Babcd.method (); + foo (Babcd); + + foo (Aabcd, Babcd); + foo (Aabcd, Aabaa); + foo (Aabcd, Aabab); + + n::na na; + n::nb nb; + foo (na, nb); + a<n::na> ana; + b<n::nb> bnb; + foo (ana, bnb); + + n::NA<n::na, n::nb> NAnanb; + n::NB<n::na, n::nb> Nbnanb; + foo (NAnanb, Nbnanb); +} + /* Code for the template2-ret-type tests. */ template <typename T> @@ -381,6 +488,7 @@ main () template2_struct_inst.template2_fn<int, int> (); template_struct_int.template_overload_fn(0); template_struct_long.template_overload_fn(0); + template_function_foo (); return 0; } diff --git a/gdb/utils.c b/gdb/utils.c index 0a072fe..6222f26 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -2271,13 +2271,45 @@ skip_abi_tag (const char **name) return false; } +/* If *NAME points at a template parameter list, skip it and return true. + Otherwise do nothing and return false. */ + +static bool +skip_template_parameter_list (const char **name) +{ + const char *p = *name; + + if (*p == '<') + { + const char *template_param_list_end = find_toplevel_char (p + 1, '>'); + + if (template_param_list_end == NULL) + return false; + + p = template_param_list_end + 1; + + /* Skip any whitespace that might occur after the closing of the + parameter list, but only if it is the end of parameter list. */ + const char *q = p; + while (isspace (*q)) + ++q; + if (*q == '>') + p = q; + *name = p; + return true; + } + + return false; +} + /* See utils.h. */ int strncmp_iw_with_mode (const char *string1, const char *string2, size_t string2_len, strncmp_iw_mode mode, enum language language, - completion_match_for_lcd *match_for_lcd) + completion_match_for_lcd *match_for_lcd, + bool ignore_template_params) { const char *string1_start = string1; const char *end_str2 = string2 + string2_len; @@ -2327,6 +2359,48 @@ strncmp_iw_with_mode (const char *string1, const char *string2, string1++; } + /* Skip template parameters in STRING1 if STRING2 does not contain + any. E.g.: + + Case 1: User is looking for all functions named "foo". + string1: foo <...> (...) + string2: foo + + Case 2: User is looking for all methods named "foo" in all template + class instantiations. + string1: Foo<...>::foo <...> (...) + string2: Foo::foo (...) + + Case 3: User is looking for a specific overload of a template + function or method. + string1: foo<...> + string2: foo(...) + + Case 4: User is looking for a specific overload of a specific + template instantiation. + string1: foo<A> (...) + string2: foo<B> (...) + + Case 5: User is looking wild parameter match. + string1: foo<A<a<b<...> > > > (...) + string2: foo<A + */ + if (language == language_cplus && ignore_template_params + && *string1 == '<' && *string2 != '<') + { + /* Skip any parameter list in STRING1. */ + const char *template_start = string1; + + if (skip_template_parameter_list (&string1)) + { + /* Don't mark the parameter list ignored if the user didn't + try to ignore it. [Case #5 above] */ + if (*string2 != '\0' + && match_for_lcd != NULL && template_start != string1) + match_for_lcd->mark_ignored_range (template_start, string1); + } + } + if (*string1 == '\0' || string2 == end_str2) break; @@ -2435,6 +2509,12 @@ strncmp_iw_with_mode (const char *string1, const char *string2, break; if (*string1 == '(' || *string2 == '(') break; + + /* If STRING1 or STRING2 starts with a template + parameter list, break out of operator processing. */ + skip_ws (string1, string2, end_str2); + if (*string1 == '<' || *string2 == '<') + break; } continue; diff --git a/gdb/utils.h b/gdb/utils.h index c1195f6..453ac59 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -57,11 +57,14 @@ enum class strncmp_iw_mode MATCH_FOR_LCD is passed down so that the function can mark parts of the symbol name as ignored for completion matching purposes (e.g., - to handle abi tags). */ + to handle abi tags). If IGNORE_TEMPLATE_PARAMS is true, all template + parameter lists will be ignored when language is C++. */ + extern int strncmp_iw_with_mode (const char *string1, const char *string2, size_t string2_len, strncmp_iw_mode mode, enum language language, - completion_match_for_lcd *match_for_lcd = NULL); + completion_match_for_lcd *match_for_lcd = NULL, + bool ignore_template_params = false); /* Do a strncmp() type operation on STRING1 and STRING2, ignoring any differences in whitespace. STRING2_LEN is STRING2's length. |