diff options
29 files changed, 1233 insertions, 125 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0c9d0891031..d65337a655b 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. @@ -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 52ca081a828..5027f6a464b 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 b48c405b084..d4d095d87ee 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 49077c7171e..8d96f94cbb2 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 fd82b860314..701f5782455 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 6c6825be90a..172d8219f47 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 44d82696c58..010fc9bcb3f 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 2a1eb76d15c..49c494b5684 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 675f6e7bc82..7a71739e0b3 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 334d8c2e055..2572179a753 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 ec75be589f0..f84815e739e 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 (©, - current_language); + event_location_up eloc + = string_to_event_location_basic (©, + current_language, + symbol_name_match_type::WILD); TRY { diff --git a/gdb/linespec.c b/gdb/linespec.c index f1e1ea97749..909dc328d26 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 b955728ff35..85beb6263e7 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 5ed3623f0a2..6752462bcf1 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 d954eac7207..fcfa8fb5696 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 833bdc09ca9..6cb1d710fde 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 86719d1b6eb..5bc073ece65 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 (©, current_language); + = string_to_event_location_basic (©, 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 9ed9b6b1ca2..c29a46b4486 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 5b78c7dccfb..690495a1723 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 8dcd5eee6f6..03c690c3d7b 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 08f1464e27e..50690ab5d23 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 640ee4f30b2..4a6b86378d4 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 00000000000..8dc2682d327 --- /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 00000000000..8498f24e7b6 --- /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 873dc785cda..832ef07320f 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 9cf0162f16b..b592d29efba 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 25332cc0a49..c7cc1c97558 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 8d6972ab1fc..fc0278b9da5 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] |