diff --git a/examples/188-block-string-arg.sx b/examples/188-block-string-arg.sx new file mode 100644 index 0000000..1fe8a8e --- /dev/null +++ b/examples/188-block-string-arg.sx @@ -0,0 +1,28 @@ +// Generic `Into(Block)` impl with a `string`-typed arg in the +// closure signature. The block trampoline declares the param with +// callconv(.c); without the abi-collapse fix, sx `string` got +// silently collapsed to `ptr` (the libc `char *` heuristic) and +// the caller's 16-byte `{ptr, len}` value mismatched the +// trampoline's 8-byte `ptr` slot. Result: segfault inside the +// trampoline's first read. +// +// The fix lives in `abiCoerceParamTypeEx`: the `string`/`slice` → +// `ptr` collapse only applies to `is_extern` foreign decls (libc +// interop). sx-internal `callconv(.c)` keeps the full slice +// shape, which lands as `[2 x i64]` at the LLVM signature site +// and matches the caller's two-register pass on AArch64. + +#import "modules/std.sx"; +#import "modules/std/objc_block.sx"; + +g_s: string = ""; + +main :: () -> s32 { + cl := (s: string) => { g_s = s; }; + b : Block = xx cl; + invoke_fn : (*Block, string) -> void callconv(.c) = xx b.invoke; + invoke_fn(@b, "hello"); + if g_s.len == 0 { print("FAIL: empty\n"); return 1; } + print("got: <{}>\n", g_s); + 0; +} diff --git a/tests/expected/188-block-string-arg.exit b/tests/expected/188-block-string-arg.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/188-block-string-arg.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/188-block-string-arg.txt b/tests/expected/188-block-string-arg.txt new file mode 100644 index 0000000..30da966 --- /dev/null +++ b/tests/expected/188-block-string-arg.txt @@ -0,0 +1 @@ +got: