aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog97
-rw-r--r--gdb/NEWS20
-rw-r--r--gdb/ax-gdb.c3
-rw-r--r--gdb/breakpoint.c32
-rw-r--r--gdb/c-lang.c2
-rw-r--r--gdb/completer.c44
-rw-r--r--gdb/cp-support.c163
-rw-r--r--gdb/cp-support.h7
-rw-r--r--gdb/doc/ChangeLog7
-rw-r--r--gdb/doc/gdb.texinfo43
-rw-r--r--gdb/dwarf2read.c48
-rw-r--r--gdb/guile/scm-breakpoint.c6
-rw-r--r--gdb/linespec.c51
-rw-r--r--gdb/linespec.h12
-rw-r--r--gdb/location.c90
-rw-r--r--gdb/location.h38
-rw-r--r--gdb/mi/mi-cmd-break.c3
-rw-r--r--gdb/python/py-breakpoint.c3
-rw-r--r--gdb/python/python.c3
-rw-r--r--gdb/testsuite/ChangeLog18
-rw-r--r--gdb/testsuite/gdb.base/langs.exp2
-rw-r--r--gdb/testsuite/gdb.cp/meth-typedefs.exp39
-rw-r--r--gdb/testsuite/gdb.cp/namespace.exp2
-rw-r--r--gdb/testsuite/gdb.cp/save-bp-qualified.cc40
-rw-r--r--gdb/testsuite/gdb.cp/save-bp-qualified.exp74
-rw-r--r--gdb/testsuite/gdb.linespec/cpcompletion.exp423
-rw-r--r--gdb/testsuite/gdb.linespec/explicit.exp80
-rw-r--r--gdb/testsuite/lib/completion-support.exp2
-rw-r--r--gdb/testsuite/lib/gdb.exp6
29 files changed, 1233 insertions, 125 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0c9d089..d65337a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,102 @@
2017-11-29 Pedro Alves <palves@redhat.com>
+ * NEWS: Mention that breakpoints on C++ functions are now set on
+ on all namespaces/classes by default, and mention "break
+ -qualified".
+ * ax-gdb.c (agent_command_1): Adjust to pass a
+ symbol_name_match_type to new_linespec_location.
+ * breakpoint.c (parse_breakpoint_sals): Adjust to
+ get_linespec_location's return type change.
+ (strace_marker_create_sals_from_location): Adjust to pass a
+ symbol_name_match_type to new_linespec_location.
+ (strace_marker_decode_location): Adjust to get_linespec_location's
+ return type change.
+ (strace_command): Adjust to pass a symbol_name_match_type to
+ new_linespec_location.
+ (LOCATION_HELP_STRING): Add paragraph about wildmatching, and
+ mention "-qualified".
+ * c-lang.c (cplus_language_defn): Install cp_search_name_hash.
+ * completer.c (explicit_location_match_type::MATCH_QUALIFIED): New
+ enumerator.
+ (complete_address_and_linespec_locations): New parameter
+ 'match_type'. Pass it down.
+ (explicit_options): Add "-qualified".
+ (collect_explicit_location_matches): Pass the requested match type
+ to the linespec completers. Handle MATCH_QUALIFIED.
+ (location_completer): Handle "-qualified" combined with linespecs.
+ * cp-support.c (cp_search_name_hash): New.
+ (cp_symbol_name_matches_1): Implement wild matching for C++.
+ (cp_fq_symbol_name_matches): Reimplement.
+ (cp_get_symbol_name_matcher): Return different matchers depending
+ on the lookup name's match type.
+ (selftests::test_cp_symbol_name_matches): Add wild matching tests.
+ * cp-support.h (cp_search_name_hash): New declaration.
+ * dwarf2read.c
+ (selftests::dw2_expand_symtabs_matching::test_symbols): Add
+ symbols.
+ (test_dw2_expand_symtabs_matching_symbol): Add wild matching
+ tests.
+ * guile/scm-breakpoint.c (gdbscm_register_breakpoint_x): Adjust to
+ pass a symbol_name_match_type to new_linespec_location.
+ * linespec.c (linespec_parse_basic): Lookup function symbols using
+ the parser's symbol name match type.
+ (convert_explicit_location_to_linespec): New
+ symbol_name_match_type parameter. Pass it down to
+ find_linespec_symbols.
+ (convert_explicit_location_to_sals): Pass the location's name
+ match type to convert_explicit_location_to_linespec.
+ (parse_linespec): New match_type parameter. Save it in the
+ parser.
+ (linespec_parser_new): Default to symbol_name_match_type::WILD.
+ (linespec_complete_function): New symbol_name_match_type
+ parameter. Use it.
+ (complete_linespec_component): Pass down the parser's recorded
+ name match type.
+ (linespec_complete_label): New symbol_name_match_type parameter.
+ Use it.
+ (linespec_complete): New symbol_name_match_type parameter. Save
+ it in the parser and pass it down. Adjust to
+ get_linespec_location's prototype change.
+ (find_function_symbols, find_linespec_symbols): New
+ symbol_name_match_type parameter. Pass it down instead of
+ assuming symbol_name_match_type::WILD.
+ * linespec.h (linespec_complete, linespec_complete_function)
+ (linespec_complete_label): New symbol_name_match_type parameter.
+ * location.c (event_location::linespec_location): Now a struct
+ linespec_location.
+ (EL_LINESPEC): Adjust.
+ (initialize_explicit_location): Default to
+ symbol_name_match_type::WILD.
+ (new_linespec_location): New symbol_name_match_type parameter.
+ Record it in the location.
+ (get_linespec_location): Now returns a struct linespec_location.
+ (new_explicit_location): Also copy func_name_match_type.
+ (explicit_to_string_internal)
+ (string_to_explicit_location): Handle "-qualified".
+ (copy_event_location): Adjust to LINESPEC_LOCATION type change.
+ Copy symbol_name_match_type fields.
+ (event_location_deleter::operator()): Adjust to LINESPEC_LOCATION
+ type change.
+ (event_location_to_string): Adjust to LINESPEC_LOCATION type
+ change. Handle "-qualfied".
+ (string_to_explicit_location): Handle "-qualified".
+ (string_to_event_location_basic): New symbol_name_match_type
+ parameter. Pass it down.
+ (string_to_event_location): Handle "-qualified".
+ * location.h (struct linespec_location): New.
+ (explicit_location::func_name_match_type): New field.
+ (new_linespec_location): Now returns a const linespec_location *.
+ (string_to_event_location_basic): New symbol_name_match_type
+ parameter.
+ (explicit_completion_info::saw_explicit_location_option): New
+ field.
+ * mi/mi-cmd-break.c (mi_cmd_break_insert_1): Adjust to pass a
+ symbol_name_match_type to new_linespec_location.
+ * python/py-breakpoint.c (bppy_init): Likewise.
+ * python/python.c (gdbpy_decode_line): Likewise.
+
+2017-11-29 Pedro Alves <palves@redhat.com>
+
* ada-lang.c (ada_lookup_name_info::matches): Change type of
parameter from completion_match to completion_match_result.
Adjust.
diff --git a/gdb/NEWS b/gdb/NEWS
index 754ce10..984fd96 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -52,6 +52,26 @@
** The "complete" command now mimics TAB completion accurately.
+* Breakpoints on C++ functions are now set on all scopes by default
+
+ By default, breakpoints on functions/methods are now interpreted as
+ specifying all functions with the given name ignoring missing
+ leading scopes (namespaces and classes).
+
+ For example, assuming a C++ program with symbols named:
+
+ A::B::func()
+ B::func()
+
+ both commands "break func()" and "break B::func()" set a breakpoint
+ on both symbols.
+
+ You can use the new flag "-qualified" to override this. This makes
+ GDB interpret the specified function name as a complete
+ fully-qualified name instead. For example, using the same C++
+ program, the "break -q B::func" command sets a breakpoint on
+ "B::func", only.
+
* Python Scripting
** New events gdb.new_inferior, gdb.inferior_deleted, and
diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index 52ca081..5027f6a 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2638,7 +2638,8 @@ agent_command_1 (const char *exp, int eval)
exp = skip_spaces (exp);
- event_location_up location = new_linespec_location (&exp);
+ event_location_up location
+ = new_linespec_location (&exp, symbol_name_match_type::WILD);
decode_line_full (location.get (), DECODE_LINE_FUNFIRSTLINE, NULL,
(struct symtab *) NULL, 0, &canonical,
NULL, NULL);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index b48c405..d4d095d 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -9100,9 +9100,9 @@ parse_breakpoint_sals (const struct event_location *location,
if (event_location_type (location) == LINESPEC_LOCATION)
{
- const char *address = get_linespec_location (location);
+ const char *spec = get_linespec_location (location)->spec_string;
- if (address == NULL)
+ if (spec == NULL)
{
/* The last displayed codepoint, if it's valid, is our default
breakpoint address. */
@@ -9148,15 +9148,15 @@ parse_breakpoint_sals (const struct event_location *location,
cursal = get_current_source_symtab_and_line ();
if (last_displayed_sal_is_valid ())
{
- const char *address = NULL;
+ const char *spec = NULL;
if (event_location_type (location) == LINESPEC_LOCATION)
- address = get_linespec_location (location);
+ spec = get_linespec_location (location)->spec_string;
if (!cursal.symtab
- || (address != NULL
- && strchr ("+-", address[0]) != NULL
- && address[1] != '['))
+ || (spec != NULL
+ && strchr ("+-", spec[0]) != NULL
+ && spec[1] != '['))
{
decode_line_full (location, DECODE_LINE_FUNFIRSTLINE, NULL,
get_last_displayed_symtab (),
@@ -13147,12 +13147,13 @@ strace_marker_create_sals_from_location (const struct event_location *location,
struct linespec_sals lsal;
const char *arg_start, *arg;
- arg = arg_start = get_linespec_location (location);
+ arg = arg_start = get_linespec_location (location)->spec_string;
lsal.sals = decode_static_tracepoint_spec (&arg);
std::string str (arg_start, arg - arg_start);
const char *ptr = str.c_str ();
- canonical->location = new_linespec_location (&ptr);
+ canonical->location
+ = new_linespec_location (&ptr, symbol_name_match_type::FULL);
lsal.canonical
= xstrdup (event_location_to_string (canonical->location.get ()));
@@ -13213,7 +13214,7 @@ strace_marker_decode_location (struct breakpoint *b,
struct program_space *search_pspace)
{
struct tracepoint *tp = (struct tracepoint *) b;
- const char *s = get_linespec_location (location);
+ const char *s = get_linespec_location (location)->spec_string;
std::vector<symtab_and_line> sals = decode_static_tracepoint_spec (&s);
if (sals.size () > tp->static_trace_marker_id_idx)
@@ -14759,7 +14760,7 @@ strace_command (const char *arg, int from_tty)
if (arg && startswith (arg, "-m") && isspace (arg[2]))
{
ops = &strace_marker_breakpoint_ops;
- location = new_linespec_location (&arg);
+ location = new_linespec_location (&arg, symbol_name_match_type::FULL);
}
else
{
@@ -15289,7 +15290,14 @@ Explicit locations are similar to linespecs but use an option/argument\n\
syntax to specify location parameters.\n\
Example: To specify the start of the label named \"the_top\" in the\n\
function \"fact\" in the file \"factorial.c\", use \"-source factorial.c\n\
--function fact -label the_top\".\n"
+-function fact -label the_top\".\n\
+\n\
+By default, a specified function is matched against the program's\n\
+functions in all scopes. For C++, this means in all namespaces and\n\
+classes. For Ada, this means in all packages. E.g., in C++,\n\
+\"func()\" matches \"A::func()\", \"A::B::func()\", etc. The\n\
+\"-qualified\" flag overrides this behavior, making GDB interpret the\n\
+specified name as a complete fully-qualified name instead.\n"
/* This help string is used for the break, hbreak, tbreak and thbreak
commands. It is defined as a macro to prevent duplication.
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 49077c7..8d96f94 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -1016,7 +1016,7 @@ extern const struct language_defn cplus_language_defn =
c_watch_location_expression,
cp_get_symbol_name_matcher,
iterate_over_symbols,
- default_search_name_hash,
+ cp_search_name_hash,
&cplus_varobj_ops,
NULL,
NULL,
diff --git a/gdb/completer.c b/gdb/completer.c
index fd82b86..701f578 100644
--- a/gdb/completer.c
+++ b/gdb/completer.c
@@ -76,6 +76,9 @@ enum explicit_location_match_type
/* The name of a function or method. */
MATCH_FUNCTION,
+ /* The fully-qualified name of a function or method. */
+ MATCH_QUALIFIED,
+
/* A line number. */
MATCH_LINE,
@@ -579,7 +582,8 @@ complete_source_filenames (const char *text)
static void
complete_address_and_linespec_locations (completion_tracker &tracker,
- const char *text)
+ const char *text,
+ symbol_name_match_type match_type)
{
if (*text == '*')
{
@@ -591,7 +595,7 @@ complete_address_and_linespec_locations (completion_tracker &tracker,
}
else
{
- linespec_complete (tracker, text);
+ linespec_complete (tracker, text, match_type);
}
}
@@ -602,6 +606,7 @@ static const char *const explicit_options[] =
{
"-source",
"-function",
+ "-qualified",
"-line",
"-label",
NULL
@@ -638,6 +643,9 @@ collect_explicit_location_matches (completion_tracker &tracker,
const struct explicit_location *explicit_loc
= get_explicit_location (location);
+ /* True if the option expects an argument. */
+ bool needs_arg = true;
+
/* Note, in the various MATCH_* below, we complete on
explicit_loc->foo instead of WORD, because only the former will
have already skipped past any quote char. */
@@ -656,10 +664,14 @@ collect_explicit_location_matches (completion_tracker &tracker,
{
const char *function = string_or_empty (explicit_loc->function_name);
linespec_complete_function (tracker, function,
+ explicit_loc->func_name_match_type,
explicit_loc->source_filename);
}
break;
+ case MATCH_QUALIFIED:
+ needs_arg = false;
+ break;
case MATCH_LINE:
/* Nothing to offer. */
break;
@@ -670,6 +682,7 @@ collect_explicit_location_matches (completion_tracker &tracker,
linespec_complete_label (tracker, language,
explicit_loc->source_filename,
explicit_loc->function_name,
+ explicit_loc->func_name_match_type,
label);
}
break;
@@ -678,7 +691,7 @@ collect_explicit_location_matches (completion_tracker &tracker,
gdb_assert_not_reached ("unhandled explicit_location_match_type");
}
- if (tracker.completes_to_completion_word (word))
+ if (!needs_arg || tracker.completes_to_completion_word (word))
{
tracker.discard_completions ();
tracker.advance_custom_word_point_by (strlen (word));
@@ -867,7 +880,7 @@ location_completer (struct cmd_list_element *ignore,
tracker.advance_custom_word_point_by (1);
}
- if (location != NULL)
+ if (completion_info.saw_explicit_location_option)
{
if (*copy != '\0')
{
@@ -907,10 +920,29 @@ location_completer (struct cmd_list_element *ignore,
}
}
+ /* This is an address or linespec location. */
+ else if (location != NULL)
+ {
+ /* Handle non-explicit location options. */
+
+ int keyword = skip_keyword (tracker, explicit_options, &text);
+ if (keyword == -1)
+ complete_on_enum (tracker, explicit_options, text, text);
+ else
+ {
+ tracker.advance_custom_word_point_by (copy - text);
+ text = copy;
+
+ symbol_name_match_type match_type
+ = get_explicit_location (location.get ())->func_name_match_type;
+ complete_address_and_linespec_locations (tracker, text, match_type);
+ }
+ }
else
{
- /* This is an address or linespec location. */
- complete_address_and_linespec_locations (tracker, text);
+ /* No options. */
+ complete_address_and_linespec_locations (tracker, text,
+ symbol_name_match_type::WILD);
}
/* Add matches for option names, if either:
diff --git a/gdb/cp-support.c b/gdb/cp-support.c
index 6c6825b..172d821 100644
--- a/gdb/cp-support.c
+++ b/gdb/cp-support.c
@@ -1615,11 +1615,48 @@ gdb_sniff_from_mangled_name (const char *mangled, char **demangled)
return *demangled != NULL;
}
-/* C++ symbol_name_matcher_ftype implementation. */
+/* See cp-support.h. */
+
+unsigned int
+cp_search_name_hash (const char *search_name)
+{
+ /* cp_entire_prefix_len assumes a fully-qualified name with no
+ leading "::". */
+ if (startswith (search_name, "::"))
+ search_name += 2;
+
+ unsigned int prefix_len = cp_entire_prefix_len (search_name);
+ if (prefix_len != 0)
+ search_name += prefix_len + 2;
+
+ return default_search_name_hash (search_name);
+}
+
+/* Helper for cp_symbol_name_matches (i.e., symbol_name_matcher_ftype
+ implementation for symbol_name_match_type::WILD matching). Split
+ to a separate function for unit-testing convenience.
+
+ If SYMBOL_SEARCH_NAME has more scopes than LOOKUP_NAME, we try to
+ match ignoring the extra leading scopes of SYMBOL_SEARCH_NAME.
+ This allows conveniently setting breakpoints on functions/methods
+ inside any namespace/class without specifying the fully-qualified
+ name.
+
+ E.g., these match:
-/* Helper for cp_fq_symbol_name_matches (i.e.,
- symbol_name_matcher_ftype implementation). Split to a separate
- function for unit-testing convenience.
+ [symbol search name] [lookup name]
+ foo::bar::func foo::bar::func
+ foo::bar::func bar::func
+ foo::bar::func func
+
+ While these don't:
+
+ [symbol search name] [lookup name]
+ foo::zbar::func bar::func
+ foo::bar::func foo::func
+
+ See more examples in the test_cp_symbol_name_matches selftest
+ function below.
See symbol_name_matcher_ftype for description of SYMBOL_SEARCH_NAME
and COMP_MATCH_RES.
@@ -1636,8 +1673,68 @@ cp_symbol_name_matches_1 (const char *symbol_search_name,
strncmp_iw_mode mode,
completion_match_result *comp_match_res)
{
+ const char *sname = symbol_search_name;
+
+ while (true)
+ {
+ if (strncmp_iw_with_mode (sname, lookup_name, lookup_name_len,
+ mode, language_cplus) == 0)
+ {
+ if (comp_match_res != NULL)
+ {
+ /* Note here we set different MATCH and MATCH_FOR_LCD
+ strings. This is because with
+
+ (gdb) b push_bac[TAB]
+
+ we want the completion matches to list
+
+ std::vector<int>::push_back(...)
+ std::vector<char>::push_back(...)
+
+ etc., which are SYMBOL_SEARCH_NAMEs, while we want
+ the input line to auto-complete to
+
+ (gdb) push_back(...)
+
+ which is SNAME, not to
+
+ (gdb) std::vector<
+
+ which would be the regular common prefix between all
+ the matches otherwise. */
+ comp_match_res->set_match (symbol_search_name, sname);
+ }
+ return true;
+ }
+
+ unsigned int len = cp_find_first_component (sname);
+
+ if (sname[len] == '\0')
+ return false;
+
+ gdb_assert (sname[len] == ':');
+ /* Skip the '::'. */
+ sname += len + 2;
+ }
+}
+
+/* C++ symbol_name_matcher_ftype implementation. */
+
+static bool
+cp_fq_symbol_name_matches (const char *symbol_search_name,
+ const lookup_name_info &lookup_name,
+ completion_match_result *comp_match_res)
+{
+ /* Get the demangled name. */
+ const std::string &name = lookup_name.cplus ().lookup_name ();
+
+ strncmp_iw_mode mode = (lookup_name.completion_mode ()
+ ? strncmp_iw_mode::NORMAL
+ : strncmp_iw_mode::MATCH_PARAMS);
+
if (strncmp_iw_with_mode (symbol_search_name,
- lookup_name, lookup_name_len,
+ name.c_str (), name.size (),
mode, language_cplus) == 0)
{
if (comp_match_res != NULL)
@@ -1648,12 +1745,13 @@ cp_symbol_name_matches_1 (const char *symbol_search_name,
return false;
}
-/* C++ symbol_name_matcher_ftype implementation. */
+/* C++ symbol_name_matcher_ftype implementation for wild matches.
+ Defers work to cp_symbol_name_matches_1. */
static bool
-cp_fq_symbol_name_matches (const char *symbol_search_name,
- const lookup_name_info &lookup_name,
- completion_match_result *comp_match_res)
+cp_symbol_name_matches (const char *symbol_search_name,
+ const lookup_name_info &lookup_name,
+ completion_match_result *comp_match_res)
{
/* Get the demangled name. */
const std::string &name = lookup_name.cplus ().lookup_name ();
@@ -1672,7 +1770,16 @@ cp_fq_symbol_name_matches (const char *symbol_search_name,
symbol_name_matcher_ftype *
cp_get_symbol_name_matcher (const lookup_name_info &lookup_name)
{
- return cp_fq_symbol_name_matches;
+ switch (lookup_name.match_type ())
+ {
+ case symbol_name_match_type::FULL:
+ case symbol_name_match_type::EXPRESSION:
+ return cp_fq_symbol_name_matches;
+ case symbol_name_match_type::WILD:
+ return cp_symbol_name_matches;
+ }
+
+ gdb_assert_not_reached ("");
}
#if GDB_SELF_TEST
@@ -1807,6 +1914,42 @@ test_cp_symbol_name_matches ()
CHECK_MATCH_C ("abc::def::ghi()", "abc::def::ghi ( )");
CHECK_MATCH_C ("function()", "function()");
CHECK_MATCH_C ("bar::function()", "bar::function()");
+
+ /* Wild matching tests follow. */
+
+ /* Tests matching symbols in some scope. */
+ CHECK_MATCH_C ("foo::function()", "function");
+ CHECK_MATCH_C ("foo::function(int)", "function");
+ CHECK_MATCH_C ("foo::bar::function()", "function");
+ CHECK_MATCH_C ("bar::function()", "bar::function");
+ CHECK_MATCH_C ("foo::bar::function()", "bar::function");
+ CHECK_MATCH_C ("foo::bar::function(int)", "bar::function");
+
+ /* Same, with parameters in the lookup name. */
+ CHECK_MATCH_C ("foo::function()", "function()");
+ CHECK_MATCH_C ("foo::bar::function()", "function()");
+ CHECK_MATCH_C ("foo::function(int)", "function(int)");
+ CHECK_MATCH_C ("foo::function()", "foo::function()");
+ CHECK_MATCH_C ("foo::bar::function()", "bar::function()");
+ CHECK_MATCH_C ("foo::bar::function(int)", "bar::function(int)");
+ CHECK_MATCH_C ("bar::function()", "bar::function()");
+
+ CHECK_NOT_MATCH_C ("foo::bar::function(int)", "bar::function()");
+
+ CHECK_MATCH_C ("(anonymous namespace)::bar::function(int)",
+ "bar::function(int)");
+ CHECK_MATCH_C ("foo::(anonymous namespace)::bar::function(int)",
+ "function(int)");
+
+ /* Lookup scope wider than symbol scope, should not match. */
+ CHECK_NOT_MATCH_C ("function()", "bar::function");
+ CHECK_NOT_MATCH_C ("function()", "bar::function()");
+
+ /* Explicit global scope doesn't match. */
+ CHECK_NOT_MATCH_C ("foo::function()", "::function");
+ CHECK_NOT_MATCH_C ("foo::function()", "::function()");
+ CHECK_NOT_MATCH_C ("foo::function(int)", "::function()");
+ CHECK_NOT_MATCH_C ("foo::function(int)", "::function(int)");
}
/* If non-NULL, return STR wrapped in quotes. Otherwise, return a
diff --git a/gdb/cp-support.h b/gdb/cp-support.h
index 44d8269..010fc9b 100644
--- a/gdb/cp-support.h
+++ b/gdb/cp-support.h
@@ -116,6 +116,13 @@ extern struct symbol **make_symbol_overload_list_adl (struct type **arg_types,
extern struct type *cp_lookup_rtti_type (const char *name,
struct block *block);
+/* Produce an unsigned hash value from SEARCH_NAME that is compatible
+ with cp_symbol_name_matches. Only the last component in
+ "foo::bar::function()" is considered for hashing purposes (i.e.,
+ the entire prefix is skipped), so that later on looking up for
+ "function" or "bar::function" in all namespaces is possible. */
+extern unsigned int cp_search_name_hash (const char *search_name);
+
/* Implement the "la_get_symbol_name_matcher" language_defn method for
C++. */
extern symbol_name_matcher_ftype *cp_get_symbol_name_matcher
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 2a1eb76..49c494b 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,10 @@
+2017-11-29 Pedro Alves <palves@redhat.com>
+
+ * gdb.texinfo (Linespec Locations): Document how "function" is
+ interpreted in C++ and Ada. Document "-qualified".
+ (Explicit Locations): Document how "-function" is interpreted in
+ C++ and Ada. Document "-qualified".
+
2017-11-26 Dominik Czarnota <dominik.b.czarnota@gmail.com>
PR gdb/21945
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 675f6e7..7a71739 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -7918,6 +7918,22 @@ name of @file{/build/trunk/gcc/expr.c}, but not
Specifies the line that begins the body of the function @var{function}.
For example, in C, this is the line with the open brace.
+By default, in C@t{++} and Ada, @var{function} is interpreted as
+specifying all functions named @var{function} in all scopes. For
+C@t{++}, this means in all namespaces and classes. For Ada, this
+means in all packages.
+
+For example, assuming a program with C@t{++} symbols named
+@code{A::B::func} and @code{B::func}, both commands @w{@kbd{break
+func}} and @w{@kbd{break B::func}} set a breakpoint on both symbols.
+
+Commands that accept a linespec let you override this with the
+@code{-qualified} option. For example, @w{@kbd{break -qualified
+func}} sets a breakpoint on a free-function named @code{func} ignoring
+any C@t{++} class methods and namespace functions called @code{func}.
+
+@xref{Explicit Locations}.
+
@item @var{function}:@var{label}
Specifies the line where @var{label} appears in @var{function}.
@@ -7982,6 +7998,31 @@ on function locations unmodified by other options (such as @code{-label}
or @code{-line}) refer to the line that begins the body of the function.
In C, for example, this is the line with the open brace.
+By default, in C@t{++} and Ada, @var{function} is interpreted as
+specifying all functions named @var{function} in all scopes. For
+C@t{++}, this means in all namespaces and classes. For Ada, this
+means in all packages.
+
+For example, assuming a program with C@t{++} symbols named
+@code{A::B::func} and @code{B::func}, both commands @w{@kbd{break
+-function func}} and @w{@kbd{break -function B::func}} set a
+breakpoint on both symbols.
+
+You can use the @kbd{-qualified} flag to override this (see below).
+
+@item -qualified
+
+This flag makes @value{GDBN} interpret a function name specified with
+@kbd{-function} as a complete fully-qualified name.
+
+For example, assuming a C@t{++} program with symbols named
+@code{A::B::func} and @code{B::func}, the @w{@kbd{break -qualified
+-function B::func}} command sets a breakpoint on @code{B::func}, only.
+
+(Note: the @kbd{-qualified} option can precede a linespec as well
+(@pxref{Linespec Locations}), so the particular example above could be
+simplified as @w{@kbd{break -qualified B::func}}.)
+
@item -label @var{label}
The value specifies the name of a label. When the function
name is not specified, the label is searched in the function of the currently
@@ -7995,7 +8036,7 @@ relative to the current line.
@end table
Explicit location options may be abbreviated by omitting any non-unique
-trailing characters from the option name, e.g., @code{break -s main.c -li 3}.
+trailing characters from the option name, e.g., @w{@kbd{break -s main.c -li 3}}.
@node Address Locations
@subsection Address Locations
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 334d8c2..2572179 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4604,6 +4604,8 @@ static const char *test_symbols[] = {
"ns::foo<char*>",
"ns::foo<int>",
"ns::foo<long>",
+ "ns2::tmpl<int>::foo2",
+ "(anonymous namespace)::A::B::C",
/* These are used to check that the increment-last-char in the
matching algorithm for completion doesn't match "t1_fund" when
@@ -4790,6 +4792,8 @@ test_dw2_expand_symtabs_matching_symbol ()
{
CHECK_MATCH ("w", symbol_name_match_type::FULL, true,
EXPECT ("w1::w2"));
+ CHECK_MATCH ("w", symbol_name_match_type::WILD, true,
+ EXPECT ("w1::w2"));
}
/* Same, with a "complicated" symbol. */
@@ -4817,6 +4821,10 @@ test_dw2_expand_symtabs_matching_symbol ()
{
CHECK_MATCH ("std::zfunction(int)", symbol_name_match_type::FULL, true,
EXPECT ("std::zfunction", "std::zfunction2"));
+ CHECK_MATCH ("zfunction(int)", symbol_name_match_type::WILD, true,
+ EXPECT ("std::zfunction", "std::zfunction2"));
+ CHECK_MATCH ("zfunc", symbol_name_match_type::WILD, true,
+ EXPECT ("std::zfunction", "std::zfunction2"));
}
/* Check that whitespace is ignored appropriately. A symbol with a
@@ -4825,6 +4833,8 @@ test_dw2_expand_symtabs_matching_symbol ()
static const char expected[] = "ns::foo<int>";
CHECK_MATCH ("ns :: foo < int > ", symbol_name_match_type::FULL, false,
EXPECT (expected));
+ CHECK_MATCH ("foo < int > ", symbol_name_match_type::WILD, false,
+ EXPECT (expected));
}
/* Check that whitespace is ignored appropriately. A symbol with a
@@ -4837,9 +4847,13 @@ test_dw2_expand_symtabs_matching_symbol ()
{
CHECK_MATCH ("ns :: foo < char * >", symbol_name_match_type::FULL,
completion_mode[i], EXPECT (expected));
+ CHECK_MATCH ("foo < char * >", symbol_name_match_type::WILD,
+ completion_mode[i], EXPECT (expected));
CHECK_MATCH ("ns :: foo < char * > (int)", symbol_name_match_type::FULL,
completion_mode[i], EXPECT (expected));
+ CHECK_MATCH ("foo < char * > (int)", symbol_name_match_type::WILD,
+ completion_mode[i], EXPECT (expected));
}
}
@@ -4850,14 +4864,48 @@ test_dw2_expand_symtabs_matching_symbol ()
symbol_name_match_type::FULL, true, EXPECT (expected));
CHECK_MATCH ("ns :: foo < char * > ( int ) &&",
symbol_name_match_type::FULL, true, EXPECT (expected));
+ CHECK_MATCH ("foo < char * > ( int ) const",
+ symbol_name_match_type::WILD, true, EXPECT (expected));
+ CHECK_MATCH ("foo < char * > ( int ) &&",
+ symbol_name_match_type::WILD, true, EXPECT (expected));
}
/* Test lookup names that don't match anything. */
{
+ CHECK_MATCH ("bar2", symbol_name_match_type::WILD, false,
+ {});
+
CHECK_MATCH ("doesntexist", symbol_name_match_type::FULL, false,
{});
}
+ /* Some wild matching tests, exercising "(anonymous namespace)",
+ which should not be confused with a parameter list. */
+ {
+ static const char *syms[] = {
+ "A::B::C",
+ "B::C",
+ "C",
+ "A :: B :: C ( int )",
+ "B :: C ( int )",
+ "C ( int )",
+ };
+
+ for (const char *s : syms)
+ {
+ CHECK_MATCH (s, symbol_name_match_type::WILD, false,
+ EXPECT ("(anonymous namespace)::A::B::C"));
+ }
+ }
+
+ {
+ static const char expected[] = "ns2::tmpl<int>::foo2";
+ CHECK_MATCH ("tmp", symbol_name_match_type::WILD, true,
+ EXPECT (expected));
+ CHECK_MATCH ("tmpl<", symbol_name_match_type::WILD, true,
+ EXPECT (expected));
+ }
+
SELF_CHECK (!any_mismatch);
#undef EXPECT
diff --git a/gdb/guile/scm-breakpoint.c b/gdb/guile/scm-breakpoint.c
index ec75be5..f84815e 100644
--- a/gdb/guile/scm-breakpoint.c
+++ b/gdb/guile/scm-breakpoint.c
@@ -424,8 +424,10 @@ gdbscm_register_breakpoint_x (SCM self)
pending_breakpoint_scm = self;
location = bp_smob->spec.location;
copy = skip_spaces (location);
- event_location_up eloc = string_to_event_location_basic (&copy,
- current_language);
+ event_location_up eloc
+ = string_to_event_location_basic (&copy,
+ current_language,
+ symbol_name_match_type::WILD);
TRY
{
diff --git a/gdb/linespec.c b/gdb/linespec.c
index f1e1ea9..909dc32 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -359,6 +359,7 @@ static VEC (symbolp) *find_label_symbols (struct linespec_state *self,
static void find_linespec_symbols (struct linespec_state *self,
VEC (symtab_ptr) *file_symtabs,
const char *name,
+ symbol_name_match_type name_match_type,
VEC (symbolp) **symbols,
VEC (bound_minimal_symbol_d) **minsyms);
@@ -1865,9 +1866,12 @@ linespec_parse_basic (linespec_parser *parser)
completion_tracker tmp_tracker;
const char *source_filename
= PARSER_EXPLICIT (parser)->source_filename;
+ symbol_name_match_type match_type
+ = PARSER_EXPLICIT (parser)->func_name_match_type;
linespec_complete_function (tmp_tracker,
parser->completion_word,
+ match_type,
source_filename);
if (tmp_tracker.have_completions ())
@@ -1892,6 +1896,7 @@ linespec_parse_basic (linespec_parser *parser)
/* Try looking it up as a function/method. */
find_linespec_symbols (PARSER_STATE (parser),
PARSER_RESULT (parser)->file_symtabs, name,
+ PARSER_EXPLICIT (parser)->func_name_match_type,
&symbols, &minimal_symbols);
if (symbols != NULL || minimal_symbols != NULL)
@@ -2383,12 +2388,15 @@ convert_explicit_location_to_linespec (struct linespec_state *self,
linespec_p result,
const char *source_filename,
const char *function_name,
+ symbol_name_match_type fname_match_type,
const char *label_name,
struct line_offset line_offset)
{
VEC (symbolp) *symbols, *labels;
VEC (bound_minimal_symbol_d) *minimal_symbols;
+ result->explicit_loc.func_name_match_type = fname_match_type;
+
if (source_filename != NULL)
{
TRY
@@ -2412,8 +2420,8 @@ convert_explicit_location_to_linespec (struct linespec_state *self,
if (function_name != NULL)
{
find_linespec_symbols (self, result->file_symtabs,
- function_name, &symbols,
- &minimal_symbols);
+ function_name, fname_match_type,
+ &symbols, &minimal_symbols);
if (symbols == NULL && minimal_symbols == NULL)
symbol_not_found_error (function_name,
@@ -2453,6 +2461,7 @@ convert_explicit_location_to_sals (struct linespec_state *self,
convert_explicit_location_to_linespec (self, result,
explicit_loc->source_filename,
explicit_loc->function_name,
+ explicit_loc->func_name_match_type,
explicit_loc->label_name,
explicit_loc->line_offset);
return convert_linespec_to_sals (self, result);
@@ -2506,10 +2515,12 @@ convert_explicit_location_to_sals (struct linespec_state *self,
if no file is validly specified. Callers must check that.
Also, the line number returned may be invalid. */
-/* Parse the linespec in ARG. */
+/* Parse the linespec in ARG. MATCH_TYPE indicates how function names
+ should be matched. */
static std::vector<symtab_and_line>
-parse_linespec (linespec_parser *parser, const char *arg)
+parse_linespec (linespec_parser *parser, const char *arg,
+ symbol_name_match_type match_type)
{
linespec_token token;
struct gdb_exception file_exception = exception_none;
@@ -2539,6 +2550,7 @@ parse_linespec (linespec_parser *parser, const char *arg)
parser->lexer.stream = arg;
parser->completion_word = arg;
parser->complete_what = linespec_complete_what::FUNCTION;
+ PARSER_EXPLICIT (parser)->func_name_match_type = match_type;
/* Initialize the default symtab and line offset. */
initialize_defaults (&PARSER_STATE (parser)->default_symtab,
@@ -2747,6 +2759,8 @@ linespec_parser_new (linespec_parser *parser,
memset (parser, 0, sizeof (linespec_parser));
parser->lexer.current.type = LSTOKEN_CONSUMED;
memset (PARSER_RESULT (parser), 0, sizeof (struct linespec));
+ PARSER_EXPLICIT (parser)->func_name_match_type
+ = symbol_name_match_type::WILD;
PARSER_EXPLICIT (parser)->line_offset.sign = LINE_OFFSET_UNKNOWN;
linespec_state_constructor (PARSER_STATE (parser), flags, language,
search_pspace,
@@ -2828,10 +2842,10 @@ linespec_lex_to_end (const char **stringp)
void
linespec_complete_function (completion_tracker &tracker,
const char *function,
+ symbol_name_match_type func_match_type,
const char *source_filename)
{
complete_symbol_mode mode = complete_symbol_mode::LINESPEC;
- symbol_name_match_type func_match_type = symbol_name_match_type::WILD;
if (source_filename != NULL)
{
@@ -2870,7 +2884,9 @@ complete_linespec_component (linespec_parser *parser,
{
completion_list fn_list;
- linespec_complete_function (tracker, text, source_filename);
+ symbol_name_match_type match_type
+ = PARSER_EXPLICIT (parser)->func_name_match_type;
+ linespec_complete_function (tracker, text, match_type, source_filename);
if (source_filename == NULL)
{
/* Haven't seen a source component, like in "b
@@ -2940,6 +2956,7 @@ linespec_complete_label (completion_tracker &tracker,
const struct language_defn *language,
const char *source_filename,
const char *function_name,
+ symbol_name_match_type func_name_match_type,
const char *label_name)
{
linespec_parser parser;
@@ -2956,6 +2973,7 @@ linespec_complete_label (completion_tracker &tracker,
PARSER_RESULT (&parser),
source_filename,
function_name,
+ func_name_match_type,
NULL, unknown_offset);
}
CATCH (ex, RETURN_MASK_ERROR)
@@ -2973,7 +2991,8 @@ linespec_complete_label (completion_tracker &tracker,
/* See description in linespec.h. */
void
-linespec_complete (completion_tracker &tracker, const char *text)
+linespec_complete (completion_tracker &tracker, const char *text,
+ symbol_name_match_type match_type)
{
linespec_parser parser;
struct cleanup *cleanup;
@@ -2982,6 +3001,7 @@ linespec_complete (completion_tracker &tracker, const char *text)
linespec_parser_new (&parser, 0, current_language, NULL, NULL, 0, NULL);
cleanup = make_cleanup (linespec_parser_delete, &parser);
parser.lexer.saved_arg = text;
+ PARSER_EXPLICIT (&parser)->func_name_match_type = match_type;
PARSER_STREAM (&parser) = text;
parser.completion_tracker = &tracker;
@@ -2991,7 +3011,7 @@ linespec_complete (completion_tracker &tracker, const char *text)
furthest completion point we managed to parse to. */
TRY
{
- parse_linespec (&parser, text);
+ parse_linespec (&parser, text, match_type);
}
CATCH (except, RETURN_MASK_ERROR)
{
@@ -3039,7 +3059,7 @@ linespec_complete (completion_tracker &tracker, const char *text)
VEC (bound_minimal_symbol_d) *minimal_symbols;
find_linespec_symbols (PARSER_STATE (&parser),
PARSER_RESULT (&parser)->file_symtabs,
- func_name,
+ func_name, match_type,
&function_symbols, &minimal_symbols);
PARSER_RESULT (&parser)->function_symbols = function_symbols;
@@ -3181,7 +3201,9 @@ event_location_to_sals (linespec_parser *parser,
PARSER_STATE (parser)->is_linespec = 1;
TRY
{
- result = parse_linespec (parser, get_linespec_location (location));
+ const linespec_location *ls = get_linespec_location (location);
+ result = parse_linespec (parser,
+ ls->spec_string, ls->match_type);
}
CATCH (except, RETURN_MASK_ERROR)
{
@@ -3492,7 +3514,8 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
else
str = saved_arg;
- self->canonical->location = new_linespec_location (&str);
+ self->canonical->location
+ = new_linespec_location (&str, symbol_name_match_type::FULL);
}
}
@@ -3936,6 +3959,7 @@ symtabs_from_filename (const char *filename,
static void
find_function_symbols (struct linespec_state *state,
VEC (symtab_ptr) *file_symtabs, const char *name,
+ symbol_name_match_type name_match_type,
VEC (symbolp) **symbols,
VEC (bound_minimal_symbol_d) **minsyms)
{
@@ -3955,8 +3979,7 @@ find_function_symbols (struct linespec_state *state,
add_all_symbol_names_from_pspace (&info, state->search_pspace,
symbol_names, FUNCTIONS_DOMAIN);
else
- add_matching_symbols_to_info (name, symbol_name_match_type::WILD,
- FUNCTIONS_DOMAIN,
+ add_matching_symbols_to_info (name, name_match_type, FUNCTIONS_DOMAIN,
&info, state->search_pspace);
do_cleanups (cleanup);
@@ -3985,6 +4008,7 @@ static void
find_linespec_symbols (struct linespec_state *state,
VEC (symtab_ptr) *file_symtabs,
const char *lookup_name,
+ symbol_name_match_type name_match_type,
VEC (symbolp) **symbols,
VEC (bound_minimal_symbol_d) **minsyms)
{
@@ -4002,6 +4026,7 @@ find_linespec_symbols (struct linespec_state *state,
2) break class::method where method is in class (and not a baseclass) */
find_function_symbols (state, file_symtabs, lookup_name,
+ name_match_type,
symbols, minsyms);
/* If we were unable to locate a symbol of the same name, try dividing
diff --git a/gdb/linespec.h b/gdb/linespec.h
index b955728..85beb62 100644
--- a/gdb/linespec.h
+++ b/gdb/linespec.h
@@ -180,14 +180,17 @@ extern const char * const linespec_keywords[];
/* Complete a linespec. */
extern void linespec_complete (completion_tracker &tracker,
- const char *text);
+ const char *text,
+ symbol_name_match_type match_type);
-/* Complete a function symbol, in linespec mode. If SOURCE_FILENAME
- is non-NULL, limits completion to the list of functions defined in
- source files that match SOURCE_FILENAME. */
+/* Complete a function symbol, in linespec mode, according to
+ FUNC_MATCH_TYPE. If SOURCE_FILENAME is non-NULL, limits completion
+ to the list of functions defined in source files that match
+ SOURCE_FILENAME. */
extern void linespec_complete_function (completion_tracker &tracker,
const char *function,
+ symbol_name_match_type func_match_type,
const char *source_filename);
/* Complete a label symbol, in linespec mode. Only labels of
@@ -199,6 +202,7 @@ extern void linespec_complete_label (completion_tracker &tracker,
const struct language_defn *language,
const char *source_filename,
const char *function_name,
+ symbol_name_match_type name_match_type,
const char *label_name);
/* Evaluate the expression pointed to by EXP_PTR into a CORE_ADDR,
diff --git a/gdb/location.c b/gdb/location.c
index 5ed3623..6752462 100644
--- a/gdb/location.c
+++ b/gdb/location.c
@@ -41,13 +41,14 @@ struct event_location
union
{
- /* A generic "this is a string specification" for a location.
- This representation is used by both "normal" linespecs and
- probes. */
+ /* A probe. */
char *addr_string;
-#define EL_LINESPEC(P) ((P)->u.addr_string)
#define EL_PROBE(P) ((P)->u.addr_string)
+ /* A "normal" linespec. */
+ struct linespec_location linespec_location;
+#define EL_LINESPEC(P) (&(P)->u.linespec_location)
+
/* An address in the inferior. */
CORE_ADDR address;
#define EL_ADDRESS(P) (P)->u.address
@@ -78,17 +79,20 @@ initialize_explicit_location (struct explicit_location *explicit_loc)
{
memset (explicit_loc, 0, sizeof (struct explicit_location));
explicit_loc->line_offset.sign = LINE_OFFSET_UNKNOWN;
+ explicit_loc->func_name_match_type = symbol_name_match_type::WILD;
}
/* See description in location.h. */
event_location_up
-new_linespec_location (const char **linespec)
+new_linespec_location (const char **linespec,
+ symbol_name_match_type match_type)
{
struct event_location *location;
location = XCNEW (struct event_location);
EL_TYPE (location) = LINESPEC_LOCATION;
+ EL_LINESPEC (location)->match_type = match_type;
if (*linespec != NULL)
{
const char *p;
@@ -97,14 +101,14 @@ new_linespec_location (const char **linespec)
linespec_lex_to_end (linespec);
p = remove_trailing_whitespace (orig, *linespec);
if ((p - orig) > 0)
- EL_LINESPEC (location) = savestring (orig, p - orig);
+ EL_LINESPEC (location)->spec_string = savestring (orig, p - orig);
}
return event_location_up (location);
}
/* See description in location.h. */
-const char *
+const linespec_location *
get_linespec_location (const struct event_location *location)
{
gdb_assert (EL_TYPE (location) == LINESPEC_LOCATION);
@@ -180,6 +184,9 @@ new_explicit_location (const struct explicit_location *explicit_loc)
initialize_explicit_location (EL_EXPLICIT (&tmp));
if (explicit_loc != NULL)
{
+ EL_EXPLICIT (&tmp)->func_name_match_type
+ = explicit_loc->func_name_match_type;
+
if (explicit_loc->source_filename != NULL)
{
EL_EXPLICIT (&tmp)->source_filename
@@ -244,6 +251,8 @@ explicit_to_string_internal (int as_linespec,
{
if (need_space)
buf.putc (space);
+ if (explicit_loc->func_name_match_type == symbol_name_match_type::FULL)
+ buf.puts ("-qualified ");
if (!as_linespec)
buf.puts ("-function ");
buf.puts (explicit_loc->function_name);
@@ -307,8 +316,10 @@ copy_event_location (const struct event_location *src)
switch (EL_TYPE (src))
{
case LINESPEC_LOCATION:
- if (EL_LINESPEC (src) != NULL)
- EL_LINESPEC (dst) = xstrdup (EL_LINESPEC (src));
+ EL_LINESPEC (dst)->match_type = EL_LINESPEC (src)->match_type;
+ if (EL_LINESPEC (src)->spec_string != NULL)
+ EL_LINESPEC (dst)->spec_string
+ = xstrdup (EL_LINESPEC (src)->spec_string);
break;
case ADDRESS_LOCATION:
@@ -316,6 +327,8 @@ copy_event_location (const struct event_location *src)
break;
case EXPLICIT_LOCATION:
+ EL_EXPLICIT (dst)->func_name_match_type
+ = EL_EXPLICIT (src)->func_name_match_type;
if (EL_EXPLICIT (src)->source_filename != NULL)
EL_EXPLICIT (dst)->source_filename
= xstrdup (EL_EXPLICIT (src)->source_filename);
@@ -353,7 +366,7 @@ event_location_deleter::operator() (event_location *location) const
switch (EL_TYPE (location))
{
case LINESPEC_LOCATION:
- xfree (EL_LINESPEC (location));
+ xfree (EL_LINESPEC (location)->spec_string);
break;
case ADDRESS_LOCATION:
@@ -388,8 +401,17 @@ event_location_to_string (struct event_location *location)
switch (EL_TYPE (location))
{
case LINESPEC_LOCATION:
- if (EL_LINESPEC (location) != NULL)
- EL_STRING (location) = xstrdup (EL_LINESPEC (location));
+ if (EL_LINESPEC (location)->spec_string != NULL)
+ {
+ linespec_location *ls = EL_LINESPEC (location);
+ if (ls->match_type == symbol_name_match_type::FULL)
+ {
+ EL_STRING (location)
+ = concat ("-qualified ", ls->spec_string, (char *) NULL);
+ }
+ else
+ EL_STRING (location) = xstrdup (ls->spec_string);
+ }
break;
case ADDRESS_LOCATION:
@@ -756,12 +778,23 @@ string_to_explicit_location (const char **argp,
argument. */
bool have_oarg = false;
+ /* True if the option needs an argument. */
+ bool need_oarg = false;
+
/* Convenience to consistently set both OARG/HAVE_OARG from
ARG. */
auto set_oarg = [&] (gdb::unique_xmalloc_ptr<char> arg)
{
+ if (completion_info != NULL)
+ {
+ /* We do this here because the set of options that take
+ arguments matches the set of explicit location
+ options. */
+ completion_info->saw_explicit_location_option = true;
+ }
oarg = std::move (arg);
have_oarg = oarg != NULL;
+ need_oarg = true;
};
if (strncmp (opt.get (), "-source", len) == 0)
@@ -776,6 +809,11 @@ string_to_explicit_location (const char **argp,
completion_info));
EL_EXPLICIT (location)->function_name = oarg.release ();
}
+ else if (strncmp (opt.get (), "-qualified", len) == 0)
+ {
+ EL_EXPLICIT (location)->func_name_match_type
+ = symbol_name_match_type::FULL;
+ }
else if (strncmp (opt.get (), "-line", len) == 0)
{
set_oarg (explicit_location_lex_one (argp, language, NULL));
@@ -814,7 +852,7 @@ string_to_explicit_location (const char **argp,
case, it provides a much better user experience to issue
the "invalid argument" error before any missing
argument error. */
- if (!have_oarg && completion_info == NULL)
+ if (need_oarg && !have_oarg && completion_info == NULL)
error (_("missing argument for \"%s\""), opt.get ());
}
@@ -837,7 +875,8 @@ string_to_explicit_location (const char **argp,
event_location_up
string_to_event_location_basic (const char **stringp,
- const struct language_defn *language)
+ const struct language_defn *language,
+ symbol_name_match_type match_type)
{
event_location_up location;
const char *cs;
@@ -865,7 +904,7 @@ string_to_event_location_basic (const char **stringp,
else
{
/* Everything else is a linespec. */
- location = new_linespec_location (stringp);
+ location = new_linespec_location (stringp, match_type);
}
}
@@ -879,6 +918,7 @@ string_to_event_location (const char **stringp,
const struct language_defn *language)
{
const char *arg, *orig;
+ symbol_name_match_type match_type = symbol_name_match_type::WILD;
/* Try an explicit location. */
orig = arg = *stringp;
@@ -888,15 +928,21 @@ string_to_event_location (const char **stringp,
/* It was a valid explicit location. Advance STRINGP to
the end of input. */
*stringp += arg - orig;
- }
- else
- {
- /* Everything else is a "basic" linespec, address, or probe
- location. */
- location = string_to_event_location_basic (stringp, language);
+
+ /* If the user really specified a location, then we're done. */
+ if (!event_location_empty_p (location.get ()))
+ return location;
+
+ /* Otherwise, the user _only_ specified optional flags like
+ "-qualified", otherwise string_to_explicit_location would
+ have thrown an error. Save the flags for "basic" linespec
+ parsing below and discard the explicit location. */
+ match_type = EL_EXPLICIT (location)->func_name_match_type;
}
- return location;
+ /* Everything else is a "basic" linespec, address, or probe
+ location. */
+ return string_to_event_location_basic (stringp, language, match_type);
}
/* See description in location.h. */
diff --git a/gdb/location.h b/gdb/location.h
index d954eac..fcfa8fb 100644
--- a/gdb/location.h
+++ b/gdb/location.h
@@ -66,6 +66,17 @@ enum event_location_type
PROBE_LOCATION
};
+/* A traditional linespec. */
+
+struct linespec_location
+{
+ /* Whether the function name is fully-qualified or not. */
+ symbol_name_match_type match_type;
+
+ /* The linespec. */
+ char *spec_string;
+};
+
/* An explicit location. This structure is used to bypass the
parsing done on linespecs. It still has the same requirements
as linespecs, though. For example, source_filename requires
@@ -79,6 +90,9 @@ struct explicit_location
/* The function name. Malloc'd. */
char *function_name;
+ /* Whether the function name is fully-qualified or not. */
+ symbol_name_match_type func_name_match_type;
+
/* The name of a label. Malloc'd. */
char *label_name;
@@ -107,7 +121,7 @@ extern char *
/* Return a string representation of the LOCATION.
This function may return NULL for unspecified linespecs,
- e.g, LOCATION_LINESPEC and addr_string is NULL.
+ e.g, LINESPEC_LOCATION and spec_string is NULL.
The result is cached in LOCATION. */
@@ -127,12 +141,13 @@ typedef std::unique_ptr<event_location, event_location_deleter>
/* Create a new linespec location. */
-extern event_location_up new_linespec_location (const char **linespec);
+extern event_location_up new_linespec_location
+ (const char **linespec, symbol_name_match_type match_type);
-/* Return the linespec location (a string) of the given event_location
- (which must be of type LINESPEC_LOCATION). */
+/* Return the linespec location of the given event_location (which
+ must be of type LINESPEC_LOCATION). */
-extern const char *
+extern const linespec_location *
get_linespec_location (const struct event_location *location);
/* Create a new address location.
@@ -211,12 +226,14 @@ extern event_location_up
string_to_event_location (const char **argp,
const struct language_defn *langauge);
-/* Like string_to_event_location, but does not attempt to parse explicit
- locations. */
+/* Like string_to_event_location, but does not attempt to parse
+ explicit locations. MATCH_TYPE indicates how function names should
+ be matched. */
extern event_location_up
string_to_event_location_basic (const char **argp,
- const struct language_defn *language);
+ const struct language_defn *language,
+ symbol_name_match_type match_type);
/* Structure filled in by string_to_explicit_location to aid the
completer. */
@@ -233,6 +250,11 @@ struct explicit_completion_info
If the last option is not quoted, then both are set to NULL. */
const char *quoted_arg_start = NULL;
const char *quoted_arg_end = NULL;
+
+ /* True if we saw an explicit location option, as opposed to only
+ flags that affect both explicit locations and linespecs, like
+ "-qualified". */
+ bool saw_explicit_location_option = false;
};
/* Attempt to convert the input string in *ARGP into an explicit location.
diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c
index 833bdc0..6cb1d71 100644
--- a/gdb/mi/mi-cmd-break.c
+++ b/gdb/mi/mi-cmd-break.c
@@ -337,7 +337,8 @@ mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc)
}
else
{
- location = string_to_event_location_basic (&address, current_language);
+ location = string_to_event_location_basic (&address, current_language,
+ symbol_name_match_type::WILD);
if (*address)
error (_("Garbage '%s' at end of location"), address);
}
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 86719d1..5bc073e 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -681,7 +681,8 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs)
case bp_breakpoint:
{
event_location_up location
- = string_to_event_location_basic (&copy, current_language);
+ = string_to_event_location_basic (&copy, current_language,
+ symbol_name_match_type::WILD);
create_breakpoint (python_gdbarch,
location.get (), NULL, -1, NULL,
0,
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 9ed9b6b..c29a46b 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -838,7 +838,8 @@ gdbpy_decode_line (PyObject *self, PyObject *args)
return NULL;
if (arg != NULL)
- location = string_to_event_location_basic (&arg, python_language);
+ location = string_to_event_location_basic (&arg, python_language,
+ symbol_name_match_type::WILD);
std::vector<symtab_and_line> decoded_sals;
symtab_and_line def_sal;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 5b78c7d..690495a 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,21 @@
+2017-11-29 Pedro Alves <palves@redhat.com>
+
+ * gdb.base/langs.exp: Use -qualified.
+ * gdb.cp/meth-typedefs.exp: Use -qualified, and add tests without
+ it.
+ * gdb.cp/namespace.exp: Use -qualified.
+ * gdb.linespec/cpcompletion.exp (overload-2, fqn, fqn-2)
+ (overload-3, template-overload, template-ret-type, const-overload)
+ (const-overload-quoted, anon-ns, ambiguous-prefix): New
+ procedures.
+ (test_driver): Call them.
+ * gdb.cp/save-bp-qualified.cc: New.
+ * gdb.cp/save-bp-qualified.exp: New.
+ * gdb.linespec/explicit.exp: Test -qualified.
+ * lib/completion-support.exp (completion::explicit_opts_list): Add
+ "-qualified".
+ * lib/gdb.exp (gdb_breakpoint): Handle "qualified".
+
2017-11-29 Phil Muldoon <pmuldoon@redhat.com>
* gdb.python/py-rbreak.exp: Set nosharedlibrary before tests.
diff --git a/gdb/testsuite/gdb.base/langs.exp b/gdb/testsuite/gdb.base/langs.exp
index 8dcd5ee..03c690c 100644
--- a/gdb/testsuite/gdb.base/langs.exp
+++ b/gdb/testsuite/gdb.base/langs.exp
@@ -38,7 +38,7 @@ if [get_compiler_info] {
return -1
}
-gdb_test_multiple "b langs0" "break on nonexistent function in langs.exp" {
+gdb_test_multiple "b -qualified langs0" "break on nonexistent function in langs.exp" {
-re "Function \"langs0\" not defined\..*Make breakpoint pending on future shared library load.*y or .n.. $" {
gdb_test "n" "" "break on nonexistent function in langs.exp"
diff --git a/gdb/testsuite/gdb.cp/meth-typedefs.exp b/gdb/testsuite/gdb.cp/meth-typedefs.exp
index 08f1464..50690ab 100644
--- a/gdb/testsuite/gdb.cp/meth-typedefs.exp
+++ b/gdb/testsuite/gdb.cp/meth-typedefs.exp
@@ -145,15 +145,42 @@ foreach test $methods {
set func [lindex $test 0]
set result [lindex $test 1]
- gdb_test "list $func" $result
- gdb_test "list '$func'" $result
- if {[gdb_breakpoint $func]} {
- pass "break $func"
+ gdb_test "list -qualified $func" $result
+ gdb_test "list -qualified '$func'" $result
+ if {[gdb_breakpoint "-qualified $func"]} {
+ pass "break -qualified $func"
}
- if {[gdb_breakpoint '$func']} {
- pass "break '$func'"
+ if {[gdb_breakpoint "-qualified '$func'"]} {
+ pass "break -qualified '$func'"
}
}
+# The tests above use -qualified to explicitly pick the one "test"
+# symbol each test cares about. Now check that both "break test(..)"
+# and "list test(..)" without -qualified find "test(..)" in all the 3
+# scopes that have the this particular overload.
+set func "test(aenum, astruct const&, aunion const***)"
+set func_re "test\\(anon_enum, anon_struct const&, anon_union const\\*\\*\\*\\)"
+set line1 [gdb_get_line_number " A::FOO::$func"]
+set line2 [gdb_get_line_number " B::$func"]
+set line3 [gdb_get_line_number " $func"]
+
+foreach f [list "$func" "'$func'"] {
+ set any "\[^\r\n\]*"
+ gdb_test \
+ "list $f" \
+ [multi_line \
+ "file: \".*$srcfile\", line number: $line1, symbol: \"A::foo::$func_re\"" \
+ "$line1${any}A::FOO::test${any}" \
+ "file: \".*$srcfile\", line number: $line2, symbol: \"B::$func_re\"" \
+ "$line2${any}B::test${any}" \
+ "file: \".*$srcfile\", line number: $line3, symbol: \"$func_re\"" \
+ "$line3${any}// test${any}"] \
+ "list $f"
+
+ delete_breakpoints
+ gdb_test "break $f" "\\(3 locations\\)"
+}
+
gdb_exit
return 0
diff --git a/gdb/testsuite/gdb.cp/namespace.exp b/gdb/testsuite/gdb.cp/namespace.exp
index 640ee4f..4a6b863 100644
--- a/gdb/testsuite/gdb.cp/namespace.exp
+++ b/gdb/testsuite/gdb.cp/namespace.exp
@@ -120,7 +120,7 @@ gdb_test "break AAA::xyzq" \
# Break on a function in the global namespace.
-gdb_test "break ::ensureOtherRefs" \
+gdb_test "break -qualified ::ensureOtherRefs" \
"Breakpoint.*at $hex: file.*$srcfile2, line $decimal\\."
# Call a function in a nested namespace
diff --git a/gdb/testsuite/gdb.cp/save-bp-qualified.cc b/gdb/testsuite/gdb.cp/save-bp-qualified.cc
new file mode 100644
index 0000000..8dc2682
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/save-bp-qualified.cc
@@ -0,0 +1,40 @@
+/* Copyright 2017 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+struct S
+{
+ static void function ();
+};
+
+void
+S::function ()
+{
+}
+
+void
+function ()
+{
+}
+
+int
+main ()
+{
+ S::function ();
+ function ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.cp/save-bp-qualified.exp b/gdb/testsuite/gdb.cp/save-bp-qualified.exp
new file mode 100644
index 0000000..8498f24
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/save-bp-qualified.exp
@@ -0,0 +1,74 @@
+# Copyright (C) 2011-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/>.
+
+# Test "save breakpoints" + "break -qualified".
+
+standard_testfile .cc
+
+if { [build_executable "failed to prepare" ${testfile} $srcfile {debug c++}] } {
+ return -1
+}
+
+proc restart {} {
+ global testfile
+
+ clean_restart $testfile
+
+ if ![runto_main] {
+ untested "could not run to main"
+ return 0
+ }
+ # Delete all breakpoints so that the "runto_main" breakpoint above
+ # does not interfere with our testing.
+ delete_breakpoints
+
+ return 1
+}
+
+with_test_prefix "save" {
+ if ![restart] {
+ return -1
+ }
+
+ gdb_breakpoint "function" qualified
+ gdb_breakpoint "function"
+
+ # Save the breakpoints into a file.
+ if {[is_remote host]} {
+ set bps bps
+ } else {
+ set bps [standard_output_file bps]
+ }
+ remote_file host delete "$bps"
+ gdb_test "save breakpoint $bps" "" "save breakpoint bps"
+}
+
+with_test_prefix "restore" {
+ if ![restart] {
+ return -1
+ }
+
+ # Restore the breakpoints.
+ gdb_test "source $bps" "" "source bps"
+
+ # Verify that all breakpoints have been created correctly.
+ gdb_test "info break" [multi_line \
+ "Num +Type +Disp +Enb +Address +What" \
+ "$decimal +breakpoint +keep +y +$hex +in function\\(\\) at \[^\r\n\]*$srcfile:$decimal" \
+ "$decimal +breakpoint +keep +y +<MULTIPLE> +" \
+ "$decimal.$decimal +y +$hex +in S::function\\(\\) at \[^\r\n\]*$srcfile:$decimal" \
+ "$decimal.$decimal +y +$hex +in function\\(\\) at \[^\r\n\]*$srcfile:$decimal" \
+ ]
+}
diff --git a/gdb/testsuite/gdb.linespec/cpcompletion.exp b/gdb/testsuite/gdb.linespec/cpcompletion.exp
index 873dc78..832ef07 100644
--- a/gdb/testsuite/gdb.linespec/cpcompletion.exp
+++ b/gdb/testsuite/gdb.linespec/cpcompletion.exp
@@ -118,6 +118,339 @@ proc_with_prefix overload {} {
}
}
+# 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 {} {
+
+ # "-qualified" works with both explicit locations and linespecs.
+ # Also test that combining a source file with a function name
+ # still results in a full match, with both linespecs and explicit
+ # locations.
+ foreach cmd_prefix {
+ "b -qualified "
+ "b -qualified -function "
+ "b -qualified cpls.cc:"
+ "b -qualified -source cpls.cc -function "
+ "b -source cpls.cc -qualified -function "
+ } {
+ 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 lookup name doesn'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 ".
@@ -341,6 +674,73 @@ proc_with_prefix incomplete-scope-colon {} {
}
}
+# Test completing functions/methods in anonymous namespaces.
+
+proc_with_prefix anon-ns {} {
+ foreach cmd_prefix {"b" "b -function"} {
+ foreach qc $completion::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.
@@ -368,6 +768,19 @@ proc_with_prefix operator< {} {
}
}
+# 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 {} {
@@ -516,13 +929,23 @@ proc_with_prefix if-expression {} {
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
diff --git a/gdb/testsuite/gdb.linespec/explicit.exp b/gdb/testsuite/gdb.linespec/explicit.exp
index 9cf0162..b592d29 100644
--- a/gdb/testsuite/gdb.linespec/explicit.exp
+++ b/gdb/testsuite/gdb.linespec/explicit.exp
@@ -401,51 +401,66 @@ namespace eval $testfile {
"-function"
"-label"
"-line"
+ "-qualified"
"-source"
"if"
"task"
"thread"
}
foreach what { "-function" "-label" "-line" "-source" } {
- with_test_prefix "complete after $what" {
- if {$what != "-line"} {
- set w "$what argument "
- test_gdb_complete_multiple \
- "b $w" "" "" $completions_list
- test_gdb_complete_unique \
- "b $w thr" \
- "b $w thread"
- test_gdb_complete_unique \
- "b $w -fun" \
- "b $w -function"
- } else {
- # After -line, we expect a number / offset.
- foreach line {"10" "+10" "-10"} {
- set w "-line $line"
- test_gdb_complete_multiple \
- "b $w " "" "" $completions_list
- test_gdb_complete_unique \
- "b $w thr" \
- "b $w thread"
- test_gdb_complete_unique \
- "b $w -fun" \
- "b $w -function"
+ # Also test with "-qualified" appearing before the
+ # explicit location.
+ foreach prefix {"" "-qualified "} {
+
+ # ... and with "-qualified" appearing after the
+ # explicit location.
+ foreach suffix {"" " -qualified"} {
+ with_test_prefix "complete after $prefix$what$suffix" {
+ if {$what != "-line"} {
+ set w "$prefix$what argument$suffix "
+ test_gdb_complete_multiple \
+ "b $w" "" "" $completions_list
+ test_gdb_complete_unique \
+ "b $w thr" \
+ "b $w thread"
+ test_gdb_complete_unique \
+ "b $w -fun" \
+ "b $w -function"
+ } else {
+ # After -line, we expect a number / offset.
+ foreach line {"10" "+10" "-10"} {
+ set w "$prefix-line $line$suffix"
+ test_gdb_complete_multiple \
+ "b $w " "" "" $completions_list
+ test_gdb_complete_unique \
+ "b $w thr" \
+ "b $w thread"
+ test_gdb_complete_unique \
+ "b $w -fun" \
+ "b $w -function"
+ }
+
+ # With an invalid -line argument, we don't get any
+ # completions.
+ test_gdb_complete_none "b $prefix-line argument$suffix "
+ }
+
}
- # 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"
+ # These tests don't make sense with "-qualified" after
+ # the location.
+ with_test_prefix "complete after $prefix$what" {
+ # Don't complete a linespec keyword ("thread") or
+ # another option name when expecting an option
+ # argument.
+ test_gdb_complete_none "b $prefix$what thr"
+ test_gdb_complete_none "b $prefix$what -fun"
+ }
}
}
-
# Tests that ensure that after "if" we complete on expressions
# are in cpcompletion.exp.
@@ -518,6 +533,7 @@ namespace eval $testfile {
"-probe"
"-probe-dtrace"
"-probe-stap"
+ "-qualified"
"-source"
}
with_test_prefix "complete with no arguments and no symbols" {
diff --git a/gdb/testsuite/lib/completion-support.exp b/gdb/testsuite/lib/completion-support.exp
index 25332cc..c7cc1c9 100644
--- a/gdb/testsuite/lib/completion-support.exp
+++ b/gdb/testsuite/lib/completion-support.exp
@@ -30,7 +30,7 @@ namespace eval completion {
variable keyword_list {"if" "task" "thread"}
variable explicit_opts_list \
- {"-function" "-label" "-line" "-source"}
+ {"-function" "-label" "-line" "-qualified" "-source"}
}
# Make a regular expression that matches a TAB completion list.
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 8d6972a..fc0278b 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -422,7 +422,7 @@ proc gdb_starti_cmd {args} {
# Set a breakpoint at FUNCTION. If there is an additional argument it is
# a list of options; the supported options are allow-pending, temporary,
-# message, no-message, and passfail.
+# message, no-message, passfail and qualified.
# The result is 1 for success, 0 for failure.
#
# Note: The handling of message vs no-message is messed up, but it's based
@@ -447,6 +447,10 @@ proc gdb_breakpoint { function args } {
set break_message "Temporary breakpoint"
}
+ if {[lsearch -exact $args qualified] != -1} {
+ append break_command " -qualified"
+ }
+
set print_pass 0
set print_fail 1
set no_message_loc [lsearch -exact $args no-message]