Files
sx/examples/issue-0045.sx
agra 3d32ab0fc6 ffi issue-0045: pack-fn block-body call — lock in LLVM verifier crash
Filed `issues/0045-pack-fn-call-llvm-verifier-failure.md`.
Surfaced by probing step 2 territory of the variadic
heterogeneous type packs feature: any `..$args` fn whose body
is a block containing `return X;` (or any comptime fn with a
non-void return, comptime params, and explicit `return` in a
block body) trips LLVM's "Terminator found in the middle of a
basic block" verifier.

`lowerComptimeCall` inlines the body's statements directly into
the caller's LLVM function. `lowerReturn` then emits a `ret`
into the caller's basic block — but the caller still has
trailing instructions, hence the verifier failure.

`examples/issue-0045.sx` reproduces the crash with the minimum
pack-fn shape (`foo :: (..$args) -> s64 { return 42; }`). Same
shape with a plain comptime param (`($x: s32) -> s64 { return
42; }`) reproduces identically, so the bug is broader than
packs. Arrow-form bodies (`=> 42`) work today because they have
no `return` statement.

Next commit teaches `lowerComptimeCall` to allocate a result
slot when the body contains a `return`, and reroutes
`lowerReturn` to store into that slot + flag the block as
terminated so the inliner picks up the value.
2026-05-27 13:19:49 +03:00

26 lines
963 B
Plaintext

// issue-0045 — calling a comptime fn whose body is a block
// containing an explicit `return X;` trips LLVM's "Terminator found
// in the middle of a basic block" verifier.
//
// Surfaced by the variadic heterogeneous type packs feature (step
// 1 made `..$args` parseable, so the simplest pack-fn smoke test
// exercised the bug). The root cause is broader than packs: ANY
// comptime fn with `is_comptime` params, a non-void return, and a
// block body with `return X;` had the same crash. `format`/`print`
// use arrow form (`=> expr`) or `#insert`-only bodies, so the bug
// was invisible until pack-fn bodies surfaced it.
//
// Once fixed, calling foo() reaches the body's `return 42;`, the
// inliner stores 42 into a result slot, the caller loads it as the
// inline value, and main prints "42".
#import "modules/std.sx";
foo :: (..$args) -> s64 { return 42; }
main :: () -> s32 {
n : s64 = foo(1, "hello");
print("{}\n", n);
return 0;
}