aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-05-12 15:37:10 -0700
committerMichael Forney <mforney@mforney.org>2019-05-12 15:45:35 -0700
commite70ee0ec1a0f7784dac638ac2d782afec4dd7a4c (patch)
tree826e0e24fc93c1973c96cfaaffc4224357065ed4
parentf7b471b8576846e575f8c73ef6b70c4b06ff377d (diff)
downloadcproc-e70ee0ec1a0f7784dac638ac2d782afec4dd7a4c.tar.xz
eval: Keep track of kind of constant expression we are evaluating
When we are evaluating an arithmetic constant expression, we don't want to indroduce static data definitions for string or compound literals. Fixes #59.
-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
+}