From e243a262720a19224a4ae4a99466808711fb0acd Mon Sep 17 00:00:00 2001 From: lemon Date: Sat, 18 Apr 2026 19:47:33 +0200 Subject: frontend: GNU statement expressions --- src/c.c | 88 ++++++++++++++++++++++++++++++++++++++++------------------------- src/c.h | 3 +++ 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/c.c b/src/c.c index c45d1e6..8e99be1 100644 --- a/src/c.c +++ b/src/c.c @@ -1002,13 +1002,16 @@ tkprec(int tt) return ((uint)tt < countof(bintab)) ? bintab[tt].prec : 0; } -static Expr initializer(CComp *cm, Type *ty, enum evalmode ev, - bool globl, enum qualifier qual, internstr name); +static Expr initializer(CComp *, Type *ty, enum evalmode ev, + bool globl, enum qualifier qual, internstr name); + +static void block(CComp *, Ref *stmtexprval, Type *stmtexprty); static internstr istr__func__, istr_main, istr_memset; static internstr mkhiddensym(const char *fnname, const char *name, int id); + /* parse an expression with the given operator precedence */ /* param ident is a kludge to support block labels without backtracking or extra lookahead * see stmt() */ @@ -1062,7 +1065,15 @@ Unary: /* might be unary op (cast) or primary expr */ case '(': - if (!isdecltok(cm)) { /* (expr) */ + if (match(cm, &tk, '{')) { /* ({ GNU statement expression }) */ + Span span = tk.span; + Ref val; + ex.t = EIRVALUE; + block(cm, &val, &ex.ty); + ex.irref.bits = val.bits; + if (expect(cm, ')', NULL)) joinspan(&span.ex, tk.span.ex); + ex.span = span; + } else if (!isdecltok(cm)) { /* (expr) */ Span span = tk.span; ex = commaexpr(cm); joinspan(&span.ex, ex.span.ex); @@ -3030,7 +3041,7 @@ expraddr(Function *fn, const Expr *ex) assert(decl->id >= 0); return mkref(RTMP, decl->id); case SCEXTERN: case SCNONE: case SCSTATIC: - return mksymref(decl->sym, (SFUNC & -(decl->ty.t == TYFUNC)) | (SLOCAL & -(decl->scls == SCSTATIC || decl->isdef))); + return mksymref(decl->sym, (SFUNC & -(decl->ty.t == TYFUNC)) | (SLOCAL & -(decl->scls == SCSTATIC || (decl->isdef && !decl->inlin)))); default: assert(0); } @@ -3938,6 +3949,8 @@ compileexpr(Function *fn, const Expr *ex, bool discard) case ESEQ: expreffects(fn, &sub[0]); return compileexpr(fn, &sub[1], discard); + case EIRVALUE: + return (Ref){.bits = ex->irref.bits}; default: assert(!"nyi expr"); } } @@ -4219,9 +4232,8 @@ stmtterm(CComp *cm) expect(cm, ';', "to terminate previous statement"); } -static void block(CComp *cm, Function *fn); -static bool stmt(CComp *cm, Function *fn); -static void localdecl(CComp *cm, Function *fn, bool forinit); +static bool stmt(CComp *, Ref *stmtexprval, Type *stmtexprty); +static void localdecl(CComp *, bool forinit); typedef struct Label Label; struct Label { @@ -4244,8 +4256,9 @@ findlabel(CComp *cm, internstr name) } static void -deflabel(CComp *cm, Function *fn, const Span *span, internstr name) +deflabel(CComp *cm, const Span *span, internstr name) { + Function *fn = cm->fn; Label *label = findlabel(cm, name); if (label && label->usespan.ex.len == 0) { error(span, "redefinition of label '%s'", name); @@ -4279,7 +4292,7 @@ deflabel(CComp *cm, Function *fn, const Span *span, internstr name) } static bool -loopbody(CComp *cm, Function *fn, Block *brk, Block *cont) +loopbody(CComp *cm, Block *brk, Block *cont) { Block *save[2]; bool terminates = 0; @@ -4288,7 +4301,7 @@ loopbody(CComp *cm, Function *fn, Block *brk, Block *cont) cm->breakto = brk, cm->loopcont = cont; ++cm->loopdepth; - terminates = stmt(cm, fn); + terminates = stmt(cm, NULL, NULL); --cm->loopdepth; cm->breakto = save[0], cm->loopcont = save[1]; @@ -4326,9 +4339,10 @@ swsortcases(SwitchCase *cs, uint n) } static bool -genswitch(CComp *cm, Function *fn, const Expr *ex) +genswitch(CComp *cm, const Expr *ex) { Ref sel; + Function *fn = cm->fn; bool doemit = fn->curblk; Block *begin = NULL, *end = NULL, *breaksave = cm->breakto; SwitchStmt *stsave = cm->switchstmt, st = {.condtype = ex->ty}; @@ -4347,7 +4361,7 @@ genswitch(CComp *cm, Function *fn, const Expr *ex) begin = fn->curblk; fn->curblk = NULL; ++cm->switchdepth; - stmt(cm, fn); + stmt(cm, NULL, NULL); --cm->switchdepth; doemit = fn->curblk; cm->switchstmt = stsave; @@ -4396,8 +4410,9 @@ genswitch(CComp *cm, Function *fn, const Expr *ex) } static bool /* return 1 if stmt is terminating (ends with a jump) */ -stmt(CComp *cm, Function *fn) +stmt(CComp *cm, Ref *stmtexprval, Type *stmtexprty) { + Function *fn = cm->fn; Block *tr, *fl, *end, *begin; union { Arena a; @@ -4449,14 +4464,12 @@ stmt(CComp *cm, Function *fn) } } else if (tk.t == TKIDENT && match(cm, NULL, ':')) { /*