aboutsummaryrefslogtreecommitdiff
path: root/stmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'stmt.c')
-rw-r--r--stmt.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/stmt.c b/stmt.c
index 256ddd0..075feff 100644
--- a/stmt.c
+++ b/stmt.c
@@ -24,6 +24,27 @@ gotolabel(struct func *f)
return true;
}
+/* controlling expression of loops and if-statements */
+static struct expr *
+ctrlexpr(struct scope *s)
+{
+ struct expr *e;
+ struct type *t;
+
+ e = expr(s);
+ t = e->type;
+ if (!(t->prop & PROPSCALAR))
+ error(&tok.loc, "controlling expression must have scalar type");
+ /*
+ Ideally we would just do this conversion unconditionally,
+ but QBE is not currently able to optimize the conversion
+ away for int.
+ */
+ if (t->prop & PROPFLOAT || t->size > 4)
+ e = exprconvert(e, &typebool);
+ return e;
+}
+
/* 6.8 Statements and blocks */
void
stmt(struct func *f, struct scope *s)
@@ -91,7 +112,7 @@ stmt(struct func *f, struct scope *s)
next();
s = mkscope(s);
expect(TLPAREN, "after 'if'");
- e = exprconvert(expr(s), &typebool);
+ e = ctrlexpr(s);
v = funcexpr(f, e);
delexpr(e);
expect(TRPAREN, "after expression");
@@ -154,7 +175,7 @@ stmt(struct func *f, struct scope *s)
next();
s = mkscope(s);
expect(TLPAREN, "after 'while'");
- e = exprconvert(expr(s), &typebool);
+ e = ctrlexpr(s);
expect(TRPAREN, "after expression");
label[0] = mkblock("while_cond");
@@ -192,7 +213,7 @@ stmt(struct func *f, struct scope *s)
expect(TWHILE, "after 'do' statement");
expect(TLPAREN, "after 'while'");
funclabel(f, label[1]);
- e = exprconvert(expr(s), &typebool);
+ e = ctrlexpr(s);
expect(TRPAREN, "after expression");
v = funcexpr(f, e);
@@ -221,7 +242,7 @@ stmt(struct func *f, struct scope *s)
funclabel(f, label[0]);
if (tok.kind != TSEMICOLON) {
- e = exprconvert(expr(s), &typebool);
+ e = ctrlexpr(s);
v = funcexpr(f, e);
funcjnz(f, v, label[1], label[3]);
delexpr(e);