commit e2b6d35ded1f3dd0cb8657553950f373c2734c6b
parent dd50ca7740408e3c6e41c0ca48b59b9f7f5911f2
Author: Lassi Pulkkinen <lassi@pulk.fi>
Date: Thu, 16 Mar 2023 16:18:15 +0200
Don't use gen_expr_at for assignments
This caused the assignment to be partially observable from the rhs
expression if it contained a reference to the destination, e.g.
let x = (1, 0);
x = (2, x.0);
fmt::println(x.1)!;
prints "2" when it should print "1".
Signed-off-by: Lassi Pulkkinen <lassi@pulk.fi>
Diffstat:
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/gen.c b/src/gen.c
@@ -916,7 +916,7 @@ gen_expr_assign(struct gen_context *ctx, const struct expression *expr)
abort(); // Invariant
}
if (expr->assign.op == BIN_LEQUAL) {
- gen_expr_at(ctx, value, obj);
+ gen_store(ctx, obj, gen_expr(ctx, value));
} else if (expr->assign.op == BIN_LAND || expr->assign.op == BIN_LOR) {
struct qbe_statement lrval, lshort;
struct qbe_value brval = mklabel(ctx, &lrval, ".%d");
diff --git a/tests/01-arrays.ha b/tests/01-arrays.ha
@@ -60,8 +60,11 @@ fn assignment() void = {
let y = x;
let z = [0, 0, 0];
z = y;
+ let w = [1, 0];
+ w = [2, w[0]];
assert(y[0] == 1 && y[1] == 2 && y[2] == 3);
assert(z[0] == 1 && z[1] == 2 && z[2] == 3);
+ assert(w[0] == 2 && w[1] == 1);
assert(compile("
export fn main() void = {
diff --git a/tests/21-tuples.ha b/tests/21-tuples.ha
@@ -122,6 +122,10 @@ fn unpacking() void = {
// Regression tests for miscellaneous compiler bugs
fn regression() void = {
let a: (((int | void), int) | void) = (void, 0);
+
+ let x = (1, 0);
+ x = (2, x.0);
+ assert(x.0 == 2 && x.1 == 1);
};
fn reject() void = {