mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
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:
parent
17545aa1bf
commit
59498c305e
@ -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.
|
||||
|
45
gdb/c-exp.y
45
gdb/c-exp.y
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user