language_get_symbol_name_matcher -> get_symbol_name_matcher
[deliverable/binutils-gdb.git] / gdb / linespec.c
index ab59544ab35295584f4a7555e19d8a52a32c07ad..85f412766c8f93f036bb87ef5bdaf642cf86a9c5 100644 (file)
@@ -1,6 +1,6 @@
 /* Parser for linespec for the GNU debugger, GDB.
 
-   Copyright (C) 1986-2016 Free Software Foundation, Inc.
+   Copyright (C) 1986-2018 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "ada-lang.h"
 #include "stack.h"
 #include "location.h"
+#include "common/function-view.h"
+#include "common/def-vector.h"
+
+/* An enumeration of the various things a user might attempt to
+   complete for a linespec location.  */
+
+enum class linespec_complete_what
+{
+  /* Nothing, no possible completion.  */
+  NOTHING,
+
+  /* A function/method name.  Due to ambiguity between
+
+       (gdb) b source[TAB]
+       source_file.c
+       source_function
+
+     this can also indicate a source filename, iff we haven't seen a
+     separate source filename component, as in "b source.c:function".  */
+  FUNCTION,
+
+  /* A label symbol.  E.g., break file.c:function:LABEL.  */
+  LABEL,
+
+  /* An expression.  E.g., "break foo if EXPR", or "break *EXPR".  */
+  EXPRESSION,
+
+  /* A linespec keyword ("if"/"thread"/"task").
+     E.g., "break func threa<tab>".  */
+  KEYWORD,
+};
 
 typedef struct symbol *symbolp;
 DEF_VEC_P (symbolp);
@@ -143,7 +174,7 @@ struct linespec_state
   /* The 'canonical' value passed to decode_line_full, or NULL.  */
   struct linespec_result *canonical;
 
-  /* Canonical strings that mirror the symtabs_and_lines result.  */
+  /* Canonical strings that mirror the std::vector<symtab_and_line> result.  */
   struct linespec_canonical_name *canonical_names;
 
   /* This is a set of address_entry objects which is used to prevent
@@ -171,8 +202,23 @@ struct collect_info
     VEC (symbolp) *symbols;
     VEC (bound_minimal_symbol_d) *minimal_symbols;
   } result;
+
+  /* Possibly add a symbol to the results.  */
+  bool add_symbol (symbol *sym);
 };
 
+bool
+collect_info::add_symbol (symbol *sym)
+{
+  /* In list mode, add all matching symbols, regardless of class.
+     This allows the user to type "list a_global_variable".  */
+  if (SYMBOL_CLASS (sym) == LOC_BLOCK || this->state->list_mode)
+    VEC_safe_push (symbolp, this->result.symbols, sym);
+
+  /* Continue iterating.  */
+  return true;
+}
+
 /* Token types  */
 
 enum ls_token_type
@@ -200,9 +246,9 @@ enum ls_token_type
 };
 typedef enum ls_token_type linespec_token_type;
 
-/* List of keywords  */
-
-static const char * const linespec_keywords[] = { "if", "thread", "task" };
+/* List of keywords.  This is NULL-terminated so that it can be used
+   as enum completer.  */
+const char * const linespec_keywords[] = { "if", "thread", "task", NULL };
 #define IF_KEYWORD_INDEX 0
 
 /* A token of the linespec lexer  */
@@ -255,6 +301,29 @@ struct ls_parser
   /* The result of the parse.  */
   struct linespec result;
 #define PARSER_RESULT(PPTR) (&(PPTR)->result)
+
+  /* What the parser believes the current word point should complete
+     to.  */
+  linespec_complete_what complete_what;
+
+  /* The completion word point.  The parser advances this as it skips
+     tokens.  At some point the input string will end or parsing will
+     fail, and then we attempt completion at the captured completion
+     word point, interpreting the string at completion_word as
+     COMPLETE_WHAT.  */
+  const char *completion_word;
+
+  /* If the current token was a quoted string, then this is the
+     quoting character (either " or ').  */
+  int completion_quote_char;
+
+  /* If the current token was a quoted string, then this points at the
+     end of the quoted string.  */
+  const char *completion_quote_end;
+
+  /* If parsing for completion, then this points at the completion
+     tracker.  Otherwise, this is NULL.  */
+  struct completion_tracker *completion_tracker;
 };
 typedef struct ls_parser linespec_parser;
 
@@ -264,19 +333,19 @@ typedef struct ls_parser linespec_parser;
 
 /* Prototypes for local functions.  */
 
-static void iterate_over_file_blocks (struct symtab *symtab,
-                                     const char *name, domain_enum domain,
-                                     symbol_found_callback_ftype *callback,
-                                     void *data);
+static void iterate_over_file_blocks
+  (struct symtab *symtab, const lookup_name_info &name,
+   domain_enum domain,
+   gdb::function_view<symbol_found_callback_ftype> callback);
 
 static void initialize_defaults (struct symtab **default_symtab,
                                 int *default_line);
 
 CORE_ADDR linespec_expression_to_pc (const char **exp_ptr);
 
-static struct symtabs_and_lines decode_objc (struct linespec_state *self,
-                                            linespec_p ls,
-                                            const char *arg);
+static std::vector<symtab_and_line> decode_objc (struct linespec_state *self,
+                                                linespec_p ls,
+                                                const char *arg);
 
 static VEC (symtab_ptr) *symtabs_from_filename (const char *,
                                                struct program_space *pspace);
@@ -284,11 +353,13 @@ static VEC (symtab_ptr) *symtabs_from_filename (const char *,
 static VEC (symbolp) *find_label_symbols (struct linespec_state *self,
                                          VEC (symbolp) *function_symbols,
                                          VEC (symbolp) **label_funcs_ret,
-                                         const char *name);
+                                         const char *name,
+                                         bool completion_mode = false);
 
 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);
 
@@ -300,31 +371,34 @@ static int symbol_to_sal (struct symtab_and_line *result,
                          int funfirstline, struct symbol *sym);
 
 static void add_matching_symbols_to_info (const char *name,
+                                         symbol_name_match_type name_match_type,
+                                         enum search_domain search_domain,
                                          struct collect_info *info,
                                          struct program_space *pspace);
 
 static void add_all_symbol_names_from_pspace (struct collect_info *info,
                                              struct program_space *pspace,
-                                             VEC (const_char_ptr) *names);
+                                             VEC (const_char_ptr) *names,
+                                             enum search_domain search_domain);
 
 static VEC (symtab_ptr) *
   collect_symtabs_from_filename (const char *file,
                                 struct program_space *pspace);
 
-static void decode_digits_ordinary (struct linespec_state *self,
-                                   linespec_p ls,
-                                   int line,
-                                   struct symtabs_and_lines *sals,
-                                   struct linetable_entry **best_entry);
+static std::vector<symtab_and_line> decode_digits_ordinary
+  (struct linespec_state *self,
+   linespec_p ls,
+   int line,
+   linetable_entry **best_entry);
 
-static void decode_digits_list_mode (struct linespec_state *self,
-                                    linespec_p ls,
-                                    struct symtabs_and_lines *values,
-                                    struct symtab_and_line val);
+static std::vector<symtab_and_line> decode_digits_list_mode
+  (struct linespec_state *self,
+   linespec_p ls,
+   struct symtab_and_line val);
 
 static void minsym_found (struct linespec_state *self, struct objfile *objfile,
                          struct minimal_symbol *msymbol,
-                         struct symtabs_and_lines *result);
+                         std::vector<symtab_and_line> *result);
 
 static int compare_symbols (const void *a, const void *b);
 
