harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

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:
Msrc/gen.c | 2+-
Mtests/01-arrays.ha | 3+++
Mtests/21-tuples.ha | 4++++
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 = {