From 99e29bff8ded4c4809c1728a73c6f35cec6f5b73 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 17 Jun 2025 16:01:44 +0200 Subject: [PATCH] Bug in AST copying would make operator overloading like `+=` compile incorrectly #2217 --- releasenotes.md | 1 + src/compiler/copying.c | 8 ++--- src/compiler/expr.c | 2 +- test/test_suite/statements/defer_overload.c3t | 32 +++++++++++++++++++ 4 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 test/test_suite/statements/defer_overload.c3t diff --git a/releasenotes.md b/releasenotes.md index 641b5cc89..cffb42753 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -43,6 +43,7 @@ - In some cases, the compiler would dereference a compile time null. #2215 - Incorrect codegen if a macro ends with unreachable and is assigned to something. #2210 - Fix error for named arguments-order with compile-time arguments #2212 +- Bug in AST copying would make operator overloading like `+=` compile incorrectly #2217. ### Stdlib changes - Deprecate `String.is_zstr` and `String.quick_zstr` #2188. diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 56be1e979..09fa88a0d 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -297,8 +297,8 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) switch (source_expr->expr_kind) { case EXPR_TWO: - MACRO_COPY_EXPR(source_expr->two_expr.first); - MACRO_COPY_EXPR(source_expr->two_expr.last); + MACRO_COPY_EXPR(expr->two_expr.first); + MACRO_COPY_EXPR(expr->two_expr.last); return expr; case EXPR_TYPECALL: case EXPR_CT_SUBSCRIPT: @@ -333,7 +333,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) } return expr; case EXPR_MEMBER_GET: - fixup_decl(c, &source_expr->member_get_expr); + fixup_decl(c, &expr->member_get_expr); break; case EXPR_SWIZZLE: MACRO_COPY_EXPRID(expr->swizzle_expr.parent); @@ -525,7 +525,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) MACRO_COPY_TYPE(expr->expr_compound_literal.type_info); return expr; case EXPR_POISONED: - return source_expr; + return expr; case EXPR_RETHROW: MACRO_COPY_EXPR(expr->rethrow_expr.inner); return expr; diff --git a/src/compiler/expr.c b/src/compiler/expr.c index baac38ed7..201a17cc9 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -221,9 +221,9 @@ bool expr_may_addr(Expr *expr) case EXPR_ACCESS_RESOLVED: return expr_may_addr(expr->access_resolved_expr.parent); case EXPR_SUBSCRIPT: - case EXPR_SLICE: case EXPR_MEMBER_GET: return true; + case EXPR_SLICE: case EXPR_BENCHMARK_HOOK: case EXPR_TEST_HOOK: case EXPR_VECTOR_FROM_ARRAY: diff --git a/test/test_suite/statements/defer_overload.c3t b/test/test_suite/statements/defer_overload.c3t new file mode 100644 index 000000000..4535f468e --- /dev/null +++ b/test/test_suite/statements/defer_overload.c3t @@ -0,0 +1,32 @@ +// #target: macos-aarch64 +module test; +typedef Foo = int; +macro Foo Foo.add(self1, Foo other) @operator(+) => self1; +macro Foo Foo.add_self(&self, Foo other) @operator(+=) => *self = *self + other; + +macro Foo Foo.test(&self2) => *self2 += (Foo)0; + +fn int main() +{ + Foo b; + defer b.test(); + return 0; +} + +/* #expect: test.ll + +define i32 @main() #0 { +entry: + %b = alloca i32, align 4 + %self1 = alloca i32, align 4 + store i32 0, ptr %b, align 4 + %neq = icmp ne ptr %b, null + call void @llvm.assume(i1 %neq) + %neq1 = icmp ne ptr %b, null + call void @llvm.assume(i1 %neq1) + %0 = load i32, ptr %b, align 4 + store i32 %0, ptr %self1, align 4 + %1 = load i32, ptr %self1, align 4 + store i32 %1, ptr %b, align 4 + ret i32 0 +}