@@ -385,7 +459,7 @@ linespec_lexer_lex_keyword (const char *p)
 
   if (p != NULL)
     {
-      for (i = 0; i < ARRAY_SIZE (linespec_keywords); ++i)
+      for (i = 0; linespec_keywords[i] != NULL; ++i)
        {
          int len = strlen (linespec_keywords[i]);
 
@@ -405,8 +479,8 @@ linespec_lexer_lex_keyword (const char *p)
              if (i != IF_KEYWORD_INDEX)
                {
                  p += len;
-                 p = skip_spaces_const (p);
-                 for (j = 0; j < ARRAY_SIZE (linespec_keywords); ++j)
+                 p = skip_spaces (p);
+                 for (j = 0; linespec_keywords[j] != NULL; ++j)
                    {
                      int nextlen = strlen (linespec_keywords[j]);
 
@@ -527,6 +601,30 @@ find_parameter_list_end (const char *input)
   return p;
 }
 
+/* If the [STRING, STRING_LEN) string ends with what looks like a
+   keyword, return the keyword start offset in STRING.  Return -1
+   otherwise.  */
+
+static size_t
+string_find_incomplete_keyword_at_end (const char * const *keywords,
+                                      const char *string, size_t string_len)
+{
+  const char *end = string + string_len;
+  const char *p = end;
+
+  while (p > string && *p != ' ')
+    --p;
+  if (p > string)
+    {
+      p++;
+      size_t len = end - p;
+      for (size_t i = 0; keywords[i] != NULL; ++i)
+       if (strncmp (keywords[i], p, len) == 0)
+         return p - string;
+    }
+
+  return -1;
+}
 
 /* Lex a string from the input in PARSER.  */
 
@@ -574,13 +672,31 @@ linespec_lexer_lex_string (linespec_parser *parser)
       /* Skip to the ending quote.  */
       end = skip_quote_char (PARSER_STREAM (parser), quote_char);
 
-      /* Error if the input did not terminate properly.  */
-      if (end == NULL)
-       error (_("unmatched quote"));
+      /* This helps the completer mode decide whether we have a
+        complete string.  */
+      parser->completion_quote_char = quote_char;
+      parser->completion_quote_end = end;
 
-      /* Skip over the ending quote and mark the length of the string.  */
-      PARSER_STREAM (parser) = (char *) ++end;
-      LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - 2 - start;
+      /* Error if the input did not terminate properly, unless in
+        completion mode.  */
+      if (end == NULL)
+       {
+         if (parser->completion_tracker == NULL)
+           error (_("unmatched quote"));
+
+         /* In completion mode, we'll try to complete the incomplete
+            token.  */
+         token.type = LSTOKEN_STRING;
+         while (*PARSER_STREAM (parser) != '\0')
+           PARSER_STREAM (parser)++;
+         LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - 1 - start;
+       }
+      else
+       {
+         /* Skip over the ending quote and mark the length of the string.  */
+         PARSER_STREAM (parser) = (char *) ++end;
+         LS_TOKEN_STOKEN (token).length = PARSER_STREAM (parser) - 2 - start;
+       }
     }
   else
     {
@@ -598,7 +714,7 @@ linespec_lexer_lex_string (linespec_parser *parser)
        {
          if (isspace (*PARSER_STREAM (parser)))
            {
-             p = skip_spaces_const (PARSER_STREAM (parser));
+             p = skip_spaces (PARSER_STREAM (parser));
              /* When we get here we know we've found something followed by
                 a space (we skip over parens and templates below).
                 So if we find a keyword now, we know it is a keyword and not,
@@ -629,6 +745,11 @@ linespec_lexer_lex_string (linespec_parser *parser)
              if (PARSER_STREAM (parser)[1] == ':')
                ++(PARSER_STREAM (parser));
 
+             /* Do not tokenize ABI tags such as "[abi:cxx11]".  */
+             else if (PARSER_STREAM (parser) - start > 4
+                      && startswith (PARSER_STREAM (parser) - 4, "[abi"))
+               ++(PARSER_STREAM (parser));
+
              /* Do not tokenify if the input length so far is one
                 (i.e, a single-letter drive name) and the next character
                 is a directory separator.  This allows Windows-style
@@ -658,14 +779,50 @@ linespec_lexer_lex_string (linespec_parser *parser)
          else if (*PARSER_STREAM (parser) == '<'
                   || *PARSER_STREAM (parser) == '(')
            {
-             const char *p;
+             /* Don't interpret 'operator<' / 'operator<<' as a
+                template parameter list though.  */
+             if (*PARSER_STREAM (parser) == '<'
+                 && (PARSER_STATE (parser)->language->la_language
+                     == language_cplus)
+                 && (PARSER_STREAM (parser) - start) >= CP_OPERATOR_LEN)
+               {
+                 const char *p = PARSER_STREAM (parser);
 
-             p = find_parameter_list_end (PARSER_STREAM (parser));
-             if (p != NULL)
+                 while (p > start && isspace (p[-1]))
+                   p--;
+                 if (p - start >= CP_OPERATOR_LEN)
+                   {
+                     p -= CP_OPERATOR_LEN;
+                     if (strncmp (p, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0
+                         && (p == start
+                             || !(isalnum (p[-1]) || p[-1] == '_')))
+                       {
+                         /* This is an operator name.  Keep going.  */
+                         ++(PARSER_STREAM (parser));
+                         if (*PARSER_STREAM (parser) == '<')
+                           ++(PARSER_STREAM (parser));
+                         continue;
+                       }
+                   }
+               }
+
+             const char *p = find_parameter_list_end (PARSER_STREAM (parser));
+             PARSER_STREAM (parser) = p;
+
+             /* Don't loop around to the normal \0 case above because
+                we don't want to misinterpret a potential keyword at
+                the end of the token when the string isn't
+                "()<>"-balanced.  This handles "b
+                function(thread<tab>" in completion mode.  */
+             if (*p == '\0')
                {
-                 PARSER_STREAM (parser) = p;
-                 continue;
+                 LS_TOKEN_STOKEN (token).ptr = start;
+                 LS_TOKEN_STOKEN (token).length
+                   = PARSER_STREAM (parser) - start;
+                 return token;
                }
+             else
+               continue;
            }
          /* Commas are terminators, but not if they are part of an
             operator name.  */
@@ -673,10 +830,9 @@ linespec_lexer_lex_string (linespec_parser *parser)
            {
              if ((PARSER_STATE (parser)->language->la_language
                   == language_cplus)
-                 && (PARSER_STREAM (parser) - start) > 8
-                 /* strlen ("operator") */)
+                 && (PARSER_STREAM (parser) - start) > CP_OPERATOR_LEN)
                {
-                 const char *p = strstr (start, "operator");
+                 const char *p = strstr (start, CP_OPERATOR_STR);
 
                  if (p != NULL && is_operator_name (p))
                    {
@@ -710,7 +866,7 @@ linespec_lexer_lex_one (linespec_parser *parser)
   if (parser->lexer.current.type == LSTOKEN_CONSUMED)
     {
       /* Skip any whitespace.  */
-      PARSER_STREAM (parser) = skip_spaces_const (PARSER_STREAM (parser));
+      PARSER_STREAM (parser) = skip_spaces (PARSER_STREAM (parser));
 
       /* Check for a keyword, they end the linespec.  */
       keyword = linespec_lexer_lex_keyword (PARSER_STREAM (parser));
@@ -784,13 +940,48 @@ linespec_lexer_lex_one (linespec_parser *parser)
 }
 
 /* Consume the current token and return the next token in PARSER's
-   input stream.  */
+   input stream.  Also advance the completion word for completion
+   mode.  */
 
 static linespec_token
 linespec_lexer_consume_token (linespec_parser *parser)
 {
+  gdb_assert (parser->lexer.current.type != LSTOKEN_EOI);
+
+  bool advance_word = (parser->lexer.current.type != LSTOKEN_STRING
+                      || *PARSER_STREAM (parser) != '\0');
+
+  /* If we're moving past a string to some other token, it must be the
+     quote was terminated.  */
+  if (parser->completion_quote_char)
+    {
+      gdb_assert (parser->lexer.current.type == LSTOKEN_STRING);
+
+      /* If the string was the last (non-EOI) token, we're past the
+        quote, but remember that for later.  */
+      if (*PARSER_STREAM (parser) != '\0')
+       {
+         parser->completion_quote_char = '\0';
+         parser->completion_quote_end = NULL;;
+       }
+    }
+
   parser->lexer.current.type = LSTOKEN_CONSUMED;
-  return linespec_lexer_lex_one (parser);
+  linespec_lexer_lex_one (parser);
+
+  if (parser->lexer.current.type == LSTOKEN_STRING)
+    {
+      /* Advance the completion word past a potential initial
+        quote-char.  */
+      parser->completion_word = LS_TOKEN_STOKEN (parser->lexer.current).ptr;
+    }
+  else if (advance_word)
+    {
+      /* Advance the completion word past any whitespace.  */
+      parser->completion_word = PARSER_STREAM (parser);
+    }
+
+  return parser->lexer.current;
 }
 
 /* Return the next token without consuming the current token.  */
@@ -801,26 +992,21 @@ linespec_lexer_peek_token (linespec_parser *parser)
   linespec_token next;
   const char *saved_stream = PARSER_STREAM (parser);
   linespec_token saved_token = parser->lexer.current;
+  int saved_completion_quote_char = parser->completion_quote_char;
+  const char *saved_completion_quote_end = parser->completion_quote_end;
+  const char *saved_completion_word = parser->completion_word;
 
   next = linespec_lexer_consume_token (parser);
   PARSER_STREAM (parser) = saved_stream;
   parser->lexer.current = saved_token;
+  parser->completion_quote_char = saved_completion_quote_char;
+  parser->completion_quote_end = saved_completion_quote_end;
+  parser->completion_word = saved_completion_word;
   return next;
 }
 
 /* Helper functions.  */
 
-/* Add SAL to SALS.  */
-
-static void
-add_sal_to_sals_basic (struct symtabs_and_lines *sals,
-                      struct symtab_and_line *sal)
-{
-  ++sals->nelts;
-  sals->sals = XRESIZEVEC (struct symtab_and_line, sals->sals, sals->nelts);
-  sals->sals[sals->nelts - 1] = *sal;
-}
-
 /* Add SAL to SALS, and also update SELF->CANONICAL_NAMES to reflect
    the new sal, if needed.  If not NULL, SYMNAME is the name of the
    symbol to use when constructing the new canonical name.
@@ -830,19 +1016,20 @@ add_sal_to_sals_basic (struct symtabs_and_lines *sals,
 
 static void
 add_sal_to_sals (struct linespec_state *self,
-                struct symtabs_and_lines *sals,
+                std::vector<symtab_and_line> *sals,
                 struct symtab_and_line *sal,
                 const char *symname, int literal_canonical)
 {
-  add_sal_to_sals_basic (sals, sal);
+  sals->push_back (*sal);
 
   if (self->canonical)
     {
       struct linespec_canonical_name *canonical;
 
       self->canonical_names = XRESIZEVEC (struct linespec_canonical_name,
-                                         self->canonical_names, sals->nelts);
-      canonical = &self->canonical_names[sals->nelts - 1];
+                                         self->canonical_names,
+                                         sals->size ());
+      canonical = &self->canonical_names[sals->size () - 1];
       if (!literal_canonical && sal->symtab)
        {
          symtab_to_fullname (sal->symtab);
@@ -916,83 +1103,23 @@ maybe_add_address (htab_t set, struct program_space *pspace, CORE_ADDR addr)
   return 1;
 }
 
-/* A callback function and the additional data to call it with.  */
-
-struct symbol_and_data_callback
-{
-  /* The callback to use.  */
-  symbol_found_callback_ftype *callback;
-
-  /* Data to be passed to the callback.  */
-  void *data;
-};
-
-/* A helper for iterate_over_all_matching_symtabs that is used to
-   restrict calls to another callback to symbols representing inline
-   symbols only.  */
-
-static int
-iterate_inline_only (struct symbol *sym, void *d)
-{
-  if (SYMBOL_INLINED (sym))
-    {
-      struct symbol_and_data_callback *cad
-       = (struct symbol_and_data_callback *) d;
-
-      return cad->callback (sym, cad->data);
-    }
-  return 1; /* Continue iterating.  */
-}
-
-/* Some data for the expand_symtabs_matching callback.  */
-
-struct symbol_matcher_data
-{
-  /* The lookup name against which symbol name should be compared.  */
-  const char *lookup_name;
-
-  /* The routine to be used for comparison.  */
-  symbol_name_cmp_ftype symbol_name_cmp;
-};
-
-/* A helper for iterate_over_all_matching_symtabs that is passed as a
-   callback to the expand_symtabs_matching method.  */
-
-static int
-iterate_name_matcher (const char *name, void *d)
-{
-  const struct symbol_matcher_data *data
-    = (const struct symbol_matcher_data *) d;
-
-  if (data->symbol_name_cmp (name, data->lookup_name) == 0)
-    return 1; /* Expand this symbol's symbol table.  */
-  return 0; /* Skip this symbol.  */
-}
-
 /* A helper that walks over all matching symtabs in all objfiles and
    calls CALLBACK for each symbol matching NAME.  If SEARCH_PSPACE is
    not NULL, then the search is restricted to just that program
-   space.  If INCLUDE_INLINE is nonzero then symbols representing
+   space.  If INCLUDE_INLINE is true then symbols representing
    inlined instances of functions will be included in the result.  */
 
 static void
-iterate_over_all_matching_symtabs (struct linespec_state *state,
-                                  const char *name,
-                                  const domain_enum domain,
-                                  symbol_found_callback_ftype *callback,
-                                  void *data,
-                                  struct program_space *search_pspace,
-                                  int include_inline)
+iterate_over_all_matching_symtabs
+  (struct linespec_state *state,
+   const lookup_name_info &lookup_name,
+   const domain_enum name_domain,
+   enum search_domain search_domain,
+   struct program_space *search_pspace, bool include_inline,
+   gdb::function_view<symbol_found_callback_ftype> callback)
 {
   struct objfile *objfile;
   struct program_space *pspace;
-  struct symbol_matcher_data matcher_data;
-
-  matcher_data.lookup_name = name;
-  matcher_data.symbol_name_cmp =
-    state->language->la_get_symbol_name_cmp != NULL
-    ? state->language->la_get_symbol_name_cmp (name)
-    : strcmp_iw;
 
   ALL_PSPACES (pspace)
   {
@@ -1008,20 +1135,20 @@ iterate_over_all_matching_symtabs (struct linespec_state *state,
       struct compunit_symtab *cu;
 
       if (objfile->sf)
-       objfile->sf->qf->expand_symtabs_matching (objfile, NULL,
-                                                 iterate_name_matcher,
-                                                 NULL, ALL_DOMAIN,
-                                                 &matcher_data);
+       objfile->sf->qf->expand_symtabs_matching (objfile,
+                                                 NULL,
+                                                 lookup_name,
+                                                 NULL, NULL,
+                                                 search_domain);
 
       ALL_OBJFILE_COMPUNITS (objfile, cu)
        {
          struct symtab *symtab = COMPUNIT_FILETABS (cu);
 
-         iterate_over_file_blocks (symtab, name, domain, callback, data);
+         iterate_over_file_blocks (symtab, lookup_name, name_domain, callback);
 
          if (include_inline)
            {
-             struct symbol_and_data_callback cad = { callback, data };
              struct block *block;
              int i;
 
@@ -1031,7 +1158,14 @@ iterate_over_all_matching_symtabs (struct linespec_state *state,
                {
                  block = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (symtab), i);
                  state->language->la_iterate_over_symbols
-                   (block, name, domain, iterate_inline_only, &cad);
+                   (block, lookup_name, name_domain, [&] (symbol *sym)
+                    {
+                      /* Restrict calls to CALLBACK to symbols
+                         representing inline symbols only.  */
+                      if (SYMBOL_INLINED (sym))
+                        return callback (sym);
+                      return true;
+                    });
                }
            }
        }
@@ -1060,24 +1194,24 @@ get_current_search_block (void)
 /* Iterate over static and global blocks.  */
 
 static void
-iterate_over_file_blocks (struct symtab *symtab,
-                         const char *name, domain_enum domain,
-                         symbol_found_callback_ftype *callback, void *data)
+iterate_over_file_blocks
+  (struct symtab *symtab, const lookup_name_info &name,
+   domain_enum domain, gdb::function_view<symbol_found_callback_ftype> callback)
 {
   struct block *block;
 
   for (block = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (symtab), STATIC_BLOCK);
        block != NULL;
        block = BLOCK_SUPERBLOCK (block))
-    LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback, data);
+    LA_ITERATE_OVER_SYMBOLS (block, name, domain, callback);
 }
 
-/* A helper for find_method.  This finds all methods in type T which
-   match NAME.  It adds matching symbol names to RESULT_NAMES, and
-   adds T's direct superclasses to SUPERCLASSES.  */
+/* A helper for find_method.  This finds all methods in type T of
+   language T_LANG which match NAME.  It adds matching symbol names to
+   RESULT_NAMES, and adds T's direct superclasses to SUPERCLASSES.  */
 
 static void
-find_methods (struct type *t, const char *name,
+find_methods (struct type *t, enum language t_lang, const char *name,
              VEC (const_char_ptr) **result_names,
              VEC (typep) **superclasses)
 {
@@ -1090,6 +1224,9 @@ find_methods (struct type *t, const char *name,
   if (class_name)
     {
       int method_counter;
+      lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
+      symbol_name_matcher_ftype *symbol_name_compare
+       = get_symbol_name_matcher (language_def (t_lang), lookup_name);
 
       t = check_typedef (t);
 
@@ -1114,7 +1251,7 @@ find_methods (struct type *t, const char *name,
                method_name = dem_opname;
            }
 
-         if (strcmp_iw (method_name, name) == 0)
+         if (symbol_name_compare (method_name, lookup_name, NULL))
            {
              int field_counter;
 
@@ -1143,7 +1280,7 @@ find_methods (struct type *t, const char *name,
 /* Find an instance of the character C in the string S that is outside
    of all parenthesis pairs, single-quoted strings, and double-quoted
    strings.  Also, ignore the char within a template name, like a ','
-   within foo<int, int>.  */
+   within foo<int, int>, while considering C++ operator</operator<<.  */
 
 const char *
 find_toplevel_char (const char *s, char c)
@@ -1171,6 +1308,47 @@ find_toplevel_char (const char *s, char c)
        depth++;
       else if ((*scan == ')' || *scan == '>') && depth > 0)
        depth--;
+      else if (*scan == 'o' && !quoted && depth == 0)
+       {
+         /* Handle C++ operator names.  */
+         if (strncmp (scan, CP_OPERATOR_STR, CP_OPERATOR_LEN) == 0)
+           {
+             scan += CP_OPERATOR_LEN;
+             if (*scan == c)
+               return scan;
+             while (isspace (*scan))
+               {
+                 ++scan;
+                 if (*scan == c)
+                   return scan;
+               }
+             if (*scan == '\0')
+               break;
+
+             switch (*scan)
+               {
+                 /* Skip over one less than the appropriate number of
+                    characters: the for loop will skip over the last
+                    one.  */
+               case '<':
+                 if (scan[1] == '<')
+                   {
+                     scan++;
+                     if (*scan == c)
+                       return scan;
+                   }
+                 break;
+               case '>':
+                 if (scan[1] == '>')
+                   {
+                     scan++;
+                     if (*scan == c)
+                       return scan;
+                   }
+                 break;
+               }
+           }
+       }
     }
 
   return 0;
@@ -1224,7 +1402,7 @@ canonical_to_fullform (const struct linespec_canonical_name *canonical)
 
 static void
 filter_results (struct linespec_state *self,
-               struct symtabs_and_lines *result,
+               std::vector<symtab_and_line> *result,
                VEC (const_char_ptr) *filters)
 {
   int i;
@@ -1232,12 +1410,9 @@ filter_results (struct linespec_state *self,
 
   for (i = 0; VEC_iterate (const_char_ptr, filters, i, name); ++i)
     {
-      struct linespec_sals lsal;
-      int j;
+      linespec_sals lsal;
 
-      memset (&lsal, 0, sizeof (lsal));
-
-      for (j = 0; j < result->nelts; ++j)
+      for (size_t j = 0; j < result->size (); ++j)
        {
          const struct linespec_canonical_name *canonical;
          char *fullform;
@@ -1248,15 +1423,15 @@ filter_results (struct linespec_state *self,
          cleanup = make_cleanup (xfree, fullform);
 
          if (strcmp (name, fullform) == 0)
-           add_sal_to_sals_basic (&lsal.sals, &result->sals[j]);
+           lsal.sals.push_back ((*result)[j]);
 
          do_cleanups (cleanup);
        }
 
-      if (lsal.sals.nelts > 0)
+      if (!lsal.sals.empty ())
        {
          lsal.canonical = xstrdup (name);
-         VEC_safe_push (linespec_sals, self->canonical->sals, &lsal);
+         self->canonical->lsals.push_back (std::move (lsal));
        }
     }
 
@@ -1267,13 +1442,13 @@ filter_results (struct linespec_state *self,
 
 static void
 convert_results_to_lsals (struct linespec_state *self,
-                         struct symtabs_and_lines *result)
+                         std::vector<symtab_and_line> *result)
 {
   struct linespec_sals lsal;
 
   lsal.canonical = NULL;
-  lsal.sals = *result;
-  VEC_safe_push (linespec_sals, self->canonical->sals, &lsal);
+  lsal.sals = std::move (*result);
+  self->canonical->lsals.push_back (std::move (lsal));
 }
 
 /* A structure that contains two string representations of a struct
@@ -1321,25 +1496,25 @@ decode_line_2_compare_items (const void *ap, const void *bp)
 
 static void
 decode_line_2 (struct linespec_state *self,
-              struct symtabs_and_lines *result,
+              std::vector<symtab_and_line> *result,
               const char *select_mode)
 {
-  char *args, *prompt;
+  char *args;
+  const char *prompt;
   int i;
   struct cleanup *old_chain;
   VEC (const_char_ptr) *filters = NULL;
-  struct get_number_or_range_state state;
   struct decode_line_2_item *items;
   int items_count;
 
   gdb_assert (select_mode != multiple_symbols_all);
   gdb_assert (self->canonical != NULL);
-  gdb_assert (result->nelts >= 1);
+  gdb_assert (!result->empty ());
 
   old_chain = make_cleanup (VEC_cleanup (const_char_ptr), &filters);
 
   /* Prepare ITEMS array.  */
-  items_count = result->nelts;
+  items_count = result->size ();
   items = XNEWVEC (struct decode_line_2_item, items_count);
   make_cleanup (xfree, items);
   for (i = 0; i < items_count; ++i)
@@ -1409,12 +1584,10 @@ decode_line_2 (struct linespec_state *self,
   if (args == 0 || *args == 0)
     error_no_arg (_("one or more choice numbers"));
 
-  init_number_or_range (&state, args);
-  while (!state.finished)
+  number_or_range_parser parser (args);
+  while (!parser.finished ())
     {
-      int num;
-
-      num = get_number_or_range (&state);
+      int num = parser.get_number ();
 
       if (num == 0)
        error (_("canceled"));
@@ -1555,6 +1728,17 @@ source_file_not_found_error (const char *name)
   throw_error (NOT_FOUND_ERROR, _("No source file named %s."), name);
 }
 
+/* Unless at EIO, save the current stream position as completion word
+   point, and consume the next token.  */
+
+static linespec_token
+save_stream_and_consume_token (linespec_parser *parser)
+{
+  if (linespec_lexer_peek_token (parser).type != LSTOKEN_EOI)
+    parser->completion_word = PARSER_STREAM (parser);
+  return linespec_lexer_consume_token (parser);
+}
+
 /* See description in linespec.h.  */
 
 struct line_offset
@@ -1582,6 +1766,26 @@ linespec_parse_line_offset (const char *string)
   return line_offset;
 }
 
+/* In completion mode, if the user is still typing the number, there's
+   no possible completion to offer.  But if there's already input past
+   the number, setup to expect NEXT.  */
+
+static void
+set_completion_after_number (linespec_parser *parser,
+                            linespec_complete_what next)
+{
+  if (*PARSER_STREAM (parser) == ' ')
+    {
+      parser->completion_word = skip_spaces (PARSER_STREAM (parser) + 1);
+      parser->complete_what = next;
+    }
+  else
+    {
+      parser->completion_word = PARSER_STREAM (parser);
+      parser->complete_what = linespec_complete_what::NOTHING;
+    }
+}
+
 /* Parse the basic_spec in PARSER's input.  */
 
 static void
@@ -1597,11 +1801,20 @@ linespec_parse_basic (linespec_parser *parser)
   token = linespec_lexer_lex_one (parser);
 
   /* If it is EOI or KEYWORD, issue an error.  */
-  if (token.type == LSTOKEN_KEYWORD || token.type == LSTOKEN_EOI)
-    unexpected_linespec_error (parser);
+  if (token.type == LSTOKEN_KEYWORD)
+    {
+      parser->complete_what = linespec_complete_what::NOTHING;
+      unexpected_linespec_error (parser);
+    }
+  else if (token.type == LSTOKEN_EOI)
+    {
+      unexpected_linespec_error (parser);
+    }
   /* If it is a LSTOKEN_NUMBER, we have an offset.  */
   else if (token.type == LSTOKEN_NUMBER)
     {
+      set_completion_after_number (parser, linespec_complete_what::KEYWORD);
+
       /* Record the line offset and get the next token.  */
       name = copy_token_string (token);
       cleanup = make_cleanup (xfree, name);
@@ -1613,7 +1826,10 @@ linespec_parse_basic (linespec_parser *parser)
 
       /* If the next token is a comma, stop parsing and return.  */
       if (token.type == LSTOKEN_COMMA)
-       return;
+       {
+         parser->complete_what = linespec_complete_what::NOTHING;
+         return;
+       }
 
       /* If the next token is anything but EOI or KEYWORD, issue
         an error.  */
@@ -1626,16 +1842,66 @@ linespec_parse_basic (linespec_parser *parser)
 
   /* Next token must be LSTOKEN_STRING.  */
   if (token.type != LSTOKEN_STRING)
-    unexpected_linespec_error (parser);
+    {
+      parser->complete_what = linespec_complete_what::NOTHING;
+      unexpected_linespec_error (parser);
+    }
 
   /* The current token will contain the name of a function, method,
      or label.  */
-  name  = copy_token_string (token);
-  cleanup = make_cleanup (xfree, name);
+  name = copy_token_string (token);
+  cleanup = make_cleanup (free_current_contents, &name);
+
+  if (parser->completion_tracker != NULL)
+    {
+      /* If the function name ends with a ":", then this may be an
+        incomplete "::" scope operator instead of a label separator.
+        E.g.,
+          "b klass:<tab>"
+        which should expand to:
+          "b klass::method()"
+
+        Do a tentative completion assuming the later.  If we find
+        completions, advance the stream past the colon token and make
+        it part of the function name/token.  */
+
+      if (!parser->completion_quote_char
+         && strcmp (PARSER_STREAM (parser), ":") == 0)
+       {
+         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 ())
+           {
+             PARSER_STREAM (parser)++;
+             LS_TOKEN_STOKEN (token).length++;
+
+             xfree (name);
+             name = savestring (parser->completion_word,
+                                (PARSER_STREAM (parser)
+                                 - parser->completion_word));
+           }
+       }
+
+      PARSER_EXPLICIT (parser)->function_name = name;
+      discard_cleanups (cleanup);
+    }
+  else
+    {
+      /* XXX Reindent before pushing.  */
 
   /* 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)
@@ -1691,11 +1957,19 @@ linespec_parse_basic (linespec_parser *parser)
          return;
        }
     }
+    }
+
+  int previous_qc = parser->completion_quote_char;
 
   /* Get the next token.  */
   token = linespec_lexer_consume_token (parser);
 
-  if (token.type == LSTOKEN_COLON)
+  if (token.type == LSTOKEN_EOI)
+    {
+      if (previous_qc && !parser->completion_quote_char)
+       parser->complete_what = linespec_complete_what::KEYWORD;
+    }
+  else if (token.type == LSTOKEN_COLON)
     {
       /* User specified a label or a lineno.  */
       token = linespec_lexer_consume_token (parser);
@@ -1704,17 +1978,56 @@ linespec_parse_basic (linespec_parser *parser)
        {
          /* User specified an offset.  Record the line offset and
             get the next token.  */
+         set_completion_after_number (parser, linespec_complete_what::KEYWORD);
+
          name = copy_token_string (token);
          cleanup = make_cleanup (xfree, name);
          PARSER_EXPLICIT (parser)->line_offset
            = linespec_parse_line_offset (name);
          do_cleanups (cleanup);
 
-         /* Ge the next token.  */
+         /* Get the next token.  */
          token = linespec_lexer_consume_token (parser);
        }
+      else if (token.type == LSTOKEN_EOI && parser->completion_tracker != NULL)
+       {
+         parser->complete_what = linespec_complete_what::LABEL;
+       }
       else if (token.type == LSTOKEN_STRING)
        {
+         parser->complete_what = linespec_complete_what::LABEL;
+
+         /* If we have text after the label separated by whitespace
+            (e.g., "b func():lab i<tab>"), don't consider it part of
+            the label.  In completion mode that should complete to
+            "if", in normal mode, the 'i' should be treated as
+            garbage.  */
+         if (parser->completion_quote_char == '\0')
+           {
+             const char *ptr = LS_TOKEN_STOKEN (token).ptr;
+             for (size_t i = 0; i < LS_TOKEN_STOKEN (token).length; i++)
+               {
+                 if (ptr[i] == ' ')
+                   {
+                     LS_TOKEN_STOKEN (token).length = i;
+                     PARSER_STREAM (parser) = skip_spaces (ptr + i + 1);
+                     break;
+                   }
+               }
+           }
+
+         if (parser->completion_tracker != NULL)
+           {
+             if (PARSER_STREAM (parser)[-1] == ' ')
+               {
+                 parser->completion_word = PARSER_STREAM (parser);
+                 parser->complete_what = linespec_complete_what::KEYWORD;
+               }
+           }
+         else
+           {
+             /* XXX Reindent before pushing.  */
+
          /* Grab a copy of the label's name and look it up.  */
          name = copy_token_string (token);
          cleanup = make_cleanup (xfree, name);
@@ -1737,8 +2050,10 @@ linespec_parse_basic (linespec_parser *parser)
                                     name);
            }
 
+           }
+
          /* Check for a line offset.  */
-         token = linespec_lexer_consume_token (parser);
+         token = save_stream_and_consume_token (parser);
          if (token.type == LSTOKEN_COLON)
            {
              /* Get the next token.  */
@@ -1748,7 +2063,7 @@ linespec_parse_basic (linespec_parser *parser)
              if (token.type != LSTOKEN_NUMBER)
                unexpected_linespec_error (parser);
 
-             /* Record the lione offset and get the next token.  */
+             /* Record the line offset and get the next token.  */
              name = copy_token_string (token);
              cleanup = make_cleanup (xfree, name);
 
@@ -1783,8 +2098,9 @@ canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
     return;
 
   /* Save everything as an explicit location.  */
-  canon = state->canonical->location
+  state->canonical->location
     = new_explicit_location (&ls->explicit_loc);
+  canon = state->canonical->location.get ();
   explicit_loc = get_explicit_location (canon);
 
   if (explicit_loc->label_name != NULL)
@@ -1817,18 +2133,12 @@ canonicalize_linespec (struct linespec_state *state, const linespec_p ls)
 
 /* Given a line offset in LS, construct the relevant SALs.  */
 
-static struct symtabs_and_lines
+static std::vector<symtab_and_line>
 create_sals_line_offset (struct linespec_state *self,
                         linespec_p ls)
 {
-  struct symtabs_and_lines values;
-  struct symtab_and_line val;
   int use_default = 0;
 
-  init_sal (&val);
-  values.sals = NULL;
-  values.nelts = 0;
-
   /* This is where we need to make sure we have good defaults.
      We must guarantee that this section of code is never executed
      when we are called with just a function name, since
@@ -1853,6 +2163,7 @@ create_sals_line_offset (struct linespec_state *self,
       use_default = 1;
     }
 
+  symtab_and_line val;
   val.line = ls->explicit_loc.line_offset.offset;
   switch (ls->explicit_loc.line_offset.sign)
     {
@@ -1876,27 +2187,20 @@ create_sals_line_offset (struct linespec_state *self,
       break;                   /* No need to adjust val.line.  */
     }
 
+  std::vector<symtab_and_line> values;
   if (self->list_mode)
-    decode_digits_list_mode (self, ls, &values, val);
+    values = decode_digits_list_mode (self, ls, val);
   else
     {
       struct linetable_entry *best_entry = NULL;
-      int *filter;
-      const struct block **blocks;
-      struct cleanup *cleanup;
-      struct symtabs_and_lines intermediate_results;
       int i, j;
 
-      intermediate_results.sals = NULL;
-      intermediate_results.nelts = 0;
-
-      decode_digits_ordinary (self, ls, val.line, &intermediate_results,
-                             &best_entry);
-      if (intermediate_results.nelts == 0 && best_entry != NULL)
-       decode_digits_ordinary (self, ls, best_entry->line,
-                               &intermediate_results, &best_entry);
-
-      cleanup = make_cleanup (xfree, intermediate_results.sals);
+      std::vector<symtab_and_line> intermediate_results
+       = decode_digits_ordinary (self, ls, val.line, &best_entry);
+      if (intermediate_results.empty () && best_entry != NULL)
+       intermediate_results = decode_digits_ordinary (self, ls,
+                                                      best_entry->line,
+                                                      &best_entry);
 
       /* For optimized code, the compiler can scatter one source line
         across disjoint ranges of PC values, even when no duplicate
@@ -1908,24 +2212,22 @@ create_sals_line_offset (struct linespec_state *self,
         above, we see if there are other PCs that are in the same
         block.  If yes, the other PCs are filtered out.  */
 
-      filter = XNEWVEC (int, intermediate_results.nelts);
-      make_cleanup (xfree, filter);
-      blocks = XNEWVEC (const struct block *, intermediate_results.nelts);
-      make_cleanup (xfree, blocks);
+      gdb::def_vector<int> filter (intermediate_results.size ());
+      gdb::def_vector<const block *> blocks (intermediate_results.size ());
 
-      for (i = 0; i < intermediate_results.nelts; ++i)
+      for (i = 0; i < intermediate_results.size (); ++i)
        {
-         set_current_program_space (intermediate_results.sals[i].pspace);
+         set_current_program_space (intermediate_results[i].pspace);
 
          filter[i] = 1;
-         blocks[i] = block_for_pc_sect (intermediate_results.sals[i].pc,
-                                        intermediate_results.sals[i].section);
+         blocks[i] = block_for_pc_sect (intermediate_results[i].pc,
+                                        intermediate_results[i].section);
        }
 
-      for (i = 0; i < intermediate_results.nelts; ++i)
+      for (i = 0; i < intermediate_results.size (); ++i)
        {
          if (blocks[i] != NULL)
-           for (j = i + 1; j < intermediate_results.nelts; ++j)
+           for (j = i + 1; j < intermediate_results.size (); ++j)
              {
                if (blocks[j] == blocks[i])
                  {
@@ -1935,7 +2237,7 @@ create_sals_line_offset (struct linespec_state *self,
              }
        }
 
-      for (i = 0; i < intermediate_results.nelts; ++i)
+      for (i = 0; i < intermediate_results.size (); ++i)
        if (filter[i])
          {
            struct symbol *sym = (blocks[i]
@@ -1943,18 +2245,16 @@ create_sals_line_offset (struct linespec_state *self,
                                  : NULL);
 
            if (self->funfirstline)
-             skip_prologue_sal (&intermediate_results.sals[i]);
+             skip_prologue_sal (&intermediate_results[i]);
            /* Make sure the line matches the request, not what was
               found.  */
-           intermediate_results.sals[i].line = val.line;
-           add_sal_to_sals (self, &values, &intermediate_results.sals[i],
+           intermediate_results[i].line = val.line;
+           add_sal_to_sals (self, &values, &intermediate_results[i],
                             sym ? SYMBOL_NATURAL_NAME (sym) : NULL, 0);
          }
-
-      do_cleanups (cleanup);
     }
 
-  if (values.nelts == 0)
+  if (values.empty ())
     {
       if (ls->explicit_loc.source_filename)
        throw_error (NOT_FOUND_ERROR, _("No line %d in file \"%s\"."),
@@ -1969,17 +2269,16 @@ create_sals_line_offset (struct linespec_state *self,
 
 /* Convert the given ADDRESS into SaLs.  */
 
-static struct symtabs_and_lines
+static std::vector<symtab_and_line>
 convert_address_location_to_sals (struct linespec_state *self,
                                  CORE_ADDR address)
 {
-  struct symtab_and_line sal;
-  struct symtabs_and_lines sals = {NULL, 0};
-
-  sal = find_pc_line (address, 0);
+  symtab_and_line sal = find_pc_line (address, 0);
   sal.pc = address;
   sal.section = find_pc_overlay (address);
   sal.explicit_pc = 1;
+
+  std::vector<symtab_and_line> sals;
   add_sal_to_sals (self, &sals, &sal, core_addr_to_string (address), 1);
 
   return sals;
@@ -1987,10 +2286,10 @@ convert_address_location_to_sals (struct linespec_state *self,
 
 /* Create and return SALs from the linespec LS.  */
 
-static struct symtabs_and_lines
+static std::vector<symtab_and_line>
 convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
 {
-  struct symtabs_and_lines sals = {NULL, 0};
+  std::vector<symtab_and_line> sals;
 
   if (ls->labels.label_symbols != NULL)
     {
@@ -2080,37 +2379,42 @@ convert_linespec_to_sals (struct linespec_state *state, linespec_p ls)
 
   canonicalize_linespec (state, ls);
 
-  if (sals.nelts > 0 && state->canonical != NULL)
+  if (!sals.empty () && state->canonical != NULL)
     state->canonical->pre_expanded = 1;
 
   return sals;
 }
 
-/* Convert the explicit location EXPLICIT_LOC into SaLs.  */
+/* Build RESULT from the explicit location components SOURCE_FILENAME,
+   FUNCTION_NAME, LABEL_NAME and LINE_OFFSET.  */
 
-static struct symtabs_and_lines
-convert_explicit_location_to_sals (struct linespec_state *self,
-                                  linespec_p result,
-                                  const struct explicit_location *explicit_loc)
+static void
+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;
 
-  if (explicit_loc->source_filename != NULL)
+  result->explicit_loc.func_name_match_type = fname_match_type;
+
+  if (source_filename != NULL)
     {
       TRY
        {
          result->file_symtabs
-           = symtabs_from_filename (explicit_loc->source_filename,
-                                    self->search_pspace);
+           = symtabs_from_filename (source_filename, self->search_pspace);
        }
       CATCH (except, RETURN_MASK_ERROR)
        {
-         source_file_not_found_error (explicit_loc->source_filename);
+         source_file_not_found_error (source_filename);
        }
       END_CATCH
-      result->explicit_loc.source_filename
-       = xstrdup (explicit_loc->source_filename);
+      result->explicit_loc.source_filename = xstrdup (source_filename);
     }
   else
     {
@@ -2118,41 +2422,54 @@ convert_explicit_location_to_sals (struct linespec_state *self,
       VEC_safe_push (symtab_ptr, result->file_symtabs, NULL);
     }
 
-  if (explicit_loc->function_name != NULL)
+  if (function_name != NULL)
     {
       find_linespec_symbols (self, result->file_symtabs,
-                            explicit_loc->function_name, &symbols,
-                            &minimal_symbols);
+                            function_name, fname_match_type,
+                            &symbols, &minimal_symbols);
 
       if (symbols == NULL && minimal_symbols == NULL)
-       symbol_not_found_error (explicit_loc->function_name,
+       symbol_not_found_error (function_name,
                                result->explicit_loc.source_filename);
 
-      result->explicit_loc.function_name
-       = xstrdup (explicit_loc->function_name);
+      result->explicit_loc.function_name = xstrdup (function_name);
       result->function_symbols = symbols;
       result->minimal_symbols = minimal_symbols;
     }
 
-  if (explicit_loc->label_name != NULL)
+  if (label_name != NULL)
     {
       symbols = NULL;
       labels = find_label_symbols (self, result->function_symbols,
-                                  &symbols, explicit_loc->label_name);
+                                  &symbols, label_name);
 
       if (labels == NULL)
        undefined_label_error (result->explicit_loc.function_name,
-                              explicit_loc->label_name);
+                              label_name);
 
-      result->explicit_loc.label_name = xstrdup (explicit_loc->label_name);
+      result->explicit_loc.label_name = xstrdup (label_name);
       result->labels.label_symbols = labels;
       result->labels.function_symbols = symbols;
     }
 
-  if (explicit_loc->line_offset.sign != LINE_OFFSET_UNKNOWN)
-    result->explicit_loc.line_offset = explicit_loc->line_offset;
+  if (line_offset.sign != LINE_OFFSET_UNKNOWN)
+    result->explicit_loc.line_offset = line_offset;
+}
+
+/* Convert the explicit location EXPLICIT_LOC into SaLs.  */
 
-   return convert_linespec_to_sals (self, result);
+static std::vector<symtab_and_line>
+convert_explicit_location_to_sals (struct linespec_state *self,
+                                  linespec_p result,
+                                  const struct explicit_location *explicit_loc)
+{
+  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);
 }
 
 /* Parse a string that specifies a linespec.
@@ -2203,13 +2520,14 @@ 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 struct symtabs_and_lines
-parse_linespec (linespec_parser *parser, const char *arg)
+static std::vector<symtab_and_line>
+parse_linespec (linespec_parser *parser, const char *arg,
+               symbol_name_match_type match_type)
 {
   linespec_token token;
-  struct symtabs_and_lines values;
   struct gdb_exception file_exception = exception_none;
   struct cleanup *cleanup;
 
@@ -2217,7 +2535,8 @@ parse_linespec (linespec_parser *parser, const char *arg)
      IDEs to work around bugs in the previous parser by quoting
      the entire linespec, so we attempt to deal with this nicely.  */
   parser->is_quote_enclosed = 0;
-  if (!is_ada_operator (arg)
+  if (parser->completion_tracker == NULL
+      && !is_ada_operator (arg)
       && strchr (linespec_quote_characters, *arg) != NULL)
     {
       const char *end;
@@ -2234,20 +2553,36 @@ parse_linespec (linespec_parser *parser, const char *arg)
 
   parser->lexer.saved_arg = 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,
                       &PARSER_STATE (parser)->default_line);
 
   /* Objective-C shortcut.  */
-  values = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), arg);
-  if (values.sals != NULL)
-    return values;
+  if (parser->completion_tracker == NULL)
+    {
+      std::vector<symtab_and_line> values
+       = decode_objc (PARSER_STATE (parser), PARSER_RESULT (parser), arg);
+      if (!values.empty ())
+       return values;
+    }
+  else
+    {
+      /* "-"/"+" is either an objc selector, or a number.  There's
+        nothing to complete the latter to, so just let the caller
+        complete on functions, which finds objc selectors, if there's
+        any.  */
+      if ((arg[0] == '-' || arg[0] == '+') && arg[1] == '\0')
+       return {};
+    }
 
   /* Start parsing.  */
 
   /* Get the first token.  */
-  token = linespec_lexer_lex_one (parser);
+  token = linespec_lexer_consume_token (parser);
 
   /* It must be either LSTOKEN_STRING or LSTOKEN_NUMBER.  */
   if (token.type == LSTOKEN_STRING && *LS_TOKEN_STOKEN (token).ptr == '$')
@@ -2255,7 +2590,8 @@ parse_linespec (linespec_parser *parser, const char *arg)
       char *var;
 
       /* A NULL entry means to use GLOBAL_DEFAULT_SYMTAB.  */
-      VEC_safe_push (symtab_ptr, PARSER_RESULT (parser)->file_symtabs, NULL);
+      if (parser->completion_tracker == NULL)
+       VEC_safe_push (symtab_ptr, PARSER_RESULT (parser)->file_symtabs, NULL);
 
       /* User specified a convenience variable or history value.  */
       var = copy_token_string (token);
@@ -2274,8 +2610,16 @@ parse_linespec (linespec_parser *parser, const char *arg)
          goto convert_to_sals;
        }
     }
+  else if (token.type == LSTOKEN_EOI && parser->completion_tracker != NULL)
+    {
+      /* Let the default linespec_complete_what::FUNCTION kick in.  */
+      unexpected_linespec_error (parser);
+    }
   else if (token.type != LSTOKEN_STRING && token.type != LSTOKEN_NUMBER)
-    unexpected_linespec_error (parser);
+    {
+      parser->complete_what = linespec_complete_what::NOTHING;
+      unexpected_linespec_error (parser);
+    }
 
   /* Shortcut: If the next token is not LSTOKEN_COLON, we know that
      this token cannot represent a filename.  */
@@ -2323,8 +2667,9 @@ parse_linespec (linespec_parser *parser, const char *arg)
        }
     }
   /* If the next token is not EOI, KEYWORD, or COMMA, issue an error.  */
-  else if (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD
-          && token.type != LSTOKEN_COMMA)
+  else if (parser->completion_tracker == NULL
+          && (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD
+              && token.type != LSTOKEN_COMMA))
     {
       /* TOKEN is the _next_ token, not the one currently in the parser.
         Consuming the token will give the correct error message.  */
@@ -2340,7 +2685,8 @@ parse_linespec (linespec_parser *parser, const char *arg)
   /* Parse the rest of the linespec.  */
   linespec_parse_basic (parser);
 
-  if (PARSER_RESULT (parser)->function_symbols == NULL
+  if (parser->completion_tracker == NULL
+      && PARSER_RESULT (parser)->function_symbols == NULL
       && PARSER_RESULT (parser)->labels.label_symbols == NULL
       && PARSER_EXPLICIT (parser)->line_offset.sign == LINE_OFFSET_UNKNOWN
       && PARSER_RESULT (parser)->minimal_symbols == NULL)
@@ -2361,13 +2707,23 @@ parse_linespec (linespec_parser *parser, const char *arg)
      if necessary.  */
   token = linespec_lexer_lex_one (parser);
   if (token.type != LSTOKEN_EOI && token.type != LSTOKEN_KEYWORD)
-    PARSER_STREAM (parser) = LS_TOKEN_STOKEN (token).ptr;
+    unexpected_linespec_error (parser);
+  else if (token.type == LSTOKEN_KEYWORD)
+    {
+      /* Setup the completion word past the keyword.  Lexing never
+        advances past a keyword automatically, so skip it
+        manually.  */
+      parser->completion_word
+       = skip_spaces (skip_to_space (PARSER_STREAM (parser)));
+      parser->complete_what = linespec_complete_what::EXPRESSION;
+    }
 
   /* Convert the data in PARSER_RESULT to SALs.  */
-  values = convert_linespec_to_sals (PARSER_STATE (parser),
+  if (parser->completion_tracker == NULL)
+    return convert_linespec_to_sals (PARSER_STATE (parser),
                                     PARSER_RESULT (parser));
 
-  return values;
+  return {};
 }
 
 
@@ -2408,6 +2764,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,
@@ -2454,7 +2812,7 @@ linespec_parser_delete (void *arg)
 /* See description in linespec.h.  */
 
 void
-linespec_lex_to_end (char **stringp)
+linespec_lex_to_end (const char **stringp)
 {
   linespec_parser parser;
   struct cleanup *cleanup;
@@ -2484,14 +2842,361 @@ linespec_lex_to_end (char **stringp)
   do_cleanups (cleanup);
 }
 
+/* See linespec.h.  */
+
+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;
+
+  if (source_filename != NULL)
+    {
+      collect_file_symbol_completion_matches (tracker, mode, func_match_type,
+                                             function, function, source_filename);
+    }
+  else
+    {
+      collect_symbol_completion_matches (tracker, mode, func_match_type,
+                                        function, function);
+
+    }
+}
+
+/* Helper for complete_linespec to simplify it.  SOURCE_FILENAME is
+   only meaningful if COMPONENT is FUNCTION.  */
+
+static void
+complete_linespec_component (linespec_parser *parser,
+                            completion_tracker &tracker,
+                            const char *text,
+                            linespec_complete_what component,
+                            const char *source_filename)
+{
+  if (component == linespec_complete_what::KEYWORD)
+    {
+      complete_on_enum (tracker, linespec_keywords, text, text);
+    }
+  else if (component == linespec_complete_what::EXPRESSION)
+    {
+      const char *word
+       = advance_to_expression_complete_word_point (tracker, text);
+      complete_expression (tracker, text, word);
+    }
+  else if (component == linespec_complete_what::FUNCTION)
+    {
+      completion_list fn_list;
+
+      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
+            file.c:function[TAB]".  Maybe this wasn't a function, but
+            a filename instead, like "b file.[TAB]".  */
+         fn_list = complete_source_filenames (text);
+       }
+
+      /* If we only have a single filename completion, append a ':' for
+        the user, since that's the only thing that can usefully follow
+        the filename.  */
+      if (fn_list.size () == 1 && !tracker.have_completions ())
+       {
+         char *fn = fn_list[0].release ();
+
+         /* If we also need to append a quote char, it needs to be
+            appended before the ':'.  Append it now, and make ':' the
+            new "quote" char.  */
+         if (tracker.quote_char ())
+           {
+             char quote_char_str[2] = { tracker.quote_char () };
+
+             fn = reconcat (fn, fn, quote_char_str, (char *) NULL);
+             tracker.set_quote_char (':');
+           }
+         else
+           fn = reconcat (fn, fn, ":", (char *) NULL);
+         fn_list[0].reset (fn);
+
+         /* Tell readline to skip appending a space.  */
+         tracker.set_suppress_append_ws (true);
+       }
+      tracker.add_completions (std::move (fn_list));
+    }
+}
+
+/* Helper for linespec_complete_label.  Find labels that match
+   LABEL_NAME in the function symbols listed in the PARSER, and add
+   them to the tracker.  */
+
+static void
+complete_label (completion_tracker &tracker,
+               linespec_parser *parser,
+               const char *label_name)
+{
+  VEC (symbolp) *label_function_symbols = NULL;
+  VEC (symbolp) *labels
+    = find_label_symbols (PARSER_STATE (parser),
+                         PARSER_RESULT (parser)->function_symbols,
+                         &label_function_symbols,
+                         label_name, true);
+
+  symbol *label;
+  for (int ix = 0;
+       VEC_iterate (symbolp, labels, ix, label); ++ix)
+    {
+      char *match = xstrdup (SYMBOL_SEARCH_NAME (label));
+      tracker.add_completion (gdb::unique_xmalloc_ptr<char> (match));
+    }
+  VEC_free (symbolp, labels);
+}
+
+/* See linespec.h.  */
+
+void
+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;
+  struct cleanup *cleanup;
+
+  linespec_parser_new (&parser, 0, language, NULL, NULL, 0, NULL);
+  cleanup = make_cleanup (linespec_parser_delete, &parser);
+
+  line_offset unknown_offset = { 0, LINE_OFFSET_UNKNOWN };
+
+  TRY
+    {
+      convert_explicit_location_to_linespec (PARSER_STATE (&parser),
+                                            PARSER_RESULT (&parser),
+                                            source_filename,
+                                            function_name,
+                                            func_name_match_type,
+                                            NULL, unknown_offset);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      do_cleanups (cleanup);
+      return;
+    }
+  END_CATCH
+
+  complete_label (tracker, &parser, label_name);
+
+  do_cleanups (cleanup);
+}
+
+/* See description in linespec.h.  */
+
+void
+linespec_complete (completion_tracker &tracker, const char *text,
+                  symbol_name_match_type match_type)
+{
+  linespec_parser parser;
+  struct cleanup *cleanup;
+  const char *orig = 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;
+  PARSER_STATE (&parser)->is_linespec = 1;
+
+  /* Parse as much as possible.  parser.completion_word will hold
+     furthest completion point we managed to parse to.  */
+  TRY
+    {
+      parse_linespec (&parser, text, match_type);
+    }
+  CATCH (except, RETURN_MASK_ERROR)
+    {
+    }
+  END_CATCH
+
+  if (parser.completion_quote_char != '\0'
+      && parser.completion_quote_end != NULL
+      && parser.completion_quote_end[1] == '\0')
+    {
+      /* If completing a quoted string with the cursor right at
+        terminating quote char, complete the completion word without
+        interpretation, so that readline advances the cursor one
+        whitespace past the quote, even if there's no match.  This
+        makes these cases behave the same:
+
+          before: "b function()"
+          after:  "b function() "
+
+          before: "b 'function()'"
+          after:  "b 'function()' "
+
+        and trusts the user in this case:
+
+          before: "b 'not_loaded_function_yet()'"
+          after:  "b 'not_loaded_function_yet()' "
+      */
+      parser.complete_what = linespec_complete_what::NOTHING;
+      parser.completion_quote_char = '\0';
+
+      gdb::unique_xmalloc_ptr<char> text_copy
+       (xstrdup (parser.completion_word));
+      tracker.add_completion (std::move (text_copy));
+    }
+
+  tracker.set_quote_char (parser.completion_quote_char);
+
+  if (parser.complete_what == linespec_complete_what::LABEL)
+    {
+      parser.complete_what = linespec_complete_what::NOTHING;
+
+      const char *func_name = PARSER_EXPLICIT (&parser)->function_name;
+
+      VEC (symbolp) *function_symbols;
+      VEC (bound_minimal_symbol_d) *minimal_symbols;
+      find_linespec_symbols (PARSER_STATE (&parser),
+                            PARSER_RESULT (&parser)->file_symtabs,
+                            func_name, match_type,
+                            &function_symbols, &minimal_symbols);
+
+      PARSER_RESULT (&parser)->function_symbols = function_symbols;
+      PARSER_RESULT (&parser)->minimal_symbols = minimal_symbols;
+
+      complete_label (tracker, &parser, parser.completion_word);
+    }
+  else if (parser.complete_what == linespec_complete_what::FUNCTION)
+    {
+      /* While parsing/lexing, we didn't know whether the completion
+        word completes to a unique function/source name already or
+        not.
+
+        E.g.:
+          "b function() <tab>"
+        may need to complete either to:
+          "b function() const"
+        or to:
+          "b function() if/thread/task"
+
+        Or, this:
+          "b foo t"
+        may need to complete either to:
+          "b foo template_fun<T>()"
+        with "foo" being the template function's return type, or to:
+          "b foo thread/task"
+
+        Or, this:
+          "b file<TAB>"
+        may need to complete either to a source file name:
+          "b file.c"
+        or this, also a filename, but a unique completion:
+          "b file.c:"
+        or to a function name:
+          "b file_function"
+
+        Address that by completing assuming source or function, and
+        seeing if we find a completion that matches exactly the
+        completion word.  If so, then it must be a function (see note
+        below) and we advance the completion word to the end of input
+        and switch to KEYWORD completion mode.
+
+        Note: if we find a unique completion for a source filename,
+        then it won't match the completion word, because the LCD will
+        contain a trailing ':'.  And if we're completing at or after
+        the ':', then complete_linespec_component won't try to
+        complete on source filenames.  */
+
+      const char *word = parser.completion_word;
+
+      complete_linespec_component (&parser, tracker,
+                                  parser.completion_word,
+                                  linespec_complete_what::FUNCTION,
+                                  PARSER_EXPLICIT (&parser)->source_filename);
+
+      parser.complete_what = linespec_complete_what::NOTHING;
+
+      if (tracker.quote_char ())
+       {
+         /* The function/file name was not close-quoted, so this
+            can't be a keyword.  Note: complete_linespec_component
+            may have swapped the original quote char for ':' when we
+            get here, but that still indicates the same.  */
+       }
+      else if (!tracker.have_completions ())
+       {
+         size_t key_start;
+         size_t wordlen = strlen (parser.completion_word);
+
+         key_start
+           = string_find_incomplete_keyword_at_end (linespec_keywords,
+                                                    parser.completion_word,
+                                                    wordlen);
+
+         if (key_start != -1
+             || (wordlen > 0
+                 && parser.completion_word[wordlen - 1] == ' '))
+           {
+             parser.completion_word += key_start;
+             parser.complete_what = linespec_complete_what::KEYWORD;
+           }
+       }
+      else if (tracker.completes_to_completion_word (word))
+       {
+         /* Skip the function and complete on keywords.  */
+         parser.completion_word += strlen (word);
+         parser.complete_what = linespec_complete_what::KEYWORD;
+         tracker.discard_completions ();
+       }
+    }
+
+  tracker.advance_custom_word_point_by (parser.completion_word - orig);
+
+  complete_linespec_component (&parser, tracker,
+                              parser.completion_word,
+                              parser.complete_what,
+                              PARSER_EXPLICIT (&parser)->source_filename);
+
+  /* If we're past the "filename:function:label:offset" linespec, and
+     didn't find any match, then assume the user might want to create
+     a pending breakpoint anyway and offer the keyword
+     completions.  */
+  if (!parser.completion_quote_char
+      && (parser.complete_what == linespec_complete_what::FUNCTION
+         || parser.complete_what == linespec_complete_what::LABEL
+         || parser.complete_what == linespec_complete_what::NOTHING)
+      && !tracker.have_completions ())
+    {
+      const char *end
+       = parser.completion_word + strlen (parser.completion_word);
+
+      if (end > orig && end[-1] == ' ')
+       {
+         tracker.advance_custom_word_point_by (end - parser.completion_word);
+
+         complete_linespec_component (&parser, tracker, end,
+                                      linespec_complete_what::KEYWORD,
+                                      NULL);
+       }
+    }
+
+  do_cleanups (cleanup);
+}
+
 /* A helper function for decode_line_full and decode_line_1 to
-   turn LOCATION into symtabs_and_lines.  */
+   turn LOCATION into std::vector<symtab_and_line>.  */
 
-static struct symtabs_and_lines
+static std::vector<symtab_and_line>
 event_location_to_sals (linespec_parser *parser,
                        const struct event_location *location)
 {
-  struct symtabs_and_lines result = {NULL, 0};
+  std::vector<symtab_and_line> result;
 
   switch (event_location_type (location))
     {
@@ -2500,7 +3205,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)
          {
@@ -2567,7 +3274,6 @@ decode_line_full (const struct event_location *location, int flags,
                  const char *select_mode,
                  const char *filter)
 {
-  struct symtabs_and_lines result;
   struct cleanup *cleanups;
   VEC (const_char_ptr) *filters = NULL;
   linespec_parser parser;
@@ -2586,21 +3292,23 @@ decode_line_full (const struct event_location *location, int flags,
                       search_pspace, default_symtab,
                       default_line, canonical);
   cleanups = make_cleanup (linespec_parser_delete, &parser);
-  save_current_program_space ();
 
-  result = event_location_to_sals (&parser, location);
+  scoped_restore_current_program_space restore_pspace;
+
+  std::vector<symtab_and_line> result = event_location_to_sals (&parser,
+                                                               location);
   state = PARSER_STATE (&parser);
 
-  gdb_assert (result.nelts == 1 || canonical->pre_expanded);
+  gdb_assert (result.size () == 1 || canonical->pre_expanded);
   canonical->pre_expanded = 1;
 
   /* Arrange for allocated canonical names to be freed.  */
-  if (result.nelts > 0)
+  if (!result.empty ())
     {
       int i;
 
       make_cleanup (xfree, state->canonical_names);
-      for (i = 0; i < result.nelts; ++i)
+      for (i = 0; i < result.size (); ++i)
        {
          gdb_assert (state->canonical_names[i].suffix != NULL);
          make_cleanup (xfree, state->canonical_names[i].suffix);
@@ -2609,7 +3317,7 @@ decode_line_full (const struct event_location *location, int flags,
 
   if (select_mode == NULL)
     {
-      if (ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())))
+      if (interp_ui_out (top_level_interpreter ())->is_mi_like_p ())
        select_mode = multiple_symbols_all;
       else
        select_mode = multiple_symbols_select_mode ();
@@ -2634,13 +3342,12 @@ decode_line_full (const struct event_location *location, int flags,
 
 /* See linespec.h.  */
 
-struct symtabs_and_lines
+std::vector<symtab_and_line>
 decode_line_1 (const struct event_location *location, int flags,
               struct program_space *search_pspace,
               struct symtab *default_symtab,
               int default_line)
 {
-  struct symtabs_and_lines result;
   linespec_parser parser;
   struct cleanup *cleanups;
 
@@ -2648,9 +3355,11 @@ decode_line_1 (const struct event_location *location, int flags,
                       search_pspace, default_symtab,
                       default_line, NULL);
   cleanups = make_cleanup (linespec_parser_delete, &parser);
-  save_current_program_space ();
 
-  result = event_location_to_sals (&parser, location);
+  scoped_restore_current_program_space restore_pspace;
+
+  std::vector<symtab_and_line> result = event_location_to_sals (&parser,
+                                                               location);
 
   do_cleanups (cleanups);
   return result;
@@ -2658,58 +3367,48 @@ decode_line_1 (const struct event_location *location, int flags,
 
 /* See linespec.h.  */
 
-struct symtabs_and_lines
-decode_line_with_current_source (char *string, int flags)
+std::vector<symtab_and_line>
+decode_line_with_current_source (const char *string, int flags)
 {
-  struct symtabs_and_lines sals;
-  struct symtab_and_line cursal;
-  struct event_location *location;
-  struct cleanup *cleanup;
-
   if (string == 0)
     error (_("Empty line specification."));
 
   /* We use whatever is set as the current source line.  We do not try
      and get a default source symtab+line or it will recursively call us!  */
-  cursal = get_current_source_symtab_and_line ();
+  symtab_and_line cursal = get_current_source_symtab_and_line ();
 
-  location = string_to_event_location (&string, current_language);
-  cleanup = make_cleanup_delete_event_location (location);
-  sals = decode_line_1 (location, flags, NULL,
-                       cursal.symtab, cursal.line);
+  event_location_up location = string_to_event_location (&string,
+                                                        current_language);
+  std::vector<symtab_and_line> sals
+    = decode_line_1 (location.get (), flags, NULL, cursal.symtab, cursal.line);
 
   if (*string)
     error (_("Junk at end of line specification: %s"), string);
 
-  do_cleanups (cleanup);
   return sals;
 }
 
 /* See linespec.h.  */
 
-struct symtabs_and_lines
-decode_line_with_last_displayed (char *string, int flags)
+std::vector<symtab_and_line>
+decode_line_with_last_displayed (const char *string, int flags)
 {
-  struct symtabs_and_lines sals;
-  struct event_location *location;
-  struct cleanup *cleanup;
-
   if (string == 0)
     error (_("Empty line specification."));
 
-  location = string_to_event_location (&string, current_language);
-  cleanup = make_cleanup_delete_event_location (location);
-  if (last_displayed_sal_is_valid ())
-    sals = decode_line_1 (location, flags, NULL,
-                         get_last_displayed_symtab (),
-                         get_last_displayed_line ());
-  else
-    sals = decode_line_1 (location, flags, NULL, (struct symtab *) NULL, 0);
+  event_location_up location = string_to_event_location (&string,
+                                                        current_language);
+  std::vector<symtab_and_line> sals
+    = (last_displayed_sal_is_valid ()
+       ? decode_line_1 (location.get (), flags, NULL,
+                       get_last_displayed_symtab (),
+                       get_last_displayed_line ())
+       : decode_line_1 (location.get (), flags, NULL,
+                       (struct symtab *) NULL, 0));
 
   if (*string)
     error (_("Junk at end of line specification: %s"), string);
 
-  do_cleanups (cleanup);
   return sals;
 }
 
@@ -2761,12 +3460,11 @@ linespec_expression_to_pc (const char **exp_ptr)
    than one method that could represent the selector, then use some of
    the existing C++ code to let the user choose one.  */
 
-static struct symtabs_and_lines
+static std::vector<symtab_and_line>
 decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
 {
   struct collect_info info;
   VEC (const_char_ptr) *symbol_names = NULL;
-  struct symtabs_and_lines values;
   const char *new_argptr;
   struct cleanup *cleanup = make_cleanup (VEC_cleanup (const_char_ptr),
                                          &symbol_names);
@@ -2777,18 +3475,18 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
   make_cleanup (VEC_cleanup (symtab_ptr), &info.file_symtabs);
   info.result.symbols = NULL;
   info.result.minimal_symbols = NULL;
-  values.nelts = 0;
-  values.sals = NULL;
 
   new_argptr = find_imps (arg, &symbol_names);
   if (VEC_empty (const_char_ptr, symbol_names))
     {
       do_cleanups (cleanup);
-      return values;
+      return {};
     }
 
-  add_all_symbol_names_from_pspace (&info, NULL, symbol_names);
+  add_all_symbol_names_from_pspace (&info, NULL, symbol_names,
+                                   FUNCTIONS_DOMAIN);
 
+  std::vector<symtab_and_line> values;
   if (!VEC_empty (symbolp, info.result.symbols)
       || !VEC_empty (bound_minimal_symbol_d, info.result.minimal_symbols))
     {
@@ -2805,20 +3503,23 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
 
       if (self->canonical)
        {
-         char *str;
+         std::string holder;
+         const char *str;
 
          self->canonical->pre_expanded = 1;
 
          if (ls->explicit_loc.source_filename)
            {
-             str = xstrprintf ("%s:%s",
-                               ls->explicit_loc.source_filename, saved_arg);
+             holder = string_printf ("%s:%s",
+                                     ls->explicit_loc.source_filename,
+                                     saved_arg);
+             str = holder.c_str ();
            }
          else
-           str = xstrdup (saved_arg);
+           str = saved_arg;
 
-         make_cleanup (xfree, str);
-         self->canonical->location = new_linespec_location (&str);
+         self->canonical->location
+           = new_linespec_location (&str, symbol_name_match_type::FULL);
        }
     }
 
@@ -2827,50 +3528,76 @@ decode_objc (struct linespec_state *self, linespec_p ls, const char *arg)
   return values;
 }
 
-/* An instance of this type is used when collecting prefix symbols for
-   decode_compound.  */
+namespace {
 
-struct decode_compound_collector
+/* A function object that serves as symbol_found_callback_ftype
+   callback for iterate_over_symbols.  This is used by
+   lookup_prefix_sym to collect type symbols.  */
+class decode_compound_collector
 {
-  /* The result vector.  */
-  VEC (symbolp) *symbols;
+public:
+  decode_compound_collector ()
+    : m_symbols (NULL)
+  {
+    m_unique_syms = htab_create_alloc (1, htab_hash_pointer,
+                                      htab_eq_pointer, NULL,
+                                      xcalloc, xfree);
+  }
 
+  ~decode_compound_collector ()
+  {
+    if (m_unique_syms != NULL)
+      htab_delete (m_unique_syms);
+  }
+
+  /* Releases ownership of the collected symbols and returns them.  */
+  VEC (symbolp) *release_symbols ()
+  {
+    VEC (symbolp) *res = m_symbols;
+    m_symbols = NULL;
+    return res;
+  }
+
+  /* Callable as a symbol_found_callback_ftype callback.  */
+  bool operator () (symbol *sym);
+
+private:
   /* A hash table of all symbols we found.  We use this to avoid
      adding any symbol more than once.  */
-  htab_t unique_syms;
-};
+  htab_t m_unique_syms;
 
-/* A callback for iterate_over_symbols that is used by
-   lookup_prefix_sym to collect type symbols.  */
+  /* The result vector.  */
+  VEC (symbolp) *m_symbols;
+};
 
-static int
-collect_one_symbol (struct symbol *sym, void *d)
+bool
+decode_compound_collector::operator () (symbol *sym)
 {
-  struct decode_compound_collector *collector
-    = (struct decode_compound_collector *) d;
   void **slot;
   struct type *t;
 
   if (SYMBOL_CLASS (sym) != LOC_TYPEDEF)
-    return 1; /* Continue iterating.  */
+    return true; /* Continue iterating.  */
 
   t = SYMBOL_TYPE (sym);
   t = check_typedef (t);
   if (TYPE_CODE (t) != TYPE_CODE_STRUCT
       && TYPE_CODE (t) != TYPE_CODE_UNION
       && TYPE_CODE (t) != TYPE_CODE_NAMESPACE)
-    return 1; /* Continue iterating.  */
+    return true; /* Continue iterating.  */
 
-  slot = htab_find_slot (collector->unique_syms, sym, INSERT);
+  slot = htab_find_slot (m_unique_syms, sym, INSERT);
   if (!*slot)
     {
       *slot = sym;
-      VEC_safe_push (symbolp, collector->symbols, sym);
+      VEC_safe_push (symbolp, m_symbols, sym);
     }
 
-  return 1; /* Continue iterating.  */
+  return true; /* Continue iterating.  */
 }
 
+} // namespace
+
 /* Return any symbols corresponding to CLASS_NAME in FILE_SYMTABS.  */
 
 static VEC (symbolp) *
@@ -2879,28 +3606,20 @@ lookup_prefix_sym (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs,
 {
   int ix;
   struct symtab *elt;
-  struct decode_compound_collector collector;
-  struct cleanup *outer;
-  struct cleanup *cleanup;
+  decode_compound_collector collector;
 
-  collector.symbols = NULL;
-  outer = make_cleanup (VEC_cleanup (symbolp), &collector.symbols);
-
-  collector.unique_syms = htab_create_alloc (1, htab_hash_pointer,
-                                            htab_eq_pointer, NULL,
-                                            xcalloc, xfree);
-  cleanup = make_cleanup_htab_delete (collector.unique_syms);
+  lookup_name_info lookup_name (class_name, symbol_name_match_type::FULL);
 
   for (ix = 0; VEC_iterate (symtab_ptr, file_symtabs, ix, elt); ++ix)
     {
       if (elt == NULL)
        {
-         iterate_over_all_matching_symtabs (state, class_name, STRUCT_DOMAIN,
-                                            collect_one_symbol, &collector,
-                                            NULL, 0);
-         iterate_over_all_matching_symtabs (state, class_name, VAR_DOMAIN,
-                                            collect_one_symbol, &collector,
-                                            NULL, 0);
+         iterate_over_all_matching_symtabs (state, lookup_name,
+                                            STRUCT_DOMAIN, ALL_DOMAIN,
+                                            NULL, false, collector);
+         iterate_over_all_matching_symtabs (state, lookup_name,
+                                            VAR_DOMAIN, ALL_DOMAIN,
+                                            NULL, false, collector);
        }
       else
        {
@@ -2908,16 +3627,12 @@ lookup_prefix_sym (struct linespec_state *state, VEC (symtab_ptr) *file_symtabs,
             been filtered out earlier.  */
          gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup);
          set_current_program_space (SYMTAB_PSPACE (elt));
-         iterate_over_file_blocks (elt, class_name, STRUCT_DOMAIN,
-                                   collect_one_symbol, &collector);
-         iterate_over_file_blocks (elt, class_name, VAR_DOMAIN,
-                                   collect_one_symbol, &collector);
+         iterate_over_file_blocks (elt, lookup_name, STRUCT_DOMAIN, collector);
+         iterate_over_file_blocks (elt, lookup_name, VAR_DOMAIN, collector);
        }
     }
 
-  do_cleanups (cleanup);
-  discard_cleanups (outer);
-  return collector.symbols;
+  return collector.release_symbols ();
 }
 
 /* A qsort comparison function for symbols.  The resulting order does
@@ -2988,18 +3703,21 @@ compare_msymbols (const void *a, const void *b)
 static void
 add_all_symbol_names_from_pspace (struct collect_info *info,
                                  struct program_space *pspace,
-                                 VEC (const_char_ptr) *names)
+                                 VEC (const_char_ptr) *names,
+                                 enum search_domain search_domain)
 {
   int ix;
   const char *iter;
 
   for (ix = 0; VEC_iterate (const_char_ptr, names, ix, iter); ++ix)
-    add_matching_symbols_to_info (iter, info, pspace);
+    add_matching_symbols_to_info (iter,
+                                 symbol_name_match_type::FULL,
+                                 search_domain, info, pspace);
 }
 
 static void
 find_superclass_methods (VEC (typep) *superclasses,
-                        const char *name,
+                        const char *name, enum language name_lang,
                         VEC (const_char_ptr) **result_names)
 {
   int old_len = VEC_length (const_char_ptr, *result_names);
@@ -3015,7 +3733,7 @@ find_superclass_methods (VEC (typep) *superclasses,
 
       make_cleanup (VEC_cleanup (typep), &new_supers);
       for (ix = 0; VEC_iterate (typep, iter_classes, ix, t); ++ix)
-       find_methods (t, name, result_names, &new_supers);
+       find_methods (t, name_lang, name, result_names, &new_supers);
 
       if (VEC_length (const_char_ptr, *result_names) != old_len
          || VEC_empty (typep, new_supers))
@@ -3082,7 +3800,8 @@ find_method (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs,
       gdb_assert (!pspace->executing_startup);
       set_current_program_space (pspace);
       t = check_typedef (SYMBOL_TYPE (sym));
-      find_methods (t, method_name, &result_names, &superclass_vec);
+      find_methods (t, SYMBOL_LANGUAGE (sym),
+                   method_name, &result_names, &superclass_vec);
 
       /* Handle all items from a single program space at once; and be
         sure not to miss the last batch.  */
@@ -3095,12 +3814,13 @@ find_method (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs,
             this program space, consider superclasses.  */
          if (VEC_length (const_char_ptr, result_names) == last_result_len)
            find_superclass_methods (superclass_vec, method_name,
-                                    &result_names);
+                                    SYMBOL_LANGUAGE (sym), &result_names);
 
          /* We have a list of candidate symbol names, so now we
             iterate over the symbol tables looking for all
             matches in this pspace.  */
-         add_all_symbol_names_from_pspace (&info, pspace, result_names);
+         add_all_symbol_names_from_pspace (&info, pspace, result_names,
+                                           FUNCTIONS_DOMAIN);
 
          VEC_truncate (typep, superclass_vec, 0);
          last_result_len = VEC_length (const_char_ptr, result_names);
@@ -3123,35 +3843,63 @@ find_method (struct linespec_state *self, VEC (symtab_ptr) *file_symtabs,
 
 \f
 
-/* This object is used when collecting all matching symtabs.  */
+namespace {
 
-struct symtab_collector
+/* This function object is a callback for iterate_over_symtabs, used
+   when collecting all matching symtabs.  */
+
+class symtab_collector
 {
+public:
+  symtab_collector ()
+  {
+    m_symtabs = NULL;
+    m_symtab_table = htab_create (1, htab_hash_pointer, htab_eq_pointer,
+                                 NULL);
+  }
+
+  ~symtab_collector ()
+  {
+    if (m_symtab_table != NULL)
+      htab_delete (m_symtab_table);
+  }
+
+  /* Callable as a symbol_found_callback_ftype callback.  */
+  bool operator () (symtab *sym);
+
+  /* Releases ownership of the collected symtabs and returns them.  */
+  VEC (symtab_ptr) *release_symtabs ()
+  {
+    VEC (symtab_ptr) *res = m_symtabs;
+    m_symtabs = NULL;
+    return res;
+  }
+
+private:
   /* The result vector of symtabs.  */
-  VEC (symtab_ptr) *symtabs;
+  VEC (symtab_ptr) *m_symtabs;
 
   /* This is used to ensure the symtabs are unique.  */
-  htab_t symtab_table;
+  htab_t m_symtab_table;
 };
 
-/* Callback for iterate_over_symtabs.  */
-
-static int
-add_symtabs_to_list (struct symtab *symtab, void *d)
+bool
+symtab_collector::operator () (struct symtab *symtab)
 {
-  struct symtab_collector *data = (struct symtab_collector *) d;
   void **slot;
 
-  slot = htab_find_slot (data->symtab_table, symtab, INSERT);
+  slot = htab_find_slot (m_symtab_table, symtab, INSERT);
   if (!*slot)
     {
       *slot = symtab;
-      VEC_safe_push (symtab_ptr, data->symtabs, symtab);
+      VEC_safe_push (symtab_ptr, m_symtabs, symtab);
     }
 
-  return 0;
+  return false;
 }
 
+} // namespace
+
 /* Given a file name, return a VEC of all matching symtabs.  If
    SEARCH_PSPACE is not NULL, the search is restricted to just that
    program space.  */
@@ -3160,35 +3908,29 @@ static VEC (symtab_ptr) *
 collect_symtabs_from_filename (const char *file,
                               struct program_space *search_pspace)
 {
-  struct symtab_collector collector;
-  struct cleanup *cleanups;
-  struct program_space *pspace;
-
-  collector.symtabs = NULL;
-  collector.symtab_table = htab_create (1, htab_hash_pointer, htab_eq_pointer,
-                                       NULL);
-  cleanups = make_cleanup_htab_delete (collector.symtab_table);
+  symtab_collector collector;
 
   /* Find that file's data.  */
   if (search_pspace == NULL)
     {
+      struct program_space *pspace;
+
       ALL_PSPACES (pspace)
         {
          if (pspace->executing_startup)
            continue;
 
          set_current_program_space (pspace);
-         iterate_over_symtabs (file, add_symtabs_to_list, &collector);
+         iterate_over_symtabs (file, collector);
        }
     }
   else
     {
       set_current_program_space (search_pspace);
-      iterate_over_symtabs (file, add_symtabs_to_list, &collector);
+      iterate_over_symtabs (file, collector);
     }
 
-  do_cleanups (cleanups);
-  return collector.symtabs;
+  return collector.release_symtabs ();
 }
 
 /* Return all the symtabs associated to the FILENAME.  If SEARCH_PSPACE is
@@ -3221,6 +3963,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)
 {
@@ -3238,9 +3981,10 @@ find_function_symbols (struct linespec_state *state,
   find_imps (name, &symbol_names);
   if (!VEC_empty (const_char_ptr, symbol_names))
     add_all_symbol_names_from_pspace (&info, state->search_pspace,
-                                     symbol_names);
+                                     symbol_names, FUNCTIONS_DOMAIN);
   else
-    add_matching_symbols_to_info (name, &info, state->search_pspace);
+    add_matching_symbols_to_info (name, name_match_type, FUNCTIONS_DOMAIN,
+                                 &info, state->search_pspace);
 
   do_cleanups (cleanup);
 
@@ -3267,30 +4011,14 @@ find_function_symbols (struct linespec_state *state,
 static void
 find_linespec_symbols (struct linespec_state *state,
                       VEC (symtab_ptr) *file_symtabs,
-                      const char *name,
+                      const char *lookup_name,
+                      symbol_name_match_type name_match_type,
                       VEC (symbolp) **symbols,
                       VEC (bound_minimal_symbol_d) **minsyms)
 {
-  struct cleanup *cleanup;
-  char *canon;
-  const char *lookup_name;
-
-  cleanup = demangle_for_lookup (name, state->language->la_language,
-                                &lookup_name);
-  if (state->language->la_language == language_ada)
-    {
-      /* In Ada, the symbol lookups are performed using the encoded
-         name rather than the demangled name.  */
-      lookup_name = ada_name_for_lookup (name);
-      make_cleanup (xfree, (void *) lookup_name);
-    }
-
-  canon = cp_canonicalize_string_no_typedefs (lookup_name);
-  if (canon != NULL)
-    {
-      lookup_name = canon;
-      make_cleanup (xfree, canon);
-    }
+  std::string canon = cp_canonicalize_string_no_typedefs (lookup_name);
+  if (!canon.empty ())
+    lookup_name = canon.c_str ();
 
   /* It's important to not call expand_symtabs_matching unnecessarily
      as it can really slow things down (by unnecessarily expanding
@@ -3302,6 +4030,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
@@ -3310,7 +4039,7 @@ find_linespec_symbols (struct linespec_state *state,
   if (VEC_empty (symbolp, *symbols)
       && VEC_empty (bound_minimal_symbol_d, *minsyms))
     {
-      char *klass, *method;
+      std::string klass, method;
       const char *last, *p, *scope_op;
       VEC (symbolp) *classes;
 
@@ -3330,35 +4059,29 @@ find_linespec_symbols (struct linespec_state *state,
         we already attempted to lookup the entire name as a symbol
         and failed.  */
       if (last == NULL)
-       {
-         do_cleanups (cleanup);
-         return;
-       }
+       return;
 
       /* LOOKUP_NAME points to the class name.
         LAST points to the method name.  */
-      klass = XNEWVEC (char, last - lookup_name + 1);
-      make_cleanup (xfree, klass);
-      strncpy (klass, lookup_name, last - lookup_name);
-      klass[last - lookup_name] = '\0';
+      klass = std::string (lookup_name, last - lookup_name);
 
       /* Skip past the scope operator.  */
       last += strlen (scope_op);
-      method = XNEWVEC (char, strlen (last) + 1);
-      make_cleanup (xfree, method);
-      strcpy (method, last);
+      method = last;
 
       /* Find a list of classes named KLASS.  */
-      classes = lookup_prefix_sym (state, file_symtabs, klass);
-      make_cleanup (VEC_cleanup (symbolp), &classes);
+      classes = lookup_prefix_sym (state, file_symtabs, klass.c_str ());
+      struct cleanup *old_chain
+       = make_cleanup (VEC_cleanup (symbolp), &classes);
 
       if (!VEC_empty (symbolp, classes))
        {
          /* Now locate a list of suitable methods named METHOD.  */
          TRY
            {
-             find_method (state, file_symtabs, klass, method, classes,
-                          symbols, minsyms);
+             find_method (state, file_symtabs,
+                          klass.c_str (), method.c_str (),
+                          classes, symbols, minsyms);
            }
 
          /* If successful, we're done.  If NOT_FOUND_ERROR
@@ -3370,22 +4093,71 @@ find_linespec_symbols (struct linespec_state *state,
            }
          END_CATCH
        }
+
+      do_cleanups (old_chain);
     }
+}
 
-  do_cleanups (cleanup);
+/* Helper for find_label_symbols.  Find all labels that match name
+   NAME in BLOCK.  Return all labels that match in FUNCTION_SYMBOLS.
+   Return the actual function symbol in which the label was found in
+   LABEL_FUNC_RET.  If COMPLETION_MODE is true, then NAME is
+   interpreted as a label name prefix.  Otherwise, only a label named
+   exactly NAME match.  */
+
+static void
+find_label_symbols_in_block (const struct block *block,
+                            const char *name, struct symbol *fn_sym,
+                            bool completion_mode,
+                            VEC (symbolp) **result,
+                            VEC (symbolp) **label_funcs_ret)
+{
+  if (completion_mode)
+    {
+      struct block_iterator iter;
+      struct symbol *sym;
+      size_t name_len = strlen (name);
+
+      int (*cmp) (const char *, const char *, size_t);
+      cmp = case_sensitivity == case_sensitive_on ? strncmp : strncasecmp;
+
+      ALL_BLOCK_SYMBOLS (block, iter, sym)
+       {
+         if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+                                    SYMBOL_DOMAIN (sym), LABEL_DOMAIN)
+             && cmp (SYMBOL_SEARCH_NAME (sym), name, name_len) == 0)
+           {
+             VEC_safe_push (symbolp, *result, sym);
+             VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
+           }
+       }
+    }
+  else
+    {
+      struct symbol *sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol;
+
+      if (sym != NULL)
+       {
+         VEC_safe_push (symbolp, *result, sym);
+         VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
+       }
+    }
 }
 
-/* Return all labels named NAME in FUNCTION_SYMBOLS.  Return the
-   actual function symbol in which the label was found in LABEL_FUNC_RET.  */
+/* Return all labels that match name NAME in FUNCTION_SYMBOLS.  Return
+   the actual function symbol in which the label was found in
+   LABEL_FUNC_RET.  If COMPLETION_MODE is true, then NAME is
+   interpreted as a label name prefix.  Otherwise, only labels named
+   exactly NAME match.  */
 
 static VEC (symbolp) *
 find_label_symbols (struct linespec_state *self,
                    VEC (symbolp) *function_symbols,
-                   VEC (symbolp) **label_funcs_ret, const char *name)
+                   VEC (symbolp) **label_funcs_ret, const char *name,
+                   bool completion_mode)
 {
   int ix;
   const struct block *block;
-  struct symbol *sym;
   struct symbol *fn_sym;
   VEC (symbolp) *result = NULL;
 
@@ -3402,13 +4174,8 @@ find_label_symbols (struct linespec_state *self,
        return NULL;
       fn_sym = BLOCK_FUNCTION (block);
 
-      sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol;
-
-      if (sym != NULL)
-       {
-         VEC_safe_push (symbolp, result, sym);
-         VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
-       }
+      find_label_symbols_in_block (block, name, fn_sym, completion_mode,
+                                  &result, label_funcs_ret);
     }
   else
     {
@@ -3417,13 +4184,9 @@ find_label_symbols (struct linespec_state *self,
        {
          set_current_program_space (SYMTAB_PSPACE (symbol_symtab (fn_sym)));
          block = SYMBOL_BLOCK_VALUE (fn_sym);
-         sym = lookup_symbol (name, block, LABEL_DOMAIN, 0).symbol;
 
-         if (sym != NULL)
-           {
-             VEC_safe_push (symbolp, result, sym);
-             VEC_safe_push (symbolp, *label_funcs_ret, fn_sym);
-           }
+         find_label_symbols_in_block (block, name, fn_sym, completion_mode,
+                                      &result, label_funcs_ret);
        }
     }
 
@@ -3434,10 +4197,9 @@ find_label_symbols (struct linespec_state *self,
 
 /* A helper for create_sals_line_offset that handles the 'list_mode' case.  */
 
-static void
+static std::vector<symtab_and_line>
 decode_digits_list_mode (struct linespec_state *self,
                         linespec_p ls,
-                        struct symtabs_and_lines *values,
                         struct symtab_and_line val)
 {
   int ix;
@@ -3445,6 +4207,8 @@ decode_digits_list_mode (struct linespec_state *self,
 
   gdb_assert (self->list_mode);
 
+  std::vector<symtab_and_line> values;
+
   for (ix = 0; VEC_iterate (symtab_ptr, ls->file_symtabs, ix, elt);
        ++ix)
     {
@@ -3461,28 +4225,28 @@ decode_digits_list_mode (struct linespec_state *self,
       val.pc = 0;
       val.explicit_line = 1;
 
-      add_sal_to_sals (self, values, &val, NULL, 0);
+      add_sal_to_sals (self, &values, &val, NULL, 0);
     }
+
+  return values;
 }
 
 /* A helper for create_sals_line_offset that iterates over the symtabs,
    adding lines to the VEC.  */
 
-static void
+static std::vector<symtab_and_line>
 decode_digits_ordinary (struct linespec_state *self,
                        linespec_p ls,
                        int line,
-                       struct symtabs_and_lines *sals,
                        struct linetable_entry **best_entry)
 {
   int ix;
   struct symtab *elt;
 
+  std::vector<symtab_and_line> sals;
   for (ix = 0; VEC_iterate (symtab_ptr, ls->file_symtabs, ix, elt); ++ix)
     {
-      int i;
-      VEC (CORE_ADDR) *pcs;
-      CORE_ADDR pc;
+      std::vector<CORE_ADDR> pcs;
 
       /* The logic above should ensure this.  */
       gdb_assert (elt != NULL);
@@ -3490,20 +4254,18 @@ decode_digits_ordinary (struct linespec_state *self,
       set_current_program_space (SYMTAB_PSPACE (elt));
 
       pcs = find_pcs_for_symtab_line (elt, line, best_entry);
-      for (i = 0; VEC_iterate (CORE_ADDR, pcs, i, pc); ++i)
+      for (CORE_ADDR pc : pcs)
        {
-         struct symtab_and_line sal;
-
-         init_sal (&sal);
+         symtab_and_line sal;
          sal.pspace = SYMTAB_PSPACE (elt);
          sal.symtab = elt;
          sal.line = line;
          sal.pc = pc;
-         add_sal_to_sals_basic (sals, &sal);
+         sals.push_back (std::move (sal));
        }
-
-      VEC_free (CORE_ADDR, pcs);
     }
+
+  return sals;
 }
 
 \f
@@ -3565,20 +4327,6 @@ linespec_parse_variable (struct linespec_state *self, const char *variable)
 }
 \f
 
-/* A callback used to possibly add a symbol to the results.  */
-
-static int
-collect_symbols (struct symbol *sym, void *data)
-{
-  struct collect_info *info = (struct collect_info *) data;
-
-  /* In list mode, add all matching symbols, regardless of class.
-     This allows the user to type "list a_global_variable".  */
-  if (SYMBOL_CLASS (sym) == LOC_BLOCK || info->state->list_mode)
-    VEC_safe_push (symbolp, info->result.symbols, sym);
-  return 1; /* Continue iterating.  */
-}
-
 /* We've found a minimal symbol MSYMBOL in OBJFILE to associate with our
    linespec; return the SAL in RESULT.  This function should return SALs
    matching those from find_function_start_sal, otherwise false
@@ -3587,42 +4335,39 @@ collect_symbols (struct symbol *sym, void *data)
 static void
 minsym_found (struct linespec_state *self, struct objfile *objfile,
              struct minimal_symbol *msymbol,
-             struct symtabs_and_lines *result)
+             std::vector<symtab_and_line> *result)
 {
-  struct gdbarch *gdbarch = get_objfile_arch (objfile);
-  CORE_ADDR pc;
   struct symtab_and_line sal;
 
-  sal = find_pc_sect_line (MSYMBOL_VALUE_ADDRESS (objfile, msymbol),
-                          (struct obj_section *) 0, 0);
-  sal.section = MSYMBOL_OBJ_SECTION (objfile, msymbol);
+  CORE_ADDR func_addr;
+  if (msymbol_is_function (objfile, msymbol, &func_addr))
+    {
+      sal = find_pc_sect_line (func_addr, NULL, 0);
+
+      if (self->funfirstline)
+       {
+         if (sal.symtab != NULL
+             && (COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (sal.symtab))
+                 || SYMTAB_LANGUAGE (sal.symtab) == language_asm))
+           {
+             struct gdbarch *gdbarch = get_objfile_arch (objfile);
 
-  /* The minimal symbol might point to a function descriptor;
-     resolve it to the actual code address instead.  */
-  pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, &current_target);
-  if (pc != sal.pc)
-    sal = find_pc_sect_line (pc, NULL, 0);
-
-  if (self->funfirstline)
-    {
-      if (sal.symtab != NULL
-         && (COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (sal.symtab))
-             || SYMTAB_LANGUAGE (sal.symtab) == language_asm))
-       {
-         /* If gdbarch_convert_from_func_ptr_addr does not apply then
-            sal.SECTION, sal.LINE&co. will stay correct from above.
-            If gdbarch_convert_from_func_ptr_addr applies then
-            sal.SECTION is cleared from above and sal.LINE&co. will
-            stay correct from the last find_pc_sect_line above.  */
-         sal.pc = MSYMBOL_VALUE_ADDRESS (objfile, msymbol);
-         sal.pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc,
-                                                      &current_target);
-         if (gdbarch_skip_entrypoint_p (gdbarch))
-           sal.pc = gdbarch_skip_entrypoint (gdbarch, sal.pc);
+             sal.pc = func_addr;
+             if (gdbarch_skip_entrypoint_p (gdbarch))
+               sal.pc = gdbarch_skip_entrypoint (gdbarch, sal.pc);
+           }
+         else
+           skip_prologue_sal (&sal);
        }
-      else
-       skip_prologue_sal (&sal);
     }
+  else
+    {
+      sal.objfile = objfile;
+      sal.pc = MSYMBOL_VALUE_ADDRESS (objfile, msymbol);
+      sal.pspace = current_program_space;
+    }
+
+  sal.section = MSYMBOL_OBJ_SECTION (objfile, msymbol);
 
   if (maybe_add_address (self->addr_set, objfile->pspace, sal.pc))
     add_sal_to_sals (self, result, &sal, MSYMBOL_NATURAL_NAME (msymbol), 0);
@@ -3693,52 +4438,26 @@ static void
 add_minsym (struct minimal_symbol *minsym, void *d)
 {
   struct collect_minsyms *info = (struct collect_minsyms *) d;
-  bound_minimal_symbol_d mo;
-
-  mo.minsym = minsym;
-  mo.objfile = info->objfile;
 
   if (info->symtab != NULL)
     {
-      CORE_ADDR pc;
-      struct symtab_and_line sal;
-      struct gdbarch *gdbarch = get_objfile_arch (info->objfile);
-
-      sal = find_pc_sect_line (MSYMBOL_VALUE_ADDRESS (info->objfile, minsym),
-                              NULL, 0);
-      sal.section = MSYMBOL_OBJ_SECTION (info->objfile, minsym);
-      pc
-       = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, &current_target);
-      if (pc != sal.pc)
-       sal = find_pc_sect_line (pc, NULL, 0);
+      /* We're looking for a label for which we don't have debug
+        info.  */
+      CORE_ADDR func_addr;
+      if (msymbol_is_function (info->objfile, minsym, &func_addr))
+       {
+         symtab_and_line sal = find_pc_sect_line (func_addr, NULL, 0);
 
-      if (info->symtab != sal.symtab)
-       return;
+         if (info->symtab != sal.symtab)
+           return;
+       }
     }
 
-  /* Exclude data symbols when looking for breakpoint locations.   */
-  if (!info->list_mode)
-    switch (minsym->type)
-      {
-       case mst_slot_got_plt:
-       case mst_data:
-       case mst_bss:
-       case mst_abs:
-       case mst_file_data:
-       case mst_file_bss:
-         {
-           /* Make sure this minsym is not a function descriptor
-              before we decide to discard it.  */
-           struct gdbarch *gdbarch = get_objfile_arch (info->objfile);
-           CORE_ADDR addr = gdbarch_convert_from_func_ptr_addr
-                              (gdbarch, BMSYMBOL_VALUE_ADDRESS (mo),
-                               &current_target);
-
-           if (addr == BMSYMBOL_VALUE_ADDRESS (mo))
-             return;
-         }
-      }
+  /* Exclude data symbols when looking for breakpoint locations.  */
+  if (!info->list_mode && !msymbol_is_function (info->objfile, minsym))
+    return;
 
+  bound_minimal_symbol_d mo = {minsym, info->objfile};
   VEC_safe_push (bound_minimal_symbol_d, info->msyms, &mo);
 }
 
@@ -3750,7 +4469,8 @@ add_minsym (struct minimal_symbol *minsym, void *d)
    restrict results to the given SYMTAB.  */
 
 static void
-search_minsyms_for_name (struct collect_info *info, const char *name,
+search_minsyms_for_name (struct collect_info *info,
+                        const lookup_name_info &name,
                         struct program_space *search_pspace,
                         struct symtab *symtab)
 {
@@ -3792,8 +4512,7 @@ search_minsyms_for_name (struct collect_info *info, const char *name,
        {
          set_current_program_space (SYMTAB_PSPACE (symtab));
          local.objfile = SYMTAB_OBJFILE(symtab);
-         iterate_over_minimal_symbols (local.objfile, name, add_minsym,
-                                       &local);
+         iterate_over_minimal_symbols (local.objfile, name, add_minsym, &local);
        }
     }
 
@@ -3835,20 +4554,25 @@ search_minsyms_for_name (struct collect_info *info, const char *name,
 
 static void
 add_matching_symbols_to_info (const char *name,
+                             symbol_name_match_type name_match_type,
+                             enum search_domain search_domain,
                              struct collect_info *info,
                              struct program_space *pspace)
 {
   int ix;
   struct symtab *elt;
 
+  lookup_name_info lookup_name (name, name_match_type);
+
   for (ix = 0; VEC_iterate (symtab_ptr, info->file_symtabs, ix, elt); ++ix)
     {
       if (elt == NULL)
        {
-         iterate_over_all_matching_symtabs (info->state, name, VAR_DOMAIN,
-                                            collect_symbols, info,
-                                            pspace, 1);
-         search_minsyms_for_name (info, name, pspace, NULL);
+         iterate_over_all_matching_symtabs (info->state, lookup_name,
+                                            VAR_DOMAIN, search_domain,
+                                            pspace, true, [&] (symbol *sym)
+           { return info->add_symbol (sym); });
+         search_minsyms_for_name (info, lookup_name, pspace, NULL);
        }
       else if (pspace == NULL || pspace == SYMTAB_PSPACE (elt))
        {
@@ -3858,8 +4582,9 @@ add_matching_symbols_to_info (const char *name,
             been filtered out earlier.  */
          gdb_assert (!SYMTAB_PSPACE (elt)->executing_startup);
          set_current_program_space (SYMTAB_PSPACE (elt));
-         iterate_over_file_blocks (elt, name, VAR_DOMAIN,
-                                   collect_symbols, info);
+         iterate_over_file_blocks (elt, lookup_name, VAR_DOMAIN,
+                                   [&] (symbol *sym)
+           { return info->add_symbol (sym); });
 
          /* If no new symbols were found in this iteration and this symtab
             is in assembler, we might actually be looking for a label for
@@ -3867,7 +4592,7 @@ add_matching_symbols_to_info (const char *name,
             this case.  */
          if (prev_len == VEC_length (symbolp, info->result.symbols)
              && elt->language == language_asm)
-           search_minsyms_for_name (info, name, pspace, elt);
+           search_minsyms_for_name (info, lookup_name, pspace, elt);
        }
     }
 }
@@ -3890,8 +4615,9 @@ symbol_to_sal (struct symtab_and_line *result,
     {
       if (SYMBOL_CLASS (sym) == LOC_LABEL && SYMBOL_VALUE_ADDRESS (sym) != 0)
        {
-         init_sal (result);
+         *result = {};
          result->symtab = symbol_symtab (sym);
+         result->symbol = sym;
          result->line = SYMBOL_LINE (sym);
          result->pc = SYMBOL_VALUE_ADDRESS (sym);
          result->pspace = SYMTAB_PSPACE (result->symtab);
@@ -3905,9 +4631,11 @@ symbol_to_sal (struct symtab_and_line *result,
       else if (SYMBOL_LINE (sym) != 0)
        {
          /* We know its line number.  */
-         init_sal (result);
+         *result = {};
          result->symtab = symbol_symtab (sym);
+         result->symbol = sym;
          result->line = SYMBOL_LINE (sym);
+         result->pc = SYMBOL_VALUE_ADDRESS (sym);
          result->pspace = SYMTAB_PSPACE (result->symtab);
          return 1;
        }
@@ -3916,45 +4644,10 @@ symbol_to_sal (struct symtab_and_line *result,
   return 0;
 }
 
-/* See the comment in linespec.h.  */
-
-void
-init_linespec_result (struct linespec_result *lr)
-{
-  memset (lr, 0, sizeof (*lr));
-}
-
-/* See the comment in linespec.h.  */
-
-void
-destroy_linespec_result (struct linespec_result *ls)
-{
-  int i;
-  struct linespec_sals *lsal;
-
-  delete_event_location (ls->location);
-  for (i = 0; VEC_iterate (linespec_sals, ls->sals, i, lsal); ++i)
-    {
-      xfree (lsal->canonical);
-      xfree (lsal->sals.sals);
-    }
-  VEC_free (linespec_sals, ls->sals);
-}
-
-/* Cleanup function for a linespec_result.  */
-
-static void
-cleanup_linespec_result (void *a)
-{
-  destroy_linespec_result ((struct linespec_result *) a);
-}
-
-/* See the comment in linespec.h.  */
-
-struct cleanup *
-make_cleanup_destroy_linespec_result (struct linespec_result *ls)
+linespec_result::~linespec_result ()
 {
-  return make_cleanup (cleanup_linespec_result, ls);
+  for (linespec_sals &lsal : lsals)
+    xfree (lsal.canonical);
 }
 
 /* Return the quote characters permitted by the linespec parser.  */
This page took 0.065064 seconds and 4 git commands to generate.