Kill init_sal
[deliverable/binutils-gdb.git] / gdb / linespec.c
index 0216bf123e68624268e4100a58d2b64e6dc09da2..480180869fa4fe126f150ae51b868302415844d7 100644 (file)
 #include "location.h"
 #include "common/function-view.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);
 
@@ -144,7 +173,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
@@ -271,6 +300,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;
 
@@ -289,9 +341,9 @@ static void initialize_defaults (struct symtab **default_symtab,
 
 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);
@@ -327,20 +379,20 @@ 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);
 
@@ -543,6 +595,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.  */
 
@@ -590,13 +666,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
     {
@@ -674,14 +768,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);
+
+                 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;
+                       }
+                   }
+               }
 
-             p = find_parameter_list_end (PARSER_STREAM (parser));
-             if (p != NULL)
+             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.  */
@@ -799,13 +929,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.  */
@@ -816,26 +981,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.
@@ -845,19 +1005,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);
@@ -1112,7 +1273,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)
@@ -1140,6 +1301,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;
@@ -1193,7 +1395,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;
@@ -1201,12 +1403,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;
-
-      memset (&lsal, 0, sizeof (lsal));
+      linespec_sals 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;
@@ -1217,15 +1416,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));
        }
     }
 
@@ -1236,13 +1435,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
@@ -1290,7 +1489,7 @@ 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;
@@ -1303,12 +1502,12 @@ decode_line_2 (struct linespec_state *self,
 
   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)
@@ -1522,6 +1721,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
@@ -1549,6 +1759,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_const (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
@@ -1564,11 +1794,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);
@@ -1580,7 +1819,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.  */
@@ -1593,12 +1835,58 @@ 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;
+
+         linespec_complete_function (tmp_tracker,
+                                     parser->completion_word,
+                                     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),
@@ -1658,11 +1946,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);
@@ -1671,17 +1967,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_const (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);
@@ -1704,8 +2039,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.  */
@@ -1785,18 +2122,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
@@ -1821,6 +2152,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)
     {
@@ -1844,27 +2176,22 @@ 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
@@ -1876,24 +2203,24 @@ 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);
+      filter = XNEWVEC (int, intermediate_results.size ());
+      struct cleanup *cleanup = make_cleanup (xfree, filter);
+      blocks = XNEWVEC (const struct block *, intermediate_results.size ());
       make_cleanup (xfree, blocks);
 
