aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-12-22 20:07:17 +0100
committerlemon <lsof@mailbox.org>2025-12-22 20:18:38 +0100
commit3f67cc35c7659a3c6921caaabac8b6a4399e72cb (patch)
tree8f95d4d7c4528d5a3e6292135f6c04903ad1013d
parent1aa5016265ae67fac625d0ba4e261ae7559ccb10 (diff)
c: add _Generic
-rw-r--r--c/c.c53
-rw-r--r--todo.txt2
2 files changed, 54 insertions, 1 deletions
diff --git a/c/c.c b/c/c.c
index a93dcc6..e070924 100644
--- a/c/c.c
+++ b/c/c.c
@@ -926,6 +926,55 @@ vaargexpr(struct comp *cm, struct span *span)
return ex;
}
+static struct expr
+genericexpr(struct comp *cm, struct span *span)
+{
+ struct token tk;
+ if (expect(cm, '(', "after _Generic")) {
+ struct expr control = expr(cm), dfault = {0}, ex = {0};
+ expect(cm, ',', NULL);
+ for (;;) {
+ if (match(cm, &tk, TKWdefault)) {
+ expect(cm, ':', NULL);
+ if (dfault.t) {
+ error(&tk.span, "duplicate 'default' specifier in generic selection expression");
+ (void)expr(cm);
+ } else {
+ dfault = expr(cm);
+ }
+ } else {
+ struct decl decl = pdecl(&(struct declstate){DCASTEXPR}, cm);
+ union type ty = decl.ty;
+ expect(cm, ':', NULL);
+ if (!ex.t &&
+ (typedecay(ty).bits == typedecay(control.ty).bits
+ || ((ty.t == TYENUM || control.ty.t == TYENUM) && scalartypet(ty) == scalartypet(control.ty))))
+ ex = expr(cm);
+ else
+ (void)expr(cm);
+ }
+ if (match(cm, &tk, ')')) break;
+ else if (!expect(cm, ',', "or `)'")) {
+ if (!isdecltok(cm)) {
+ peek(cm, &tk); /* want the span */
+ break;
+ }
+ }
+ }
+ if (!ex.t) ex = dfault;
+ if (!ex.t) {
+ error(&control.span,
+ "controlling type '%ty' not compatible with any generic association type",
+ control.ty);
+ ex.ty.t = TYINT;
+ }
+ ex.span = *span;
+ joinspan(&ex.span.ex, tk.span.ex);
+ return ex;
+ }
+ return mkexpr(ENUMLIT,*span,mktype(TYINT),);
+}
+
static inline int
tkprec(int tt)
{
@@ -1086,6 +1135,10 @@ Unary:
span = tk.span;
ex = vaargexpr(cm, &span);
break;
+ case TKW_Generic:
+ span = tk.span;
+ ex = genericexpr(cm, &span);
+ break;
default:
fatal(&tk.span, "expected %s (near %'tk)", ctx == EFROMSTMT ? "statement" : "expression", &tk);
}
diff --git a/todo.txt b/todo.txt
index 94308d0..746d5c4 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,5 +1,5 @@
- aarch64 backend
-- STDC: thread local, VLAs, complex, long double, _Generic, atomics
+- STDC: thread local, VLAs, complex, long double, atomics
- test on non-GNU and non-linux POSIX systems (alpine, various BSDs). Maybe we'll need a configure script after all
- DWARF debug information
- implement GNU extensions: __attribute__, __builtin_*, ...