Add C parser support for "restrict" and "_Atomic"
authorTom Tromey <tom@tromey.com>
Sat, 14 Mar 2020 18:11:42 +0000 (12:11 -0600)
committerTom Tromey <tom@tromey.com>
Sat, 14 Mar 2020 18:32:10 +0000 (12:32 -0600)
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.

gdb/ChangeLog
gdb/c-exp.y
gdb/c-typeprint.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/cvexpr.exp
gdb/type-stack.c
gdb/type-stack.h

index 04db5e76734d0de121fa9fa782b26199a5eacd49..a0d9758418978981967f5c418ce3291007d396e6 100644 (file)
@@ -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
index 3403a857a8396190b039dd2ae595e258f3c96990..50a2eef98b58614bf41cafada3359167e92bae8f 100644 (file)
@@ -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
-               {
-                 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)
          {
index 1f27b5664673ef4c9b2341aba8605d6f1b8a2b22..50d0eaa2ddedb8c863f51cf0a703aef35e996576 100644 (file)
@@ -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
index 07ed021aa1b7e0f066a465b4968da650b165da37..a3114d3f574614e85442d381be88b98a47146c72 100644 (file)
@@ -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.
index 92a073a774e4bb0a65093a2b25d8ea574ee9c3d5..d905198a72c3e5abd5398dad4d31d9ad091731be 100644 (file)
@@ -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__"
index ab7e0261cad920fdc68d7355f1253e8295bb3225..73b7d5a8dfc0a6dd32d1ab356dad1c280e797232 100644 (file)
@@ -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 ();
index ee004d1be8d0547031e83b7cf5de9734f540dbc4..8060f2fea7827e4b839b439e23f62ebf332ef4d6 100644 (file)
@@ -40,6 +40,8 @@ enum type_pieces
     tp_const, 
     tp_volatile, 
     tp_space_identifier,
+    tp_atomic,
+    tp_restrict,
     tp_type_stack,
     tp_kind
   };