diff options
author | Michael Forney <mforney@mforney.org> | 2019-05-12 15:37:10 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2019-05-12 15:45:35 -0700 |
commit | e70ee0ec1a0f7784dac638ac2d782afec4dd7a4c (patch) | |
tree | 826e0e24fc93c1973c96cfaaffc4224357065ed4 | |
parent | f7b471b8576846e575f8c73ef6b70c4b06ff377d (diff) | |
download | cproc-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.h | 7 | ||||
-rw-r--r-- | eval.c | 20 | ||||
-rw-r--r-- | expr.c | 8 | ||||
-rw-r--r-- | qbe.c | 2 | ||||
-rw-r--r-- | test/conditional-compound-literal.c | 4 | ||||
-rw-r--r-- | test/conditional-compound-literal.qbe | 25 |
6 files changed, 52 insertions, 14 deletions
@@ -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 */ @@ -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; @@ -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 @@ -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 +} |