| author | |
| committer | |
| log | 8c6e7fb2c7488faab0c41a4ea241f0110237ce91 |
| tree | d4ca1d9e3c6a335caf311de1383e45758f221438 |
| parent | 17e6e09285ed29ead1a3de5d5bfeb4d287f23215 |
| signature |
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 }; |
| 1198 | 1199 | ||
| 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 the | 1305 | // TODO instead of enum literal type, this needs to be the |
| 1300 | // std.builtin.CallingConvention enum. We need to implement importing other files | 1306 | // 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 | }; | ||
| 1319 | 1338 | ||
| 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 | } |
| 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 | 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); |
| 1383 | 1411 | ||
| ... | @@ -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 | } |
| 3357 | 3385 | ||
| 3358 | pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!*Inst { | 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 | // 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 | } |
| 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 | pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst { | 3551 | pub 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 | } |
| 233 | 238 |
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 | } |
| 102 | 104 | ||
| ... | @@ -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, |
| 401 | 407 | ||
| 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)), |
| 539 | 547 | ||
| 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 { |
| 844 | 858 | ||
| 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 | } |
| 849 | 864 | ||
| ... | @@ -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, | ||
| 998 | 1015 | ||
| 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, |
| 1183 | 1201 | ||
| 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, |
| 1260 | 1279 | ||
| 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, |
| 1358 | 1378 | ||
| 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, |
| 1438 | 1459 | ||
| 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, |
| 1527 | 1549 | ||
| 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, |
| 1611 | 1634 | ||
| 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, | ||
| 1736 | 1760 | ||
| 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, |
| 1866 | 1891 | ||
| 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, |
| 1940 | 1966 | ||
| 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, |
| 2029 | 2056 | ||
| 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, |
| 2114 | 2142 | ||
| 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, |
| 2185 | 2214 | ||
| 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, |
| 2284 | 2314 | ||
| 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, |
| 2753 | 2788 | ||
| 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, |
| 2966 | 3004 | ||
| 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, |
| 3083 | 3122 | ||
| 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, |
| 3172 | 3212 | ||
| 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 stored | 3331 | /// 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"), |
| 3377 | 3421 | ||
| 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 | }; |
| 3484 | 3529 |
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 | }; |
| 524 | 526 | ||
| 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 here | 955 | // 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 here | 964 | // 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 | } |
| 975 | 979 | ||
| 976 | // TODO handle function calls of generic functions | 980 | // TODO handle function calls of generic functions |
| 977 | 981 | 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 | } |
| 987 | 986 | ||
| 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 | } |
| 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 | const tracy = trace(@src()); | 1506 | const tracy = trace(@src()); |
| 1508 | defer tracy.end(); | 1507 | defer tracy.end(); |
| 1509 | 1508 | ||
| ... | @@ -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 | } |
| 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 | const tracy = trace(@src()); | 1521 | const tracy = trace(@src()); |
| 1522 | defer tracy.end(); | 1522 | defer tracy.end(); |
| 1523 | 1523 | ||
| ... | @@ -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 | } |
| 1539 | 1540 | ||
| ... | @@ -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); |
| 1549 | 1551 | ||
| 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 | } |
| 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 | var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64); | 58 | var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64); |
| 46 | 59 |