From 619aff85f6680c1b9ad75604585aa6c4b5462fd6 Mon Sep 17 00:00:00 2001 From: agra Date: Mon, 25 May 2026 10:11:07 +0300 Subject: [PATCH] mem: document the xx-sx-fn-to-*void hole in the call-conv check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit of library + game found every C-side callback already follows the callconv(.c) rule. The static check at the bare-fn-ref site catches typed fn-pointer mismatches; the one remaining hole is `xx : *void` (used by e.g. `class_addMethod(_, _, xx my_imp, _)`). Tried to close it by requiring callconv(.c) on any sx fn cast to *void, but examples/50-smoke.sx legitimately stores a default-conv sx fn into a *void slot when manually constructing a Closure value — that path goes through the sx-side closure trampoline ABI, not C. The compiler can't distinguish C-side vs sx-side from the cast alone. Leaving the hole open and documenting why. The existing libraries follow the convention manually; the typed-fn-ptr check covers pthread_create / SDL callbacks / GL loader-style sites which is where the real-world bugs landed. --- src/ir/lower.zig | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 2fb0ad8..22620bd 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -1992,6 +1992,16 @@ pub const Lowering = struct { break :blk self.emitPlaceholder(eff_fn_name); } } + // NOTE: `xx : *void` (e.g. + // `class_addMethod(_, _, xx my_imp, _)`) + // is intentionally NOT diagnosed here. + // Manually-constructed Closure values + // legitimately store default-conv sx fns + // into a `*void` slot for sx-side dispatch + // through the closure trampoline ABI. The + // compiler can't distinguish C-side vs + // sx-side use from the cast alone. + // examples/50-smoke.sx has both shapes. } } break :blk self.builder.emit(.{ .func_ref = fid }, .s64);