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