From 3293bbaffac9a22fc6d1a08ac6602a4a63b5e68b Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Sat, 14 Mar 2020 12:11:42 -0600 Subject: [PATCH] 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 * 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) : 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) : New constant. (ident_tokens): Add "restrict", "__restrict__", "__restrict", and "_Atomic". (lex_one_token): Handle FLAG_C. gdb/testsuite/ChangeLog 2020-03-14 Tom Tromey * gdb.base/cvexpr.exp: Add test for _Atomic and restrict. --- gdb/ChangeLog | 25 ++++++++++ gdb/c-exp.y | 56 ++++++++++++++++------- gdb/c-typeprint.c | 27 ++++++----- gdb/testsuite/ChangeLog | 4 ++ gdb/testsuite/gdb.base/cvexpr.exp | 11 +++++ gdb/type-stack.c | 76 +++++++++++++++---------------- gdb/type-stack.h | 2 + 7 files changed, 133 insertions(+), 68 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 04db5e7673..a0d9758418 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,28 @@ +2020-03-14 Tom Tromey + + * 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) : 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) : New constant. + (ident_tokens): Add "restrict", "__restrict__", "__restrict", and + "_Atomic". + (lex_one_token): Handle FLAG_C. + 2020-03-14 Kamil Rytarowski * m68k-bsd-nat.c (fetch_registers): New variable lwp and pass diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 3403a857a8..50a2eef98b 100644 --- a/gdb/c-exp.y +++ b/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 DOLLAR_VARIABLE @@ -1169,36 +1170,43 @@ variable: name_not_typename } ; -space_identifier : '@' NAME - { - cpstate->type_stack.insert (pstate, - copy_name ($2.stoken).c_str ()); - } - ; - const_or_volatile: const_or_volatile_noopt | ; -cv_with_space_id : const_or_volatile space_identifier const_or_volatile +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_or_space_identifier_noopt: cv_with_space_id - | const_or_volatile_noopt +qualifier_seq_noopt: + single_qualifier + | qualifier_seq single_qualifier ; -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) { diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index 1f27b56646..50d0eaa2dd 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -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 diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 07ed021aa1..a3114d3f57 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2020-03-14 Tom Tromey + + * gdb.base/cvexpr.exp: Add test for _Atomic and restrict. + 2020-03-14 Tom de Vries * gdb.mi/mi-fortran-modules.exp: Use exp_continue. diff --git a/gdb/testsuite/gdb.base/cvexpr.exp b/gdb/testsuite/gdb.base/cvexpr.exp index 92a073a774..d905198a72 100644 --- a/gdb/testsuite/gdb.base/cvexpr.exp +++ b/gdb/testsuite/gdb.base/cvexpr.exp @@ -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__" diff --git a/gdb/type-stack.c b/gdb/type-stack.c index ab7e0261ca..73b7d5a8df 100644 --- a/gdb/type-stack.c +++ b/gdb/type-stack.c @@ -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 (); diff --git a/gdb/type-stack.h b/gdb/type-stack.h index ee004d1be8..8060f2fea7 100644 --- a/gdb/type-stack.h +++ b/gdb/type-stack.h @@ -40,6 +40,8 @@ enum type_pieces tp_const, tp_volatile, tp_space_identifier, + tp_atomic, + tp_restrict, tp_type_stack, tp_kind }; -- 2.34.1