diff options
author | Michael Forney <mforney@mforney.org> | 2019-04-03 00:42:09 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2019-04-03 00:46:08 -0700 |
commit | b3865e402e426387d4cdccdcd249a02d5ba1bc05 (patch) | |
tree | c5182df0ecd07259d84fcd5a313cb295c09ab8a6 | |
parent | 05e2f624ebe66b4ccc471ce091b3831773bfb4db (diff) |
Make member access its own expression type
-rw-r--r-- | expr.c | 24 | ||||
-rw-r--r-- | expr.h | 10 | ||||
-rw-r--r-- | qbe.c | 3 | ||||
-rw-r--r-- | tests/struct-return-2.qbe | 9 |
4 files changed, 25 insertions, 21 deletions
@@ -483,9 +483,7 @@ postfixexpr(struct scope *s, struct expr *r) struct type *t; enum typequal tq; struct param *p; - uint64_t offset; enum tokenkind op; - bool lvalue; if (!r) r = primaryexpr(s); @@ -566,17 +564,19 @@ postfixexpr(struct scope *s, struct expr *r) next(); if (tok.kind != TIDENT) error(&tok.loc, "expected identifier after '->' operator"); - lvalue = op == TARROW || r->unary.base->flags & EXPRFLAG_LVAL; - r = exprconvert(r, mkpointertype(&typechar)); - offset = 0; - t = typemember(t, tok.lit, &offset); - if (!t) + e = mkexpr(EXPRMEMBER, NULL, 0); + e->member.base = r; + e->member.offset = 0; + e->type = typemember(t, tok.lit, &e->member.offset); + if (!e->type) error(&tok.loc, "struct/union has no member named '%s'", tok.lit); - r = mkbinaryexpr(&tok.loc, TADD, r, mkconstexpr(&typeulong, offset)); - r = exprconvert(r, mkpointertype(mkqualifiedtype(t, tq))); - e = mkunaryexpr(TMUL, r); - if (!lvalue) - e->flags &= ~EXPRFLAG_LVAL; + if (op == TARROW || r->unary.base->flags & EXPRFLAG_LVAL) { + e->type = mkqualifiedtype(e->type, tq); + e->flags |= EXPRFLAG_LVAL; + } else { + e->type = typeunqual(e->type, NULL); + } + e = decay(e); next(); break; case TINC: @@ -6,7 +6,7 @@ enum exprkind { /* postfix expression */ EXPRCALL, - /* member E.M gets transformed to *(typeof(E.M) *)((char *)E + offsetof(typeof(E), M)) */ + EXPRMEMBER, EXPRINCDEC, EXPRCOMPOUND, /* subscript E1[E2] gets transformed to *((E1)+(E2)) */ @@ -49,14 +49,18 @@ struct expr { size_t nargs; } call; struct { - struct init *init; - } compound; + struct expr *base; + size_t offset; + } member; struct { int op; _Bool post; struct expr *base; } incdec; struct { + struct init *init; + } compound; + struct { int op; struct expr *base; } unary; @@ -479,6 +479,8 @@ objectaddr(struct func *f, struct expr *e) case EXPRSTRING: d = stringdecl(e); return d->value; + case EXPRMEMBER: + return funcinst(f, IADD, &iptr, funcexpr(f, e->member.base), mkintconst(&iptr, e->member.offset)); case EXPRCOMPOUND: d = mkdecl(DECLOBJECT, e->type, LINKNONE); funcinit(f, d, e->compound.init); @@ -599,6 +601,7 @@ funcexpr(struct func *f, struct expr *e) if (typeprop(e->type) & PROPINT || e->type->kind == TYPEPOINTER) return mkintconst(e->type->repr, e->constant.i); return mkfltconst(e->type->repr, e->constant.f); + case EXPRMEMBER: case EXPRCOMPOUND: l = objectaddr(f, e); return funcload(f, e->type, l); diff --git a/tests/struct-return-2.qbe b/tests/struct-return-2.qbe index 415ec2f..b1990ec 100644 --- a/tests/struct-return-2.qbe +++ b/tests/struct-return-2.qbe @@ -5,10 +5,7 @@ function w $f() { @body.2 %.1 =:.1 call $g() %.2 =l copy %.1 - %.3 =l copy %.2 - %.4 =l mul 4, 1 - %.5 =l add %.3, %.4 - %.6 =l copy %.5 - %.7 =w loadsw %.6 - ret %.7 + %.3 =l add %.2, 4 + %.4 =w loadsw %.3 + ret %.4 } |