Patchwork [3/3] Support template lookups in strncmp_iw_with_mode

login
register
mail settings
Submitter Keith Seitz
Date Feb. 2, 2018, 6:36 p.m.
Message ID <20180202183642.4288-3-keiths@redhat.com>
Download mbox | patch
Permalink /patch/25780/
State New
Headers show

Comments

Keith Seitz - Feb. 2, 2018, 6:36 p.m.
This patch adds support for wild template parameter list matches, similar
to how ABI tags or function overloads are now handled.

With this patch, users will be able to "gloss over" the details of matching
template parameter lists.  This is accomplished by adding (yet more) logic
to strncmp_iw_with_mode to skip parameter lists if none is explicitly given
by the user.

Here's a simple example using gdb.linespec/cpls-ops.exp:

Before
------
(gdb) ptype test_op_call
type = struct test_op_call {
  public:
    void operator()(void);
    void operator()(int);
    void operator()(long);
    void operator()<int>(int *);
}
(gdb) b test_op_call::operator()
Breakpoint 1 at 0x400583: test_op_call::operator(). (3 locations)
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>
1.1                         y     0x400583 in test_op_call::operator()(int)
                                                   at cpls-ops.cc:43
1.2                         y     0x40058e in test_op_call::operator()()
                                                   at cpls-ops.cc:47
1.3                         y     0x40059e in test_op_call::operator()(long)
                                                   at cpls-ops.cc:51

The breakpoint at test_op_call::operator()<int> was never set.

After
-----
(gdb) b test_op_call::operator()
Breakpoint 1 at 0x400583: test_op_call::operator(). (4 locations)
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>
1.1                         y     0x400583 in test_op_call::operator()(int)
                                                   at cpls-ops.cc:43
1.2                         y     0x40058e in test_op_call::operator()()
                                                   at cpls-ops.cc:47
1.3                         y     0x40059e in test_op_call::operator()(long)
                                                   at cpls-ops.cc:51
1.4                         y     0x4008d0 in test_op_call::operator()<int>(int*)
                                                   at cpls-ops.cc:57

Similar to how scope lookups work, passing "-qualified" to the break command
will cause a literal lookup of the symbol.  In the example immediately above,
this will cause GDB to only find the three non-template functions.

