aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cc.h7
-rw-r--r--eval.c20
-rw-r--r--expr.c8
-rw-r--r--qbe.c2
-rw-r--r--test/conditional-compound-literal.c4
-rw-r--r--test/conditional-compound-literal.qbe25
6 files changed, 52 insertions, 14 deletions
diff --git a/cc.h b/cc.h
index 4a97a99..03ae663 100644
--- a/cc.h
+++ b/cc.h
@@ -442,7 +442,12 @@ struct expr *exprpromote(struct expr *);
/* eval */
-struct expr *eval(struct expr *);
+enum evalkind {
+ EVALARITH, /* arithmetic constant expression */
+ EVALINIT, /* initializer constant expression */
+};
+
+struct expr *eval(struct expr *, enum evalkind);
/* init */
diff --git a/eval.c b/eval.c
index 1d19180..63047d8 100644
--- a/eval.c
+++ b/eval.c
@@ -87,7 +87,7 @@ binary(struct expr *expr, enum tokenkind op, struct expr *l, struct expr *r)
#undef S
struct expr *
-eval(struct expr *expr)
+eval(struct expr *expr, enum evalkind kind)
{
struct expr *l, *r, *c;
struct decl *d;
@@ -100,6 +100,8 @@ eval(struct expr *expr)
expr->constant.i = intconstvalue(expr->ident.decl->value);
break;
case EXPRCOMPOUND:
+ if (kind != EVALINIT)
+ break;
d = mkdecl(DECLOBJECT, expr->type, expr->qual, LINKNONE);
d->value = mkglobal(NULL, true);
emitdata(d, expr->compound.init);
@@ -107,13 +109,15 @@ eval(struct expr *expr)
expr->ident.decl = d;
break;
case EXPRUNARY:
- l = eval(expr->base);
+ if (kind != EVALINIT)
+ break;
+ l = eval(expr->base, kind);
if (expr->op != TBAND)
break;
switch (l->kind) {
case EXPRUNARY:
if (l->op == TMUL)
- expr = eval(l->base);
+ expr = eval(l->base, kind);
break;
case EXPRSTRING:
l->ident.decl = stringdecl(l);
@@ -123,7 +127,7 @@ eval(struct expr *expr)
}
break;
case EXPRCAST:
- l = eval(expr->base);
+ l = eval(expr->base, kind);
if (l->kind == EXPRCONST) {
expr->kind = EXPRCONST;
if (l->type->prop & PROPINT && expr->type->prop & PROPFLOAT)
@@ -138,8 +142,8 @@ eval(struct expr *expr)
}
break;
case EXPRBINARY:
- l = eval(expr->binary.l);
- r = eval(expr->binary.r);
+ l = eval(expr->binary.l, kind);
+ r = eval(expr->binary.r, kind);
expr->binary.l = l;
expr->binary.r = r;
switch (expr->op) {
@@ -176,10 +180,10 @@ eval(struct expr *expr)
case EXPRCOND:
l = expr->cond.t;
r = expr->cond.f;
- c = eval(expr->base);
+ c = eval(expr->base, kind);
if (c->kind != EXPRCONST)
break;
- return eval(c->constant.i ? l : r);
+ return eval(c->constant.i ? l : r, kind);
}
return expr;
diff --git a/expr.c b/expr.c
index 49e01c0..2e74ba4 100644
--- a/expr.c
+++ b/expr.c
@@ -557,7 +557,7 @@ builtinfunc(struct scope *s, enum builtinkind kind)
e->base = exprconvert(assignexpr(s), &typeulong);
break;
case BUILTINCONSTANTP:
- e = mkconstexpr(&typeint, eval(condexpr(s))->kind == EXPRCONST);
+ e = mkconstexpr(&typeint, eval(condexpr(s), EVALARITH)->kind == EXPRCONST);
break;
case BUILTININFF:
e = mkexpr(EXPRCONST, &typefloat);
@@ -969,8 +969,8 @@ condexpr(struct scope *s)
} else if (t == &typevoid && f == &typevoid) {
e->type = &typevoid;
} else {
- e->cond.t = eval(e->cond.t);
- e->cond.f = eval(e->cond.f);
+ e->cond.t = eval(e->cond.t, EVALARITH);
+ e->cond.f = eval(e->cond.f, EVALARITH);
if (nullpointer(e->cond.t) && f->kind == TYPEPOINTER) {
e->type = f;
} else if (nullpointer(e->cond.f) && t->kind == TYPEPOINTER) {
@@ -998,7 +998,7 @@ condexpr(struct scope *s)
struct expr *
constexpr(struct scope *s)
{
- return eval(condexpr(s));
+ return eval(condexpr(s), EVALARITH);
}
uint64_t
diff --git a/qbe.c b/qbe.c
index 4389e27..5135eca 100644
--- a/qbe.c
+++ b/qbe.c
@@ -1269,7 +1269,7 @@ emitdata(struct decl *d, struct init *init)
else if (d->align < d->type->align)
error(&tok.loc, "object requires alignment %d, which is stricter than %d", d->type->align, d->align);
for (cur = init; cur; cur = cur->next)
- cur->expr = eval(cur->expr);
+ cur->expr = eval(cur->expr, EVALINIT);
if (d->linkage == LINKEXTERN)
fputs("export ", stdout);
fputs("data ", stdout);
diff --git a/test/conditional-compound-literal.c b/test/conditional-compound-literal.c
new file mode 100644
index 0000000..33a5416
--- /dev/null
+++ b/test/conditional-compound-literal.c
@@ -0,0 +1,4 @@
+int main(void) {
+ int x = 0, *p = 0 ? 0 : &(int){x};
+ return *p;
+}
diff --git a/test/conditional-compound-literal.qbe b/test/conditional-compound-literal.qbe
new file mode 100644
index 0000000..9e9c5f7
--- /dev/null
+++ b/test/conditional-compound-literal.qbe
@@ -0,0 +1,25 @@
+export
+function w $main() {
+@start.1
+ %.1 =l alloc4 4
+ %.3 =l alloc8 8
+ %.6 =l alloc4 4
+@body.2
+ %.2 =l add %.1, 0
+ storew 0, %.2
+ %.4 =l add %.3, 0
+ %.5 =w cnew 0, 0
+ jnz %.5, @cond_true.3, @cond_false.4
+@cond_true.3
+ jmp @cond_join.5
+@cond_false.4
+ %.7 =l add %.6, 0
+ %.8 =w loadsw %.1
+ storew %.8, %.7
+@cond_join.5
+ %.9 =l phi @cond_true.3 0, @cond_false.4 %.6
+ storel %.9, %.4
+ %.10 =l loadl %.3
+ %.11 =w loadsw %.10
+ ret %.11
+}