Add C parser support for "restrict" and "_Atomic"
A user noticed that "watch -location" would fail with a "restrict" pointer. The issue here is that if the DWARF mentions "restrict", gdb will put this into the type name -- but then the C parser will not be able to parse this type. This patch adds support for "restrict" and "_Atomic" to the C parser. C++ doesn't have "restrict", but does have some GCC extensions. The type printer is changed to handle this difference as well, so that watch expressions will work properly. gdb/ChangeLog 2020-03-14 Tom Tromey <tom@tromey.com> * c-typeprint.c (cp_type_print_method_args): Print "__restrict__" for C++. (c_type_print_modifier): Likewise. Add "language" parameter. (c_type_print_varspec_prefix, c_type_print_base_struct_union) (c_type_print_base_1): Update. * type-stack.h (enum type_pieces) <tp_atomic, tp_restrict>: New constants. * type-stack.c (type_stack::insert): Handle tp_atomic and tp_restrict. (type_stack::follow_type_instance_flags): Likewise. (type_stack::follow_types): Likewise. Merge type-following code. * c-exp.y (RESTRICT, ATOMIC): New tokens. (space_identifier, cv_with_space_id) (const_or_volatile_or_space_identifier_noopt) (const_or_volatile_or_space_identifier): Remove. (single_qualifier, qualifier_seq_noopt, qualifier_seq): New rules. (ptr_operator, typebase): Update. (enum token_flag) <FLAG_C>: New constant. (ident_tokens): Add "restrict", "__restrict__", "__restrict", and "_Atomic". (lex_one_token): Handle FLAG_C. gdb/testsuite/ChangeLog 2020-03-14 Tom Tromey <tom@tromey.com> * gdb.base/cvexpr.exp: Add test for _Atomic and restrict.
This commit is contained in:
parent
ab44624cea
commit
3293bbaffa
|
@ -1,3 +1,28 @@
|
|||
2020-03-14 Tom Tromey <tom@tromey.com>
|
||||
|
||||
* c-typeprint.c (cp_type_print_method_args): Print "__restrict__"
|
||||
for C++.
|
||||
(c_type_print_modifier): Likewise. Add "language" parameter.
|
||||
(c_type_print_varspec_prefix, c_type_print_base_struct_union)
|
||||
(c_type_print_base_1): Update.
|
||||
* type-stack.h (enum type_pieces) <tp_atomic, tp_restrict>: New
|
||||
constants.
|
||||
* type-stack.c (type_stack::insert): Handle tp_atomic and
|
||||
tp_restrict.
|
||||
(type_stack::follow_type_instance_flags): Likewise.
|
||||
(type_stack::follow_types): Likewise. Merge type-following code.
|
||||
* c-exp.y (RESTRICT, ATOMIC): New tokens.
|
||||
(space_identifier, cv_with_space_id)
|
||||
(const_or_volatile_or_space_identifier_noopt)
|
||||
(const_or_volatile_or_space_identifier): Remove.
|
||||
(single_qualifier, qualifier_seq_noopt, qualifier_seq): New
|
||||
rules.
|
||||
(ptr_operator, typebase): Update.
|
||||
(enum token_flag) <FLAG_C>: New constant.
|
||||
(ident_tokens): Add "restrict", "__restrict__", "__restrict", and
|
||||
"_Atomic".
|
||||
(lex_one_token): Handle FLAG_C.
|
||||
|
||||
2020-03-14 Kamil Rytarowski <n54@gmx.com>
|
||||
|
||||
* m68k-bsd-nat.c (fetch_registers): New variable lwp and pass
|
||||
|
|
56
gdb/c-exp.y
56
gdb/c-exp.y
|
@ -237,6 +237,7 @@ static void c_print_token (FILE *file, int type, YYSTYPE value);
|
|||
/* Special type cases, put in to allow the parser to distinguish different
|
||||
legal basetypes. */
|
||||
%token SIGNED_KEYWORD LONG SHORT INT_KEYWORD CONST_KEYWORD VOLATILE_KEYWORD DOUBLE_KEYWORD
|
||||
%token RESTRICT ATOMIC
|
||||
|
||||
%token <sval> DOLLAR_VARIABLE
|
||||
|
||||
|
@ -1169,36 +1170,43 @@ variable: name_not_typename
|
|||
}
|
||||
;
|
||||
|
||||
space_identifier : '@' NAME
|
||||
const_or_volatile: const_or_volatile_noopt
|
||||
|
|
||||
;
|
||||
|
||||
single_qualifier:
|
||||
CONST_KEYWORD
|
||||
{ cpstate->type_stack.insert (tp_const); }
|
||||
| VOLATILE_KEYWORD
|
||||
{ cpstate->type_stack.insert (tp_volatile); }
|
||||
| ATOMIC
|
||||
{ cpstate->type_stack.insert (tp_atomic); }
|
||||
| RESTRICT
|
||||
{ cpstate->type_stack.insert (tp_restrict); }
|
||||
| '@' NAME
|
||||
{
|
||||
cpstate->type_stack.insert (pstate,
|
||||
copy_name ($2.stoken).c_str ());
|
||||
}
|
||||
;
|
||||
|
||||
const_or_volatile: const_or_volatile_noopt
|
||||
|
|
||||
qualifier_seq_noopt:
|
||||
single_qualifier
|
||||
| qualifier_seq single_qualifier
|
||||
;
|
||||
|
||||
cv_with_space_id : const_or_volatile space_identifier const_or_volatile
|
||||
;
|
||||
|
||||
const_or_volatile_or_space_identifier_noopt: cv_with_space_id
|
||||
| const_or_volatile_noopt
|
||||
;
|
||||
|
||||
const_or_volatile_or_space_identifier:
|
||||
const_or_volatile_or_space_identifier_noopt
|
||||
qualifier_seq:
|
||||
qualifier_seq_noopt
|
||||
|
|
||||
;
|
||||
|
||||
ptr_operator:
|
||||
ptr_operator '*'
|
||||
{ cpstate->type_stack.insert (tp_pointer); }
|
||||
const_or_volatile_or_space_identifier
|
||||
qualifier_seq
|
||||
| '*'
|
||||
{ cpstate->type_stack.insert (tp_pointer); }
|
||||
const_or_volatile_or_space_identifier
|
||||
qualifier_seq
|
||||
| '&'
|
||||
{ cpstate->type_stack.insert (tp_reference); }
|
||||
| '&' ptr_operator
|
||||
|
@ -1472,9 +1480,9 @@ typebase
|
|||
(copy_name($2).c_str (), $4,
|
||||
pstate->expression_context_block);
|
||||
}
|
||||
| const_or_volatile_or_space_identifier_noopt typebase
|
||||
| qualifier_seq_noopt typebase
|
||||
{ $$ = cpstate->type_stack.follow_types ($2); }
|
||||
| typebase const_or_volatile_or_space_identifier_noopt
|
||||
| typebase qualifier_seq_noopt
|
||||
{ $$ = cpstate->type_stack.follow_types ($1); }
|
||||
;
|
||||
|
||||
|
@ -2345,11 +2353,15 @@ enum token_flag
|
|||
|
||||
FLAG_CXX = 1,
|
||||
|
||||
/* If this bit is set, the token is C-only. */
|
||||
|
||||
FLAG_C = 2,
|
||||
|
||||
/* If this bit is set, the token is conditional: if there is a
|
||||
symbol of the same name, then the token is a symbol; otherwise,
|
||||
the token is a keyword. */
|
||||
|
||||
FLAG_SHADOW = 2
|
||||
FLAG_SHADOW = 4
|
||||
};
|
||||
DEF_ENUM_FLAGS_TYPE (enum token_flag, token_flags);
|
||||
|
||||
|
@ -2416,6 +2428,10 @@ static const struct token ident_tokens[] =
|
|||
{"union", UNION, OP_NULL, 0},
|
||||
{"short", SHORT, OP_NULL, 0},
|
||||
{"const", CONST_KEYWORD, OP_NULL, 0},
|
||||
{"restrict", RESTRICT, OP_NULL, FLAG_C | FLAG_SHADOW},
|
||||
{"__restrict__", RESTRICT, OP_NULL, 0},
|
||||
{"__restrict", RESTRICT, OP_NULL, 0},
|
||||
{"_Atomic", ATOMIC, OP_NULL, 0},
|
||||
{"enum", ENUM, OP_NULL, 0},
|
||||
{"long", LONG, OP_NULL, 0},
|
||||
{"true", TRUEKEYWORD, OP_NULL, FLAG_CXX},
|
||||
|
@ -2550,6 +2566,7 @@ lex_one_token (struct parser_state *par_state, bool *is_quoted_name)
|
|||
if ((tokentab3[i].flags & FLAG_CXX) != 0
|
||||
&& par_state->language ()->la_language != language_cplus)
|
||||
break;
|
||||
gdb_assert ((tokentab3[i].flags & FLAG_C) == 0);
|
||||
|
||||
pstate->lexptr += 3;
|
||||
yylval.opcode = tokentab3[i].opcode;
|
||||
|
@ -2563,6 +2580,7 @@ lex_one_token (struct parser_state *par_state, bool *is_quoted_name)
|
|||
if ((tokentab2[i].flags & FLAG_CXX) != 0
|
||||
&& par_state->language ()->la_language != language_cplus)
|
||||
break;
|
||||
gdb_assert ((tokentab3[i].flags & FLAG_C) == 0);
|
||||
|
||||
pstate->lexptr += 2;
|
||||
yylval.opcode = tokentab2[i].opcode;
|
||||
|
@ -2857,6 +2875,10 @@ lex_one_token (struct parser_state *par_state, bool *is_quoted_name)
|
|||
if ((ident_tokens[i].flags & FLAG_CXX) != 0
|
||||
&& par_state->language ()->la_language != language_cplus)
|
||||
break;
|
||||
if ((ident_tokens[i].flags & FLAG_C) != 0
|
||||
&& par_state->language ()->la_language != language_c
|
||||
&& par_state->language ()->la_language != language_objc)
|
||||
break;
|
||||
|
||||
if ((ident_tokens[i].flags & FLAG_SHADOW) != 0)
|
||||
{
|
||||
|
|
|
@ -58,7 +58,7 @@ static void c_type_print_varspec_prefix (struct type *,
|
|||
/* Print "const", "volatile", or address space modifiers. */
|
||||
static void c_type_print_modifier (struct type *,
|
||||
struct ui_file *,
|
||||
int, int);
|
||||
int, int, enum language);
|
||||
|
||||
static void c_type_print_base_1 (struct type *type, struct ui_file *stream,
|
||||
int show, int level, enum language language,
|
||||
|
@ -337,7 +337,9 @@ cp_type_print_method_args (struct type *mtype, const char *prefix,
|
|||
fprintf_filtered (stream, " volatile");
|
||||
|
||||
if (TYPE_RESTRICT (domain))
|
||||
fprintf_filtered (stream, " restrict");
|
||||
fprintf_filtered (stream, (language == language_cplus
|
||||
? " __restrict__"
|
||||
: " restrict"));
|
||||
|
||||
if (TYPE_ATOMIC (domain))
|
||||
fprintf_filtered (stream, " _Atomic");
|
||||
|
@ -383,7 +385,7 @@ c_type_print_varspec_prefix (struct type *type,
|
|||
stream, show, 1, 1, language, flags,
|
||||
podata);
|
||||
fprintf_filtered (stream, "*");
|
||||
c_type_print_modifier (type, stream, 1, need_post_space);
|
||||
c_type_print_modifier (type, stream, 1, need_post_space, language);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_MEMBERPTR:
|
||||
|
@ -420,7 +422,7 @@ c_type_print_varspec_prefix (struct type *type,
|
|||
stream, show, 1, 0, language, flags,
|
||||
podata);
|
||||
fprintf_filtered (stream, TYPE_CODE(type) == TYPE_CODE_REF ? "&" : "&&");
|
||||
c_type_print_modifier (type, stream, 1, need_post_space);
|
||||
c_type_print_modifier (type, stream, 1, need_post_space, language);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_METHOD:
|
||||
|
@ -481,7 +483,8 @@ c_type_print_varspec_prefix (struct type *type,
|
|||
|
||||
static void
|
||||
c_type_print_modifier (struct type *type, struct ui_file *stream,
|
||||
int need_pre_space, int need_post_space)
|
||||
int need_pre_space, int need_post_space,
|
||||
enum language language)
|
||||
{
|
||||
int did_print_modifier = 0;
|
||||
const char *address_space_id;
|
||||
|
@ -509,7 +512,9 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
|
|||
{
|
||||
if (did_print_modifier || need_pre_space)
|
||||
fprintf_filtered (stream, " ");
|
||||
fprintf_filtered (stream, "restrict");
|
||||
fprintf_filtered (stream, (language == language_cplus
|
||||
? "__restrict__"
|
||||
: "restrict"));
|
||||
did_print_modifier = 1;
|
||||
}
|
||||
|
||||
|
@ -1050,7 +1055,7 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
|
|||
hash_holder.reset (local_flags.local_typedefs);
|
||||
}
|
||||
|
||||
c_type_print_modifier (type, stream, 0, 1);
|
||||
c_type_print_modifier (type, stream, 0, 1, language);
|
||||
if (TYPE_CODE (type) == TYPE_CODE_UNION)
|
||||
fprintf_filtered (stream, "union ");
|
||||
else if (TYPE_DECLARED_CLASS (type))
|
||||
|
@ -1477,7 +1482,7 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
|
|||
if (show <= 0
|
||||
&& TYPE_NAME (type) != NULL)
|
||||
{
|
||||
c_type_print_modifier (type, stream, 0, 1);
|
||||
c_type_print_modifier (type, stream, 0, 1, language);
|
||||
|
||||
/* If we have "typedef struct foo {. . .} bar;" do we want to
|
||||
print it as "struct foo" or as "bar"? Pick the latter for
|
||||
|
@ -1542,7 +1547,7 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
|
|||
break;
|
||||
|
||||
case TYPE_CODE_ENUM:
|
||||
c_type_print_modifier (type, stream, 0, 1);
|
||||
c_type_print_modifier (type, stream, 0, 1, language);
|
||||
fprintf_filtered (stream, "enum ");
|
||||
if (TYPE_DECLARED_CLASS (type))
|
||||
fprintf_filtered (stream, "class ");
|
||||
|
@ -1615,7 +1620,7 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
|
|||
|
||||
local_flags.local_typedefs = NULL;
|
||||
|
||||
c_type_print_modifier (type, stream, 0, 1);
|
||||
c_type_print_modifier (type, stream, 0, 1, language);
|
||||
fprintf_filtered (stream, "flag ");
|
||||
print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
|
||||
if (show > 0)
|
||||
|
@ -1689,7 +1694,7 @@ c_type_print_base_1 (struct type *type, struct ui_file *stream,
|
|||
type name, then complain. */
|
||||
if (TYPE_NAME (type) != NULL)
|
||||
{
|
||||
c_type_print_modifier (type, stream, 0, 1);
|
||||
c_type_print_modifier (type, stream, 0, 1, language);
|
||||
print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2020-03-14 Tom Tromey <tom@tromey.com>
|
||||
|
||||
* gdb.base/cvexpr.exp: Add test for _Atomic and restrict.
|
||||
|
||||
2020-03-14 Tom de Vries <tdevries@suse.de>
|
||||
|
||||
* gdb.mi/mi-fortran-modules.exp: Use exp_continue.
|
||||
|
|
|
@ -509,3 +509,14 @@ foreach testspec $specs {
|
|||
do_test $prefix $opts
|
||||
}
|
||||
}
|
||||
|
||||
# These tests don't rely on the debug format.
|
||||
gdb_test "ptype _Atomic int" "type = _Atomic int"
|
||||
gdb_test "ptype int * restrict" "type = int \\* restrict"
|
||||
|
||||
# C++ does not have "restrict".
|
||||
gdb_test_no_output "set lang c++"
|
||||
gdb_test "ptype int * restrict" "A syntax error in expression.*"
|
||||
|
||||
# There is a GCC extension for __restrict__, though.
|
||||
gdb_test "ptype int * __restrict__" "type = int \\* __restrict__"
|
||||
|
|
|
@ -33,12 +33,14 @@ type_stack::insert (enum type_pieces tp)
|
|||
|
||||
gdb_assert (tp == tp_pointer || tp == tp_reference
|
||||
|| tp == tp_rvalue_reference || tp == tp_const
|
||||
|| tp == tp_volatile);
|
||||
|| tp == tp_volatile || tp == tp_restrict
|
||||
|| tp == tp_atomic);
|
||||
|
||||
/* If there is anything on the stack (we know it will be a
|
||||
tp_pointer), insert the qualifier above it. Otherwise, simply
|
||||
push this on the top of the stack. */
|
||||
if (!m_elements.empty () && (tp == tp_const || tp == tp_volatile))
|
||||
if (!m_elements.empty () && (tp == tp_const || tp == tp_volatile
|
||||
|| tp == tp_restrict))
|
||||
slot = 1;
|
||||
else
|
||||
slot = 0;
|
||||
|
@ -88,6 +90,12 @@ type_stack::follow_type_instance_flags ()
|
|||
case tp_volatile:
|
||||
flags |= TYPE_INSTANCE_FLAG_VOLATILE;
|
||||
break;
|
||||
case tp_atomic:
|
||||
flags |= TYPE_INSTANCE_FLAG_ATOMIC;
|
||||
break;
|
||||
case tp_restrict:
|
||||
flags |= TYPE_INSTANCE_FLAG_RESTRICT;
|
||||
break;
|
||||
default:
|
||||
gdb_assert_not_reached ("unrecognized tp_ value in follow_types");
|
||||
}
|
||||
|
@ -102,6 +110,8 @@ type_stack::follow_types (struct type *follow_type)
|
|||
int make_const = 0;
|
||||
int make_volatile = 0;
|
||||
int make_addr_space = 0;
|
||||
bool make_restrict = false;
|
||||
bool make_atomic = false;
|
||||
int array_size;
|
||||
|
||||
while (!done)
|
||||
|
@ -109,19 +119,7 @@ type_stack::follow_types (struct type *follow_type)
|
|||
{
|
||||
case tp_end:
|
||||
done = 1;
|
||||
if (make_const)
|
||||
follow_type = make_cv_type (make_const,
|
||||
TYPE_VOLATILE (follow_type),
|
||||
follow_type, 0);
|
||||
if (make_volatile)
|
||||
follow_type = make_cv_type (TYPE_CONST (follow_type),
|
||||
make_volatile,
|
||||
follow_type, 0);
|
||||
if (make_addr_space)
|
||||
follow_type = make_type_with_address_space (follow_type,
|
||||
make_addr_space);
|
||||
make_const = make_volatile = 0;
|
||||
make_addr_space = 0;
|
||||
goto process_qualifiers;
|
||||
break;
|
||||
case tp_const:
|
||||
make_const = 1;
|
||||
|
@ -132,41 +130,39 @@ type_stack::follow_types (struct type *follow_type)
|
|||
case tp_space_identifier:
|
||||
make_addr_space = pop_int ();
|
||||
break;
|
||||
case tp_atomic:
|
||||
make_atomic = true;
|
||||
break;
|
||||
case tp_restrict:
|
||||
make_restrict = true;
|
||||
break;
|
||||
case tp_pointer:
|
||||
follow_type = lookup_pointer_type (follow_type);
|
||||
goto process_qualifiers;
|
||||
case tp_reference:
|
||||
follow_type = lookup_lvalue_reference_type (follow_type);
|
||||
goto process_qualifiers;
|
||||
case tp_rvalue_reference:
|
||||
follow_type = lookup_rvalue_reference_type (follow_type);
|
||||
process_qualifiers:
|
||||
if (make_const)
|
||||
follow_type = make_cv_type (make_const,
|
||||
TYPE_VOLATILE (follow_type),
|
||||
follow_type = make_cv_type (make_const,
|
||||
TYPE_VOLATILE (follow_type),
|
||||
follow_type, 0);
|
||||
if (make_volatile)
|
||||
follow_type = make_cv_type (TYPE_CONST (follow_type),
|
||||
make_volatile,
|
||||
follow_type = make_cv_type (TYPE_CONST (follow_type),
|
||||
make_volatile,
|
||||
follow_type, 0);
|
||||
if (make_addr_space)
|
||||
follow_type = make_type_with_address_space (follow_type,
|
||||
follow_type = make_type_with_address_space (follow_type,
|
||||
make_addr_space);
|
||||
if (make_restrict)
|
||||
follow_type = make_restrict_type (follow_type);
|
||||
if (make_atomic)
|
||||
follow_type = make_atomic_type (follow_type);
|
||||
make_const = make_volatile = 0;
|
||||
make_addr_space = 0;
|
||||
break;
|
||||
case tp_reference:
|
||||
follow_type = lookup_lvalue_reference_type (follow_type);
|
||||
goto process_reference;
|
||||
case tp_rvalue_reference:
|
||||
follow_type = lookup_rvalue_reference_type (follow_type);
|
||||
process_reference:
|
||||
if (make_const)
|
||||
follow_type = make_cv_type (make_const,
|
||||
TYPE_VOLATILE (follow_type),
|
||||
follow_type, 0);
|
||||
if (make_volatile)
|
||||
follow_type = make_cv_type (TYPE_CONST (follow_type),
|
||||
make_volatile,
|
||||
follow_type, 0);
|
||||
if (make_addr_space)
|
||||
follow_type = make_type_with_address_space (follow_type,
|
||||
make_addr_space);
|
||||
make_const = make_volatile = 0;
|
||||
make_addr_space = 0;
|
||||
make_restrict = make_atomic = false;
|
||||
break;
|
||||
case tp_array:
|
||||
array_size = pop_int ();
|
||||
|
|
|
@ -40,6 +40,8 @@ enum type_pieces
|
|||
tp_const,
|
||||
tp_volatile,
|
||||
tp_space_identifier,
|
||||
tp_atomic,
|
||||
tp_restrict,
|
||||
tp_type_stack,
|
||||
tp_kind
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue