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_;
|
const is_extern_decl = fd.extern_export == .extern_;
|
||||||
var is_variadic = false;
|
var is_variadic = false;
|
||||||
var effective_params = fd.params;
|
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;
|
is_variadic = true;
|
||||||
effective_params = fd.params[0 .. fd.params.len - 1];
|
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,
|
/// Detects variadic params in the function decl, packs remaining args into a typed slice,
|
||||||
/// and replaces the args list with [fixed_args..., slice_ref].
|
/// 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 {
|
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 —
|
// A lib-less C-import variadic — `#foreign` (foreign_expr body) OR the new
|
||||||
// extras are passed through directly with default argument promotion
|
// `extern` keyword — uses the C calling convention's `...` tail: extras are
|
||||||
// (handled at the call site), not packed into an sx slice.
|
// passed through directly with default argument promotion (handled at the
|
||||||
if (fd.body.data == .foreign_expr and fd.params.len > 0 and fd.params[fd.params.len - 1].is_variadic) {
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
// Find variadic param index. The two surface forms differ in
|
// Find variadic param index. The two surface forms differ in
|
||||||
|
|||||||
Reference in New Issue
Block a user