diff --git a/parse.c b/parse.c index 763bf22..b178928 100644 --- a/parse.c +++ b/parse.c @@ -410,6 +410,13 @@ static Type *typespec(Token **rest, Token *tok, VarAttr *attr) { continue; } + // These keywords are recognized but ignored. + if (consume(&tok, tok, "const") || consume(&tok, tok, "volatile") || + consume(&tok, tok, "auto") || consume(&tok, tok, "register") || + consume(&tok, tok, "restrict") || consume(&tok, tok, "__restrict") || + consume(&tok, tok, "__restrict__") || consume(&tok, tok, "_Noreturn")) + continue; + if (equal(tok, "_Alignas")) { if (!attr) error_tok(tok, "_Alignas is not allowed in this context"); @@ -595,10 +602,21 @@ static Type *type_suffix(Token **rest, Token *tok, Type *ty) { return ty; } -// declarator = "*"* ("(" ident ")" | "(" declarator ")" | ident) type-suffix -static Type *declarator(Token **rest, Token *tok, Type *ty) { - while (consume(&tok, tok, "*")) +// pointers = ("*" ("const" | "volatile" | "restrict")*)* +static Type *pointers(Token **rest, Token *tok, Type *ty) { + while (consume(&tok, tok, "*")) { ty = pointer_to(ty); + while (equal(tok, "const") || equal(tok, "volatile") || equal(tok, "restrict") || + equal(tok, "__restrict") || equal(tok, "__restrict__")) + tok = tok->next; + } + *rest = tok; + return ty; +} + +// declarator = pointers ("(" ident ")" | "(" declarator ")" | ident) type-suffix +static Type *declarator(Token **rest, Token *tok, Type *ty) { + ty = pointers(&tok, tok, ty); if (equal(tok, "(")) { Token *start = tok; @@ -616,12 +634,9 @@ static Type *declarator(Token **rest, Token *tok, Type *ty) { return ty; } -// abstract-declarator = "*"* ("(" abstract-declarator ")")? type-suffix +// abstract-declarator = pointers ("(" abstract-declarator ")")? type-suffix static Type *abstract_declarator(Token **rest, Token *tok, Type *ty) { - while (equal(tok, "*")) { - ty = pointer_to(ty); - tok = tok->next; - } + ty = pointers(&tok, tok, ty); if (equal(tok, "(")) { Token *start = tok; @@ -1093,6 +1108,8 @@ static bool is_typename(Token *tok) { static char *kw[] = { "void", "_Bool", "char", "short", "int", "long", "struct", "union", "typedef", "enum", "static", "extern", "_Alignas", "signed", "unsigned", + "const", "volatile", "auto", "register", "restrict", "__restrict", + "__restrict__", "_Noreturn", }; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) diff --git a/test/compat.c b/test/compat.c new file mode 100644 index 0000000..a636204 --- /dev/null +++ b/test/compat.c @@ -0,0 +1,17 @@ +#include "test.h" + +_Noreturn noreturn_fn(int restrict x) { + exit(0); +} + +int main() { + { volatile x; } + { int volatile x; } + { volatile int x; } + { volatile int volatile volatile x; } + { int volatile * volatile volatile x; } + { auto ** restrict __restrict __restrict__ const volatile *x; } + + printf("OK\n"); + return 0; +} diff --git a/test/const.c b/test/const.c new file mode 100644 index 0000000..a45478b --- /dev/null +++ b/test/const.c @@ -0,0 +1,14 @@ +#include "test.h" + +int main() { + { const x; } + { int const x; } + { const int x; } + { const int const const x; } + ASSERT(5, ({ const x = 5; x; })); + ASSERT(8, ({ const x = 8; int *const y=&x; *y; })); + ASSERT(6, ({ const x = 6; *(const * const)&x; })); + + printf("OK\n"); + return 0; +} diff --git a/test/test.h b/test/test.h index de46a32..3d5f5a9 100644 --- a/test/test.h +++ b/test/test.h @@ -5,3 +5,4 @@ int printf(char *fmt, ...); int sprintf(char *buf, char *fmt, ...); int strcmp(char *p, char *q); int memcmp(char *p, char *q, long n); +void exit(int n); diff --git a/tokenize.c b/tokenize.c index e28dcaa..0fbce44 100644 --- a/tokenize.c +++ b/tokenize.c @@ -127,7 +127,8 @@ static bool is_keyword(Token *tok) { "struct", "union", "short", "long", "void", "typedef", "_Bool", "enum", "static", "goto", "break", "continue", "switch", "case", "default", "extern", "_Alignof", "_Alignas", "do", "signed", - "unsigned", + "unsigned", "const", "volatile", "auto", "register", "restrict", + "__restrict", "__restrict__", "_Noreturn", }; for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)