aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-17 13:01:51 -0800
committerMichael Forney <mforney@mforney.org>2019-02-17 14:12:44 -0800
commit0beaca9548a524557d33d3c618e5ec586cf489d3 (patch)
treecdde2e5e82a24bbd5bb9a8b6fa5564d278abdc06
parented176e4211b27218b9182ead05a13fd6d27d46ac (diff)
Allow computing address of non-lvalue structs/unions
We currently compile '.' member access as taking the address of the struct, adding the offset, and then dereferencing as the member type. However, the '.' operator is allowed on non-lvalues, even though the '&' operator is not. So, we need to handle arbitrary struct/union expressions in objectaddr by just compiling them normally, then converting them to regular pointers (since struct/union values are just pointers with additional type information).
-rw-r--r--qbe.c9
-rw-r--r--tests/struct-return-2.c6
-rw-r--r--tests/struct-return-2.qbe14
3 files changed, 20 insertions, 9 deletions
diff --git a/qbe.c b/qbe.c
index 2080e7c..29f005b 100644
--- a/qbe.c
+++ b/qbe.c
@@ -463,8 +463,13 @@ objectaddr(struct function *f, struct expression *e)
funcinit(f, d, e->compound.init);
return d->value;
case EXPRUNARY:
- if (e->unary.op == TMUL)
- return funcexpr(f, e->unary.base);
+ if (e->unary.op != TMUL)
+ break;
+ return funcexpr(f, e->unary.base);
+ default:
+ if (e->type->kind != TYPESTRUCT && e->type->kind != TYPEUNION)
+ break;
+ return funcinst(f, ICOPY, &iptr, (struct value *[]){funcexpr(f, e)});
}
error(&tok.loc, "expression is not an object");
}
diff --git a/tests/struct-return-2.c b/tests/struct-return-2.c
index 9fa50f5..726e667 100644
--- a/tests/struct-return-2.c
+++ b/tests/struct-return-2.c
@@ -1,4 +1,4 @@
-struct s {int x;} g(void);
-void f(void) {
- g();
+struct {int x, y;} g(void);
+int f(void) {
+ return g().y;
}
diff --git a/tests/struct-return-2.qbe b/tests/struct-return-2.qbe
index 2f1d3da..415ec2f 100644
--- a/tests/struct-return-2.qbe
+++ b/tests/struct-return-2.qbe
@@ -1,8 +1,14 @@
-type :s.1 = { w, }
+type :.1 = { w, w, }
export
-function $f() {
+function w $f() {
@start.1
@body.2
- %.1 =:s.1 call $g()
- ret
+ %.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
}