[35/40] Comprehensive C++ linespec/completer tests

Message ID 1496406158-12663-36-git-send-email-palves@redhat.com
State New, archived
Headers

Commit Message

Pedro Alves June 2, 2017, 12:22 p.m. UTC
  Exercises all sorts of aspects fixed by the previous patches.

 - Exercises label completion, linespecs and explicit locations.

 - Exercises both quoting vs non-quoting, source filenames, function
   names, labels, with both linespecs and explicit locations.

 - Tests corner cases around not-quoting function names, and
   whitespace and/and completing inside a parameter or template
   argument list, anonymous namespace awareness, etc.

   E.g.,

     "break foo<[TAB]"          -> "break foo<int>()"
     "break bar ( int[TAB]"     -> "break bar ( int)
     "break ( anon"             -> "break ( anonymous namespace)::func()"
     "b cfunc() [tab]"          -> "b cfunc() const"
     "b rettype templfunc[tab]" -> "b rettype templfunc<bar>()"

   ... and others.

 - Tests the "b source.c[TAB] -> b source.cc:" feature.  I.e., colon
   auto-appending.

 - Exercises corner cases around C++ "operator<" / "operator<<".
   (Much more extensive C++ operator completion/linespec handling in a
   separate patch.)

 - Exercises both tab completion and "complete" command completion,
   using routines that handle it automatically, to ensure no test
   forgets either mode.

 - Many of the completion tests test completion at at prefix of a
   given tricky name, to make sure all corner cases are covered.
   E.g., completing before, at and after ":", "(", "<".

 - Exercises "keyword" completion.  I.e., "b function() [TAB]"
   displaying "if task thread" as completion match list.  Likewise for
   display explicit location options matches at the appropriate
   points.

 - Exercises matching symbols in all scopes (wild matching).  Ensures
   that the completer finds the same breakpoint locations that setting
   a breakpoint finds.

 - Tests that linespec/location completion doesn't find data symbols.

 - Tests that expression completion still kicks in after a
   linespec/location keyword.  I.e., this:

     "b function () if global1 + global[TAB]"

   knows that after "if", you're completing on an expression, and thus
   breaks words after "if" as an expression and matches on "global" as
   a data symbol.

 - Adds common routines to help with all the above, to be used by
   multiple completion and linespec/location test cases.

 - More...

Grows the gdb.linespec/ tests like this:

  -# of expected passes           573
  +# of expected passes           4458

gdb/testsuite/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* gdb.linespec/cpcompletion.exp: New file.
	* gdb.linespec/cpls-hyphen.cc: New file.
	* gdb.linespec/cpls.cc: New file.
	* gdb.linespec/cpls2.cc: New file.
	* gdb.linespec/explicit.exp: Load completion-support.exp.  Adjust
	test to use test_gdb_complete_unique.  Add label completion,
	keyword completion and explicit location completion tests.
	* lib/completion-support.exp: New file.
---
 gdb/testsuite/gdb.linespec/cpcompletion.exp | 959 ++++++++++++++++++++++++++++
 gdb/testsuite/gdb.linespec/cpls-hyphen.cc   |  14 +
 gdb/testsuite/gdb.linespec/cpls.cc          | 386 +++++++++++
 gdb/testsuite/gdb.linespec/cpls2.cc         |  46 ++
 gdb/testsuite/gdb.linespec/explicit.exp     | 209 +++++-
 gdb/testsuite/lib/completion-support.exp    | 513 +++++++++++++++
 6 files changed, 2120 insertions(+), 7 deletions(-)
 create mode 100644 gdb/testsuite/gdb.linespec/cpcompletion.exp
 create mode 100644 gdb/testsuite/gdb.linespec/cpls-hyphen.cc
 create mode 100644 gdb/testsuite/gdb.linespec/cpls.cc
 create mode 100644 gdb/testsuite/gdb.linespec/cpls2.cc
 create mode 100644 gdb/testsuite/lib/completion-support.exp
  

Comments

Keith Seitz Aug. 9, 2017, 5:30 p.m. UTC | #1
On 06/02/2017 05:22 AM, Pedro Alves wrote:
> Exercises all sorts of aspects fixed by the previous patches.

SUPER!

> Grows the gdb.linespec/ tests like this:
> 
>   -# of expected passes           573
>   +# of expected passes           4458

/me drools

> gdb/testsuite/ChangeLog:
> yyyy-mm-dd  Pedro Alves  <palves@redhat.com>
> 
> 	* gdb.linespec/cpcompletion.exp: New file.
> 	* gdb.linespec/cpls-hyphen.cc: New file.
> 	* gdb.linespec/cpls.cc: New file.
> 	* gdb.linespec/cpls2.cc: New file.
> 	* gdb.linespec/explicit.exp: Load completion-support.exp.  Adjust
> 	test to use test_gdb_complete_unique.  Add label completion,
> 	keyword completion and explicit location completion tests.
> 	* lib/completion-support.exp: New file.

> diff --git a/gdb/testsuite/gdb.linespec/cpls-hyphen.cc b/gdb/testsuite/gdb.linespec/cpls-hyphen.cc
> new file mode 100644
> index 0000000..fdc063f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.linespec/cpls-hyphen.cc
> @@ -0,0 +1,14 @@
> +int
> +ns_hyphen_function (int i)
> +{
> +  if (i > 0)
> +    {
> +    label1:
> +      return i + 20;
> +    }
> +  else
> +    {
> +    label2:
> +      return i + 10;
> +    }
> +}

Does this file not require a copyright header?

> diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
> index 65d78ca..998b70a 100644
> --- a/gdb/testsuite/gdb.linespec/explicit.exp
> +++ b/gdb/testsuite/gdb.linespec/explicit.exp
> @@ -326,10 +329,202 @@ namespace eval $testfile {
[snip]
>  
> +	# Follows completion tests that require having no symbols
> +	# loaded.

"The following completion tests," perhaps?

> +	gdb_exit
> +	gdb_start
> +
> +	# The match list you get when you complete with no options
> +	# specified at all.
> +	set completion_list {
> +	    "-function"
> +	    "-label"
> +	    "-line"
> +	    "-probe"
> +	    "-probe-dtrace"
> +	    "-probe-stap"
> +	    "-qualified"
> +	    "-source"
> +	}
> +	with_test_prefix "complete with no arguments and no symbols" {
> +	    test_gdb_complete_multiple "b " "" "-" $completion_list
> +	    test_gdb_complete_multiple "b " "-" "" $completion_list
> +	}
>      }
>      # End of completion tests.
>  
> diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp
> new file mode 100644
> index 0000000..ef78269
> --- /dev/null
> +++ b/gdb/testsuite/lib/completion-support.exp
> @@ -0,0 +1,513 @@
[snip]
> +
> +# Test that completing INPUT_LINE with TAB completes to
> +# COMPLETE_LINE_RE.  APPEND_CHAR_RE is the character expected to be
> +# appended after EXPECTED_OUTPUT.  Normally that's a whitespace, but
> +# in some cases it's some other character, like a colon.
> +
> +proc test_gdb_complete_tab_unique { input_line complete_line_re append_char_re } {
> +
> +    set test "tab complete \"$input_line\""
> +    send_gdb "$input_line\t"
> +    gdb_test_multiple "" "$test" {
> +	-re "^$complete_line_re$append_char_re$" {
> +	    pass "$test"
> +	}
> +    }
> +
> +    clear_input_line $test
> +}
> +
> +# Test that completing INPUT_LINE with TAB completes to "INPUT_LINE +
> +# ADD_COMPLETED_LINE" and that is displays the completion matches in
                                  ^^

s/is/it/

> +# COMPLETION_LIST.
> +

