From 31f6b60f650a72d7727d386cef160f4baae70f38 Mon Sep 17 00:00:00 2001 From: lemon Date: Thu, 11 Dec 2025 17:57:07 +0100 Subject: _Alignof and stuff --- c/c.c | 29 ++++++++++++++++++----------- common.h | 2 ++ embedfilesdir.c | 9 +++++++++ io.c | 4 ++-- test/13-c11.c | 22 ++++++++++++++++++++++ 5 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 test/13-c11.c diff --git a/c/c.c b/c/c.c index d5e4d9e..259058f 100644 --- a/c/c.c +++ b/c/c.c @@ -443,13 +443,17 @@ subscriptcheck(const struct expr *ex, const struct expr *rhs, const struct span return ty; } -static void /* 6.5.3.4 The sizeof operator */ -sizeofcheck(const struct span *span, union type ty) +static void /* 6.5.3.4 The sizeof and _Alignof operators */ +sizeofalignofcheck(const struct span *span, enum toktag tt, union type ty, const struct expr *ex) { if (isincomplete(ty)) - error(span, "cannot apply sizeof to incomplete type '%ty'", ty); + error(span, "cannot apply %'tt to incomplete type '%ty'", tt); else if (ty.t == TYFUNC) - error(span, "cannot apply sizeof to function type '%ty'", ty); + error(span, "cannot apply %'tt to function type '%ty'", tt); + else if (tt == TKWsizeof && ex && ex->t == EGETF && ex->fld.bitsiz) + error(span, "cannot apply %'tt to bitfield", tt); + if (tt != TKWsizeof && ex && ccopt.pedant) + warn(span, "%'tt applied to an expression is a GNU extension", tt); } static bool /* 6.5.8 Relational operators */ @@ -998,25 +1002,28 @@ Unary: ex = mkexpr(ESYM, tk.span, decl->ty, .qual = decl->qual, .sym = decl); } break; - case TKWsizeof: + case TKWsizeof: case TKW_Alignof: case TKWalignof: span = tk.span; - if (!match(cm, NULL, '(')) /* sizeof expr */ + if (!match(cm, NULL, '(')) /* sizeof/alignof expr */ goto Unops; - else if (isdecltok(cm)) { /* sizeof (type) */ + else if (isdecltok(cm)) { /* sizeof/alignof (type) */ + enum toktag tt = tk.t; struct declstate st = { DCASTEXPR }; ty = pdecl(&st, cm).ty; peek(cm, &tk); if (expect(cm, ')', NULL)) joinspan(&span.ex, tk.span.ex); - } else { /* sizeof expr */ + sizeofalignofcheck(&span, tt, ty, NULL); + } else { /* sizeof/alignof expr */ + enum toktag tt = tk.t; tmp = commaexpr(cm); peek(cm, &tk); if (expect(cm, ')', NULL)) joinspan(&span.ex, tk.span.ex); ppostfixopers(cm, &tmp); ty = tmp.ty; + sizeofalignofcheck(&span, tt, ty, &tmp); } - sizeofcheck(&span, ty); ex = mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = typesize(ty)); break; case TKW__builtin_va_arg: @@ -1081,8 +1088,8 @@ Unary: error(&span, "cannot take address of bitfield"); ex = mkexpr(EADDROF, span, mkptrtype(ex.ty, ex.qual), .sub = exprdup(cm, &ex)); break; - case TKWsizeof: - sizeofcheck(&span, ex.ty); + case TKWsizeof: case TKW_Alignof: case TKWalignof: + sizeofalignofcheck(&span, unops[nunop].tt, ex.ty, &ex); ex = mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = typesize(ex.ty)); break; default: assert(0); diff --git a/common.h b/common.h index ce7d604..2b2bfd7 100644 --- a/common.h +++ b/common.h @@ -16,6 +16,7 @@ typedef unsigned short ushort; typedef unsigned long long uvlong; typedef signed long long vlong; typedef unsigned uint; + #if __STDC_VERSION__ >= 202311L #define NORETURN [[noreturn]] #elif __STDC_VERSION__ >= 201112L @@ -29,6 +30,7 @@ typedef unsigned uint; #else #define HAS_BUILTIN(_) 0 #endif + #define static_assert(x) _Static_assert(x, #x) #define in_range(x, Lo, Hi) ((uint) (x) - (Lo) <= (Hi) - (Lo)) /* lo <= x <= hi; lo > 0, hi > 0 */ #define alignup(x, A) (((x) + ((A) - 1)) & -(A)) diff --git a/embedfilesdir.c b/embedfilesdir.c index 72a2ce1..7d97f98 100644 --- a/embedfilesdir.c +++ b/embedfilesdir.c @@ -85,6 +85,15 @@ typedef __builtin_va_list __gnuc_va_list;\n\ {"stdnoreturn.h", S("\ #define noreturn _Noreturn\n\ +")}, + +{"stdalign.h", S("\ +#if __STDC_VERSION__ < 202311L\n\ +#define alignas _Alignas\n\ +#define alignof _Alignof\n\ +#define __alignas_is_defined 1\n\ +#define __alignof_is_defined 1\n\ +#endif\n\ ")}, {NULL} diff --git a/io.c b/io.c index b2d4364..dc4cd5d 100644 --- a/io.c +++ b/io.c @@ -595,8 +595,8 @@ vbfmt(struct wbuf *out, const char *fmt, va_list ap) #include "c/keywords.def" #undef _ }; - n += bfmt(buf, "%s", tab[tok->t - TKWBEGIN_]); - break; + tok->s = tab[tok->t - TKWBEGIN_]; + tok->len = strlen(tok->s); } goto Tok; } diff --git a/test/13-c11.c b/test/13-c11.c new file mode 100644 index 0000000..479c2d7 --- /dev/null +++ b/test/13-c11.c @@ -0,0 +1,22 @@ +/* CFLAGS: -std=c11 -Werror */ +/* EXPECT: +*/ + +#include +#include +#include + +noreturn void quit(int x) { + exit(x); +} + +int foo(int x) { + if (x < 0) quit(alignof(int *)); + else return x; +} + +struct x{int h:2;} X; +int main(int argc, char **argv) { + return foo(0); +} + -- cgit v1.2.3