summaryrefslogtreecommitdiff
path: root/gdb/linespec.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2017-07-17 20:28:12 +0100
committerPedro Alves <palves@redhat.com>2017-07-17 20:28:12 +0100
commitbe966d4207ff8df6572a23b911e5a69a2ab9370f (patch)
tree339fc204a3a7af66f9e4f6160605f25cafe4fd26 /gdb/linespec.c
parenta245927022bc4351fafd9e6275e217021ec93e08 (diff)
Linespec lexing and C++ operators
There's some lexing code in linespec that isn't handling C++ operators correctly. It's the usual confusion with operator< / operator<<, in code that wants to skip past template parameters. The linespec_lexer_lex_string change is necessary otherwise we get this (with current master): (gdb) break 'operator<' unmatched quote The need for the find_toplevel_char change was exposed by the use of that function in the explicit location completer. Without the fix, that completer is not able to "see" past operator< symbols, without quoting, like: (gdb) b -function operator<(int, int) -labe[TAB] # nothing happens gdb incorrectly thinks "-labe" is part of the "unclosed" template parameter list started with "<". gdb/ChangeLog: 2017-07-17 Pedro Alves <palves@redhat.com> * linespec.c (linespec_lexer_lex_string, find_toplevel_char): Handle 'operator<' / 'operator<<'.
Diffstat (limited to 'gdb/linespec.c')
-rw-r--r--gdb/linespec.c89
1 files changed, 83 insertions, 6 deletions
diff --git a/gdb/linespec.c b/gdb/linespec.c
index 0216bf123e..26baad0bda 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -674,14 +674,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;
+ }
+ }
+ }
+
+ const char *p = find_parameter_list_end (PARSER_STREAM (parser));
+ PARSER_STREAM (parser) = p;
- p = find_parameter_list_end (PARSER_STREAM (parser));
- if (p != NULL)
+ /* 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. */
@@ -1112,7 +1148,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 +1176,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;