From 585c66100d9d6554daa9a1ea62e5febc7e216326 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 19 Feb 2026 20:43:39 +0100 Subject: [PATCH] - Member access on a struct returned by the assignment expression, cause crash #2947 --- releasenotes.md | 1 + src/compiler/llvm_codegen_expr.c | 9 +++++- .../assign_from_call_to_struct.c3t | 28 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/test_suite/expressions/assign_from_call_to_struct.c3t diff --git a/releasenotes.md b/releasenotes.md index ab8021956..7cf6bfd58 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -46,6 +46,7 @@ - `--safe=no` disabled compile-time errors on compile-time known runtime @require checks #2936 - On assert known false, the message was not show for no-args. - Adding the incorrect sized vector to a pointer vector would cause a crash. +- Member access on a struct returned by the assignment expression, cause crash #2947 ## 0.7.9 Change list diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 7df5136ad..ed9cf0629 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -216,7 +216,14 @@ BEValue llvm_emit_assign_expr(GenContext *c, BEValue *ref, Expr *ref_expr, Expr if (ref_expr && c->current_block) llvm_emit_expr(c, ref, ref_expr); } if (!c->current_block) goto AFTER_STORE; - if (value.type != type_void) llvm_store(c, ref, &value); + if (value.type == type_void) + { + value = *ref; + } + else + { + llvm_store(c, ref, &value); + } } if (optional) diff --git a/test/test_suite/expressions/assign_from_call_to_struct.c3t b/test/test_suite/expressions/assign_from_call_to_struct.c3t new file mode 100644 index 000000000..b0bf734d1 --- /dev/null +++ b/test/test_suite/expressions/assign_from_call_to_struct.c3t @@ -0,0 +1,28 @@ +// #target: macos-x64 +module test; +struct Test +{ + long a; + long b; + char c; +} + +fn Test f() => {}; + +fn int main() +{ + Test t; + (t = f()).b; + return 0; +} + +/* #expect: test.ll + +define i32 @main() #0 { +entry: + %t = alloca %Test, align 8 + call void @llvm.memset.p0.i64(ptr align 8 %t, i8 0, i64 24, i1 false) + call void @test.f(ptr sret(%Test) align 8 %t) + %ptradd = getelementptr inbounds i8, ptr %t, i64 8 + ret i32 0 +}