From 8035991ac3e8433517b353fe755d4360db549df0 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 10 Sep 2025 10:47:14 +0200 Subject: [PATCH] `??` with void results on both sides cause a compiler crash #2472 --- releasenotes.md | 1 + src/compiler/llvm_codegen_expr.c | 8 ++++ test/test_suite/errors/else_with_void.c3t | 54 +++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 test/test_suite/errors/else_with_void.c3t diff --git a/releasenotes.md b/releasenotes.md index b6d575d7e..68ad582d3 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -19,6 +19,7 @@ - Any register allowed in X86_64 inline asm address. #2463 - int val = some_int + some_distinct_inline_int errors that int cannot be cast to DistinctInt #2468 - Compiler hang with unaligned load-store pair. #2470 +- `??` with void results on both sides cause a compiler crash #2472. ### Stdlib changes - Added generic `InterfaceList` to store a list of values that implement a specific interface diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 4db1d1a1c..ad1bcd551 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -3907,6 +3907,14 @@ static void llvm_emit_else(GenContext *c, BEValue *be_value, Expr *expr) assert(success_end_block && else_block_exit); + // We might have a void here + if (!real_value.value) + { + assert(type_flatten(expr->type) == type_void); + assert(!else_value.value); + llvm_value_set(be_value, NULL, type_void); + return; + } // Emit an address if the phi is was by address if (was_address) { diff --git a/test/test_suite/errors/else_with_void.c3t b/test/test_suite/errors/else_with_void.c3t new file mode 100644 index 000000000..881830ed8 --- /dev/null +++ b/test/test_suite/errors/else_with_void.c3t @@ -0,0 +1,54 @@ +// #target: macos-x64 +module func_point_test; +import std::io; +import std::collections; + +alias FuncPoint = fn void(String text); + +fn void test(String text = "test123") +{ + io::printn(text); +} + +fn void main() +{ + HashMap{String, FuncPoint} map; + map.tinit(); + map.set("test", &test); + + String test_index = "index"; + + map[test_index]("Hello World") ?? test(); +} + +/* #expect: func_point_test.ll + +define void @func_point_test.main() #0 { +entry: + %map = alloca %HashMap, align 8 + %test_index = alloca %"char[]", align 8 + %retparam = alloca ptr, align 8 + call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 48, i1 false) + %0 = call ptr @"std_collections_map$String$fn$void$String$$.HashMap.tinit"(ptr %map, i32 16, float 7.500000e-01) + %1 = call i8 @"std_collections_map$String$fn$void$String$$.HashMap.set"(ptr %map, ptr @.str, i64 4, ptr @func_point_test.test) + store %"char[]" { ptr @.str.1, i64 5 }, ptr %test_index, align 8 + %lo = load ptr, ptr %test_index, align 8 + %ptradd = getelementptr inbounds i8, ptr %test_index, i64 8 + %hi = load i64, ptr %ptradd, align 8 + %2 = call i64 @"std_collections_map$String$fn$void$String$$.HashMap.get"(ptr %retparam, ptr %map, ptr %lo, i64 %hi) + %not_err = icmp eq i64 %2, 0 + %3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %3, label %after_check, label %else_block + +after_check: ; preds = %entry + %4 = load ptr, ptr %retparam, align 8 + call void %4(ptr @.str.2, i64 11) + br label %phi_block + +else_block: ; preds = %entry + call void @func_point_test.test(ptr @.str.3, i64 7) + br label %phi_block + +phi_block: ; preds = %else_block, %after_check + ret void +}