authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-01-29 12:19:10+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-06 15:55:29+02:00
log8c6e7fb2c7488faab0c41a4ea241f0110237ce91
treed4ca1d9e3c6a335caf311de1383e45758f221438
parent17e6e09285ed29ead1a3de5d5bfeb4d287f23215
signature Commit is signed but in an unrecognized format.

stage2: implement var args


7 files changed, 147 insertions(+), 34 deletions(-)

src/Module.zig+54-14
......@@ -1183,7 +1183,8 @@ fn astgenAndSemaFn(
11831183 const param_count = blk: {
11841184 var count: usize = 0;
11851185 var it = fn_proto.iterate(tree);
1186 while (it.next()) |_| {
1186 while (it.next()) |param| {
1187 if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;
11871188 count += 1;
11881189 }
11891190 break :blk count;
......@@ -1196,6 +1197,7 @@ fn astgenAndSemaFn(
11961197 });
11971198 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
11981199
1200 var is_var_args = false;
11991201 {
12001202 var param_type_i: usize = 0;
12011203 var it = fn_proto.iterate(tree);
......@@ -1208,12 +1210,10 @@ fn astgenAndSemaFn(
12081210 "TODO implement anytype parameter",
12091211 .{},
12101212 ),
1211 .ellipsis3 => return mod.failTok(
1212 &fn_type_scope.base,
1213 token,
1214 "TODO implement var args",
1215 .{},
1216 ),
1213 .ellipsis3 => {
1214 is_var_args = true;
1215 break;
1216 },
12171217 else => unreachable,
12181218 }
12191219 }
......@@ -1295,7 +1295,13 @@ fn astgenAndSemaFn(
12951295 type_type_rl,
12961296 fn_proto.ast.return_type,
12971297 );
1298 const fn_type_inst = if (fn_proto.ast.callconv_expr != 0) cc: {
1298
1299 const is_extern = if (fn_proto.extern_export_token) |maybe_export_token|
1300 token_tags[maybe_export_token] == .keyword_extern
1301 else
1302 false;
1303
1304 const cc_inst = if (fn_proto.ast.callconv_expr != 0) cc: {
12991305 // TODO instead of enum literal type, this needs to be the
13001306 // std.builtin.CallingConvention enum. We need to implement importing other files
13011307 // and enums in order to fix this.
......@@ -1304,18 +1310,31 @@ fn astgenAndSemaFn(
13041310 .ty = Type.initTag(.type),
13051311 .val = Value.initTag(.enum_literal_type),
13061312 });
1307 const cc = try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
1313 break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
13081314 .ty = enum_lit_ty,
13091315 }, fn_proto.ast.callconv_expr);
1310 break :cc try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type_cc, .{
1316 } else if (is_extern) cc: {
1317 // note: https://github.com/ziglang/zig/issues/5269
1318 const src = token_starts[fn_proto.extern_export_token.?];
1319 break :cc try astgen.addZIRInst(mod, &fn_type_scope.base, src, zir.Inst.EnumLiteral, .{ .name = "C" }, .{});
1320 } else null;
1321
1322 const fn_type_inst = if (cc_inst) |cc| fn_type: {
1323 var fn_type = try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type_cc, .{
13111324 .return_type = return_type_inst,
13121325 .param_types = param_types,
13131326 .cc = cc,
13141327 });
1315 } else try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{
1316 .return_type = return_type_inst,
1317 .param_types = param_types,
1318 });
1328 if (is_var_args) fn_type.tag = .fn_type_cc_var_args;
1329 break :fn_type fn_type;
1330 } else fn_type: {
1331 var fn_type = try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{
1332 .return_type = return_type_inst,
1333 .param_types = param_types,
1334 });
1335 if (is_var_args) fn_type.tag = .fn_type_var_args;
1336 break :fn_type fn_type;
1337 };
13191338
13201339 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
13211340 zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};
......@@ -1348,7 +1367,12 @@ fn astgenAndSemaFn(
13481367 const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{
13491368 .instructions = fn_type_scope.instructions.items,
13501369 });
1370
13511371 if (body_node == 0) {
1372 if (!is_extern) {
1373 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});
1374 }
1375
13521376 // Extern function.
13531377 var type_changed = true;
13541378 if (decl.typedValueManaged()) |tvm| {
......@@ -1378,6 +1402,10 @@ fn astgenAndSemaFn(
13781402 return type_changed;
13791403 }
13801404
1405 if (fn_type.fnIsVarArgs()) {
1406 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
1407 }
1408
13811409 const new_func = try decl_arena.allocator.create(Fn);
13821410 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
13831411
......@@ -3356,6 +3384,9 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
33563384}
33573385
33583386pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!*Inst {
3387 if (dest_type.tag() == .var_args_param) {
3388 return self.coerceVarArgParam(scope, inst);
3389 }
33593390 // If the types are the same, we can return the operand.
33603391 if (dest_type.eql(inst.ty))
33613392 return inst;
......@@ -3508,6 +3539,15 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) Inn
35083539 return null;
35093540}
35103541
3542pub fn coerceVarArgParam(mod: *Module, scope: *Scope, inst: *Inst) !*Inst {
3543 switch (inst.ty.zigTypeTag()) {
3544 .ComptimeInt, .ComptimeFloat => return mod.fail(scope, inst.src, "integer and float literals in var args function must be casted", .{}),
3545 else => {},
3546 }
3547 // TODO implement more of this function.
3548 return inst;
3549}
3550
35113551pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
35123552 if (ptr.ty.isConstPtr())
35133553 return self.fail(scope, src, "cannot assign to constant", .{});
src/codegen/c.zig+7-2
......@@ -215,8 +215,9 @@ pub const DeclGen = struct {
215215 try dg.renderType(w, tv.ty.fnReturnType());
216216 const decl_name = mem.span(dg.decl.name);
217217 try w.print(" {s}(", .{decl_name});
218 var param_len = tv.ty.fnParamLen();
219 if (param_len == 0)
218 const param_len = tv.ty.fnParamLen();
219 const is_var_args = tv.ty.fnIsVarArgs();
220 if (param_len == 0 and !is_var_args)
220221 try w.writeAll("void")
221222 else {
222223 var index: usize = 0;
......@@ -228,6 +229,10 @@ pub const DeclGen = struct {
228229 try w.print(" a{d}", .{index});
229230 }
230231 }
232 if (is_var_args) {
233 if (param_len != 0) try w.writeAll(", ");
234 try w.writeAll("...");
235 }
231236 try w.writeByte(')');
232237 }
233238
src/test.zig+1
......@@ -871,6 +871,7 @@ pub const TestContext = struct {
871871 "-std=c89",
872872 "-pedantic",
873873 "-Werror",
874 "-Wno-incompatible-library-redeclaration", // https://github.com/ziglang/zig/issues/875
874875 "-Wno-declaration-after-statement",
875876 "--",
876877 "-lc",
src/type.zig+46-1
......@@ -97,6 +97,8 @@ pub const Type = extern union {
9797 .@"struct", .empty_struct => return .Struct,
9898 .@"enum" => return .Enum,
9999 .@"union" => return .Union,
100
101 .var_args_param => unreachable, // can be any type
100102 }
101103 }
102104
......@@ -258,6 +260,8 @@ pub const Type = extern union {
258260 if (!a.fnParamType(i).eql(b.fnParamType(i)))
259261 return false;
260262 }
263 if (a.fnIsVarArgs() != b.fnIsVarArgs())
264 return false;
261265 return true;
262266 },
263267 .Optional => {
......@@ -323,6 +327,7 @@ pub const Type = extern union {
323327 while (i < params_len) : (i += 1) {
324328 std.hash.autoHash(&hasher, self.fnParamType(i).hash());
325329 }
330 std.hash.autoHash(&hasher, self.fnIsVarArgs());
326331 },
327332 .Optional => {
328333 var buf: Payload.ElemType = undefined;
......@@ -397,6 +402,7 @@ pub const Type = extern union {
397402 .@"anyframe",
398403 .inferred_alloc_const,
399404 .inferred_alloc_mut,
405 .var_args_param,
400406 => unreachable,
401407
402408 .array_u8,
......@@ -446,6 +452,7 @@ pub const Type = extern union {
446452 .return_type = try payload.return_type.copy(allocator),
447453 .param_types = param_types,
448454 .cc = payload.cc,
455 .is_var_args = payload.is_var_args,
449456 });
450457 },
451458 .pointer => {
......@@ -535,6 +542,7 @@ pub const Type = extern union {
535542 .comptime_int,
536543 .comptime_float,
537544 .noreturn,
545 .var_args_param,
538546 => return out_stream.writeAll(@tagName(t)),
539547
540548 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
......@@ -558,6 +566,12 @@ pub const Type = extern union {
558566 if (i != 0) try out_stream.writeAll(", ");
559567 try param_type.format("", .{}, out_stream);
560568 }
569 if (payload.is_var_args) {
570 if (payload.param_types.len != 0) {
571 try out_stream.writeAll(", ");
572 }
573 try out_stream.writeAll("...");
574 }
561575 try out_stream.writeAll(") callconv(.");
562576 try out_stream.writeAll(@tagName(payload.cc));
563577 try out_stream.writeAll(")");
......@@ -844,6 +858,7 @@ pub const Type = extern union {
844858
845859 .inferred_alloc_const => unreachable,
846860 .inferred_alloc_mut => unreachable,
861 .var_args_param => unreachable,
847862 };
848863 }
849864
......@@ -969,6 +984,7 @@ pub const Type = extern union {
969984 .inferred_alloc_const,
970985 .inferred_alloc_mut,
971986 .@"opaque",
987 .var_args_param,
972988 => unreachable,
973989 };
974990 }
......@@ -995,6 +1011,7 @@ pub const Type = extern union {
9951011 .inferred_alloc_const => unreachable,
9961012 .inferred_alloc_mut => unreachable,
9971013 .@"opaque" => unreachable,
1014 .var_args_param => unreachable,
9981015
9991016 .u8,
10001017 .i8,
......@@ -1179,6 +1196,7 @@ pub const Type = extern union {
11791196 .@"struct",
11801197 .@"union",
11811198 .@"opaque",
1199 .var_args_param,
11821200 => false,
11831201
11841202 .single_const_pointer,
......@@ -1256,6 +1274,7 @@ pub const Type = extern union {
12561274 .@"struct",
12571275 .@"union",
12581276 .@"opaque",
1277 .var_args_param,
12591278 => unreachable,
12601279
12611280 .const_slice,
......@@ -1354,6 +1373,7 @@ pub const Type = extern union {
13541373 .@"struct",
13551374 .@"union",
13561375 .@"opaque",
1376 .var_args_param,
13571377 => false,
13581378
13591379 .const_slice,
......@@ -1434,6 +1454,7 @@ pub const Type = extern union {
14341454 .@"struct",
14351455 .@"union",
14361456 .@"opaque",
1457 .var_args_param,
14371458 => false,
14381459
14391460 .single_const_pointer,
......@@ -1523,6 +1544,7 @@ pub const Type = extern union {
15231544 .@"struct",
15241545 .@"union",
15251546 .@"opaque",
1547 .var_args_param,
15261548 => false,
15271549
15281550 .pointer => {
......@@ -1607,6 +1629,7 @@ pub const Type = extern union {
16071629 .@"struct",
16081630 .@"union",
16091631 .@"opaque",
1632 .var_args_param,
16101633 => false,
16111634
16121635 .pointer => {
......@@ -1733,6 +1756,7 @@ pub const Type = extern union {
17331756 .@"struct" => unreachable,
17341757 .@"union" => unreachable,
17351758 .@"opaque" => unreachable,
1759 .var_args_param => unreachable,
17361760
17371761 .array => self.castTag(.array).?.data.elem_type,
17381762 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
......@@ -1862,6 +1886,7 @@ pub const Type = extern union {
18621886 .@"struct",
18631887 .@"union",
18641888 .@"opaque",
1889 .var_args_param,
18651890 => unreachable,
18661891
18671892 .array => self.castTag(.array).?.data.len,
......@@ -1936,6 +1961,7 @@ pub const Type = extern union {
19361961 .@"struct",
19371962 .@"union",
19381963 .@"opaque",
1964 .var_args_param,
19391965 => unreachable,
19401966
19411967 .single_const_pointer,
......@@ -2025,6 +2051,7 @@ pub const Type = extern union {
20252051 .@"struct",
20262052 .@"union",
20272053 .@"opaque",
2054 .var_args_param,
20282055 => false,
20292056
20302057 .int_signed,
......@@ -2110,6 +2137,7 @@ pub const Type = extern union {
21102137 .@"struct",
21112138 .@"union",
21122139 .@"opaque",
2140 .var_args_param,
21132141 => false,
21142142
21152143 .int_unsigned,
......@@ -2181,6 +2209,7 @@ pub const Type = extern union {
21812209 .@"struct",
21822210 .@"union",
21832211 .@"opaque",
2212 .var_args_param,
21842213 => unreachable,
21852214
21862215 .int_unsigned => .{
......@@ -2280,6 +2309,7 @@ pub const Type = extern union {
22802309 .@"struct",
22812310 .@"union",
22822311 .@"opaque",
2312 .var_args_param,
22832313 => false,
22842314
22852315 .usize,
......@@ -2400,6 +2430,7 @@ pub const Type = extern union {
24002430 .@"struct",
24012431 .@"union",
24022432 .@"opaque",
2433 .var_args_param,
24032434 => unreachable,
24042435 };
24052436 }
......@@ -2486,6 +2517,7 @@ pub const Type = extern union {
24862517 .@"struct",
24872518 .@"union",
24882519 .@"opaque",
2520 .var_args_param,
24892521 => unreachable,
24902522 }
24912523 }
......@@ -2571,6 +2603,7 @@ pub const Type = extern union {
25712603 .@"struct",
25722604 .@"union",
25732605 .@"opaque",
2606 .var_args_param,
25742607 => unreachable,
25752608 }
25762609 }
......@@ -2656,6 +2689,7 @@ pub const Type = extern union {
26562689 .@"struct",
26572690 .@"union",
26582691 .@"opaque",
2692 .var_args_param,
26592693 => unreachable,
26602694 };
26612695 }
......@@ -2738,6 +2772,7 @@ pub const Type = extern union {
27382772 .@"struct",
27392773 .@"union",
27402774 .@"opaque",
2775 .var_args_param,
27412776 => unreachable,
27422777 };
27432778 }
......@@ -2749,7 +2784,7 @@ pub const Type = extern union {
27492784 .fn_void_no_args => false,
27502785 .fn_naked_noreturn_no_args => false,
27512786 .fn_ccc_void_no_args => false,
2752 .function => false,
2787 .function => self.castTag(.function).?.data.is_var_args,
27532788
27542789 .f16,
27552790 .f32,
......@@ -2820,6 +2855,7 @@ pub const Type = extern union {
28202855 .@"struct",
28212856 .@"union",
28222857 .@"opaque",
2858 .var_args_param,
28232859 => unreachable,
28242860 };
28252861 }
......@@ -2902,6 +2938,7 @@ pub const Type = extern union {
29022938 .@"struct",
29032939 .@"union",
29042940 .@"opaque",
2941 .var_args_param,
29052942 => false,
29062943 };
29072944 }
......@@ -2962,6 +2999,7 @@ pub const Type = extern union {
29622999 .error_set,
29633000 .error_set_single,
29643001 .@"opaque",
3002 .var_args_param,
29653003 => return null,
29663004
29673005 .@"enum" => @panic("TODO onePossibleValue enum"),
......@@ -3079,6 +3117,7 @@ pub const Type = extern union {
30793117 .@"struct",
30803118 .@"union",
30813119 .@"opaque",
3120 .var_args_param,
30823121 => return false,
30833122
30843123 .c_const_pointer,
......@@ -3168,6 +3207,7 @@ pub const Type = extern union {
31683207 .pointer,
31693208 .inferred_alloc_const,
31703209 .inferred_alloc_mut,
3210 .var_args_param,
31713211 => unreachable,
31723212
31733213 .empty_struct => self.castTag(.empty_struct).?.data,
......@@ -3285,6 +3325,9 @@ pub const Type = extern union {
32853325 anyerror_void_error_union,
32863326 @"anyframe",
32873327 const_slice_u8,
3328 /// This is a special type for variadic parameters of a function call.
3329 /// Casts to it will validate that the type can be passed to a c calling convetion function.
3330 var_args_param,
32883331 /// This is a special value that tracks a set of types that have been stored
32893332 /// to an inferred allocation. It does not support most of the normal type queries.
32903333 /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.
......@@ -3373,6 +3416,7 @@ pub const Type = extern union {
33733416 .const_slice_u8,
33743417 .inferred_alloc_const,
33753418 .inferred_alloc_mut,
3419 .var_args_param,
33763420 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
33773421
33783422 .array_u8,
......@@ -3479,6 +3523,7 @@ pub const Type = extern union {
34793523 param_types: []Type,
34803524 return_type: Type,
34813525 cc: std.builtin.CallingConvention,
3526 is_var_args: bool,
34823527 },
34833528 };
34843529
src/zir.zig+8-2
......@@ -178,8 +178,12 @@ pub const Inst = struct {
178178 @"fn",
179179 /// Returns a function type, assuming unspecified calling convention.
180180 fn_type,
181 /// Same as `fn_type` but the function is variadic.
182 fn_type_var_args,
181183 /// Returns a function type, with a calling convention instruction operand.
182184 fn_type_cc,
185 /// Same as `fn_type_cc` but the function is variadic.
186 fn_type_cc_var_args,
183187 /// @import(operand)
184188 import,
185189 /// Integer literal.
......@@ -502,8 +506,8 @@ pub const Inst = struct {
502506 .@"export" => Export,
503507 .param_type => ParamType,
504508 .primitive => Primitive,
505 .fn_type => FnType,
506 .fn_type_cc => FnTypeCc,
509 .fn_type, .fn_type_var_args => FnType,
510 .fn_type_cc, .fn_type_cc_var_args => FnTypeCc,
507511 .elem_ptr, .elem_val => Elem,
508512 .condbr => CondBr,
509513 .ptr_type => PtrType,
......@@ -579,7 +583,9 @@ pub const Inst = struct {
579583 .field_val_named,
580584 .@"fn",
581585 .fn_type,
586 .fn_type_var_args,
582587 .fn_type_cc,
588 .fn_type_cc_var_args,
583589 .int,
584590 .intcast,
585591 .int_type,
src/zir_sema.zig+18-15
......@@ -91,8 +91,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
9191 .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?),
9292 .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?),
9393 .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?),
94 .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?),
95 .fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?),
94 .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?, false),
95 .fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?, false),
96 .fn_type_var_args => return zirFnType(mod, scope, old_inst.castTag(.fn_type_var_args).?, true),
97 .fn_type_cc_var_args => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc_var_args).?, true),
9698 .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?),
9799 .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?),
98100 .floatcast => return zirFloatcast(mod, scope, old_inst.castTag(.floatcast).?),
......@@ -522,9 +524,11 @@ fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerErr
522524 },
523525 };
524526
525 // TODO support C-style var args
526527 const param_count = fn_ty.fnParamLen();
527528 if (arg_index >= param_count) {
529 if (fn_ty.fnIsVarArgs()) {
530 return mod.constType(scope, inst.base.src, Type.initTag(.var_args_param));
531 }
528532 return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
529533 arg_index,
530534 fn_ty,
......@@ -946,6 +950,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
946950 const call_params_len = inst.positionals.args.len;
947951 const fn_params_len = func.ty.fnParamLen();
948952 if (func.ty.fnIsVarArgs()) {
953 assert(cc == .C);
949954 if (call_params_len < fn_params_len) {
950955 // TODO add error note: declared here
951956 return mod.fail(
......@@ -955,7 +960,6 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
955960 .{ fn_params_len, call_params_len },
956961 );
957962 }
958 return mod.fail(scope, inst.base.src, "TODO implement support for calling var args functions", .{});
959963 } else if (fn_params_len != call_params_len) {
960964 // TODO add error note: declared here
961965 return mod.fail(
......@@ -974,15 +978,10 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
974978 }
975979
976980 // TODO handle function calls of generic functions
977
978 const fn_param_types = try mod.gpa.alloc(Type, fn_params_len);
979 defer mod.gpa.free(fn_param_types);
980 func.ty.fnParamTypes(fn_param_types);
981
982 const casted_args = try scope.arena().alloc(*Inst, fn_params_len);
981 const casted_args = try scope.arena().alloc(*Inst, call_params_len);
983982 for (inst.positionals.args) |src_arg, i| {
984 const uncasted_arg = try resolveInst(mod, scope, src_arg);
985 casted_args[i] = try mod.coerce(scope, fn_param_types[i], uncasted_arg);
983 // the args are already casted to the result of a param type instruction.
984 casted_args[i] = try resolveInst(mod, scope, src_arg);
986985 }
987986
988987 const ret_type = func.ty.fnReturnType();
......@@ -1503,7 +1502,7 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp)
15031502 return mod.constVoid(scope, unwrap.base.src);
15041503}
15051504
1506fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
1505fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType, var_args: bool) InnerError!*Inst {
15071506 const tracy = trace(@src());
15081507 defer tracy.end();
15091508
......@@ -1514,10 +1513,11 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*
15141513 fntype.positionals.param_types,
15151514 fntype.positionals.return_type,
15161515 .Unspecified,
1516 var_args,
15171517 );
15181518}
15191519
1520fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerError!*Inst {
1520fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args: bool) InnerError!*Inst {
15211521 const tracy = trace(@src());
15221522 defer tracy.end();
15231523
......@@ -1534,6 +1534,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerErr
15341534 fntype.positionals.param_types,
15351535 fntype.positionals.return_type,
15361536 cc,
1537 var_args,
15371538 );
15381539}
15391540
......@@ -1544,11 +1545,12 @@ fn fnTypeCommon(
15441545 zir_param_types: []*zir.Inst,
15451546 zir_return_type: *zir.Inst,
15461547 cc: std.builtin.CallingConvention,
1548 var_args: bool,
15471549) InnerError!*Inst {
15481550 const return_type = try resolveType(mod, scope, zir_return_type);
15491551
15501552 // Hot path for some common function types.
1551 if (zir_param_types.len == 0) {
1553 if (zir_param_types.len == 0 and !var_args) {
15521554 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
15531555 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
15541556 }
......@@ -1581,6 +1583,7 @@ fn fnTypeCommon(
15811583 .param_types = param_types,
15821584 .return_type = return_type,
15831585 .cc = cc,
1586 .is_var_args = var_args,
15841587 });
15851588 return mod.constType(scope, zir_inst.src, fn_ty);
15861589}
test/stage2/cbe.zig+13
......@@ -41,6 +41,19 @@ pub fn addCases(ctx: *TestContext) !void {
4141 , "yo!" ++ std.cstr.line_sep);
4242 }
4343
44 {
45 var case = ctx.exeFromCompiledC("var args", .{});
46
47 case.addCompareOutput(
48 \\extern fn printf(format: [*:0]const u8, ...) c_int;
49 \\
50 \\export fn main() c_int {
51 \\ _ = printf("Hello, %s!\n", "world");
52 \\ return 0;
53 \\}
54 , "Hello, world!\n");
55 }
56
4457 {
4558 var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64);
4659