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
signaturelock-open 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(...@@ -1183,7 +1183,8 @@ fn astgenAndSemaFn(
1183 const param_count = blk: {1183 const param_count = blk: {
1184 var count: usize = 0;1184 var count: usize = 0;
1185 var it = fn_proto.iterate(tree);1185 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;
1187 count += 1;1188 count += 1;
1188 }1189 }
1189 break :blk count;1190 break :blk count;
...@@ -1196,6 +1197,7 @@ fn astgenAndSemaFn(...@@ -1196,6 +1197,7 @@ fn astgenAndSemaFn(
1196 });1197 });
1197 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };1198 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
11981199
1200 var is_var_args = false;
1199 {1201 {
1200 var param_type_i: usize = 0;1202 var param_type_i: usize = 0;
1201 var it = fn_proto.iterate(tree);1203 var it = fn_proto.iterate(tree);
...@@ -1208,12 +1210,10 @@ fn astgenAndSemaFn(...@@ -1208,12 +1210,10 @@ fn astgenAndSemaFn(
1208 "TODO implement anytype parameter",1210 "TODO implement anytype parameter",
1209 .{},1211 .{},
1210 ),1212 ),
1211 .ellipsis3 => return mod.failTok(1213 .ellipsis3 => {
1212 &fn_type_scope.base,1214 is_var_args = true;
1213 token,1215 break;
1214 "TODO implement var args",1216 },
1215 .{},
1216 ),
1217 else => unreachable,1217 else => unreachable,
1218 }1218 }
1219 }1219 }
...@@ -1295,7 +1295,13 @@ fn astgenAndSemaFn(...@@ -1295,7 +1295,13 @@ fn astgenAndSemaFn(
1295 type_type_rl,1295 type_type_rl,
1296 fn_proto.ast.return_type,1296 fn_proto.ast.return_type,
1297 );1297 );
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: {
1299 // TODO instead of enum literal type, this needs to be the1305 // TODO instead of enum literal type, this needs to be the
1300 // std.builtin.CallingConvention enum. We need to implement importing other files1306 // std.builtin.CallingConvention enum. We need to implement importing other files
1301 // and enums in order to fix this.1307 // and enums in order to fix this.
...@@ -1304,18 +1310,31 @@ fn astgenAndSemaFn(...@@ -1304,18 +1310,31 @@ fn astgenAndSemaFn(
1304 .ty = Type.initTag(.type),1310 .ty = Type.initTag(.type),
1305 .val = Value.initTag(.enum_literal_type),1311 .val = Value.initTag(.enum_literal_type),
1306 });1312 });
1307 const cc = try astgen.comptimeExpr(mod, &fn_type_scope.base, .{1313 break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
1308 .ty = enum_lit_ty,1314 .ty = enum_lit_ty,
1309 }, fn_proto.ast.callconv_expr);1315 }, 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, .{
1311 .return_type = return_type_inst,1324 .return_type = return_type_inst,
1312 .param_types = param_types,1325 .param_types = param_types,
1313 .cc = cc,1326 .cc = cc,
1314 });1327 });
1315 } else try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{1328 if (is_var_args) fn_type.tag = .fn_type_cc_var_args;
1316 .return_type = return_type_inst,1329 break :fn_type fn_type;
1317 .param_types = param_types,1330 } else fn_type: {
1318 });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
1320 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {1339 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
1321 zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};1340 zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};
...@@ -1348,7 +1367,12 @@ fn astgenAndSemaFn(...@@ -1348,7 +1367,12 @@ fn astgenAndSemaFn(
1348 const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{1367 const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{
1349 .instructions = fn_type_scope.instructions.items,1368 .instructions = fn_type_scope.instructions.items,
1350 });1369 });
1370
1351 if (body_node == 0) {1371 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
1352 // Extern function.1376 // Extern function.
1353 var type_changed = true;1377 var type_changed = true;
1354 if (decl.typedValueManaged()) |tvm| {1378 if (decl.typedValueManaged()) |tvm| {
...@@ -1378,6 +1402,10 @@ fn astgenAndSemaFn(...@@ -1378,6 +1402,10 @@ fn astgenAndSemaFn(
1378 return type_changed;1402 return type_changed;
1379 }1403 }
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
1381 const new_func = try decl_arena.allocator.create(Fn);1409 const new_func = try decl_arena.allocator.create(Fn);
1382 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);1410 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...@@ -3356,6 +3384,9 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
3356}3384}
33573385
3358pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!*Inst {3386pub 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 }
3359 // If the types are the same, we can return the operand.3390 // If the types are the same, we can return the operand.
3360 if (dest_type.eql(inst.ty))3391 if (dest_type.eql(inst.ty))
3361 return inst;3392 return inst;
...@@ -3508,6 +3539,15 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) Inn...@@ -3508,6 +3539,15 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) Inn
3508 return null;3539 return null;
3509}3540}
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
3511pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {3551pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
3512 if (ptr.ty.isConstPtr())3552 if (ptr.ty.isConstPtr())
3513 return self.fail(scope, src, "cannot assign to constant", .{});3553 return self.fail(scope, src, "cannot assign to constant", .{});
src/codegen/c.zig+7-2
...@@ -215,8 +215,9 @@ pub const DeclGen = struct {...@@ -215,8 +215,9 @@ pub const DeclGen = struct {
215 try dg.renderType(w, tv.ty.fnReturnType());215 try dg.renderType(w, tv.ty.fnReturnType());
216 const decl_name = mem.span(dg.decl.name);216 const decl_name = mem.span(dg.decl.name);
217 try w.print(" {s}(", .{decl_name});217 try w.print(" {s}(", .{decl_name});
218 var param_len = tv.ty.fnParamLen();218 const param_len = tv.ty.fnParamLen();
219 if (param_len == 0)219 const is_var_args = tv.ty.fnIsVarArgs();
220 if (param_len == 0 and !is_var_args)
220 try w.writeAll("void")221 try w.writeAll("void")
221 else {222 else {
222 var index: usize = 0;223 var index: usize = 0;
...@@ -228,6 +229,10 @@ pub const DeclGen = struct {...@@ -228,6 +229,10 @@ pub const DeclGen = struct {
228 try w.print(" a{d}", .{index});229 try w.print(" a{d}", .{index});
229 }230 }
230 }231 }
232 if (is_var_args) {
233 if (param_len != 0) try w.writeAll(", ");
234 try w.writeAll("...");
235 }
231 try w.writeByte(')');236 try w.writeByte(')');
232 }237 }
233238
src/test.zig+1
...@@ -871,6 +871,7 @@ pub const TestContext = struct {...@@ -871,6 +871,7 @@ pub const TestContext = struct {
871 "-std=c89",871 "-std=c89",
872 "-pedantic",872 "-pedantic",
873 "-Werror",873 "-Werror",
874 "-Wno-incompatible-library-redeclaration", // https://github.com/ziglang/zig/issues/875
874 "-Wno-declaration-after-statement",875 "-Wno-declaration-after-statement",
875 "--",876 "--",
876 "-lc",877 "-lc",
src/type.zig+46-1
...@@ -97,6 +97,8 @@ pub const Type = extern union {...@@ -97,6 +97,8 @@ pub const Type = extern union {
97 .@"struct", .empty_struct => return .Struct,97 .@"struct", .empty_struct => return .Struct,
98 .@"enum" => return .Enum,98 .@"enum" => return .Enum,
99 .@"union" => return .Union,99 .@"union" => return .Union,
100
101 .var_args_param => unreachable, // can be any type
100 }102 }
101 }103 }
102104
...@@ -258,6 +260,8 @@ pub const Type = extern union {...@@ -258,6 +260,8 @@ pub const Type = extern union {
258 if (!a.fnParamType(i).eql(b.fnParamType(i)))260 if (!a.fnParamType(i).eql(b.fnParamType(i)))
259 return false;261 return false;
260 }262 }
263 if (a.fnIsVarArgs() != b.fnIsVarArgs())
264 return false;
261 return true;265 return true;
262 },266 },
263 .Optional => {267 .Optional => {
...@@ -323,6 +327,7 @@ pub const Type = extern union {...@@ -323,6 +327,7 @@ pub const Type = extern union {
323 while (i < params_len) : (i += 1) {327 while (i < params_len) : (i += 1) {
324 std.hash.autoHash(&hasher, self.fnParamType(i).hash());328 std.hash.autoHash(&hasher, self.fnParamType(i).hash());
325 }329 }
330 std.hash.autoHash(&hasher, self.fnIsVarArgs());
326 },331 },
327 .Optional => {332 .Optional => {
328 var buf: Payload.ElemType = undefined;333 var buf: Payload.ElemType = undefined;
...@@ -397,6 +402,7 @@ pub const Type = extern union {...@@ -397,6 +402,7 @@ pub const Type = extern union {
397 .@"anyframe",402 .@"anyframe",
398 .inferred_alloc_const,403 .inferred_alloc_const,
399 .inferred_alloc_mut,404 .inferred_alloc_mut,
405 .var_args_param,
400 => unreachable,406 => unreachable,
401407
402 .array_u8,408 .array_u8,
...@@ -446,6 +452,7 @@ pub const Type = extern union {...@@ -446,6 +452,7 @@ pub const Type = extern union {
446 .return_type = try payload.return_type.copy(allocator),452 .return_type = try payload.return_type.copy(allocator),
447 .param_types = param_types,453 .param_types = param_types,
448 .cc = payload.cc,454 .cc = payload.cc,
455 .is_var_args = payload.is_var_args,
449 });456 });
450 },457 },
451 .pointer => {458 .pointer => {
...@@ -535,6 +542,7 @@ pub const Type = extern union {...@@ -535,6 +542,7 @@ pub const Type = extern union {
535 .comptime_int,542 .comptime_int,
536 .comptime_float,543 .comptime_float,
537 .noreturn,544 .noreturn,
545 .var_args_param,
538 => return out_stream.writeAll(@tagName(t)),546 => return out_stream.writeAll(@tagName(t)),
539547
540 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),548 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
...@@ -558,6 +566,12 @@ pub const Type = extern union {...@@ -558,6 +566,12 @@ pub const Type = extern union {
558 if (i != 0) try out_stream.writeAll(", ");566 if (i != 0) try out_stream.writeAll(", ");
559 try param_type.format("", .{}, out_stream);567 try param_type.format("", .{}, out_stream);
560 }568 }
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 }
561 try out_stream.writeAll(") callconv(.");575 try out_stream.writeAll(") callconv(.");
562 try out_stream.writeAll(@tagName(payload.cc));576 try out_stream.writeAll(@tagName(payload.cc));
563 try out_stream.writeAll(")");577 try out_stream.writeAll(")");
...@@ -844,6 +858,7 @@ pub const Type = extern union {...@@ -844,6 +858,7 @@ pub const Type = extern union {
844858
845 .inferred_alloc_const => unreachable,859 .inferred_alloc_const => unreachable,
846 .inferred_alloc_mut => unreachable,860 .inferred_alloc_mut => unreachable,
861 .var_args_param => unreachable,
847 };862 };
848 }863 }
849864
...@@ -969,6 +984,7 @@ pub const Type = extern union {...@@ -969,6 +984,7 @@ pub const Type = extern union {
969 .inferred_alloc_const,984 .inferred_alloc_const,
970 .inferred_alloc_mut,985 .inferred_alloc_mut,
971 .@"opaque",986 .@"opaque",
987 .var_args_param,
972 => unreachable,988 => unreachable,
973 };989 };
974 }990 }
...@@ -995,6 +1011,7 @@ pub const Type = extern union {...@@ -995,6 +1011,7 @@ pub const Type = extern union {
995 .inferred_alloc_const => unreachable,1011 .inferred_alloc_const => unreachable,
996 .inferred_alloc_mut => unreachable,1012 .inferred_alloc_mut => unreachable,
997 .@"opaque" => unreachable,1013 .@"opaque" => unreachable,
1014 .var_args_param => unreachable,
9981015
999 .u8,1016 .u8,
1000 .i8,1017 .i8,
...@@ -1179,6 +1196,7 @@ pub const Type = extern union {...@@ -1179,6 +1196,7 @@ pub const Type = extern union {
1179 .@"struct",1196 .@"struct",
1180 .@"union",1197 .@"union",
1181 .@"opaque",1198 .@"opaque",
1199 .var_args_param,
1182 => false,1200 => false,
11831201
1184 .single_const_pointer,1202 .single_const_pointer,
...@@ -1256,6 +1274,7 @@ pub const Type = extern union {...@@ -1256,6 +1274,7 @@ pub const Type = extern union {
1256 .@"struct",1274 .@"struct",
1257 .@"union",1275 .@"union",
1258 .@"opaque",1276 .@"opaque",
1277 .var_args_param,
1259 => unreachable,1278 => unreachable,
12601279
1261 .const_slice,1280 .const_slice,
...@@ -1354,6 +1373,7 @@ pub const Type = extern union {...@@ -1354,6 +1373,7 @@ pub const Type = extern union {
1354 .@"struct",1373 .@"struct",
1355 .@"union",1374 .@"union",
1356 .@"opaque",1375 .@"opaque",
1376 .var_args_param,
1357 => false,1377 => false,
13581378
1359 .const_slice,1379 .const_slice,
...@@ -1434,6 +1454,7 @@ pub const Type = extern union {...@@ -1434,6 +1454,7 @@ pub const Type = extern union {
1434 .@"struct",1454 .@"struct",
1435 .@"union",1455 .@"union",
1436 .@"opaque",1456 .@"opaque",
1457 .var_args_param,
1437 => false,1458 => false,
14381459
1439 .single_const_pointer,1460 .single_const_pointer,
...@@ -1523,6 +1544,7 @@ pub const Type = extern union {...@@ -1523,6 +1544,7 @@ pub const Type = extern union {
1523 .@"struct",1544 .@"struct",
1524 .@"union",1545 .@"union",
1525 .@"opaque",1546 .@"opaque",
1547 .var_args_param,
1526 => false,1548 => false,
15271549
1528 .pointer => {1550 .pointer => {
...@@ -1607,6 +1629,7 @@ pub const Type = extern union {...@@ -1607,6 +1629,7 @@ pub const Type = extern union {
1607 .@"struct",1629 .@"struct",
1608 .@"union",1630 .@"union",
1609 .@"opaque",1631 .@"opaque",
1632 .var_args_param,
1610 => false,1633 => false,
16111634
1612 .pointer => {1635 .pointer => {
...@@ -1733,6 +1756,7 @@ pub const Type = extern union {...@@ -1733,6 +1756,7 @@ pub const Type = extern union {
1733 .@"struct" => unreachable,1756 .@"struct" => unreachable,
1734 .@"union" => unreachable,1757 .@"union" => unreachable,
1735 .@"opaque" => unreachable,1758 .@"opaque" => unreachable,
1759 .var_args_param => unreachable,
17361760
1737 .array => self.castTag(.array).?.data.elem_type,1761 .array => self.castTag(.array).?.data.elem_type,
1738 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,1762 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
...@@ -1862,6 +1886,7 @@ pub const Type = extern union {...@@ -1862,6 +1886,7 @@ pub const Type = extern union {
1862 .@"struct",1886 .@"struct",
1863 .@"union",1887 .@"union",
1864 .@"opaque",1888 .@"opaque",
1889 .var_args_param,
1865 => unreachable,1890 => unreachable,
18661891
1867 .array => self.castTag(.array).?.data.len,1892 .array => self.castTag(.array).?.data.len,
...@@ -1936,6 +1961,7 @@ pub const Type = extern union {...@@ -1936,6 +1961,7 @@ pub const Type = extern union {
1936 .@"struct",1961 .@"struct",
1937 .@"union",1962 .@"union",
1938 .@"opaque",1963 .@"opaque",
1964 .var_args_param,
1939 => unreachable,1965 => unreachable,
19401966
1941 .single_const_pointer,1967 .single_const_pointer,
...@@ -2025,6 +2051,7 @@ pub const Type = extern union {...@@ -2025,6 +2051,7 @@ pub const Type = extern union {
2025 .@"struct",2051 .@"struct",
2026 .@"union",2052 .@"union",
2027 .@"opaque",2053 .@"opaque",
2054 .var_args_param,
2028 => false,2055 => false,
20292056
2030 .int_signed,2057 .int_signed,
...@@ -2110,6 +2137,7 @@ pub const Type = extern union {...@@ -2110,6 +2137,7 @@ pub const Type = extern union {
2110 .@"struct",2137 .@"struct",
2111 .@"union",2138 .@"union",
2112 .@"opaque",2139 .@"opaque",
2140 .var_args_param,
2113 => false,2141 => false,
21142142
2115 .int_unsigned,2143 .int_unsigned,
...@@ -2181,6 +2209,7 @@ pub const Type = extern union {...@@ -2181,6 +2209,7 @@ pub const Type = extern union {
2181 .@"struct",2209 .@"struct",
2182 .@"union",2210 .@"union",
2183 .@"opaque",2211 .@"opaque",
2212 .var_args_param,
2184 => unreachable,2213 => unreachable,
21852214
2186 .int_unsigned => .{2215 .int_unsigned => .{
...@@ -2280,6 +2309,7 @@ pub const Type = extern union {...@@ -2280,6 +2309,7 @@ pub const Type = extern union {
2280 .@"struct",2309 .@"struct",
2281 .@"union",2310 .@"union",
2282 .@"opaque",2311 .@"opaque",
2312 .var_args_param,
2283 => false,2313 => false,
22842314
2285 .usize,2315 .usize,
...@@ -2400,6 +2430,7 @@ pub const Type = extern union {...@@ -2400,6 +2430,7 @@ pub const Type = extern union {
2400 .@"struct",2430 .@"struct",
2401 .@"union",2431 .@"union",
2402 .@"opaque",2432 .@"opaque",
2433 .var_args_param,
2403 => unreachable,2434 => unreachable,
2404 };2435 };
2405 }2436 }
...@@ -2486,6 +2517,7 @@ pub const Type = extern union {...@@ -2486,6 +2517,7 @@ pub const Type = extern union {
2486 .@"struct",2517 .@"struct",
2487 .@"union",2518 .@"union",
2488 .@"opaque",2519 .@"opaque",
2520 .var_args_param,
2489 => unreachable,2521 => unreachable,
2490 }2522 }
2491 }2523 }
...@@ -2571,6 +2603,7 @@ pub const Type = extern union {...@@ -2571,6 +2603,7 @@ pub const Type = extern union {
2571 .@"struct",2603 .@"struct",
2572 .@"union",2604 .@"union",
2573 .@"opaque",2605 .@"opaque",
2606 .var_args_param,
2574 => unreachable,2607 => unreachable,
2575 }2608 }
2576 }2609 }
...@@ -2656,6 +2689,7 @@ pub const Type = extern union {...@@ -2656,6 +2689,7 @@ pub const Type = extern union {
2656 .@"struct",2689 .@"struct",
2657 .@"union",2690 .@"union",
2658 .@"opaque",2691 .@"opaque",
2692 .var_args_param,
2659 => unreachable,2693 => unreachable,
2660 };2694 };
2661 }2695 }
...@@ -2738,6 +2772,7 @@ pub const Type = extern union {...@@ -2738,6 +2772,7 @@ pub const Type = extern union {
2738 .@"struct",2772 .@"struct",
2739 .@"union",2773 .@"union",
2740 .@"opaque",2774 .@"opaque",
2775 .var_args_param,
2741 => unreachable,2776 => unreachable,
2742 };2777 };
2743 }2778 }
...@@ -2749,7 +2784,7 @@ pub const Type = extern union {...@@ -2749,7 +2784,7 @@ pub const Type = extern union {
2749 .fn_void_no_args => false,2784 .fn_void_no_args => false,
2750 .fn_naked_noreturn_no_args => false,2785 .fn_naked_noreturn_no_args => false,
2751 .fn_ccc_void_no_args => false,2786 .fn_ccc_void_no_args => false,
2752 .function => false,2787 .function => self.castTag(.function).?.data.is_var_args,
27532788
2754 .f16,2789 .f16,
2755 .f32,2790 .f32,
...@@ -2820,6 +2855,7 @@ pub const Type = extern union {...@@ -2820,6 +2855,7 @@ pub const Type = extern union {
2820 .@"struct",2855 .@"struct",
2821 .@"union",2856 .@"union",
2822 .@"opaque",2857 .@"opaque",
2858 .var_args_param,
2823 => unreachable,2859 => unreachable,
2824 };2860 };
2825 }2861 }
...@@ -2902,6 +2938,7 @@ pub const Type = extern union {...@@ -2902,6 +2938,7 @@ pub const Type = extern union {
2902 .@"struct",2938 .@"struct",
2903 .@"union",2939 .@"union",
2904 .@"opaque",2940 .@"opaque",
2941 .var_args_param,
2905 => false,2942 => false,
2906 };2943 };
2907 }2944 }
...@@ -2962,6 +2999,7 @@ pub const Type = extern union {...@@ -2962,6 +2999,7 @@ pub const Type = extern union {
2962 .error_set,2999 .error_set,
2963 .error_set_single,3000 .error_set_single,
2964 .@"opaque",3001 .@"opaque",
3002 .var_args_param,
2965 => return null,3003 => return null,
29663004
2967 .@"enum" => @panic("TODO onePossibleValue enum"),3005 .@"enum" => @panic("TODO onePossibleValue enum"),
...@@ -3079,6 +3117,7 @@ pub const Type = extern union {...@@ -3079,6 +3117,7 @@ pub const Type = extern union {
3079 .@"struct",3117 .@"struct",
3080 .@"union",3118 .@"union",
3081 .@"opaque",3119 .@"opaque",
3120 .var_args_param,
3082 => return false,3121 => return false,
30833122
3084 .c_const_pointer,3123 .c_const_pointer,
...@@ -3168,6 +3207,7 @@ pub const Type = extern union {...@@ -3168,6 +3207,7 @@ pub const Type = extern union {
3168 .pointer,3207 .pointer,
3169 .inferred_alloc_const,3208 .inferred_alloc_const,
3170 .inferred_alloc_mut,3209 .inferred_alloc_mut,
3210 .var_args_param,
3171 => unreachable,3211 => unreachable,
31723212
3173 .empty_struct => self.castTag(.empty_struct).?.data,3213 .empty_struct => self.castTag(.empty_struct).?.data,
...@@ -3285,6 +3325,9 @@ pub const Type = extern union {...@@ -3285,6 +3325,9 @@ pub const Type = extern union {
3285 anyerror_void_error_union,3325 anyerror_void_error_union,
3286 @"anyframe",3326 @"anyframe",
3287 const_slice_u8,3327 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,
3288 /// This is a special value that tracks a set of types that have been stored3331 /// This is a special value that tracks a set of types that have been stored
3289 /// to an inferred allocation. It does not support most of the normal type queries.3332 /// to an inferred allocation. It does not support most of the normal type queries.
3290 /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.3333 /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.
...@@ -3373,6 +3416,7 @@ pub const Type = extern union {...@@ -3373,6 +3416,7 @@ pub const Type = extern union {
3373 .const_slice_u8,3416 .const_slice_u8,
3374 .inferred_alloc_const,3417 .inferred_alloc_const,
3375 .inferred_alloc_mut,3418 .inferred_alloc_mut,
3419 .var_args_param,
3376 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),3420 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
33773421
3378 .array_u8,3422 .array_u8,
...@@ -3479,6 +3523,7 @@ pub const Type = extern union {...@@ -3479,6 +3523,7 @@ pub const Type = extern union {
3479 param_types: []Type,3523 param_types: []Type,
3480 return_type: Type,3524 return_type: Type,
3481 cc: std.builtin.CallingConvention,3525 cc: std.builtin.CallingConvention,
3526 is_var_args: bool,
3482 },3527 },
3483 };3528 };
34843529
src/zir.zig+8-2
...@@ -178,8 +178,12 @@ pub const Inst = struct {...@@ -178,8 +178,12 @@ pub const Inst = struct {
178 @"fn",178 @"fn",
179 /// Returns a function type, assuming unspecified calling convention.179 /// Returns a function type, assuming unspecified calling convention.
180 fn_type,180 fn_type,
181 /// Same as `fn_type` but the function is variadic.
182 fn_type_var_args,
181 /// Returns a function type, with a calling convention instruction operand.183 /// Returns a function type, with a calling convention instruction operand.
182 fn_type_cc,184 fn_type_cc,
185 /// Same as `fn_type_cc` but the function is variadic.
186 fn_type_cc_var_args,
183 /// @import(operand)187 /// @import(operand)
184 import,188 import,
185 /// Integer literal.189 /// Integer literal.
...@@ -502,8 +506,8 @@ pub const Inst = struct {...@@ -502,8 +506,8 @@ pub const Inst = struct {
502 .@"export" => Export,506 .@"export" => Export,
503 .param_type => ParamType,507 .param_type => ParamType,
504 .primitive => Primitive,508 .primitive => Primitive,
505 .fn_type => FnType,509 .fn_type, .fn_type_var_args => FnType,
506 .fn_type_cc => FnTypeCc,510 .fn_type_cc, .fn_type_cc_var_args => FnTypeCc,
507 .elem_ptr, .elem_val => Elem,511 .elem_ptr, .elem_val => Elem,
508 .condbr => CondBr,512 .condbr => CondBr,
509 .ptr_type => PtrType,513 .ptr_type => PtrType,
...@@ -579,7 +583,9 @@ pub const Inst = struct {...@@ -579,7 +583,9 @@ pub const Inst = struct {
579 .field_val_named,583 .field_val_named,
580 .@"fn",584 .@"fn",
581 .fn_type,585 .fn_type,
586 .fn_type_var_args,
582 .fn_type_cc,587 .fn_type_cc,
588 .fn_type_cc_var_args,
583 .int,589 .int,
584 .intcast,590 .intcast,
585 .int_type,591 .int_type,
src/zir_sema.zig+18-15
...@@ -91,8 +91,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -91,8 +91,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
91 .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?),91 .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?),
92 .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?),92 .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?),
93 .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?),93 .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?),
94 .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?),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).?),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),
96 .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?),98 .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?),
97 .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?),99 .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?),
98 .floatcast => return zirFloatcast(mod, scope, old_inst.castTag(.floatcast).?),100 .floatcast => return zirFloatcast(mod, scope, old_inst.castTag(.floatcast).?),
...@@ -522,9 +524,11 @@ fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerErr...@@ -522,9 +524,11 @@ fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerErr
522 },524 },
523 };525 };
524526
525 // TODO support C-style var args
526 const param_count = fn_ty.fnParamLen();527 const param_count = fn_ty.fnParamLen();
527 if (arg_index >= param_count) {528 if (arg_index >= param_count) {
529 if (fn_ty.fnIsVarArgs()) {
530 return mod.constType(scope, inst.base.src, Type.initTag(.var_args_param));
531 }
528 return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{532 return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
529 arg_index,533 arg_index,
530 fn_ty,534 fn_ty,
...@@ -946,6 +950,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {...@@ -946,6 +950,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
946 const call_params_len = inst.positionals.args.len;950 const call_params_len = inst.positionals.args.len;
947 const fn_params_len = func.ty.fnParamLen();951 const fn_params_len = func.ty.fnParamLen();
948 if (func.ty.fnIsVarArgs()) {952 if (func.ty.fnIsVarArgs()) {
953 assert(cc == .C);
949 if (call_params_len < fn_params_len) {954 if (call_params_len < fn_params_len) {
950 // TODO add error note: declared here955 // TODO add error note: declared here
951 return mod.fail(956 return mod.fail(
...@@ -955,7 +960,6 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {...@@ -955,7 +960,6 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
955 .{ fn_params_len, call_params_len },960 .{ fn_params_len, call_params_len },
956 );961 );
957 }962 }
958 return mod.fail(scope, inst.base.src, "TODO implement support for calling var args functions", .{});
959 } else if (fn_params_len != call_params_len) {963 } else if (fn_params_len != call_params_len) {
960 // TODO add error note: declared here964 // TODO add error note: declared here
961 return mod.fail(965 return mod.fail(
...@@ -974,15 +978,10 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {...@@ -974,15 +978,10 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
974 }978 }
975979
976 // TODO handle function calls of generic functions980 // TODO handle function calls of generic functions
977981 const casted_args = try scope.arena().alloc(*Inst, call_params_len);
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);
983 for (inst.positionals.args) |src_arg, i| {982 for (inst.positionals.args) |src_arg, i| {
984 const uncasted_arg = try resolveInst(mod, scope, src_arg);983 // the args are already casted to the result of a param type instruction.
985 casted_args[i] = try mod.coerce(scope, fn_param_types[i], uncasted_arg);984 casted_args[i] = try resolveInst(mod, scope, src_arg);
986 }985 }
987986
988 const ret_type = func.ty.fnReturnType();987 const ret_type = func.ty.fnReturnType();
...@@ -1503,7 +1502,7 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp)...@@ -1503,7 +1502,7 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp)
1503 return mod.constVoid(scope, unwrap.base.src);1502 return mod.constVoid(scope, unwrap.base.src);
1504}1503}
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 {
1507 const tracy = trace(@src());1506 const tracy = trace(@src());
1508 defer tracy.end();1507 defer tracy.end();
15091508
...@@ -1514,10 +1513,11 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*...@@ -1514,10 +1513,11 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*
1514 fntype.positionals.param_types,1513 fntype.positionals.param_types,
1515 fntype.positionals.return_type,1514 fntype.positionals.return_type,
1516 .Unspecified,1515 .Unspecified,
1516 var_args,
1517 );1517 );
1518}1518}
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 {
1521 const tracy = trace(@src());1521 const tracy = trace(@src());
1522 defer tracy.end();1522 defer tracy.end();
15231523
...@@ -1534,6 +1534,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerErr...@@ -1534,6 +1534,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerErr
1534 fntype.positionals.param_types,1534 fntype.positionals.param_types,
1535 fntype.positionals.return_type,1535 fntype.positionals.return_type,
1536 cc,1536 cc,
1537 var_args,
1537 );1538 );
1538}1539}
15391540
...@@ -1544,11 +1545,12 @@ fn fnTypeCommon(...@@ -1544,11 +1545,12 @@ fn fnTypeCommon(
1544 zir_param_types: []*zir.Inst,1545 zir_param_types: []*zir.Inst,
1545 zir_return_type: *zir.Inst,1546 zir_return_type: *zir.Inst,
1546 cc: std.builtin.CallingConvention,1547 cc: std.builtin.CallingConvention,
1548 var_args: bool,
1547) InnerError!*Inst {1549) InnerError!*Inst {
1548 const return_type = try resolveType(mod, scope, zir_return_type);1550 const return_type = try resolveType(mod, scope, zir_return_type);
15491551
1550 // Hot path for some common function types.1552 // Hot path for some common function types.
1551 if (zir_param_types.len == 0) {1553 if (zir_param_types.len == 0 and !var_args) {
1552 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {1554 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
1553 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args));1555 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
1554 }1556 }
...@@ -1581,6 +1583,7 @@ fn fnTypeCommon(...@@ -1581,6 +1583,7 @@ fn fnTypeCommon(
1581 .param_types = param_types,1583 .param_types = param_types,
1582 .return_type = return_type,1584 .return_type = return_type,
1583 .cc = cc,1585 .cc = cc,
1586 .is_var_args = var_args,
1584 });1587 });
1585 return mod.constType(scope, zir_inst.src, fn_ty);1588 return mod.constType(scope, zir_inst.src, fn_ty);
1586}1589}
test/stage2/cbe.zig+13
...@@ -41,6 +41,19 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -41,6 +41,19 @@ pub fn addCases(ctx: *TestContext) !void {
41 , "yo!" ++ std.cstr.line_sep);41 , "yo!" ++ std.cstr.line_sep);
42 }42 }
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
44 {57 {
45 var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64);58 var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64);
4659