aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-04-03 00:42:09 -0700
committerMichael Forney <mforney@mforney.org>2019-04-03 00:46:08 -0700
commitb3865e402e426387d4cdccdcd249a02d5ba1bc05 (patch)
treec5182df0ecd07259d84fcd5a313cb295c09ab8a6
parent05e2f624ebe66b4ccc471ce091b3831773bfb4db (diff)
Make member access its own expression type
-rw-r--r--expr.c24
-rw-r--r--expr.h10
-rw-r--r--qbe.c3
-rw-r--r--tests/struct-return-2.qbe9
4 files changed, 25 insertions, 21 deletions
diff --git a/expr.c b/expr.c
index d30669c..629ae22 100644
--- a/expr.c
+++ b/expr.c
@@ -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:
diff --git a/expr.h b/expr.h
index e660848..5667839 100644
--- a/expr.h
+++ b/expr.h
@@ -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;
diff --git a/qbe.c b/qbe.c
index a40540a..66cc271 100644
--- a/qbe.c
+++ b/qbe.c
@@ -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
}