From be966d4207ff8df6572a23b911e5a69a2ab9370f Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 17 Jul 2017 20:28:12 +0100 Subject: [PATCH] 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 * linespec.c (linespec_lexer_lex_string, find_toplevel_char): Handle 'operator<' / 'operator<<'. --- gdb/ChangeLog | 5 +++ gdb/linespec.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index acf0b51e71..8147cc661e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2017-07-17 Pedro Alves + + * linespec.c (linespec_lexer_lex_string, find_toplevel_char): + Handle 'operator<' / 'operator<<'. + 2017-07-17 Pedro Alves * completer.c (collect_explicit_location_matches): Handle 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" 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. */ + within foo, while considering C++ operator') && 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; -- 2.34.1