Add C parser support for "restrict" and "_Atomic"

Message ID 20200301030013.4619-1-tom@tromey.com
State New
Headers show
Series
  • Add C parser support for "restrict" and "_Atomic"
Related show

Commit Message

Tom Tromey March 1, 2020, 3 a.m.
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.
It is done only for C and Objective C, not C++.

I wasn't sure if "restrict" should be marked FLAG_SHADOW to support
older dialects of C, where this was not a keyword.

gdb/ChangeLog
2020-02-29  Tom Tromey  <tom@tromey.com>

	* 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" and "_Atomic".
	(lex_one_token): Handle FLAG_C.

gdb/testsuite/ChangeLog
2020-02-29  Tom Tromey  <tom@tromey.com>

	* gdb.base/cvexpr.exp: Add test for _Atomic and restrict.
---
 gdb/ChangeLog                     | 19 ++++++++
 gdb/c-exp.y                       | 52 ++++++++++++++-------
 gdb/testsuite/ChangeLog           |  4 ++
 gdb/testsuite/gdb.base/cvexpr.exp |  4 ++
 gdb/type-stack.c                  | 76 +++++++++++++++----------------
 gdb/type-stack.h                  |  2 +
 6 files changed, 101 insertions(+), 56 deletions(-)

-- 
2.17.2

Comments

Ruslan Kabatsayev March 1, 2020, 4:16 p.m. | #1
On Sun, 1 Mar 2020 at 06:01, Tom Tromey <tom@tromey.com> wrote:
>

> 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.

> It is done only for C and Objective C, not C++.


GCC has the keywords __restrict__ and __restrict that work in C++ too.
These are also affected, including the use in C++.

>

> I wasn't sure if "restrict" should be marked FLAG_SHADOW to support

> older dialects of C, where this was not a keyword.

>

> gdb/ChangeLog

> 2020-02-29  Tom Tromey  <tom@tromey.com>

>

>         * 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" and "_Atomic".

>         (lex_one_token): Handle FLAG_C.

>

> gdb/testsuite/ChangeLog

> 2020-02-29  Tom Tromey  <tom@tromey.com>

>

>         * gdb.base/cvexpr.exp: Add test for _Atomic and restrict.

> ---

>  gdb/ChangeLog                     | 19 ++++++++

>  gdb/c-exp.y                       | 52 ++++++++++++++-------

>  gdb/testsuite/ChangeLog           |  4 ++

>  gdb/testsuite/gdb.base/cvexpr.exp |  4 ++

>  gdb/type-stack.c                  | 76 +++++++++++++++----------------

>  gdb/type-stack.h                  |  2 +

>  6 files changed, 101 insertions(+), 56 deletions(-)

>

> diff --git a/gdb/c-exp.y b/gdb/c-exp.y

> index 3403a857a83..1b35ef2e60a 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 <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,6 +2353,10 @@ enum token_flag

>

>    FLAG_CXX = 1,

>

> +  /* If this bit is set, the token is C-only.  */

> +

> +  FLAG_C = 1,

> +

>    /* 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.  */

> @@ -2416,6 +2428,8 @@ 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, 0},

> +    {"_Atomic", ATOMIC, OP_NULL, 0},

>      {"enum", ENUM, OP_NULL, 0},

>      {"long", LONG, OP_NULL, 0},

>      {"true", TRUEKEYWORD, OP_NULL, FLAG_CXX},

> @@ -2550,6 +2564,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 +2578,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 +2873,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/testsuite/gdb.base/cvexpr.exp b/gdb/testsuite/gdb.base/cvexpr.exp

> index 92a073a774e..cf5d2c4a553 100644

> --- a/gdb/testsuite/gdb.base/cvexpr.exp

> +++ b/gdb/testsuite/gdb.base/cvexpr.exp

> @@ -509,3 +509,7 @@ 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"

> diff --git a/gdb/type-stack.c b/gdb/type-stack.c

> index ab7e0261cad..73b7d5a8dfc 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 ee004d1be8d..8060f2fea78 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.17.2

