diff --git a/examples/157-pack-if-return.sx b/examples/157-pack-if-return.sx new file mode 100644 index 0000000..fb770f8 --- /dev/null +++ b/examples/157-pack-if-return.sx @@ -0,0 +1,39 @@ +// Variadic heterogeneous type packs — control-flow follow-up to +// issue-0045 fix (commit 9e78790). +// +// issue-0045's fix routes inline-comptime-body `return X;` into a +// result slot so the caller's basic block isn't terminated +// mid-flight. But the fix sets `block_terminated = true` after +// the inline return — which leaks PAST the enclosing `if`'s +// merge block. When the body shape is +// if cond { return X; } +// return Y; +// only the then-branch's `return X;` runs; `block_terminated` +// stays true in the merge block, so `lowerBlockValue`'s loop +// exits before the trailing `return Y;` lowers. The trailing +// return never stores into the slot — for the false-condition +// path the load reads uninitialised stack memory. +// +// Pack-fn `..$args` is the shortest repro because `args.len` +// gives a comptime-feeling test for the condition. The bug is +// actually shape-agnostic — any comptime body with `if cond +// { return X; }; return Y;` regresses the same way. +// +// `maybe()` with zero call-args takes the false branch and +// should fall through to `return -1;`. Today it loads garbage +// from the uninitialised slot. + +#import "modules/std.sx"; + +maybe :: (..$args) -> s64 { + if args.len > 0 { + return 42; + } + return -1; +} + +main :: () -> s32 { + print("{}\n", maybe()); // expect -1 + print("{}\n", maybe(99)); // expect 42 + return 0; +} diff --git a/tests/expected/157-pack-if-return.exit b/tests/expected/157-pack-if-return.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/157-pack-if-return.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/157-pack-if-return.txt b/tests/expected/157-pack-if-return.txt new file mode 100644 index 0000000..1e218e9 --- /dev/null +++ b/tests/expected/157-pack-if-return.txt @@ -0,0 +1,2 @@ +8354116000 +42