diff options
author | Michael Forney <mforney@mforney.org> | 2022-05-09 13:22:45 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2022-05-11 11:15:56 -0700 |
commit | d99805f26575a0e0a7323fdaf56daec7b1857eda (patch) | |
tree | 6c794bdca32cc91c87cf23e828fc8e375fb34971 /expr.c | |
parent | ef3b6b33eba80b82ae3da1d8e322b531bfc99902 (diff) |
expr: Implement type-checking for casts and assignments
Diffstat (limited to 'expr.c')
-rw-r--r-- | expr.c | 99 |
1 files changed, 70 insertions, 29 deletions
@@ -156,6 +156,59 @@ bitfieldwidth(struct expr *e) return e->type->size * 8 - e->u.bitfield.bits.before - e->u.bitfield.bits.after; } +static struct expr * +exprconvert(struct expr *e, struct type *t) +{ + if (typecompatible(e->type, t)) + return e; + return mkexpr(EXPRCAST, t, e); +} + +static bool +nullpointer(struct expr *e) +{ + if (e->kind != EXPRCONST) + return false; + if (!(e->type->prop & PROPINT) && (e->type->kind != TYPEPOINTER || e->type->base != &typevoid)) + return false; + return e->u.constant.u == 0; +} + +struct expr * +exprassign(struct expr *e, struct type *t) +{ + struct type *et; + + et = e->type; + switch (t->kind) { + case TYPEBOOL: + if (!(et->prop & PROPARITH) && et->kind != TYPEPOINTER) + error(&tok.loc, "assignment to _Bool must be from arithmetic or pointer type"); + break; + case TYPEPOINTER: + if (nullpointer(e)) + break; + if (et->kind != TYPEPOINTER) + error(&tok.loc, "assignment to pointer must be from pointer or null pointer constant"); + if (t->base != &typevoid && et->base != &typevoid && !typecompatible(t->base, et->base)) + error(&tok.loc, "base types of pointer assignment must be compatible or void"); + if ((et->qual & t->qual) != et->qual) + error(&tok.loc, "assignment to pointer discards qualifiers"); + break; + case TYPESTRUCT: + case TYPEUNION: + if (!typecompatible(t, et)) + error(&tok.loc, "assignment to %s type must be from compatible type", tokstr[t->kind]); + break; + default: + assert(t->prop & PROPARITH); + if (!(et->prop & PROPARITH)) + error(&tok.loc, "assignment to arithmetic type must be from arithmetic type"); + break; + } + return exprconvert(e, t); +} + struct expr * exprpromote(struct expr *e) { @@ -177,16 +230,6 @@ commonreal(struct expr **e1, struct expr **e2) return t; } -static bool -nullpointer(struct expr *e) -{ - if (e->kind != EXPRCONST) - return false; - if (!(e->type->prop & PROPINT) && (e->type->kind != TYPEPOINTER || e->type->base != &typevoid)) - return false; - return e->u.constant.u == 0; -} - static struct expr * mkbinaryexpr(struct location *loc, enum tokenkind op, struct expr *l, struct expr *r) { @@ -708,7 +751,7 @@ builtinfunc(struct scope *s, enum builtinkind kind) switch (kind) { case BUILTINALLOCA: - e = exprconvert(assignexpr(s), &typeulong); + e = exprassign(assignexpr(s), &typeulong); e = mkexpr(EXPRBUILTIN, mkpointertype(&typevoid, QUALNONE), e); e->u.builtin.kind = BUILTINALLOCA; break; @@ -786,7 +829,7 @@ builtinfunc(struct scope *s, enum builtinkind kind) e = assignexpr(s); if (!typesame(e->type, typeadjvalist)) error(&tok.loc, "va_end argument must have type va_list"); - e = exprconvert(e, &typevoid); + e = mkexpr(EXPRCAST, &typevoid, e); break; case BUILTINVASTART: e = mkexpr(EXPRBUILTIN, &typevoid, assignexpr(s)); @@ -881,7 +924,7 @@ postfixexpr(struct scope *s, struct expr *r) if (!t->u.func.isprototype || (t->u.func.isvararg && !p)) *end = exprpromote(*end); else - *end = exprconvert(*end, p->type); + *end = exprassign(*end, p->type); end = &(*end)->next; ++e->u.call.nargs; if (p) @@ -1035,10 +1078,11 @@ unaryexpr(struct scope *s) static struct expr * castexpr(struct scope *s) { - struct type *t; + struct type *t, *ct; enum typequal tq; struct expr *r, *e, **end; + ct = NULL; end = &r; while (consume(TLPAREN)) { tq = QUALNONE; @@ -1046,8 +1090,8 @@ castexpr(struct scope *s) if (!t) { e = expr(s); expect(TRPAREN, "after expression to match '('"); - *end = postfixexpr(s, e); - return r; + e = postfixexpr(s, e); + goto done; } expect(TRPAREN, "after type name"); if (tok.kind == TLBRACE) { @@ -1055,17 +1099,22 @@ castexpr(struct scope *s) e->qual = tq; e->lvalue = true; e->u.compound.init = parseinit(s, t); - e = decay(e); - *end = postfixexpr(s, e); - return r; + e = postfixexpr(s, decay(e)); + goto done; } + if (t != &typevoid && !(t->prop & PROPSCALAR)) + error(&tok.loc, "cast type must be scalar"); e = mkexpr(EXPRCAST, t, NULL); - /* XXX check types 6.5.4 */ *end = e; end = &e->base; + ct = t; } - *end = unaryexpr(s); + e = unaryexpr(s); +done: + if (ct && ct != &typevoid && !(e->type->prop & PROPSCALAR)) + error(&tok.loc, "cast operand must have scalar type"); + *end = e; return r; } @@ -1269,11 +1318,3 @@ expr(struct scope *s) return r; return mkexpr(EXPRCOMMA, e->type, r); } - -struct expr * -exprconvert(struct expr *e, struct type *t) -{ - if (typecompatible(e->type, t)) - return e; - return mkexpr(EXPRCAST, t, e); -} |