+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
 
 /* 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
 
                        }
        ;
 
-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
                            (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); }
        ;
 
 
   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);
 
     {"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},
        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;
        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;
        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)
          {
 
 /* 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,
        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");
                                   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:
                                   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:
 
 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;
     {
       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;
     }
 
       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))
   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
       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 ");
 
        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)
          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
 
+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.
 
        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__"
 
 
   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;
       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");
       }
   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)
       {
       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;
       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 ();
 
     tp_const, 
     tp_volatile, 
     tp_space_identifier,
+    tp_atomic,
+    tp_restrict,
     tp_type_stack,
     tp_kind
   };