Re: [PATCH 17/40] Linespec lexing and C++ operators

Keith Seitz
2017-07-14T21:45:58Z

On 06/02/2017 05:22 AM, Pedro Alves wrote:
> 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 "<".

Ouch. The best laid plans...

Just a few trivial things.

> diff --git a/gdb/linespec.c b/gdb/linespec.c
> index 0216bf1..f24cca2 100644
> --- a/gdb/linespec.c
> +++ b/gdb/linespec.c
> @@ -674,14 +674,49 @@ 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;

This is a cut-n-paste-o (that's a typo propagated via cut-n-paste). Missing a space before the operator.

> + 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;

Line length > 80?

> + return token;
> }
> + else
> + continue;
> }
> /* Commas are terminators, but not if they are part of an
> operator name. */

Keith