commit 716dad41aebc0dc43aaead5e091a811c2b7081f0
parent c1adb055de5d65842866e689754e16a2eae4d386
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 25 Jul 2021 09:35:55 +0200
gen: fix non-access field/index expressions
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
2 files changed, 59 insertions(+), 5 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -220,16 +220,26 @@ gen_address_field(struct gen_context *ctx, struct gen_temp *temp,
assert(access->type == ACCESS_FIELD);
const struct expression *object = access->_struct;
- assert(object->type == EXPR_ACCESS); // TODO: Other cases?
+ // XXX: If gen_temp had an "allocate before use" flag, we might be able
+ // to avoid allocating it here. It remains to be seen if this would be
+ // useful; other expressions will tell (such as len() or casts).
struct gen_temp base = {0};
- struct qbe_value qbase = {0}, field = {0}, offset = {0};
- gen_access_address(ctx, &base, object);
+ if (object->type == EXPR_ACCESS) {
+ gen_access_address(ctx, &base, object);
+ } else {
+ alloc_temp(ctx, &base, object->result, "fieldtemp.%d");
+ gen_expr(ctx, object, &base);
+ }
+
gen_auto_deref(ctx, &base);
+
+ struct qbe_value qbase = {0}, field = {0}, offset = {0};
qval_temp(ctx, &qbase, &base);
gen_qtemp(ctx, &field, ctx->arch.ptr, "field.%d");
constl(&offset, access->field->offset);
pushi(ctx->current, &field, Q_ADD, &qbase, &offset, NULL);
+
temp->name = field.name;
temp->type = access->field->type;
temp->indirect = true;
@@ -244,10 +254,18 @@ gen_address_index(struct gen_context *ctx, struct gen_temp *temp,
const struct type *atype = type_dereference(access->array->result);
assert(atype->storage == STORAGE_ARRAY);
const struct expression *object = access->array;
- assert(object->type == EXPR_ACCESS); // TODO: Other cases?
+ // XXX: If gen_temp had an "allocate before use" flag, we might be able
+ // to avoid allocating it here. It remains to be seen if this would be
+ // useful; other expressions will tell (such as len() or casts).
struct gen_temp base = {0};
- gen_access_address(ctx, &base, object);
+ if (object->type == EXPR_ACCESS) {
+ gen_access_address(ctx, &base, object);
+ } else {
+ alloc_temp(ctx, &base, object->result, "indextemp.%d");
+ gen_expr(ctx, object, &base);
+ }
+
gen_auto_deref(ctx, &base);
struct gen_temp index = {0};
diff --git a/tests/903-postfix.ha b/tests/903-postfix.ha
@@ -1,10 +1,44 @@
type coords = struct { x: size, y: size };
+type coords3 = struct { _2: coords, z: size };
fn foo() size = 2;
fn equal(x: int, y: int) bool = x == y;
fn aggregate(c: coords) coords = c;
fn not(x: bool) bool = x == false;
+fn nested() void = {
+ let c = coords3 {
+ _2 = coords {
+ x = 10,
+ y = 20,
+ },
+ z = 30,
+ };
+ assert(c._2.x == 10);
+ assert(c._2.y == 20);
+ assert(c.z == 30);
+
+ let x = coords { x = 10, y = 20 };
+ let a = [x, x, x, x];
+ assert(a[0].x == 10);
+ assert(a[0].y == 20);
+ assert(a[1].x == 10);
+ assert(a[1].y == 20);
+ assert(a[2].x == 10);
+ assert(a[2].y == 20);
+ assert(a[3].x == 10);
+ assert(a[3].y == 20);
+};
+
+fn nonaccess() void = {
+ let c = coords { x = 10, y = 20 };
+ assert(aggregate(coords { x = 10, y = 20 }).x == 10);
+ assert(aggregate(c).y == 20);
+ assert(coords { x = 10, y = 20 }.x == 10);
+ assert(coords { x = 10, y = 20 }.y == 20);
+ assert([1, 2, 3, 4][2] == 3);
+};
+
fn deref() void = {
let a = coords { x = 10, y = 20 };
let b = &a;
@@ -54,6 +88,8 @@ fn calls() void = {
};
export fn main() int = {
+ nested();
+ nonaccess();
deref();
calls();
return 0;