gdb/ChangeLog:

	* NEWS: Mention new template parameter support for
	locations/completion.
	* cp-support.c (cp_search_name_hash): Break on '<', too.
	(cp_symbol_name_matches_1): Tell strncmp_iw_with_mode to ignore
	template parameter lists.
	* utils.c (skip_template_parameter_list): New function.
	(strncmp_iw_with_mode): Support "ignoring" of template parameter lists.
	* utils.h (strncmp_iw_with_mode): Add new parameter
	`ignore_template_params'.

gdb/doc/ChangeLog:

	* gdb.texinfo (Debugging C Plus Plus): Document setting breakpoints
	in templates.

gdb/testsuite/ChangeLog:

	* gdb.cp/templates.cc (Foozle, operator<, operator<<): New.
	(main): Add uses of new functions/types.
	* gdb.cp/templates.exp: Add template parameter list tests.
	* gdb.linespec/cpcompletion.exp (template-no-list): New procedure.
	(template-ret-type): Split range completion to account for template
	names completing without template parameter list.
	Change "setting breakpoint without template parameter test" to pass.
	(test_driver): Call template-no-list test procedure.
	* gdb.linespec/cpls-ops.exp (test_operator_ambiguous): Remove
	template restriction.
	Pass "(" as completion word to test_gdb_complete_multiple.
	Add new whitespace tests for template functions.
	Add a few more overload tests.
---
 gdb/NEWS                                    |   4 ++
 gdb/cp-support.c                            |   4 +-
 gdb/doc/gdb.texinfo                         |  46 +++++++++++++
 gdb/testsuite/gdb.cp/templates.cc           |  47 +++++++++++++
 gdb/testsuite/gdb.cp/templates.exp          |  67 ++++++++++++++++++
 gdb/testsuite/gdb.linespec/cpcompletion.exp | 102 ++++++++++++++++++++++++++--
 gdb/testsuite/gdb.linespec/cpls-ops.exp     |  55 +++++++--------
 gdb/utils.c                                 |  70 ++++++++++++++++++-
 gdb/utils.h                                 |   7 +-
 9 files changed, 359 insertions(+), 43 deletions(-)
Pedro Alves - Feb. 6, 2018, 6:15 p.m.
Hi Keith,

Exciting!  Thanks for pushing through with this.

I've run the new tests locally and noticed a couple duplicated
test messages.  Please fix those:

      2 PASS: gdb.linespec/cpcompletion.exp: template-no-list: compare "b -function template_struct::template_overload_fn" completion list with bp location list: matches
      2 PASS: gdb.linespec/cpcompletion.exp: template-no-list: compare "b template_struct::template_overload_fn" completion list with bp location list: matches


I've experimented a little (though not much) with the new
feature, and I ran into something that looks a bit odd.
Let me explain.

Using gdb.linespec/cpcompletion, we see:

 (gdb) complete b template2_fn<int, int>(template2_ret_typ
 b template2_fn<int, int>(template2_ret_type<int>, int, int)
                                           ^^^^^^^^^^^^^^^^^

 (gdb) complete b template2_fn<int, int>(template2_ret_type
 b template2_fn<int, int>(template2_ret_type, int, int)
                                            ^^^^^^^^^^^

Notice how in the first case, we completed at the character
before "template2_ret_type", and in that case, we include
the template parameters in the match.  

However, if we complete right at the end of "template2_ret_type",
as in the second case, then we don't include the template arguments.

Actually, I see the same if we complete before the parameters
too:

 (gdb) complete b template2_f
 b template2_fn<int, int>(template2_ret_type<int>, int, int)
               ^^^^^^^^^^^
 (gdb) complete b template2_fn
 b template2_fn(template2_ret_type<int>, int, int)
               ^

Did you notice this?  I was not able to reproduce the same
behavior with completing ABI tabs.

Otherwise, skimming the patch, I didn't find anything
that made me pause.  It all seems to fit in the existing framework.
I'm glad that this turned out to be not that invasive.

Can you address the above issues, and repost?  I suspect we'll
get this over with in the next iteration.

One tiny nit below:

>  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 +2351,44 @@ strncmp_iw_with_mode (const char *string1, const char *string2,
>  	    string1++;
>  	}
>  
> +      /* Skip C++ template parameters in the symbol name if the lookup name
> +	 doesn't include them.  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.

Space vs tabs mixup above.

> +	 string1: foo<...>
> +	 string2: foo(...)
> +
Thanks,
Pedro Alves
Keith Seitz - Feb. 6, 2018, 7:24 p.m.
On 02/06/2018 10:15 AM, Pedro Alves wrote:
>       2 PASS: gdb.linespec/cpcompletion.exp: template-no-list: compare "b -function template_struct::template_overload_fn" completion list with bp location list: matches
>       2 PASS: gdb.linespec/cpcompletion.exp: template-no-list: compare "b template_struct::template_overload_fn" completion list with bp location list: matches
> 

I thought I'd checked that. Fixed.

> Using gdb.linespec/cpcompletion, we see:
> 
>  (gdb) complete b template2_fn<int, int>(template2_ret_typ
>  b template2_fn<int, int>(template2_ret_type<int>, int, int)
>                                            ^^^^^^^^^^^^^^^^^
> 
>  (gdb) complete b template2_fn<int, int>(template2_ret_type
>  b template2_fn<int, int>(template2_ret_type, int, int)
>                                             ^^^^^^^^^^^
> 
> Notice how in the first case, we completed at the character
> before "template2_ret_type", and in that case, we include
> the template parameters in the match.  

Yeah, that's how it is currently implemented. My intent was to mimick overloaded functions. Looking at it now, though, I see that I didn't quite get it right (for some reason):

(gdb) b template2_fn<TAB>
-->
(gdb) b template2_fn(template2_ret<int>, int, int)

Compared with (gdb.cp/cpexprs.exp): 

(gdb) b overload<TAB>
-->
(gdb) b overload(
base::overload() const       base::overload(int) const
base::overload(base&) const  base::overload(long) const
base::overload(char*) const  base::overload(short) const

Let me see if I can fix that.

Keith

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 9cd38f3d91..487fffab22 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -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 dde417be80..a60fbe2c9b 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -1634,7 +1634,7 @@  cp_search_name_hash (const char *search_name)
     {
       string = skip_spaces (string);
 
-      if (*string == '(')
+      if (*string == '(' || *string == '<')
 	break;
 
       /* Ignore ABI tags such as "[abi:cxx11].  */
@@ -1696,7 +1696,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 4ed5f6bbb2..fd535227dd 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -15181,6 +15181,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 db2dfe8a58..1a0500dba9 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 af722689c7..25bab75d48 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>" message
+    gdb_breakpoint "operator<< <$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 d8aa5b2a49..1ec0d6c8f9 100644
--- a/gdb/testsuite/gdb.linespec/cpcompletion.exp
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -346,10 +346,78 @@  proc_with_prefix template-overload {} {
     }
 }
 
+# Test completing template class/functions without parameter lists.
+
+proc_with_prefix template-no-list {} {
+    set completion_list {
+	"template_struct<int>::template_overload_fn(int)"
+	"template_struct<long>::template_overload_fn(long)"
+    }
+    set location "template_struct::template_overload_fn"
+    foreach cmd_prefix {"b" "b -function"} {
+	test_gdb_complete_multiple "$cmd_prefix " \
+	    $location "(" $completion_list
+	check_bp_locations_match_list "$cmd_prefix $location" $completion_list
+	check_bp_locations_match_list \
+	    "$cmd_prefix template_struct::template_overload_fn" \
+	    $completion_list
+    }
+
+    # Also check -qualified.  LOCATION_TEST_LIST is a pair-oriented list
+    # of linespec function and a boolean indicating whether this should yield
+    # a unique breakpoint location.
+
+    # The expected completion regexp.
+    set ret_type "template2_ret_type<int>"
+    set completion "template2_struct<$ret_type >::"
+    append completion "template2_fn<int, int>($ret_type, int, int)"
+    set completion_ret "$ret_type $completion"
+
+    set location_test_list [list "template2_fn" ""]
+    lappend location_test_list "template2_fn<int, int>" ""
+    lappend location_test_list "template2_struct::template2_fn" ""
+    lappend location_test_list "template2_struct::template2_fn<int, int>" ""
+    lappend location_test_list \
+	"template2_struct<$ret_type >::template2_fn" $completion
+    lappend location_test_list \
+	"template2_struct<$ret_type >::template2_fn<int, int>" $completion
+    lappend location_test_list "template2_ret_type" $completion_ret
+    lappend location_test_list \
+	"template2_ret_type template2_struct::template2_fn" ""
+    lappend location_test_list \
+	"template2_ret_type template2_struct::template2_fn<int, int>" ""
+    lappend location_test_list \
+	"template2_ret_type template2_struct<int>:template2_fn" ""
+    lappend location_test_list \
+	"template2_ret_type template2_struct<int>::template2_fn<int, int>" ""
+    lappend location_test_list \
+	"template2_ret_type<int> template2_struct::template2_fn" ""
+    lappend location_test_list \
+	"template2_ret_type<int> template2_struct::template2_fn<int, int>" ""
+    lappend location_test_list \
+	"template2_ret_type<int> template2_struct<$ret_type>:template2_fn" ""
+    lappend location_test_list \
+	"template2_ret_type<int> template2_struct<$ret_type >::template2_fn<int, int>" \
+	$completion_ret
+
+    foreach {location comp} $location_test_list {
+	foreach cmd_prefix {"b -qualified" "b -qualified -function"} {
+	    if {$comp != ""} {
+		send_log "\nExpecting: $cmd_prefix $comp\n"
+		test_gdb_complete_unique "$cmd_prefix $location" \
+		    "$cmd_prefix $comp"
+	    } else {
+		test_gdb_complete_none "$cmd_prefix $location"
+	    }
+	}
+    }
+}
+
 # Test completing template methods with non-void return type.
 
 proc_with_prefix template-ret-type {} {
-    set method_name "template2_fn<int, int>"
+    set method_base_name "template2_fn"
+    set method_name "$method_base_name<int, int>"
     set param_list "(template2_ret_type<int>, int, int)"
     set struct_type "template2_struct<template2_ret_type<int> >"
     set ret_type "template2_ret_type<int>"
@@ -361,7 +429,7 @@  proc_with_prefix template-ret-type {} {
 	    [list \
 		 "${ret_type} ${struct_type}::${method_name}${param_list}" \
 		 "${struct_type}::${method_name}${param_list}"]
-	test_gdb_complete_multiple "$cmd_prefix " "template2_" "" $completion_list
+	    test_gdb_complete_multiple "$cmd_prefix " "template2_" "" $completion_list
 
 	# Add one character more after "2_", and the linespec becomes
 	# unambiguous.  Test completing the whole prefix range after that,
@@ -374,13 +442,32 @@  proc_with_prefix template-ret-type {} {
 	    set linespec $t
 	    set complete_line "$cmd_prefix $linespec"
 	    set start [index_after $s $complete_line]
-	    test_complete_prefix_range $complete_line $start
+	    # With template parameter lists, any template name will complete
+	    # (but without the template parameters in the completion).
+	    # Break the ranges into subranges where this will not interfere
+	    # with the test.  These skipped completions are tested elsewhere.
+	    set end 0
+	    foreach substr [split $complete_line "<"] {
+		set sublen [string length $substr]
+		if {$end == 0} {
+		    # First time -- remove length of S, which is start + 1.
+		    incr sublen [expr {-($start + 1)}]
+		}
+		set end [expr {$start + $sublen - 1}]
+		test_complete_prefix_range $complete_line $start $end
+		set start [expr {$end + 2}]
+	    }
 	}
 
-	# 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
+	# Setting a breakpoint without the template params should work, too.
+	test_gdb_complete_unique "$cmd_prefix template2_fn" \
+	    "$cmd_prefix ${method_base_name}${param_list}"
+	check_bp_locations_match_list \
+	    "$cmd_prefix template2_fn" \
+	    [list "${struct_type}::${method_name}${param_list}"]
+
+	# Setting a breakpoint with template params and without
+	# the method params also works, just like with non-template
 	# functions.  It also works with or without return type.
 	foreach linespec [list \
 			      "${method_name}" \
@@ -935,6 +1022,7 @@  proc test_driver {} {
     overload-3
     template-overload
     template-ret-type
+    template-no-list
     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 355735eb41..630c941e8b 100644
--- a/gdb/testsuite/gdb.linespec/cpls-ops.exp
+++ b/gdb/testsuite/gdb.linespec/cpls-ops.exp
@@ -238,22 +238,8 @@  proc test_operator_ambiguous {class_name opn cls} {
 		     $location_list]
 	}
 	test_gdb_complete_multiple \
-	    "$cmd_prefix " "$linespec_noparams" "" $location_list
+	    "$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/utils.c b/gdb/utils.c
index 0a072fee6b..19b6934dae 100644
--- a/gdb/utils.c
+++ b/gdb/utils.c
@@ -2271,13 +2271,37 @@  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;
+      *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 +2351,44 @@  strncmp_iw_with_mode (const char *string1, const char *string2,
 	    string1++;
 	}
 
+      /* Skip C++ template parameters in the symbol name if the lookup name
+	 doesn't include them.  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> (...)
+	 In this case, skip the below branch, regardless of
+	   IGNORE_TEMPLATE_PARAMS.  The lists must match.  */
+      if (language == language_cplus && ignore_template_params
+	  && *string2 != '<')
+	{
+	  const char *template_start = string1;
+
+	  if (skip_template_parameter_list (&string1))
+	    {
+	      if (match_for_lcd != NULL && template_start != string1)
+		match_for_lcd->mark_ignored_range (template_start, string1);
+
+	      while (isspace (*string1))
+		++string1;
+	    }
+	}
+
       if (*string1 == '\0' || string2 == end_str2)
 	break;
 
@@ -2435,6 +2497,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 c1195f65b5..453ac59ce9 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.