From 975d76cfc99fcf797ebe0ac254dd3252405bd778 Mon Sep 17 00:00:00 2001 From: lemon Date: Sun, 22 Feb 2026 18:32:40 +0100 Subject: c: fix using string literal as conditional expression conditional --- .gitmodules | 3 +++ c/c.c | 40 ++++++++++++++++++++++++++++------------ test/external/sqlite | 1 + 3 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 .gitmodules create mode 160000 test/external/sqlite diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..badbe0a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "test/external/sqlite"] + path = test/external/sqlite + url = https://github.com/sqlite/sqlite diff --git a/c/c.c b/c/c.c index a5ac0b6..d4e0aa6 100644 --- a/c/c.c +++ b/c/c.c @@ -1238,7 +1238,7 @@ Unary: struct expr *sub; span.sl = tk.span.sl; span.ex = ex.span.ex; - if (!isscalar(ex.ty)) + if (!isscalar(ex.ty) && !isptrcvt(ex.ty)) error(&ex.span, "?: condition is not a scalar type: '%ty'", ex.ty); tmp = commaexpr(cm); joinspan(&tk.span.ex, tmp.span.ex); @@ -3469,6 +3469,26 @@ genbitfstore(struct function *fn, const union type ty, union ref addr, genstore(fn, ty, addr, val); } +static bool +knowntruthy(bool *t, struct expr *ex) +{ + if (!eval(ex, EVFOLD)) return 0; + + switch (ex->t) { + default: assert(0 && "!scalar?"); + case ENUMLIT: + *t = isflt(ex->ty) ? ex->f != 0.0 : ex->u != 0; + break; + case ESYM: + assert(isptrcvt(ex->ty)); + case ESTRLIT: + /* string literals & symbol addresses are always truthy */ + *t = 1; + break; + } + return 1; +} + union ref compileexpr(struct function *fn, const struct expr *ex, bool discard) { @@ -3738,12 +3758,10 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard) return narrow(fn, cls, ex->ty, r, 0); return r; case ECOND: - if (eval(&ex->sub[0], EVFOLD)) { - bool k = isflt(ex->sub[0].ty) ? ex->sub[0].f != 0.0 : ex->sub[0].u != 0; - assert(ex->sub[0].t == ENUMLIT); - r = compileexpr(fn, &ex->sub[2-k], discard); + for (bool c; knowntruthy(&c, &ex->sub[0]);) { + r = compileexpr(fn, &ex->sub[2-c], discard); if (discard) return NOREF; - return cvt(fn, ex->ty, ex->sub[2-k].ty, r); + return cvt(fn, ex->ty, ex->sub[2-c].ty, r); } if (ex->ty.t == TYVOID || discard) { @@ -3764,13 +3782,11 @@ compileexpr(struct function *fn, const struct expr *ex, bool discard) return condexprvalue(fn, ex, discard); case ELOGAND: case ELOGIOR: - if (eval(&ex->sub[0], EVFOLD)) { - bool k = isflt(ex->sub[0].ty) ? ex->sub[0].f != 0.0 : ex->sub[0].u != 0; - assert(ex->sub[0].t == ENUMLIT); - k ^= ex->t == ELOGIOR; - r = compileexpr(fn, &ex->sub[k], discard); + for (bool c; knowntruthy(&c, &ex->sub[0]);) { + c ^= ex->t == ELOGIOR; + r = compileexpr(fn, &ex->sub[c], discard); if (discard) return NOREF; - return cvt(fn, mktype(TYBOOL), ex->sub[k].ty, r); + return cvt(fn, mktype(TYBOOL), ex->sub[c].ty, r); } return condexprvalue(fn, ex, discard); case ESEQ: diff --git a/test/external/sqlite b/test/external/sqlite new file mode 160000 index 0000000..60f132b --- /dev/null +++ b/test/external/sqlite @@ -0,0 +1 @@ +Subproject commit 60f132bf1288549ef1e7043f4a88fe6e199f0cf4 -- cgit v1.2.3