diff --git a/src/ir/lower/decl.zig b/src/ir/lower/decl.zig index 8457fb36..109dcc2e 100644 --- a/src/ir/lower/decl.zig +++ b/src/ir/lower/decl.zig @@ -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]; } diff --git a/src/ir/lower/pack.zig b/src/ir/lower/pack.zig index 80a3da50..d08c3b3e 100644 --- a/src/ir/lower/pack.zig +++ b/src/ir/lower/pack.zig @@ -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