-      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])
                  {
@@ -1903,7 +2230,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]
@@ -1911,18 +2238,18 @@ 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\"."),
@@ -1937,17 +2264,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;
@@ -1955,10 +2281,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)
     {
@@ -2048,7 +2374,7 @@ 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;
@@ -2124,7 +2450,7 @@ convert_explicit_location_to_linespec (struct linespec_state *self,
 
 /* Convert the explicit location EXPLICIT_LOC into SaLs.  */
 
-static struct symtabs_and_lines
+static std::vector<symtab_and_line>
 convert_explicit_location_to_sals (struct linespec_state *self,
                                   linespec_p result,
                                   const struct explicit_location *explicit_loc)
@@ -2187,11 +2513,10 @@ convert_explicit_location_to_sals (struct linespec_state *self,
 
 /* Parse the linespec in ARG.  */
 
-static struct symtabs_and_lines
+static std::vector<symtab_and_line>
 parse_linespec (linespec_parser *parser, const char *arg)
 {
   linespec_token token;
-  struct symtabs_and_lines values;
   struct gdb_exception file_exception = exception_none;
   struct cleanup *cleanup;
 
@@ -2199,7 +2524,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;
@@ -2216,20 +2542,35 @@ 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;
 
   /* 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 == '$')
@@ -2237,7 +2578,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);
@@ -2256,8 +2598,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.  */
@@ -2305,8 +2655,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.  */
@@ -2322,7 +2673,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)
@@ -2343,13 +2695,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_const (skip_to_space_const (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 {};
 }
 
 
@@ -2485,6 +2847,67 @@ linespec_complete_function (completion_tracker &tracker,
     collect_symbol_completion_matches (tracker, mode, 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;
+
+      linespec_complete_function (tracker, text, 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.  */
@@ -2548,14 +2971,209 @@ linespec_complete_label (completion_tracker &tracker,
   do_cleanups (cleanup);
 }
 
+/* See description in linespec.h.  */
+
+void
+linespec_complete (completion_tracker &tracker, const char *text)
+{
+  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_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);
+    }
+  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,
+                            &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 *text = parser.completion_word;
+      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))
     {
@@ -2631,7 +3249,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;
@@ -2653,19 +3270,20 @@ decode_line_full (const struct event_location *location, int flags,
 
   scoped_restore_current_program_space restore_pspace;
 
-  result = event_location_to_sals (&parser, location);
+  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);
@@ -2699,13 +3317,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;
 
@@ -2716,7 +3333,8 @@ decode_line_1 (const struct event_location *location, int flags,
 
   scoped_restore_current_program_space restore_pspace;
 
-  result = event_location_to_sals (&parser, location);
+  std::vector<symtab_and_line> result = event_location_to_sals (&parser,
+                                                               location);
 
   do_cleanups (cleanups);
   return result;
@@ -2724,23 +3342,20 @@ decode_line_1 (const struct event_location *location, int flags,
 
 /* See linespec.h.  */
 
-struct symtabs_and_lines
+std::vector<symtab_and_line>
 decode_line_with_current_source (char *string, int flags)
 {
-  struct symtabs_and_lines sals;
-  struct symtab_and_line cursal;
-
   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 ();
 
   event_location_up location = string_to_event_location (&string,
                                                         current_language);
-  sals = decode_line_1 (location.get (), flags, NULL,
-                       cursal.symtab, cursal.line);
+  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);
@@ -2750,23 +3365,21 @@ decode_line_with_current_source (char *string, int flags)
 
 /* See linespec.h.  */
 
-struct symtabs_and_lines
+std::vector<symtab_and_line>
 decode_line_with_last_displayed (char *string, int flags)
 {
-  struct symtabs_and_lines sals;
-
   if (string == 0)
     error (_("Empty line specification."));
 
   event_location_up location = string_to_event_location (&string,
                                                         current_language);
-  if (last_displayed_sal_is_valid ())
-    sals = decode_line_1 (location.get (), flags, NULL,
-                         get_last_displayed_symtab (),
-                         get_last_displayed_line ());
-  else
-    sals = decode_line_1 (location.get (), flags, NULL,
-                         (struct symtab *) NULL, 0);
+  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);
@@ -2822,12 +3435,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);
@@ -2838,18 +3450,17 @@ 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);
 
+  std::vector<symtab_and_line> values;
   if (!VEC_empty (symbolp, info.result.symbols)
       || !VEC_empty (bound_minimal_symbol_d, info.result.minimal_symbols))
     {
@@ -3563,10 +4174,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;
@@ -3574,6 +4184,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)
     {
@@ -3590,23 +4202,25 @@ 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)
     {
       std::vector<CORE_ADDR> pcs;
@@ -3619,16 +4233,16 @@ decode_digits_ordinary (struct linespec_state *self,
       pcs = find_pcs_for_symtab_line (elt, line, best_entry);
       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));
        }
     }
+
+  return sals;
 }
 
 \f
@@ -3698,7 +4312,7 @@ linespec_parse_variable (struct linespec_state *self, const char *variable)
 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;
@@ -4001,7 +4615,7 @@ 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->line = SYMBOL_LINE (sym);
          result->pc = SYMBOL_VALUE_ADDRESS (sym);
@@ -4016,7 +4630,7 @@ 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->line = SYMBOL_LINE (sym);
          result->pspace = SYMTAB_PSPACE (result->symtab);
@@ -4029,15 +4643,8 @@ symbol_to_sal (struct symtab_and_line *result,
 
 linespec_result::~linespec_result ()
 {
-  int i;
-  struct linespec_sals *lsal;
-
-  for (i = 0; VEC_iterate (linespec_sals, sals, i, lsal); ++i)
-    {
-      xfree (lsal->canonical);
-      xfree (lsal->sals.sals);
-    }
-  VEC_free (linespec_sals, sals);
+  for (linespec_sals &lsal : lsals)
+    xfree (lsal.canonical);
 }
 
 /* Return the quote characters permitted by the linespec parser.  */
This page took 0.043879 seconds and 4 git commands to generate.