>
Tom Tromey March 4, 2020, 12:39 a.m. | #2
>>>>> "Ruslan" == Ruslan Kabatsayev <b7.10110111@gmail.com> writes:


Ruslan> On Sun, 1 Mar 2020 at 06:01, Tom Tromey <tom@tromey.com> wrote:
>> 

>> 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.

>> It is done only for C and Objective C, not C++.


Ruslan> GCC has the keywords __restrict__ and __restrict that work in C++ too.
Ruslan> These are also affected, including the use in C++.

Thanks, I'll add those.

>> I wasn't sure if "restrict" should be marked FLAG_SHADOW to support

>> older dialects of C, where this was not a keyword.


I'll have to check how C++ prints a restrict type.
Maybe gdb will need another tweak here.

>> +    {"restrict", RESTRICT, OP_NULL, 0},


I forgot to actually use FLAG_C here, oops.

Tom
Tom Tromey March 14, 2020, 6:30 p.m. | #3
>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:


Ruslan> GCC has the keywords __restrict__ and __restrict that work in C++ too.
Ruslan> These are also affected, including the use in C++.

Tom> Thanks, I'll add those.

>>> I wasn't sure if "restrict" should be marked FLAG_SHADOW to support

>>> older dialects of C, where this was not a keyword.


Tom> I'll have to check how C++ prints a restrict type.
Tom> Maybe gdb will need another tweak here.

>>> +    {"restrict", RESTRICT, OP_NULL, 0},


Tom> I forgot to actually use FLAG_C here, oops.

Here's an updated patch.
I'm checking this in.

Tom

commit fd7fda86e41744cd6b052ab63d0496f6208413a1
Author: Tom Tromey <tom@tromey.com>
Date:   Sat Mar 14 12:11:42 2020 -0600

    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.

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a4ed9944407..4869693a341 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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-13  Tom Tromey  <tom@tromey.com>
 
 	* value.h (val_print): Don't declare.
diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 3403a857a83..50a2eef98b5 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 <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)
 	  {
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 1f27b566467..50d0eaa2dde 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 ec22de89d57..1f16e344563 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2020-03-14  Tom Tromey  <tom@tromey.com>
+
+	* gdb.base/cvexpr.exp: Add test for _Atomic and restrict.
+
 2020-03-13  Tom Tromey  <tom@tromey.com>
 
 	* gdb.base/printcmds.exp (test_print_strings): Add regression
diff --git a/gdb/testsuite/gdb.base/cvexpr.exp b/gdb/testsuite/gdb.base/cvexpr.exp
index 92a073a774e..d905198a72c 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 ab7e0261cad..73b7d5a8dfc 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 ee004d1be8d..8060f2fea78 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
   };

Patch

diff --git a/gdb/c-exp.y b/gdb/c-exp.y
index 3403a857a83..1b35ef2e60a 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 <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,6 +2353,10 @@  enum token_flag
 
   FLAG_CXX = 1,
 
+  /* If this bit is set, the token is C-only.  */
+
+  FLAG_C = 1,
+
   /* 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.  */
@@ -2416,6 +2428,8 @@  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, 0},
+    {"_Atomic", ATOMIC, OP_NULL, 0},
     {"enum", ENUM, OP_NULL, 0},
     {"long", LONG, OP_NULL, 0},
     {"true", TRUEKEYWORD, OP_NULL, FLAG_CXX},
@@ -2550,6 +2564,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 +2578,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 +2873,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/testsuite/gdb.base/cvexpr.exp b/gdb/testsuite/gdb.base/cvexpr.exp
index 92a073a774e..cf5d2c4a553 100644
--- a/gdb/testsuite/gdb.base/cvexpr.exp
+++ b/gdb/testsuite/gdb.base/cvexpr.exp
@@ -509,3 +509,7 @@  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"
diff --git a/gdb/type-stack.c b/gdb/type-stack.c
index ab7e0261cad..73b7d5a8dfc 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 ee004d1be8d..8060f2fea78 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
   };