> +proc test_gdb_complete_tab_multiple { input_line add_completed_line \
> +					  completion_list } {
> +    global gdb_prompt
> +    global bell_re
[snip]
> +
> +proc test_gdb_complete_menu { line expected_output } {
> +

Is this used? Maybe in a subsequent patch?

> +    set test "menu complete $line"
> +#    send_gdb "$expr\033?"
> +#    send_gdb "$expr^\[?"
> +    send_gdb "$expr"
> +    send_gdb "\x1b"
> +    send_gdb "?"
> +    gdb_test_multiple "" "$test" {
> +	-re "$expected_output" {
> +	    pass "$test"
> +	}
> +    }
> +}
> +
[snip]
> +
> +proc test_gdb_complete_unique_re { input_line complete_line_re {append_char " "} {max_completions 0}} {

This procedure is only called from this file. If it is meant to be called by
test writers, it deserves a comment, even if trivial.

If it is only meant for use here, then it should be named differently to
differentiate it, or stick it into an appropriately namespace so that it is
more obvious to potential users of this code that it is not meant to be
"exported." There's a lot of (sometimes mindless) cut-n-paste going on in the
test suite.

> +    set append_char_re [string_to_regexp $append_char]
> +    test_gdb_complete_tab_unique $input_line $complete_line_re $append_char_re
> +
> +    # Trim INPUT_LINE and COMPLETE LINE, for the case we're completing
> +    # a command with leading whitespace.  Leading command whitespace
> +    # is discarded by GDB.
> +    set input_line [string trimleft $input_line]
> +    set expected_output_re [string trimleft $complete_line_re]
> +    if {$append_char_re != " "} {
> +	append expected_output_re $append_char_re
> +    }
> +    if {$max_completions} {
> +	set max_completion_reached_msg \
> +	    "*** List may be truncated, max-completions reached. ***"
> +	set input_line_re \
> +	    [string_to_regexp $input_line]
> +	set max_completion_reached_msg_re \
> +	    [string_to_regexp $max_completion_reached_msg]
> +
> +	append expected_output_re \
> +	    "\r\n$input_line_re $max_completion_reached_msg_re"
> +    }
> +
> +    test_gdb_complete_cmd_unique $input_line $expected_output_re
> +}
[snip]
> +
> +# Test completing all the substring prefixes of COMPLETION from
> +# [0..START) to [0..END) complete to COMPLETION.  If END is ommitted,
> +# default to the length of COMPLETION.
> +
> +proc test_complete_prefix_range {completion start {end -1}} {
> +    if {$end == -1} {
> +	set end [string length $completion]
> +    }
> +
> +    for {set i $start} {$i < $end} {incr i} {
> +	set line [string range $completion 0 $i]
> +	test_gdb_complete_unique "$line" "$completion"
> +    }
> +}
> +
> +proc test_complete_prefix_range_input {input completion_re start {end -1}} {

This procedure also isn't used. Maybe also a later patch? Ditto the "if it
is meant to be used, ..., or renamed/hidden."

> +    if {$end == -1} {
> +	set end [string length $input]
> +    }
> +
> +    for {set i $start} {$i < $end} {incr i} {
> +	set line [string range $input 0 $i]
> +	test_gdb_complete_unique_re "$line" $completion_re
> +    }
> +}
> +
[snip]
> +# Return true if lists A and B have the same elements.  Order of
> +# elements does not matter.
> +
> +proc gdb_leq {a b} {
> +    return [expr {[lsort $a] eq [lsort $b]}]
> +}
> +
> +# Check that creating the breakpoint at LINESPEC finds the same
> +# breakpoint locations as completing LINESPEC.  COMPLETION_LIST is
> +# expected completion match list.

You mention "LINESPEC" here, but this procedure actually takes a breakpoint
command and a linepsec (or location?), no?

> +
> +proc check_bp_locations_match_list {break_command completion_list} {
> +    global gdb_prompt
> +    global hex
> +
> +    with_test_prefix "compare \"$break_command\" completion list with bp location list" {
> +	set num_locations [create_bp $break_command]
> +
> +	set found_list ""
> +
> +	set any "\[^\r\n\]*"
> +
> +	gdb_test_multiple "info breakpoint \$bpnum" "info breakpoint" {
> +	    -re "in \(\[^\r\n\]*\) at " {
> +		# A function location.
> +		set found_location "$expect_out(1,string)"
> +		lappend found_list $found_location
> +		exp_continue
> +	    }
> +	    -re "breakpoint${any}keep${any}y${any}$hex\[ \t]*\(${any}\)\r\n" {
> +		# A label location.
> +		set found_location "$expect_out(1,string)"
> +		lappend found_list $found_location
> +		exp_continue
> +	    }
> +	    -re "$gdb_prompt $" {
> +	    }
> +	}
> +
> +	gdb_assert {[gdb_leq $found_list $completion_list]} "matches"
> +
> +	delete_breakpoints
> +    }
> +}
> +
[snip]

Keith
  

Patch

diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp
new file mode 100644
index 0000000..dd9bf70
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -0,0 +1,959 @@ 
+# Copyright 2017 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/>.
+
+# This file is part of the gdb testsuite.
+
+load_lib completion-support.exp
+
+standard_testfile cpls.cc cpls2.cc cpls-hyphen.cc
+
+if {[prepare_for_testing "failed to prepare" $testfile \
+	 [list $srcfile $srcfile2 $srcfile3] {debug}]} {
+    return -1
+}
+
+# Disable the completion limit for the whole testcase.
+gdb_test_no_output "set max-completions unlimited"
+
+set timeout 5
+
+# Start of tests.
+
+# Test completion of all parameter prefixes, crossing "(" and ")",
+# with and without whitespace.
+
+proc_with_prefix all-param-prefixes {} {
+
+    # Test both linespecs and explicit locations.
+    foreach cmd_prefix {"b" "b -function"} {
+	set line "$cmd_prefix param_prefixes_test_long(long)"
+	set start [index_after "test_long" $line]
+	test_complete_prefix_range $line $start
+
+	# Same, but with extra spaces.  Note that the original spaces in
+	# the input line are preserved after completion.
+	test_gdb_complete_unique \
+	    "$cmd_prefix param_prefixes_test_long(long "   \
+	    "$cmd_prefix param_prefixes_test_long(long )"
+	test_gdb_complete_unique \
+	    "$cmd_prefix param_prefixes_test_long( long "  \
+	    "$cmd_prefix param_prefixes_test_long( long )"
+	test_gdb_complete_unique \
+	    "$cmd_prefix param_prefixes_test_long ( long " \
+	    "$cmd_prefix param_prefixes_test_long ( long )"
+
+	# Complete all parameter prefixes between "(i" and "(int*, int&)".
+	# Note that this exercises completing when the point is at the
+	# space in "param_prefixes_test_intp_intr(int*, ".
+	set line "$cmd_prefix param_prefixes_test_intp_intr(int*, int&)"
+	set start [index_after "intp_intr" $line]
+	test_complete_prefix_range $line $start
+
+	# Similar, but with extra spaces.
+	test_gdb_complete_unique \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int* " \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int* , int&)"
+
+	test_gdb_complete_unique \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int *" \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int *, int&)"
+
+	test_gdb_complete_unique \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int *, int " \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int *, int &)"
+
+	test_gdb_complete_unique \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int *,  int & " \
+	    "$cmd_prefix param_prefixes_test_intp_intr (  int *,  int & )"
+    }
+}
+
+# Test completion of an overloaded function.
+
+proc_with_prefix overload {} {
+    set completion_list {
+	"overload_ambiguous_test(int, int)"
+	"overload_ambiguous_test(int, long)"
+	"overload_ambiguous_test(long)"
+    }
+
+    foreach cmd_prefix {"b" "b -function"} {
+	test_gdb_complete_multiple \
+	    "$cmd_prefix " "overload_ambiguous_" "test(" \
+	    $completion_list
+	check_bp_locations_match_list \
+	    "$cmd_prefix overload_ambiguous_test" \
+	    $completion_list
+
+	# Test disambiguating by typing enough to pick the "int" as
+	# first parameter type.  This then tests handling ambiguity in
+	# the second parameter, which checks that tab completion when
+	# the point is at the whitespace behaves naturally, by showing
+	# the remaining matching overloads to the user.
+	test_gdb_complete_multiple \
+	    "$cmd_prefix " "overload_ambiguous_test(i" "nt, " {
+	    "overload_ambiguous_test(int, int)"
+	    "overload_ambiguous_test(int, long)"
+	}
+
+	# Add a few more characters to make the completion
+	# unambiguous.
+	test_gdb_complete_unique \
+	    "$cmd_prefix overload_ambiguous_test(int, i" \
+	    "$cmd_prefix overload_ambiguous_test(int, int)"
+	check_bp_locations_match_list \
+	    "$cmd_prefix overload_ambiguous_test(int, int)" {
+		"overload_ambiguous_test(int, int)"
+	    }
+    }
+}
+
+# Test completion of a function that is defined in different scopes
+# with different parameters.
+
+proc_with_prefix overload-2 {} {
+    with_test_prefix "all" {
+	set completion_list {
+	    "(anonymous namespace)::overload2_function(overload2_arg3)"
+	    "(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg4)"
+	    "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+	    "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+	    "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+	    "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+	    "ns_overload2_test::overload2_function(overload2_arg5)"
+	    "ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)"
+	    "overload2_function(overload2_arg1)"
+	    "struct_overload2_test::overload2_function(overload2_arg2)"
+	}
+	foreach cmd_prefix {"b" "b -function"} {
+	    test_gdb_complete_multiple \
+		"$cmd_prefix " "overload2_func" "tion(overload2_arg" $completion_list
+	    check_bp_locations_match_list \
+		"$cmd_prefix overload2_function" $completion_list
+	}
+    }
+
+    # Same, but restrict to functions/methods in some scope.
+    with_test_prefix "restrict scope" {
+	set completion_list {
+	    "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+	    "ns_overload2_test::overload2_function(overload2_arg5)"
+	}
+	foreach cmd_prefix {"b" "b -function"} {
+	    test_gdb_complete_multiple \
+		"$cmd_prefix " "ns_overload2_test::overload2_func" "tion(overload2_arg" $completion_list
+	    check_bp_locations_match_list \
+		"$cmd_prefix ns_overload2_test::overload2_function" $completion_list
+	}
+    }
+
+    # Restrict to anonymous namespace scopes.
+    with_test_prefix "restrict scope 2" {
+	set completion_list {
+	    "(anonymous namespace)::overload2_function(overload2_arg3)"
+	    "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+	}
+	foreach cmd_prefix {"b" "b -function"} {
+	    test_gdb_complete_multiple \
+		"$cmd_prefix " "(anonymous namespace)::overload2_func" "tion(overload2_arg" $completion_list
+	    check_bp_locations_match_list \
+		"$cmd_prefix (anonymous namespace)::overload2_function" $completion_list
+	}
+    }
+
+    # Add enough scopes, and we get a unique completion.
+    with_test_prefix "unique completion" {
+	foreach cmd_prefix {"b" "b -function"} {
+	    test_gdb_complete_unique \
+		"$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_func" \
+		"$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+	    check_setting_bp_fails "$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_func"
+	    check_bp_locations_match_list \
+		"$cmd_prefix ns_overload2_test::(anonymous namespace)::overload2_function" \
+		{"ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"}
+	}
+    }
+}
+
+# Test linespecs / locations using fully-qualified names.
+
+proc_with_prefix fqn {} {
+    set cmd_prefix "b -qualified"
+
+    test_gdb_complete_unique \
+	"$cmd_prefix overload2_func" \
+	"$cmd_prefix overload2_function(overload2_arg1)"
+
+    # Drill down until we find a unique completion.
+    test_gdb_complete_multiple "$cmd_prefix " "ns_overload2_test::" "" {
+	"ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+	"ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+	"ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+	"ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+	"ns_overload2_test::overload2_function(overload2_arg5)"
+	"ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)"
+    }
+
+    test_gdb_complete_multiple "$cmd_prefix " "ns_overload2_test::(anonymous namespace)::" "" {
+	"ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+	"ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+	"ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+	"ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+    }
+
+    test_gdb_complete_multiple "$cmd_prefix " "ns_overload2_test::(anonymous namespace)::ns_overload2_test::" "" {
+	"ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+	"ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+    }
+
+    test_gdb_complete_unique \
+	"$cmd_prefix ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_func" \
+	"$cmd_prefix ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+}
+
+# Check that a fully-qualified looked name don't match symbols in
+# nested scopes.
+
+proc_with_prefix fqn-2 {} {
+    set linespec "struct_overload2_test::overload2_function(overload2_arg6)"
+    set cmd_prefix "b -qualified"
+    check_setting_bp_fails "$cmd_prefix $linespec"
+    test_gdb_complete_none "$cmd_prefix $linespec"
+
+    # Check that using the same name, but not fully-qualifying it,
+    # would find something, just to make sure the test above is
+    # testing what we intend to test.
+    set cmd_prefix "b -function"
+    test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec"
+    check_bp_locations_match_list \
+	"$cmd_prefix $linespec" \
+	{"ns_overload2_test::struct_overload2_test::overload2_function(overload2_arg6)"}
+}
+
+# Test completion of functions in different scopes that have the same
+# name and parameters.  Restricting the scopes should find fewer and
+# fewer matches.
+
+proc_with_prefix overload-3 {} {
+    with_test_prefix "all overloads" {
+	set completion_list {
+	    "(anonymous namespace)::overload3_function(int)"
+	    "(anonymous namespace)::overload3_function(long)"
+	    "(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+	    "(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::struct_overload3_test::overload3_function(long)"
+	    "overload3_function(int)"
+	    "overload3_function(long)"
+	    "struct_overload3_test::overload3_function(int)"
+	    "struct_overload3_test::overload3_function(long)"
+	}
+	foreach cmd_prefix {"b" "b -function"} {
+	    test_gdb_complete_multiple "$cmd_prefix " "overload3_func" "tion(" $completion_list
+	    check_bp_locations_match_list "$cmd_prefix overload3_function" $completion_list
+	}
+    }
+
+    with_test_prefix "restrict overload" {
+	foreach cmd_prefix {"b" "b -function"} {
+	    test_gdb_complete_unique \
+		"$cmd_prefix overload3_function(int)" \
+		"$cmd_prefix overload3_function(int)"
+	    check_bp_locations_match_list "$cmd_prefix overload3_function(int)" {
+		"(anonymous namespace)::overload3_function(int)"
+		"(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+		"ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)"
+		"ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+		"ns_overload3_test::(anonymous namespace)::overload3_function(int)"
+		"ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+		"ns_overload3_test::overload3_function(int)"
+		"ns_overload3_test::struct_overload3_test::overload3_function(int)"
+		"overload3_function(int)"
+		"struct_overload3_test::overload3_function(int)"
+	    }
+	}
+    }
+
+    with_test_prefix "restrict scope" {
+	set completion_list {
+	    "(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+	    "(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::struct_overload3_test::overload3_function(long)"
+	    "struct_overload3_test::overload3_function(int)"
+	    "struct_overload3_test::overload3_function(long)"
+	}
+	foreach cmd_prefix {"b" "b -function"} {
+	    test_gdb_complete_multiple \
+		"$cmd_prefix " "struct_overload3_test::overload3_func" "tion(" \
+		$completion_list
+	    check_bp_locations_match_list \
+		"$cmd_prefix struct_overload3_test::overload3_function" \
+		$completion_list
+	}
+    }
+}
+
+# Test completing an overloaded template method.
+
+proc_with_prefix template-overload {} {
+    set completion_list {
+	"template_struct<int>::template_overload_fn(int)"
+	"template_struct<long>::template_overload_fn(long)"
+    }
+    foreach cmd_prefix {"b" "b -function"} {
+	test_gdb_complete_multiple "$cmd_prefix " "template_overload_fn" "(" $completion_list
+	check_bp_locations_match_list "$cmd_prefix template_overload_fn" $completion_list
+	check_bp_locations_match_list \
+	    "$cmd_prefix template_struct<int>::template_overload_fn" \
+	    "template_struct<int>::template_overload_fn(int)"
+    }
+}
+
+# Test completing template methods with non-void return type.
+
+proc_with_prefix template-ret-type {} {
+    set method_name "template2_fn<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>"
+
+    # Templates are listed both with and without return type, making
+    # "template2_<tab>" ambiguous.
+    foreach cmd_prefix {"b" "b -function"} {
+	set completion_list \
+	    [list \
+		 "${ret_type} ${struct_type}::${method_name}${param_list}" \
+		 "${struct_type}::${method_name}${param_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,
+	# thus testing completing either with or without return type.
+	foreach {s t} [list \
+			   "template2_r" \
+			   "${ret_type} ${struct_type}::${method_name}${param_list}" \
+			   "template2_s" \
+			   "${struct_type}::${method_name}${param_list}"] {
+	    set linespec $t
+	    set complete_line "$cmd_prefix $linespec"
+	    set start [index_after $s $complete_line]
+	    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.
+	foreach linespec [list \
+			      "${method_name}" \
+			      "${method_name}${param_list}" \
+			      "${struct_type}::${method_name}" \
+			      "${struct_type}::${method_name}${param_list}" \
+			      "${ret_type} ${struct_type}::${method_name}" \
+			      "${ret_type} ${struct_type}::${method_name}${param_list}"] {
+	    check_bp_locations_match_list \
+		"$cmd_prefix $linespec" \
+		[list "${struct_type}::${method_name}${param_list}"]
+	}
+    }
+}
+
+# Test completion of a const-overloaded funtion (const-overload).
+# Note that "const" appears after the function/method parameters.
+
+proc_with_prefix const-overload {} {
+    set completion_list {
+	"struct_with_const_overload::const_overload_fn()"
+	"struct_with_const_overload::const_overload_fn() const"
+    }
+    foreach cmd_prefix {"b" "b -function"} {
+	test_gdb_complete_multiple \
+	    "$cmd_prefix " "const_overload_fn" "()" \
+	    $completion_list
+	test_gdb_complete_multiple \
+	    "$cmd_prefix " "const_overload_fn ( " ")" \
+	    $completion_list
+	test_gdb_complete_multiple \
+	    "$cmd_prefix " "const_overload_fn()" "" \
+	    $completion_list
+
+	check_bp_locations_match_list \
+	    "$cmd_prefix const_overload_fn" \
+	    {"struct_with_const_overload::const_overload_fn()"
+		"struct_with_const_overload::const_overload_fn() const"}
+
+	check_setting_bp_fails "$cmd_prefix const_overload_fn("
+	check_bp_locations_match_list \
+	    "$cmd_prefix const_overload_fn()" \
+	    {"struct_with_const_overload::const_overload_fn()"}
+	check_bp_locations_match_list \
+	    "$cmd_prefix const_overload_fn() const" \
+	    {"struct_with_const_overload::const_overload_fn() const"}
+    }
+}
+
+# Same but quote-enclose the function name.  This makes the overload
+# no longer be ambiguous.
+
+proc_with_prefix const-overload-quoted {} {
+    foreach cmd_prefix {"b" "b -function"} {
+	set linespec "'const_overload_fn()'"
+	test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec"
+	check_bp_locations_match_list \
+	    "$cmd_prefix $linespec" {
+		"struct_with_const_overload::const_overload_fn()"
+	    }
+
+	set linespec "'const_overload_fn() const'"
+	test_gdb_complete_unique "$cmd_prefix $linespec" "$cmd_prefix $linespec"
+	check_bp_locations_match_list \
+	    "$cmd_prefix $linespec" {
+		"struct_with_const_overload::const_overload_fn() const"
+	    }
+    }
+}
+
+# Test that when the function is unambiguous, linespec completion
+# appends the end quote char automatically, both ' and ".
+
+proc_with_prefix append-end-quote-char-when-unambiguous {} {
+    global all_quotes_list
+
+    foreach cmd_prefix {"b" "b -function"} {
+	foreach qc $all_quotes_list {
+	    set linespec "${qc}not_overloaded_fn()${qc}"
+	    foreach cmd [list "$cmd_prefix ${qc}not_overloaded_fn()" \
+			      "$cmd_prefix ${qc}not_overloaded_fn" \
+			      "$cmd_prefix ${qc}not_overloaded_"] {
+		test_gdb_complete_unique $cmd "$cmd_prefix $linespec"
+	    }
+	    check_bp_locations_match_list \
+		"$cmd_prefix $linespec" {"not_overloaded_fn()"}
+	}
+    }
+}
+
+# Test completing symbols of source files.
+
+proc_with_prefix in-source-file-unconstrained {} {
+    # First test that unconstrained matching picks up functions from
+    # multiple files.
+    test_gdb_complete_multiple "b " "file_constrained_test" "_cpls" {
+	"file_constrained_test_cpls2_function(int)"
+	"file_constrained_test_cpls_function(int)"
+    }
+    check_setting_bp_fails "b file_constrained_test_cpls"
+}
+
+# Test an unambiguous completion that would be ambiguous if it weren't
+# for the source file component, due to
+# "file_constrained_test_cpls_function" in cpls.cc.  Test with
+# different components quoted, and with whitespace before the function
+# name.
+
+proc_with_prefix in-source-file-unambiguous {} {
+    global maybe_quoted_list
+
+    foreach sqc $maybe_quoted_list {
+	foreach fqc $maybe_quoted_list {
+	    # Linespec.
+	    foreach sep {":" ": "} {
+		set linespec "${sqc}cpls2.cc${sqc}${sep}${fqc}file_constrained_test_cpls2_function(int)${fqc}"
+		set complete_line "b $linespec"
+		set start [index_after "constrained_test" $complete_line]
+		set input_line [string range $complete_line 0 $start]
+		test_gdb_complete_unique $input_line ${complete_line}
+		check_bp_locations_match_list "b $linespec" {
+		    "file_constrained_test_cpls2_function(int)"
+		}
+	    }
+
+	    # Explicit location.
+	    set source_opt "-source ${sqc}cpls2.cc${sqc}"
+	    set function_opt "-function ${fqc}file_constrained_test_cpls2_function(int)${fqc}"
+	    set complete_line "b $source_opt $function_opt"
+	    set start [index_after "cpls2_functio" $complete_line]
+	    set input_line [string range $complete_line 0 $start]
+	    test_gdb_complete_unique $input_line ${complete_line}
+	    check_bp_locations_match_list "$complete_line" {
+		    "file_constrained_test_cpls2_function(int)"
+	    }
+	}
+    }
+}
+
+# Test an ambiguous completion constrained by a source file.  Test
+# with different components quoted, and with whitespace before the
+# function name.
+
+proc_with_prefix in-source-file-ambiguous {} {
+    global maybe_quoted_list
+
+    foreach sqc $maybe_quoted_list {
+	foreach fqc $maybe_quoted_list {
+	    # Linespec.
+	    foreach sep {":" ": "} {
+		set cmd_prefix "b ${sqc}cpls2.cc${sqc}${sep}"
+		test_gdb_complete_multiple "${cmd_prefix}" ${fqc} "" {
+		    "another_file_constrained_test_cpls2_function(int)"
+		    "file_constrained_test_cpls2_function(int)"
+		} ${fqc} ${fqc}
+	    }
+
+	    # Explicit location.
+	    test_gdb_complete_multiple \
+		"b -source ${sqc}cpls2.cc${sqc} -function " ${fqc} "" {
+		"another_file_constrained_test_cpls2_function(int)"
+		"file_constrained_test_cpls2_function(int)"
+	    } ${fqc} ${fqc}
+	}
+    }
+}
+
+# Check that completing a file name in a linespec auto-appends a colon
+# instead of a whitespace character.
+
+proc_with_prefix source-complete-appends-colon {} {
+    global maybe_quoted_list
+    global all_quotes_list
+    global keyword_list
+
+    # Test with quotes to make sure the end quote char is put at the
+    # right place.
+    foreach qc $maybe_quoted_list {
+	test_gdb_complete_unique \
+	    "b ${qc}cpls2." \
+	    "b ${qc}cpls2.cc${qc}" ":"
+	test_gdb_complete_unique \
+	    "b ${qc}cpls2.c" \
+	    "b ${qc}cpls2.cc${qc}" ":"
+	test_gdb_complete_unique \
+	    "b ${qc}cpls2.cc" \
+	    "b ${qc}cpls2.cc${qc}" ":"
+
+	# Same, but with a filename with an hyphen (which is normally
+	# a language word break char).
+	test_gdb_complete_unique \
+	    "b ${qc}cpls-" \
+	    "b ${qc}cpls-hyphen.cc${qc}" ":"
+	test_gdb_complete_unique \
+	    "b ${qc}cpls-hyphen" \
+	    "b ${qc}cpls-hyphen.cc${qc}" ":"
+    }
+
+    # Test the same, but with the name of a nonexisting file.
+
+    # Cursor at the end of the string.
+    test_gdb_complete_none "b nonexistingfilename.cc"
+    # Cursor past the end of the string.
+    test_gdb_complete_multiple "b nonexistingfilename.cc " "" "" $keyword_list
+    foreach qc $all_quotes_list {
+	# Unterminated quote.
+	test_gdb_complete_none "b ${qc}nonexistingfilename.cc"
+	test_gdb_complete_none "b ${qc}nonexistingfilename.cc "
+	# Terminated quote, cursor at the quote.
+	test_gdb_complete_unique \
+	    "b ${qc}nonexistingfilename.cc${qc}" \
+	    "b ${qc}nonexistingfilename.cc${qc}"
+	# Terminated quote, cursor past the quote.
+	test_gdb_complete_multiple \
+	    "b ${qc}nonexistingfilename.cc${qc} " "" "" $keyword_list
+    }
+}
+
+####################################################################
+
+# Test that a colon at the end of the linespec is understood as an
+# incomplete scope operator (incomplete-scope-colon), instead of a
+# source/function separator.
+
+proc_with_prefix incomplete-scope-colon {} {
+
+    # Helper for the loop below to simplify it.  Tests completion of
+    # the range defined by the RANGE_SS found in the constructed line.
+    #
+    # E.g., with:
+    #
+    #   source="source.cc"
+    #   fqc="'"
+    #   prototype="ns::function()"
+    #   range_ss="s::f"
+    #
+    # we'd try completing with the cursor set in each of the
+    # underlined range's positions of:
+    #
+    #   b source.cc:'ns::function()'"
+    #                 ^^^^
+    #
+    # Also test that setting a breakpoint at the constructed line
+    # finds the same breakpoint location as completion does.
+    #
+    proc incomplete_scope_colon_helper {prototype range_ss {skip_check_bp 0}} {
+	global maybe_quoted_list
+
+	foreach source {"" "cpls.cc"} {
+	    # Test with and without source quoting.
+	    foreach sqc $maybe_quoted_list {
+		if {$source == "" && $sqc != ""} {
+		    # Invalid combination.
+		    continue
+		}
+
+		# Test with and without function quoting.
+		foreach fqc $maybe_quoted_list {
+		    if {$source == ""} {
+			set linespec_source ""
+			set explicit_source ""
+		    } else {
+			set linespec_source "${sqc}${source}${sqc}:"
+			set explicit_source "-source ${sqc}${source}${sqc}"
+		    }
+
+		    # Even though this use case is trickier with
+		    # linespecs due to the ":" as separator, test both
+		    # linespecs and explicit locations for
+		    # completeness.
+		    foreach location [list \
+					  "${linespec_source}${fqc}$prototype${fqc}" \
+					  "${explicit_source} -function ${fqc}$prototype${fqc}"] {
+			set complete_line "b $location"
+			set start [string first $range_ss $complete_line]
+			set end [expr ($start + [string length $range_ss])]
+			test_complete_prefix_range $complete_line $start $end
+			if {!$skip_check_bp} {
+			    check_bp_locations_match_list "b $location" [list "$prototype"]
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    incomplete_scope_colon_helper \
+	"struct_incomplete_scope_colon_test::incomplete_scope_colon_test()" \
+	"t::i"
+
+    incomplete_scope_colon_helper \
+	"ns_incomplete_scope_colon_test::incomplete_scope_colon_test()" \
+	"t::i"
+
+    # Test completing around both "::"s.
+    foreach range_ss {"t::s" "t::i"} skip_check_bp {0 1} {
+	incomplete_scope_colon_helper \
+	    "ns2_incomplete_scope_colon_test::struct_in_ns2_incomplete_scope_colon_test::incomplete_scope_colon_test()" \
+	    $range_ss $skip_check_bp
+    }
+}
+
+# Test completing functions/methods in anonymous namespaces.
+
+proc_with_prefix anon-ns {} {
+    global maybe_quoted_list
+
+    foreach cmd_prefix {"b" "b -function"} {
+	foreach qc $maybe_quoted_list {
+	    test_gdb_complete_unique \
+		"$cmd_prefix ${qc}anon_ns_function" \
+		"$cmd_prefix ${qc}anon_ns_function()${qc}"
+	    check_bp_locations_match_list "$cmd_prefix ${qc}anon_ns_function()${qc}" {
+		"(anonymous namespace)::anon_ns_function()"
+		"(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+		"the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()"
+		"the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+	    }
+	}
+
+	# A "(" finds all anonymous namespace functions/methods in all
+	# scopes.
+	test_gdb_complete_multiple "$cmd_prefix " "(" "anonymous namespace)::" {
+	    "(anonymous namespace)::anon_ns_function()"
+	    "(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+	    "(anonymous namespace)::overload2_function(overload2_arg3)"
+	    "(anonymous namespace)::overload3_function(int)"
+	    "(anonymous namespace)::overload3_function(long)"
+	    "(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg4)"
+	    "(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+	    "(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+	    "ns_overload2_test::(anonymous namespace)::ns_overload2_test::overload2_function(overload2_arg9)"
+	    "ns_overload2_test::(anonymous namespace)::ns_overload2_test::struct_overload2_test::overload2_function(overload2_arga)"
+	    "ns_overload2_test::(anonymous namespace)::overload2_function(overload2_arg7)"
+	    "ns_overload2_test::(anonymous namespace)::struct_overload2_test::overload2_function(overload2_arg8)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::ns_overload3_test::struct_overload3_test::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::overload3_function(long)"
+	    "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(int)"
+	    "ns_overload3_test::(anonymous namespace)::struct_overload3_test::overload3_function(long)"
+	    "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()"
+	    "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_struct::anon_ns_function()"
+	}
+
+	set function "the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_function()"
+	test_gdb_complete_unique "$cmd_prefix $function" "$cmd_prefix $function"
+	check_bp_locations_match_list "$cmd_prefix $function" [list $function]
+
+	# Test completing after the "(anonymous namespace)" part.
+	test_gdb_complete_unique \
+	    "$cmd_prefix the_anon_ns_wrapper_ns::(anonymous namespace)::anon_ns_fu" \
+	    "$cmd_prefix $function"
+
+	# Test whitespace in the "(anonymous namespace)" component.
+
+	test_gdb_complete_unique \
+	    "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous   namespace )::anon_ns_fu" \
+	    "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous   namespace )::anon_ns_function()"
+	check_setting_bp_fails \
+	    "$cmd_prefix the_anon_ns_wrapper_ns::( anonymous   namespace )::anon_ns_fu"
+
+	set function_ws \
+	    "the_anon_ns_wrapper_ns::( anonymous   namespace )::anon_ns_function ( )"
+	test_gdb_complete_unique "$cmd_prefix $function_ws" "$cmd_prefix $function_ws"
+	check_bp_locations_match_list "$cmd_prefix $function_ws" [list $function]
+    }
+}
+
+# Basic test for completing "operator<".  More extensive C++ operator
+# tests in cpls-op.exp.
+
+proc_with_prefix operator< {} {
+    # Complete all prefixes between "oper" and the whole prototype.
+    set function "operator<(foo_enum, foo_enum)"
+    foreach cmd_prefix {"b" "b -function"} {
+	set line "$cmd_prefix $function"
+	set start [index_after "oper" $line]
+	test_complete_prefix_range $line $start
+    }
+
+    # There's a label in the function; try completing it.  (Exhaustive
+    # label completion tests further below.)
+    foreach location [list \
+		     "$function:label1" \
+		     "-function $function -label label1"] {
+
+	set cmd "b $location"
+	set input_line [string range $cmd 0 [expr [string length $cmd] - 3]]
+
+	test_gdb_complete_unique $input_line $cmd
+	test_gdb_complete_unique $cmd $cmd
+	check_bp_locations_match_list $cmd [list "$location"]
+    }
+}
+
+# Test completion of scopes with an ambiguous prefix.
+
+proc_with_prefix ambiguous-prefix {} {
+    foreach cmd_prefix {"b" "b -function"} {
+	test_gdb_complete_multiple "$cmd_prefix " "ambiguous_pre" "fix_" {
+	    "ambiguous_prefix_global_func()"
+	    "the_ambiguous_prefix_ns::ambiguous_prefix_ns_func()"
+	    "the_ambiguous_prefix_struct::ambiguous_prefix_method()"
+	}
+	check_setting_bp_fails "$cmd_prefix ambiguous_prefix_"
+    }
+}
+
+# Test completion of function labels.
+
+proc_with_prefix function-labels {} {
+    # Test with and without a source file component.
+    foreach_location_functions \
+	{ "" "cpls.cc" } \
+	{ "function_with_labels(int)" } \
+	{
+	    # Linespec version.  Test various spacing around the label
+	    # colon separator.
+	    foreach label_sep {":" " :" ": " " : "} {
+		set linespec "${location}${label_sep}"
+		test_gdb_complete_multiple "b $linespec" "l" "abel" {
+		    "label1"
+		    "label2"
+		}
+		check_setting_bp_fails "b ${linespec}label"
+
+		set tsep [string trim ${source_sep}]
+		check_bp_locations_match_list \
+		    "b ${linespec}label1" [list "${source}${tsep}${function}:label1"]
+		check_bp_locations_match_list \
+		    "b ${linespec}label2" [list "${source}${tsep}${function}:label2"]
+	    }
+	} \
+	{
+	    # Explicit locations version.
+	    append location " -label"
+	    test_gdb_complete_multiple "b $location " "l" "abel" {
+		"label1"
+		"label2"
+	    }
+	    check_setting_bp_fails "b $location label"
+
+	    if {$source != ""} {
+		set bp_loc_src "-source ${source} "
+	    } else {
+		set bp_loc_src ""
+	    }
+	    check_bp_locations_match_list \
+		"b ${location} label1" [list "${bp_loc_src}-function $function -label label1"]
+	    check_bp_locations_match_list \
+		"b ${location} label2" [list "${bp_loc_src}-function $function -label label2"]
+	}
+}
+
+# Test that completion after a function name offers keyword
+# (if/task/thread) matches in linespec mode, and also the explicit
+# location options in explicit locations mode.
+
+proc_with_prefix keywords-after-function {} {
+    global explicit_opts_list keyword_list
+
+    set explicit_list [concat $explicit_opts_list $keyword_list]
+
+    # Test without a source file, with a known source file, and with
+    # and unknown source file.
+    # Test a known and an unknown function.
+    foreach_location_functions \
+	{ "" "cpls.cc" "unknown_file.cc" } \
+	{ "function_with_labels(int)" "unknown_function(int)" } \
+	{
+	    # Linespec version.
+	    test_gdb_complete_multiple "b ${location} " "" "" $keyword_list
+	} \
+	{
+	    # Explicit locations version.
+	    test_gdb_complete_multiple "b ${location} " "" "" $explicit_list
+	}
+}
+
+# Same, but after a label.
+
+proc_with_prefix keywords-after-label {} {
+    global explicit_opts_list keyword_list
+
+    set explicit_list [concat $explicit_opts_list $keyword_list]
+
+    foreach_location_labels \
+	{ "" "cpls.cc" } \
+	{ "function_with_labels(int)" "unknown_function(int)" } \
+	{ "label1" "non_existing_label" } \
+	{
+	    # Linespec version.
+	    test_gdb_complete_multiple "b ${location} " "" "" $keyword_list
+	} \
+	{
+	    # Explicit locations version.
+	    test_gdb_complete_multiple "b ${location} " "" "" $explicit_list
+	}
+}
+
+# Similar, but after an unknown file, and in linespec mode only.
+
+proc_with_prefix keywords-after-unknown-file {} {
+    global maybe_quoted_list
+    global keyword_list
+
+    # Test with and without quoting.
+    foreach qc $maybe_quoted_list {
+	set line "b ${qc}unknown_file.cc${qc}: "
+	test_gdb_complete_multiple $line "" "" $keyword_list
+    }
+}
+
+# Test that linespec / function completion does not match data
+# symbols, only functions/methods.
+
+proc_with_prefix no-data-symbols {} {
+    foreach cmd_prefix {"b" "b -function"} {
+	test_gdb_complete_unique "$cmd_prefix code_" "$cmd_prefix code_function()"
+    }
+}
+
+
+# After "if", we expect an expression, which has a different completer
+# that matches data symbols as well.  Check that that works.
+
+proc_with_prefix if-expression {} {
+    foreach cmd_prefix {"b" "b -function"} {
+	test_gdb_complete_multiple "$cmd_prefix function() if " "code_" "" {
+	    "code_data"
+	    "code_function()"
+	}
+
+	test_gdb_complete_unique \
+	    "$cmd_prefix function() if code_data + another_da" \
+	    "$cmd_prefix function() if code_data + another_data"
+
+	test_gdb_complete_unique \
+	    "$cmd_prefix non_existing_function() if code_data + another_da" \
+	    "$cmd_prefix non_existing_function() if code_data + another_data"
+
+	# FIXME: For now, thread and task also use the expression
+	# completer.
+	test_gdb_complete_unique \
+	    "$cmd_prefix function() thread code_data + another_da" \
+	    "$cmd_prefix function() thread code_data + another_data"
+	test_gdb_complete_unique \
+	    "$cmd_prefix function() task code_data + another_da" \
+	    "$cmd_prefix function() task code_data + another_data"
+    }
+}
+
+# The testcase driver.  Calls all test procedures.
+
+proc test_driver {} {
+    all-param-prefixes
+    overload
+    overload-2
+    fqn
+    fqn-2
+    overload-3
+    template-overload
+    template-ret-type
+    const-overload
+    const-overload-quoted
+    append-end-quote-char-when-unambiguous
+    in-source-file-unconstrained
+    in-source-file-unambiguous
+    in-source-file-ambiguous
+    source-complete-appends-colon
+    incomplete-scope-colon
+    anon-ns
+    operator<
+    ambiguous-prefix
+    function-labels
+    keywords-after-function
+    keywords-after-label
+    keywords-after-unknown-file
+    no-data-symbols
+    if-expression
+}
+
+test_driver
diff --git a/gdb/testsuite/gdb.linespec/cpls-hyphen.cc b/gdb/testsuite/gdb.linespec/cpls-hyphen.cc
new file mode 100644
index 0000000..fdc063f
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpls-hyphen.cc
@@ -0,0 +1,14 @@ 
+int
+ns_hyphen_function (int i)
+{
+  if (i > 0)
+    {
+    label1:
+      return i + 20;
+    }
+  else
+    {
+    label2:
+      return i + 10;
+    }
+}
diff --git a/gdb/testsuite/gdb.linespec/cpls.cc b/gdb/testsuite/gdb.linespec/cpls.cc
new file mode 100644
index 0000000..776dd4c
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpls.cc
@@ -0,0 +1,386 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 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/>.  */
+
+/* Code for the all-param-prefixes test.  */
+
+void
+param_prefixes_test_long (long)
+{}
+
+void
+param_prefixes_test_intp_intr (int *, int&)
+{}
+
+/* Code for the overload test.  */
+
+void
+overload_ambiguous_test (long)
+{}
+
+void
+overload_ambiguous_test (int, int)
+{}
+
+void
+overload_ambiguous_test (int, long)
+{}
+
+/* Code for the overload-2 test.  */
+
+/* Generate functions/methods all with the same name, in different
+   scopes, but all with different parameters.  */
+
+struct overload2_arg1 {};
+struct overload2_arg2 {};
+struct overload2_arg3 {};
+struct overload2_arg4 {};
+struct overload2_arg5 {};
+struct overload2_arg6 {};
+struct overload2_arg7 {};
+struct overload2_arg8 {};
+struct overload2_arg9 {};
+struct overload2_arga {};
+
+#define GEN_OVERLOAD2_FUNCTIONS(ARG1, ARG2)		\
+  void							\
+  overload2_function (ARG1)				\
+  {}							\
+							\
+  struct struct_overload2_test				\
+  {							\
+    void overload2_function (ARG2);			\
+  };							\
+							\
+  void							\
+  struct_overload2_test::overload2_function (ARG2)	\
+  {}
+
+/* In the global namespace.  */
+GEN_OVERLOAD2_FUNCTIONS( overload2_arg1, overload2_arg2)
+
+namespace
+{
+  /* In an anonymous namespace.  */
+  GEN_OVERLOAD2_FUNCTIONS (overload2_arg3, overload2_arg4)
+}
+
+namespace ns_overload2_test
+{
+  /* In a namespace.  */
+  GEN_OVERLOAD2_FUNCTIONS (overload2_arg5, overload2_arg6)
+
+  namespace
+  {
+    /* In a nested anonymous namespace.  */
+    GEN_OVERLOAD2_FUNCTIONS (overload2_arg7, overload2_arg8)
+
+    namespace ns_overload2_test
+    {
+      /* In a nested namespace.  */
+      GEN_OVERLOAD2_FUNCTIONS (overload2_arg9, overload2_arga)
+    }
+  }
+}
+
+/* Code for the overload-3 test.  */
+
+#define GEN_OVERLOAD3_FUNCTIONS(ARG1, ARG2)		\
+  void							\
+  overload3_function (ARG1)				\
+  {}							\
+  void							\
+  overload3_function (ARG2)				\
+  {}							\
+							\
+  struct struct_overload3_test				\
+  {							\
+    void overload3_function (ARG1);			\
+    void overload3_function (ARG2);			\
+  };							\
+							\
+  void							\
+  struct_overload3_test::overload3_function (ARG1)	\
+  {}							\
+  void							\
+  struct_overload3_test::overload3_function (ARG2)	\
+  {}
+
+/* In the global namespace.  */
+GEN_OVERLOAD3_FUNCTIONS (int, long)
+
+namespace
+{
+  /* In an anonymous namespace.  */
+  GEN_OVERLOAD3_FUNCTIONS (int, long)
+}
+
+namespace ns_overload3_test
+{
+  /* In a namespace.  */
+  GEN_OVERLOAD3_FUNCTIONS (int, long)
+
+  namespace
+  {
+    /* In a nested anonymous namespace.  */
+    GEN_OVERLOAD3_FUNCTIONS (int, long)
+
+    namespace ns_overload3_test
+    {
+      /* In a nested namespace.  */
+      GEN_OVERLOAD3_FUNCTIONS (int, long)
+    }
+  }
+}
+
+/* Code for the template-overload tests.  */
+
+template <typename T>
+struct template_struct
+{
+  T template_overload_fn (T);
+};
+
+template <typename T>
+T template_struct<T>::template_overload_fn (T t)
+{
+  return t;
+}
+
+template_struct<int> template_struct_int;
+template_struct<long> template_struct_long;
+
+/* Code for the template2-ret-type tests.  */
+
+template <typename T>
+struct template2_ret_type {};
+
+template <typename T>
+struct template2_struct
+{
+  template <typename T2, typename T3>
+  T template2_fn (T = T (), T2 t2 = T2 (), T3 t3 = T3 ());
+};
+
+template <typename T>
+template <typename T2, typename T3>
+T template2_struct<T>::template2_fn (T t, T2 t2, T3 t3)
+{
+  return T ();
+}
+
+template2_struct<template2_ret_type<int> > template2_struct_inst;
+
+/* Code for the const-overload tests.  */
+
+struct struct_with_const_overload
+{
+  void const_overload_fn ();
+  void const_overload_fn () const;
+};
+
+void
+struct_with_const_overload::const_overload_fn ()
+{}
+
+void
+struct_with_const_overload::const_overload_fn () const
+{}
+
+void
+not_overloaded_fn ()
+{}
+
+/* Code for the incomplete-scope-colon tests.  */
+
+struct struct_incomplete_scope_colon_test
+{
+  void incomplete_scope_colon_test ();
+};
+
+void
+struct_incomplete_scope_colon_test::incomplete_scope_colon_test ()
+{}
+
+namespace ns_incomplete_scope_colon_test
+{
+  void incomplete_scope_colon_test () {}
+}
+
+namespace ns2_incomplete_scope_colon_test
+{
+  struct struct_in_ns2_incomplete_scope_colon_test
+  {
+    void incomplete_scope_colon_test ();
+  };
+
+  void
+  struct_in_ns2_incomplete_scope_colon_test::incomplete_scope_colon_test ()
+  {}
+}
+
+/* Code for the anon-ns tests.  */
+
+namespace
+{
+  void anon_ns_function ()
+  {}
+
+  struct anon_ns_struct
+  {
+    void anon_ns_function ();
+  };
+
+  void
+  anon_ns_struct::anon_ns_function ()
+  {}
+}
+
+namespace the_anon_ns_wrapper_ns
+{
+
+namespace
+{
+  void anon_ns_function ()
+  {}
+
+  struct anon_ns_struct
+  {
+    void anon_ns_function ();
+  };
+
+  void
+  anon_ns_struct::anon_ns_function ()
+  {}
+}
+
+} /* the_anon_ns_wrapper_ns */
+
+/* Code for the global-ns-scope-op tests.  */
+
+void global_ns_scope_op_function ()
+{
+}
+
+/* Add a function with the same name to a namespace.  We want to test
+   that "b ::global_ns_function" does NOT select it.  */
+namespace the_global_ns_scope_op_ns
+{
+  void global_ns_scope_op_function ()
+  {
+  }
+}
+
+/* Code for the ambiguous-prefix tests.  */
+
+/* Create a few functions/methods with the same "ambiguous_prefix_"
+   prefix.  They in different scopes, but "b ambiguous_prefix_<tab>"
+   should list them all, and figure out the LCD is
+   ambiguous_prefix_.  */
+
+void ambiguous_prefix_global_func ()
+{
+}
+
+namespace the_ambiguous_prefix_ns
+{
+  void ambiguous_prefix_ns_func ()
+  {
+  }
+}
+
+struct the_ambiguous_prefix_struct
+{
+  void ambiguous_prefix_method ();
+};
+
+void
+the_ambiguous_prefix_struct::ambiguous_prefix_method ()
+{
+}
+
+/* Code for the function-labels test.  */
+
+int
+function_with_labels (int i)
+{
+  if (i > 0)
+    {
+    label1:
+      return i + 20;
+    }
+  else
+    {
+    label2:
+      return i + 10;
+    }
+}
+
+/* Code for the no-data-symbols and if-expression tests.  */
+
+int code_data = 0;
+
+int another_data = 0;
+
+/* A function that has a same "code" prefix as the global above.  We
+   want to ensure that completing on "b code" doesn't offer the data
+   symbol.  */
+void
+code_function ()
+{
+}
+
+/* Code for the operator< tests.  */
+
+enum foo_enum
+  {
+    foo_value
+  };
+
+bool operator<(foo_enum lhs, foo_enum rhs)
+{
+ label1:
+	return false;
+}
+
+/* Code for the in-source-file-unconstrained /
+   in-source-file-ambiguous tests.  */
+
+int
+file_constrained_test_cpls_function (int i)
+{
+  if (i > 0)
+    {
+    label1:
+      return i + 20;
+    }
+  else
+    {
+    label2:
+      return i + 10;
+    }
+}
+
+
+int
+main ()
+{
+  template2_struct_inst.template2_fn<int, int> ();
+  template_struct_int.template_overload_fn(0);
+  template_struct_long.template_overload_fn(0);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.linespec/cpls2.cc b/gdb/testsuite/gdb.linespec/cpls2.cc
new file mode 100644
index 0000000..a8f1319
--- /dev/null
+++ b/gdb/testsuite/gdb.linespec/cpls2.cc
@@ -0,0 +1,46 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 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/>.  */
+
+int
+file_constrained_test_cpls2_function (int i)
+{
+  if (i > 0)
+    {
+    label1:
+      return i + 20;
+    }
+  else
+    {
+    label2:
+      return i + 10;
+    }
+}
+
+int
+another_file_constrained_test_cpls2_function (int i)
+{
+  if (i > 0)
+    {
+    label1:
+      return i + 20;
+    }
+  else
+    {
+    label2:
+      return i + 10;
+    }
+}
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
index 65d78ca..998b70a 100644
--- a/gdb/testsuite/gdb.linespec/explicit.exp
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -15,6 +15,8 @@ 
 
 # Tests for explicit locations
 
+load_lib completion-support.exp
+
 standard_testfile explicit.c explicit2.c 3explicit.c
 set exefile $testfile
 
@@ -222,13 +224,14 @@  namespace eval $testfile {
 	    }
 	}
 
-	set tst "complete unique file name"
-	send_gdb "break -source 3ex\t"
-	gdb_test_multiple "" $tst {
-	    -re "break -source 3explicit.c " {
-		send_gdb "\n"
-		gdb_test "" \
-		    {Source filename requires function, label, or line offset.} $tst
+	with_test_prefix "complete unique file name" {
+	    foreach qc $maybe_quoted_list {
+		set cmd "break -source ${qc}3explicit.c${qc}"
+		test_gdb_complete_unique \
+		    "break -source ${qc}3ex" \
+		    $cmd
+		gdb_test $cmd \
+		    {Source filename requires function, label, or line offset.}
 	    }
 	}
 
@@ -326,10 +329,202 @@  namespace eval $testfile {
 	    }
 	}
 
+	global maybe_quoted_list
+
+	with_test_prefix "complete unique label name" {
+	    foreach qc $maybe_quoted_list {
+		test_gdb_complete_unique \
+		    "break -function myfunction -label ${qc}to" \
+		    "break -function myfunction -label ${qc}top${qc}"
+	    }
+	}
+
+	with_test_prefix "complete unique label name with source file" {
+	    test_gdb_complete_unique \
+		"break -source explicit.c -function myfunction -label to" \
+		"break -source explicit.c -function myfunction -label top"
+	}
+
+	with_test_prefix "complete unique label name reversed" {
+	    test_gdb_complete_multiple "b -label top -function " "myfunction" "" {
+		"myfunction"
+		"myfunction2"
+		"myfunction3"
+		"myfunction4"
+	    }
+	}
+
+	with_test_prefix "complete non-unique label name" {
+	    test_gdb_complete_multiple "b -function myfunction -label " "" "" {
+		"done"
+		"top"
+	    }
+	}
+
+	# The program is stopped at myfunction, so gdb is able to
+	# infer the label's function.
+	with_test_prefix "complete label name with no function" {
+	    test_gdb_complete_unique \
+		"break -label to" \
+		"break -label top"
+	    check_bp_locations_match_list \
+		"break -label top" {
+		    "-function myfunction -label top"
+		}
+	}
+
+	# See above.
+	with_test_prefix "complete label name with source file but no function" {
+	    test_gdb_complete_unique \
+		"break -source explicit.c -label to" \
+		"break -source explicit.c -label top"
+	    check_bp_locations_match_list \
+		"break -source explicit.c -label top" {
+		    "-source explicit.c -function myfunction -label top"
+		}
+	}
+
+	with_test_prefix "complete label name with wrong source file" {
+	    test_gdb_complete_none \
+		"break -source explicit2.c -function myfunction -label to"
+	    check_setting_bp_fails \
+		"break -source explicit2.c -function myfunction -label top"
+	}
+
+	# Get rid of symbols from shared libraries, otherwise
+	# "b -source thr<tab>" could find some system library's
+	# source.
+	gdb_test_no_output "nosharedlibrary"
+
+	# Test that after a seemingly finished option argument,
+	# completion matches both the explicit location options and
+	# the linespec keywords.
+	set completions_list {
+	    "-function"
+	    "-label"
+	    "-line"
+	    "-qualified"
+	    "-source"
+	    "if"
+	    "task"
+	    "thread"
+	}
+	foreach what { "-function" "-label" "-line" "-qualified" "-source" } {
+	    with_test_prefix "complete after $what" {
+		if {$what != "-line"} {
+		    test_gdb_complete_multiple \
+			"b $what argument " "" "" $completions_list
+		    test_gdb_complete_unique \
+			"b $what argument thr" \
+			"b $what argument thread"
+		    test_gdb_complete_unique \
+			"b $what argument -fun" \
+			"b $what argument -function"
+		} else {
+		    # After -line, we expect a number / offset.
+		    foreach line {"10" "+10" "-10"} {
+			test_gdb_complete_multiple \
+			    "b -line $line " "" "" $completions_list
+			test_gdb_complete_unique \
+			    "b -line $line thr" \
+			    "b -line $line thread"
+			test_gdb_complete_unique \
+			    "b -line $line -fun" \
+			    "b -line $line -function"
+		    }
+
+		    # With an invalid -line argument, we don't get any
+		    # completions.
+		    test_gdb_complete_none "b -line argument "
+		}
+
+		# Don't complete a linespec keyword ("thread") or
+		# another option name when expecting an option
+		# argument.
+		test_gdb_complete_none "b $what thr"
+		test_gdb_complete_none "b $what -fun"
+	    }
+	}
+
+	# Tests that ensure that after "if" we complete on expressions
+	# are in cpcompletion.exp.
+
+	# Disable the completion limit for the rest of the testcase.
+	gdb_test_no_output "set max-completions unlimited"
+
+	# Get rid of symbols from shared libraries, otherwise the
+	# completions match list for "break <tab>" is huge and makes
+	# the test below quite long while the gdb_test_multiple loop
+	# below consumes the matches.  Not doing this added ~20
+	# seconds at the time of writing.  (Actually, already done above.)
+	# gdb_test_no_output "nosharedlibrary"
+
+	# Test completion with no input argument.  We should see all
+	# the options, plus all the functions.  To keep it simple, as
+	# proxy, we check for presence of one explicit location
+	# option, one probe location, and one function.
+	set saw_opt_function 0
+	set saw_opt_probe_stap 0
+	set saw_function 0
+
+	set tst "complete with no arguments"
+	send_gdb "break \t"
+	gdb_test_multiple "" $tst {
+	    "break \\\x07" {
+		send_gdb "\t\t"
+		gdb_test_multiple "" $tst {
+		    "Display all" {
+			send_gdb "y"
+			exp_continue
+		    }
+		    -re "-function" {
+			set saw_opt_function 1
+			exp_continue
+		    }
+		    -re "-probe-stap" {
+			set saw_opt_probe_stap 1
+			exp_continue
+		    }
+		    -re "myfunction4" {
+			set saw_function 1
+			exp_continue
+		    }
+		    -re "\r\n$gdb_prompt " {
+			gdb_assert {$saw_opt_function && $saw_opt_probe_stap && $saw_function} $tst
+		    }
+		    -re "  " {
+			exp_continue
+		    }
+		}
+	    }
+	}
+	clear_input_line $tst
+
 	# NOTE: We don't bother testing more elaborate combinations of options,
 	# such as "-func main -sour 3ex\t" (main is defined in explicit.c).
 	# The completer cannot handle these yet.
 
+	# Follows completion tests that require having no symbols
+	# loaded.
+	gdb_exit
+	gdb_start
+
+	# The match list you get when you complete with no options
+	# specified at all.
+	set completion_list {
+	    "-function"
+	    "-label"
+	    "-line"
+	    "-probe"
+	    "-probe-dtrace"
+	    "-probe-stap"
+	    "-qualified"
+	    "-source"
+	}
+	with_test_prefix "complete with no arguments and no symbols" {
+	    test_gdb_complete_multiple "b " "" "-" $completion_list
+	    test_gdb_complete_multiple "b " "-" "" $completion_list
+	}
     }
     # End of completion tests.
 
diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp
new file mode 100644
index 0000000..ef78269
--- /dev/null
+++ b/gdb/testsuite/lib/completion-support.exp
@@ -0,0 +1,513 @@ 
+# Copyright 2017 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/>.
+
+# This file is part of the gdb testsuite.
+
+set timeout 5
+
+set bell_re "\\\x07"
+
+# List of all quote chars.
+set all_quotes_list {"'" "\""}
+
+# List of all quote chars, including no-quote at all.
+set maybe_quoted_list {"" "'" "\""}
+
+set keyword_list {"if" "task" "thread"}
+set explicit_opts_list {"-function" "-label" "-line" "-qualified" "-source"}
+
+# Make a regular expression that matches a TAB completion list.
+
+proc make_tab_completion_list_re { completion_list } {
+    # readline separates the completion columns that fit on the same
+    # line with whitespace.  Since we're testing under "set width
+    # unlimited", all completions will be printed on the same line.
+    # The amount of whitespace depends on the length of the widest
+    # completion.  We could compute that here and expect the exact
+    # number of ws characters between each completion match, but to
+    # keep it simple, we accept any number of characters.
+    set ws " +"
+
+    set completion_list_re ""
+    foreach c $completion_list {
+	append completion_list_re [string_to_regexp $c]
+	append completion_list_re $ws
+    }
+    append completion_list_re $ws
+
+    return $completion_list_re
+}
+
+# Make a regular expression that matches a "complete" command
+# completion list.  CMD_PREFIX is the command prefix added to each
+# completion match.
+
+proc make_cmd_completion_list_re { cmd_prefix completion_list start_quote_char end_quote_char } {
+
+    set completion_list_re ""
+    foreach c $completion_list {
+	# The command prefix is included in all completion matches.
+	append completion_list_re [string_to_regexp $cmd_prefix$start_quote_char$c$end_quote_char]
+	append completion_list_re "\r\n"
+    }
+
+    return $completion_list_re
+}
+
+# Clear the input line.
+
+proc clear_input_line { test } {
+    global gdb_prompt
+
+    send_gdb "\003"
+    gdb_test_multiple "" "$test (clearing input line)" {
+	-re "Quit\r\n$gdb_prompt $" {
+	}
+    }
+}
+
+# Test that completing LINE with TAB completes to nothing.
+
+proc test_gdb_complete_tab_none { line } {
+    global bell_re
+
+    set line_re [string_to_regexp $line]
+
+    set test "tab complete \"$line\""
+    send_gdb "$line\t"
+    gdb_test_multiple "" "$test" {
+	-re "^$line_re$bell_re$" {
+	    pass "$test"
+	}
+    }
+
+    clear_input_line $test
+}
+
+# Test that completing INPUT_LINE with TAB completes to
+# COMPLETE_LINE_RE.  APPEND_CHAR_RE is the character expected to be
+# appended after EXPECTED_OUTPUT.  Normally that's a whitespace, but
+# in some cases it's some other character, like a colon.
+
+proc test_gdb_complete_tab_unique { input_line complete_line_re append_char_re } {
+
+    set test "tab complete \"$input_line\""
+    send_gdb "$input_line\t"
+    gdb_test_multiple "" "$test" {
+	-re "^$complete_line_re$append_char_re$" {
+	    pass "$test"
+	}
+    }
+
+    clear_input_line $test
+}
+
+# Test that completing INPUT_LINE with TAB completes to "INPUT_LINE +
+# ADD_COMPLETED_LINE" and that is displays the completion matches in
+# COMPLETION_LIST.
+
+proc test_gdb_complete_tab_multiple { input_line add_completed_line \
+					  completion_list } {
+    global gdb_prompt
+    global bell_re
+
+    set input_line_re [string_to_regexp $input_line]
+    set add_completed_line_re [string_to_regexp $add_completed_line]
+
+    set expected_re [make_tab_completion_list_re $completion_list]
+
+    set test "tab complete \"$input_line\""
+    send_gdb "$input_line\t"
+    gdb_test_multiple "" "$test (first tab)" {
+	-re "^${input_line_re}$bell_re$add_completed_line_re$" {
+	    send_gdb "\t"
+	    # If we auto-completed to an ambiguous prefix, we need an
+	    # extra tab to show the matches list.
+	    if {$add_completed_line != ""} {
+		send_gdb "\t"
+	    }
+	    gdb_test_multiple "" "$test (second tab)" {
+		-re "$expected_re\r\n$gdb_prompt $input_line_re$add_completed_line_re$" {
+		    pass "$test"
+		}
+	    }
+	}
+    }
+
+    clear_input_line $test
+}
+
+# Test that completing LINE with the complete command completes to
+# nothing.
+
+proc test_gdb_complete_cmd_none { line } {
+    gdb_test_no_output "complete $line" "cmd complete \"$line\""
+}
+
+# Test that completing LINE with the complete command completes to
+# COMPLETE_LINE_RE.
+
+proc test_gdb_complete_cmd_unique { input_line complete_line_re } {
+    global gdb_prompt
+
+    set cmd "complete $input_line"
+    set cmd_re [string_to_regexp $cmd]
+    set test "cmd complete \"$input_line\""
+    gdb_test_multiple $cmd $test {
+	-re "^$cmd_re\r\n$complete_line_re\r\n$gdb_prompt $" {
+	    pass $test
+	}
+    }
+}
+
+# Test that completing "CMD_PREFIX + COMPLETION_WORD" with the
+# complete command displays the COMPLETION_LIST completion list.  Each
+# entry in the list should be prefixed by CMD_PREFIX.
+
+proc test_gdb_complete_cmd_multiple { cmd_prefix completion_word completion_list start_quote_char end_quote_char } {
+    global gdb_prompt
+
+    set expected_re [make_cmd_completion_list_re $cmd_prefix $completion_list $start_quote_char $end_quote_char]
+    set cmd_re [string_to_regexp "complete $cmd_prefix$completion_word"]
+    set test "cmd complete \"$cmd_prefix$completion_word\""
+    gdb_test_multiple "complete $cmd_prefix$completion_word" $test {
+	-re "^$cmd_re\r\n$expected_re$gdb_prompt $" {
+	    pass $test
+	}
+    }
+}
+
+proc test_gdb_complete_menu { line expected_output } {
+
+    set test "menu complete $line"
+#    send_gdb "$expr\033?"
+#    send_gdb "$expr^\[?"
+    send_gdb "$expr"
+    send_gdb "\x1b"
+    send_gdb "?"
+    gdb_test_multiple "" "$test" {
+	-re "$expected_output" {
+	    pass "$test"
+	}
+    }
+}
+
+# Test that completing LINE completes to nothing.
+
+proc test_gdb_complete_none { input_line } {
+    test_gdb_complete_tab_none $input_line
+    test_gdb_complete_cmd_none $input_line
+}
+
+# Test that completing INPUT_LINE completes to COMPLETE_LINE.
+#
+# APPEND_CHAR is the character expected to be appended after
+# EXPECTED_OUTPUT when TAB completing.  Normally that's a whitespace,
+# but in some cases it's some other character, like a colon.
+#
+# If MAX_COMPLETIONS is true, then we expect the completion to hit the
+# max-completions limit.  Since we're expecting a unique completion
+# match, this will only be visible in the "complete" command output.
+# Tab completion will just auto-complete the only match and won't
+# display a match list.
+
+proc test_gdb_complete_unique { input_line complete_line {append_char " "} {max_completions 0}} {
+    set complete_line_re [string_to_regexp $complete_line]
+    set append_char_re [string_to_regexp $append_char]
+    test_gdb_complete_tab_unique $input_line $complete_line_re $append_char_re
+
+    # Trim INPUT_LINE and COMPLETE LINE, for the case we're completing
+    # a command with leading whitespace.  Leading command whitespace
+    # is discarded by GDB.
+    set input_line [string trimleft $input_line]
+    set expected_output_re [string trimleft $complete_line_re]
+    if {$append_char_re != " "} {
+	append expected_output_re $append_char_re
+    }
+    if {$max_completions} {
+	set max_completion_reached_msg \
+	    "*** List may be truncated, max-completions reached. ***"
+	set input_line_re \
+	    [string_to_regexp $input_line]
+	set max_completion_reached_msg_re \
+	    [string_to_regexp $max_completion_reached_msg]
+
+	append expected_output_re \
+	    "\r\n$input_line_re $max_completion_reached_msg_re"
+    }
+
+    test_gdb_complete_cmd_unique $input_line $expected_output_re
+}
+
+proc test_gdb_complete_unique_re { input_line complete_line_re {append_char " "} {max_completions 0}} {
+    set append_char_re [string_to_regexp $append_char]
+    test_gdb_complete_tab_unique $input_line $complete_line_re $append_char_re
+
+    # Trim INPUT_LINE and COMPLETE LINE, for the case we're completing
+    # a command with leading whitespace.  Leading command whitespace
+    # is discarded by GDB.
+    set input_line [string trimleft $input_line]
+    set expected_output_re [string trimleft $complete_line_re]
+    if {$append_char_re != " "} {
+	append expected_output_re $append_char_re
+    }
+    if {$max_completions} {
+	set max_completion_reached_msg \
+	    "*** List may be truncated, max-completions reached. ***"
+	set input_line_re \
+	    [string_to_regexp $input_line]
+	set max_completion_reached_msg_re \
+	    [string_to_regexp $max_completion_reached_msg]
+
+	append expected_output_re \
+	    "\r\n$input_line_re $max_completion_reached_msg_re"
+    }
+
+    test_gdb_complete_cmd_unique $input_line $expected_output_re
+}
+
+# Test that completing "CMD_PREFIX + COMPLETION_WORD" adds
+# ADD_COMPLETED_LINE to the input line, and that it displays
+# COMPLETION_LIST as completion match list.  COMPLETION_WORD is the
+# completion word.
+
+proc test_gdb_complete_multiple { cmd_prefix completion_word add_completed_line completion_list {start_quote_char ""} {end_quote_char ""}} {
+    test_gdb_complete_tab_multiple "$cmd_prefix$completion_word" $add_completed_line $completion_list
+    test_gdb_complete_cmd_multiple $cmd_prefix $completion_word $completion_list $start_quote_char $end_quote_char
+}
+
+# Test completing all the substring prefixes of COMPLETION from
+# [0..START) to [0..END) complete to COMPLETION.  If END is ommitted,
+# default to the length of COMPLETION.
+
+proc test_complete_prefix_range {completion start {end -1}} {
+    if {$end == -1} {
+	set end [string length $completion]
+    }
+
+    for {set i $start} {$i < $end} {incr i} {
+	set line [string range $completion 0 $i]
+	test_gdb_complete_unique "$line" "$completion"
+    }
+}
+
+proc test_complete_prefix_range_input {input completion_re start {end -1}} {
+    if {$end == -1} {
+	set end [string length $input]
+    }
+
+    for {set i $start} {$i < $end} {incr i} {
+	set line [string range $input 0 $i]
+	test_gdb_complete_unique_re "$line" $completion_re
+    }
+}
+
+# Find NEEDLE in HAYSTACK and return the index _after_ NEEDLE.  E.g.,
+# searching for "(" in "foo(int)" returns 4, which would be useful if
+# you want to find the "(" to try completing "foo(".
+
+proc index_after {needle haystack} {
+    set start [string first $needle $haystack]
+    if {$start == -1} {
+	error "could not find \"$needle\" in \"$haystack\""
+    }
+    return [expr $start + [string length $needle]]
+}
+
+# Create a breakpoint using BREAK_COMMAND, and return the number of
+# locations found.
+
+proc create_bp {break_command} {
+    global gdb_prompt
+    global decimal hex
+
+    set found_locations -1
+
+    set test "set breakpoint"
+    gdb_test_multiple "$break_command" $test {
+	-re "\\\(\($decimal\) locations\\\)\r\n$gdb_prompt $" {
+	    set found_locations "$expect_out(1,string)"
+	}
+	-re "Breakpoint $decimal at $hex: file .*, line .*$gdb_prompt $" {
+	    set found_locations 1
+	}
+	-re "Make breakpoint pending on future shared library load.*y or .n.. $" {
+	    send_gdb "n\n"
+	    gdb_test_multiple "" "$test (prompt)" {
+		-re "$gdb_prompt $" {
+		}
+	    }
+	    set found_locations 0
+	}
+	-re "invalid explicit location argument, \[^\r\n\]*\r\n$gdb_prompt $" {
+	    set found_locations 0
+	}
+	-re "Function \[^\r\n\]* not defined in \[^\r\n\]*\r\n$gdb_prompt $" {
+	    set found_locations 0
+	}
+    }
+    return $found_locations
+}
+
+# Check that trying to create a breakpoint from linespec fails.
+
+proc check_setting_bp_fails {break_command} {
+    with_test_prefix "\"$break_command\" creates no bp locations" {
+	set found_locations [create_bp $break_command]
+	gdb_assert {$found_locations == 0} "matches"
+	if {$found_locations != 0} {
+	    delete_breakpoints
+	}
+    }
+}
+
+# Return true if lists A and B have the same elements.  Order of
+# elements does not matter.
+
+proc gdb_leq {a b} {
+    return [expr {[lsort $a] eq [lsort $b]}]
+}
+
+# Check that creating the breakpoint at LINESPEC finds the same
+# breakpoint locations as completing LINESPEC.  COMPLETION_LIST is
+# expected completion match list.
+
+proc check_bp_locations_match_list {break_command completion_list} {
+    global gdb_prompt
+    global hex
+
+    with_test_prefix "compare \"$break_command\" completion list with bp location list" {
+	set num_locations [create_bp $break_command]
+
+	set found_list ""
+
+	set any "\[^\r\n\]*"
+
+	gdb_test_multiple "info breakpoint \$bpnum" "info breakpoint" {
+	    -re "in \(\[^\r\n\]*\) at " {
+		# A function location.
+		set found_location "$expect_out(1,string)"
+		lappend found_list $found_location
+		exp_continue
+	    }
+	    -re "breakpoint${any}keep${any}y${any}$hex\[ \t]*\(${any}\)\r\n" {
+		# A label location.
+		set found_location "$expect_out(1,string)"
+		lappend found_list $found_location
+		exp_continue
+	    }
+	    -re "$gdb_prompt $" {
+	    }
+	}
+
+	gdb_assert {[gdb_leq $found_list $completion_list]} "matches"
+
+	delete_breakpoints
+    }
+}
+
+# Build linespec and explicit locations out of all the combinations of
+# SOURCES, FUNCTIONS and LABELS, with all combinations of possible
+# quoting and whitespace around separators, and run BODY_LINESPEC and
+# BODY_EXPLICIT in the context of the caller for each combination.  A
+# variable named "location" is set in the callers context with the
+# currently iterated location.
+
+proc foreach_location_functions { sources functions body_linespec body_explicit } {
+    global maybe_quoted_list
+    upvar source source
+    upvar function function
+    upvar source_sep source_sep
+    upvar location location
+
+    foreach source $sources {
+	# Test with and without source quoting.
+	foreach sqc $maybe_quoted_list {
+	    if {$source == "" && $sqc != ""} {
+		# Invalid combination.
+		continue
+	    }
+
+	    # Test with and without function quoting.
+	    foreach fqc $maybe_quoted_list {
+		# Test known and unknown functions.
+		foreach function $functions {
+		    # Linespec version.  Test with and without spacing
+		    # after the source/colon colon separator.
+		    foreach source_sep {"" ":" ": "} {
+			# Skip invalid combinations.
+			if {$source == "" && $source_sep != ""} {
+			    continue
+			}
+			if {$source != "" && $source_sep == ""} {
+			    continue
+			}
+
+			set location "${sqc}${source}${sqc}${source_sep}${fqc}$function${fqc}"
+			uplevel 1 $body_linespec
+		    }
+
+		    # Explicit locations version.
+		    if {$source != ""} {
+			set loc_src "-source ${sqc}${source}${sqc} "
+		    } else {
+			set loc_src ""
+		    }
+
+		    set location "${loc_src}-function ${fqc}$function${fqc}"
+		    uplevel 1 $body_explicit
+		}
+	    }
+	}
+    }
+}
+
+# Same as foreach_locations_functions, but also iterate over
+# combinations of labels.
+proc foreach_location_labels { sources functions labels body_linespec body_explicit } {
+    global maybe_quoted_list
+    upvar source source
+    upvar function function
+    upvar label label
+    upvar source_sep source_sep
+    upvar label_sep label_sep
+    upvar location location
+
+    # Test both with a known source file and without a source file
+    # component.
+    foreach_location_functions \
+	$sources \
+	$functions \
+	{
+	    # Linespec version.  Test various spacing around the label
+	    # colon separator.
+	    set saved_location ${location}
+	    foreach label_sep {":" " :" ": " " : "} {
+		# Test both known and unknown label.
+		foreach label $labels {
+		    set location "${saved_location}${label_sep}$label"
+		    uplevel 1 $body_linespec
+		}
+	    }
+	} \
+	{
+	    # Explicit locations version.
+	    set saved_location ${location}
+	    foreach label $labels {
+		set location "${saved_location} -label $label"
+		uplevel 1 $body_explicit
+	    }
+	}
+}