Do not classify C struct members as a filename

There is existing logic in C/C++ expression parsing to avoid classifying
names as a filename when they are a field on the this object. This
change extends this logic to also avoid classifying names after a
struct-op (-> or .) as a filename, which otherwise causes a syntax
error.

Thus, it is now possible in the file

    #include <map>
    struct D {
        void map();
    }
    D d;

to call

    (gdb) print d.map()

where previously this would have been a syntax error.

Tested on gdb.cp/*.exp

gdb/ChangeLog:

        * c-exp.y (lex_one_token, classify_name, yylex): Don't classify
        names after a structop as a filename

gdb/testsuite/ChangeLog:

        * gdb.cp/filename.cc, gdb.cp/filename.exp: Test that member
        functions with the same name as an include file are parsed
        correctly.
This commit is contained in:
Leszek Swirski 2018-01-25 16:20:47 +00:00 committed by Simon Marchi
parent 17545aa1bf
commit 59498c305e
5 changed files with 74 additions and 24 deletions

View File

@ -1,3 +1,8 @@
2018-02-01 Leszek Swirski <leszeks@google.com>
* c-exp.y (lex_one_token, classify_name, yylex): Don't classify
names after a structop as a filename.
2018-02-01 Yao Qi <yao.qi@linaro.org>
* arm-tdep.c (arm_record_data_proc_misc_ld_str): Rewrite it.

View File

@ -2447,24 +2447,23 @@ static struct macro_scope *expression_macro_scope;
static int saw_name_at_eof;
/* This is set if the previously-returned token was a structure
operator -- either '.' or ARROW. This is used only when parsing to
do field name completion. */
static int last_was_structop;
operator -- either '.' or ARROW. */
static bool last_was_structop;
/* Read one token, getting characters through lexptr. */
static int
lex_one_token (struct parser_state *par_state, int *is_quoted_name)
lex_one_token (struct parser_state *par_state, bool *is_quoted_name)
{
int c;
int namelen;
unsigned int i;
const char *tokstart;
int saw_structop = last_was_structop;
bool saw_structop = last_was_structop;
char *copy;
last_was_structop = 0;
*is_quoted_name = 0;
last_was_structop = false;
*is_quoted_name = false;
retry:
@ -2505,7 +2504,7 @@ lex_one_token (struct parser_state *par_state, int *is_quoted_name)
lexptr += 2;
yylval.opcode = tokentab2[i].opcode;
if (parse_completion && tokentab2[i].token == ARROW)
if (tokentab2[i].token == ARROW)
last_was_structop = 1;
return tokentab2[i].token;
}
@ -2529,7 +2528,7 @@ lex_one_token (struct parser_state *par_state, int *is_quoted_name)
saw_name_at_eof = 0;
return COMPLETE;
}
else if (saw_structop)
else if (parse_completion && saw_structop)
return COMPLETE;
else
return 0;
@ -2569,8 +2568,7 @@ lex_one_token (struct parser_state *par_state, int *is_quoted_name)
/* Might be a floating point number. */
if (lexptr[1] < '0' || lexptr[1] > '9')
{
if (parse_completion)
last_was_structop = 1;
last_was_structop = true;
goto symbol; /* Nope, must be a symbol. */
}
/* FALL THRU into number case. */
@ -2711,7 +2709,7 @@ lex_one_token (struct parser_state *par_state, int *is_quoted_name)
{
++tokstart;
namelen = lexptr - tokstart - 1;
*is_quoted_name = 1;
*is_quoted_name = true;
goto tryname;
}
@ -2859,11 +2857,12 @@ auto_obstack name_obstack;
Updates yylval and returns the new token type. BLOCK is the block
in which lookups start; this can be NULL to mean the global scope.
IS_QUOTED_NAME is non-zero if the name token was originally quoted
in single quotes. */
in single quotes. IS_AFTER_STRUCTOP is true if this name follows
a structure operator -- either '.' or ARROW */
static int
classify_name (struct parser_state *par_state, const struct block *block,
int is_quoted_name)
bool is_quoted_name, bool is_after_structop)
{
struct block_symbol bsym;
char *copy;
@ -2907,11 +2906,13 @@ classify_name (struct parser_state *par_state, const struct block *block,
}
}
/* If we found a field, then we want to prefer it over a
/* If we found a field on the "this" object, or we are looking
up a field on a struct, then we want to prefer it over a
filename. However, if the name was quoted, then it is better
to check for a filename or a block, since this is the only
way the user has of requiring the extension to be used. */
if (is_a_field_of_this.type == NULL || is_quoted_name)
if ((is_a_field_of_this.type == NULL && !is_after_structop)
|| is_quoted_name)
{
/* See if it's a file name. */
struct symtab *symtab;
@ -2992,7 +2993,7 @@ classify_inner_name (struct parser_state *par_state,
char *copy;
if (context == NULL)
return classify_name (par_state, block, 0);
return classify_name (par_state, block, false, false);
type = check_typedef (context);
if (!type_aggregate_p (type))
@ -3066,19 +3067,21 @@ yylex (void)
struct type *context_type = NULL;
int last_to_examine, next_to_examine, checkpoint;
const struct block *search_block;
int is_quoted_name;
bool is_quoted_name, last_lex_was_structop;
if (popping && !VEC_empty (token_and_value, token_fifo))
goto do_pop;
popping = 0;
last_lex_was_structop = last_was_structop;
/* Read the first token and decide what to do. Most of the
subsequent code is C++-only; but also depends on seeing a "::" or
name-like token. */
current.token = lex_one_token (pstate, &is_quoted_name);
if (current.token == NAME)
current.token = classify_name (pstate, expression_context_block,
is_quoted_name);
is_quoted_name, last_lex_was_structop);
if (parse_language (pstate)->la_language != language_cplus
|| (current.token != TYPENAME && current.token != COLONCOLON
&& current.token != FILENAME))
@ -3091,7 +3094,7 @@ yylex (void)
last_was_coloncolon = current.token == COLONCOLON;
while (1)
{
int ignore;
bool ignore;
/* We ignore quoted names other than the very first one.
Subsequent ones do not have any special meaning. */
@ -3242,7 +3245,7 @@ c_parse (struct parser_state *par_state)
parser_debug);
/* Initialize some state used by the lexer. */
last_was_structop = 0;
last_was_structop = false;
saw_name_at_eof = 0;
VEC_free (token_and_value, token_fifo);

View File

@ -1,3 +1,9 @@
2018-02-01 Leszek Swirski <leszeks@google.com>
* gdb.cp/filename.cc, gdb.cp/filename.exp: Test that member
functions with the same name as an include file are parsed
correctly.
2018-02-01 Yao Qi <yao.qi@linaro.org>
* gdb.base/attach.exp (do_attach_tests): Set sysroot to

View File

@ -26,11 +26,31 @@ public:
}
void m() {
/* stop here */
/* stop inside C */
}
};
class D {
public:
int includefile();
void m() {
/* stop inside D */
}
};
int D::includefile() {
return 24;
}
int main() {
C c;
C* pc = &c;
c.m();
D d;
D* pd = &d;
d.m();
/* stop outside */
}

View File

@ -26,8 +26,24 @@ if ![runto_main] then {
continue
}
gdb_breakpoint [gdb_get_line_number "stop here"]
gdb_continue_to_breakpoint "stop here"
gdb_breakpoint [gdb_get_line_number "stop inside C"]
gdb_continue_to_breakpoint "stop inside C"
gdb_test "print includefile\[0\]" " = 23"
gdb_test "print this->includefile\[0\]" " = 23"
gdb_test "print 'includefile'::some_global" " = 27"
gdb_breakpoint [gdb_get_line_number "stop inside D"]
gdb_continue_to_breakpoint "stop inside D"
gdb_test "print includefile()" " = 24"
gdb_test "print this->includefile()" " = 24"
gdb_test "print 'includefile'::some_global" " = 27"
gdb_breakpoint [gdb_get_line_number "stop outside"]
gdb_continue_to_breakpoint "stop outside"
gdb_test "print c.includefile\[0\]" " = 23"
gdb_test "print pc->includefile\[0\]" " = 23"
gdb_test "print d.includefile()" " = 24"
gdb_test "print pd->includefile()" " = 24"