fix(ffi-linkage): Phase 5.0 prereq — map extern C-variadic tail to ... like #foreign
Two gates were keyed on the `#foreign` (foreign_expr) body shape only: - declareFunction: the is_variadic drop (decl.zig) — a variadic extern kept its trailing slice param in the IR signature. - packVariadicCallArgs: the call-site early-out (pack.zig) — extras were slice-packed instead of passed through the C `...` slot. Both now also fire for `extern_export == .extern_`, so a variadic `extern` drops the trailing `..args: []T`, sets is_variadic, and passes extras through the C ABI with default argument promotion — byte-identical to its `#foreign` twin. Greens example 1229. 645 corpus / 444 unit, 0 failed.
This commit is contained in:
@@ -2094,7 +2094,12 @@ pub fn declareFunction(self: *Lowering, fd: *const ast.FnDecl, name: []const u8)
|
||||
const is_extern_decl = fd.extern_export == .extern_;
|
||||
var is_variadic = false;
|
||||
var effective_params = fd.params;
|
||||
if (is_foreign and fd.params.len > 0 and fd.params[fd.params.len - 1].is_variadic) {
|
||||
// The C-variadic `...` tail applies to BOTH lib-less C-import spellings:
|
||||
// the legacy `#foreign` (foreign_expr body) and the new `extern` keyword.
|
||||
// A migrated variadic `extern` must drop the trailing slice param and set
|
||||
// the flag exactly as its `#foreign` twin did (mirrored at the call site
|
||||
// by `packVariadicCallArgs`).
|
||||
if ((is_foreign or is_extern_decl) and fd.params.len > 0 and fd.params[fd.params.len - 1].is_variadic) {
|
||||
is_variadic = true;
|
||||
effective_params = fd.params[0 .. fd.params.len - 1];
|
||||
}
|
||||
|
||||
@@ -296,10 +296,14 @@ pub fn lowerVariadicArgs(self: *Lowering, param_name: []const u8, call_args: []c
|
||||
/// Detects variadic params in the function decl, packs remaining args into a typed slice,
|
||||
/// and replaces the args list with [fixed_args..., slice_ref].
|
||||
pub fn packVariadicCallArgs(self: *Lowering, fd: *const ast.FnDecl, c: *const ast.Call, args: *std.ArrayList(Ref)) void {
|
||||
// `#foreign` variadic uses the C calling convention's `...` tail —
|
||||
// extras are passed through directly with default argument promotion
|
||||
// (handled at the call site), not packed into an sx slice.
|
||||
if (fd.body.data == .foreign_expr and fd.params.len > 0 and fd.params[fd.params.len - 1].is_variadic) {
|
||||
// A lib-less C-import variadic — `#foreign` (foreign_expr body) OR the new
|
||||
// `extern` keyword — uses the C calling convention's `...` tail: extras are
|
||||
// passed through directly with default argument promotion (handled at the
|
||||
// call site), not packed into an sx slice. Mirrors the `is_variadic` drop
|
||||
// in `declareFunction`.
|
||||
if ((fd.body.data == .foreign_expr or fd.extern_export == .extern_) and
|
||||
fd.params.len > 0 and fd.params[fd.params.len - 1].is_variadic)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Find variadic param index. The two surface forms differ in
|
||||
|
||||
Reference in New Issue
Block a user