| author | |
| committer | |
| log | 34cb5934ddd7c79fb96ffed87768764247740260 |
| tree | d4ca1d9e3c6a335caf311de1383e45758f221438 |
| parent | 9f722f43ac449caa0e09c1b7bb1bad0581ef323d |
| parent | 8c6e7fb2c7488faab0c41a4ea241f0110237ce91 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
Stage2: astgen async stuff, implement var args functions8 files changed, 370 insertions(+), 43 deletions(-)
src/Module.zig+123-16| ... | ... | @@ -370,6 +370,8 @@ pub const Scope = struct { |
| 370 | 370 | .gen_zir => return self.cast(GenZIR).?.arena, |
| 371 | 371 | .local_val => return self.cast(LocalVal).?.gen_zir.arena, |
| 372 | 372 | .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena, |
| 373 | .gen_suspend => return self.cast(GenZIR).?.arena, | |
| 374 | .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.arena, | |
| 373 | 375 | .file => unreachable, |
| 374 | 376 | .container => unreachable, |
| 375 | 377 | } |
| ... | ... | @@ -385,6 +387,8 @@ pub const Scope = struct { |
| 385 | 387 | .gen_zir => self.cast(GenZIR).?.decl, |
| 386 | 388 | .local_val => self.cast(LocalVal).?.gen_zir.decl, |
| 387 | 389 | .local_ptr => self.cast(LocalPtr).?.gen_zir.decl, |
| 390 | .gen_suspend => return self.cast(GenZIR).?.decl, | |
| 391 | .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl, | |
| 388 | 392 | .file => null, |
| 389 | 393 | .container => null, |
| 390 | 394 | }; |
| ... | ... | @@ -396,6 +400,8 @@ pub const Scope = struct { |
| 396 | 400 | .gen_zir => self.cast(GenZIR).?.decl, |
| 397 | 401 | .local_val => self.cast(LocalVal).?.gen_zir.decl, |
| 398 | 402 | .local_ptr => self.cast(LocalPtr).?.gen_zir.decl, |
| 403 | .gen_suspend => return self.cast(GenZIR).?.decl, | |
| 404 | .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl, | |
| 399 | 405 | .file => null, |
| 400 | 406 | .container => null, |
| 401 | 407 | }; |
| ... | ... | @@ -410,6 +416,8 @@ pub const Scope = struct { |
| 410 | 416 | .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container, |
| 411 | 417 | .file => return &self.cast(File).?.root_container, |
| 412 | 418 | .container => return self.cast(Container).?, |
| 419 | .gen_suspend => return self.cast(GenZIR).?.decl.container, | |
| 420 | .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl.container, | |
| 413 | 421 | } |
| 414 | 422 | } |
| 415 | 423 | |
| ... | ... | @@ -422,6 +430,8 @@ pub const Scope = struct { |
| 422 | 430 | .gen_zir => unreachable, |
| 423 | 431 | .local_val => unreachable, |
| 424 | 432 | .local_ptr => unreachable, |
| 433 | .gen_suspend => unreachable, | |
| 434 | .gen_nosuspend => unreachable, | |
| 425 | 435 | .file => unreachable, |
| 426 | 436 | .container => return self.cast(Container).?.fullyQualifiedNameHash(name), |
| 427 | 437 | } |
| ... | ... | @@ -436,6 +446,8 @@ pub const Scope = struct { |
| 436 | 446 | .local_val => return &self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree, |
| 437 | 447 | .local_ptr => return &self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree, |
| 438 | 448 | .container => return &self.cast(Container).?.file_scope.tree, |
| 449 | .gen_suspend => return &self.cast(GenZIR).?.decl.container.file_scope.tree, | |
| 450 | .gen_nosuspend => return &self.cast(Nosuspend).?.gen_zir.decl.container.file_scope.tree, | |
| 439 | 451 | } |
| 440 | 452 | } |
| 441 | 453 | |
| ... | ... | @@ -443,9 +455,10 @@ pub const Scope = struct { |
| 443 | 455 | pub fn getGenZIR(self: *Scope) *GenZIR { |
| 444 | 456 | return switch (self.tag) { |
| 445 | 457 | .block => unreachable, |
| 446 | .gen_zir => self.cast(GenZIR).?, | |
| 458 | .gen_zir, .gen_suspend => self.cast(GenZIR).?, | |
| 447 | 459 | .local_val => return self.cast(LocalVal).?.gen_zir, |
| 448 | 460 | .local_ptr => return self.cast(LocalPtr).?.gen_zir, |
| 461 | .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir, | |
| 449 | 462 | .file => unreachable, |
| 450 | 463 | .container => unreachable, |
| 451 | 464 | }; |
| ... | ... | @@ -461,6 +474,8 @@ pub const Scope = struct { |
| 461 | 474 | .gen_zir => unreachable, |
| 462 | 475 | .local_val => unreachable, |
| 463 | 476 | .local_ptr => unreachable, |
| 477 | .gen_suspend => unreachable, | |
| 478 | .gen_nosuspend => unreachable, | |
| 464 | 479 | } |
| 465 | 480 | } |
| 466 | 481 | |
| ... | ... | @@ -472,6 +487,8 @@ pub const Scope = struct { |
| 472 | 487 | .local_val => unreachable, |
| 473 | 488 | .local_ptr => unreachable, |
| 474 | 489 | .block => unreachable, |
| 490 | .gen_suspend => unreachable, | |
| 491 | .gen_nosuspend => unreachable, | |
| 475 | 492 | } |
| 476 | 493 | } |
| 477 | 494 | |
| ... | ... | @@ -486,6 +503,36 @@ pub const Scope = struct { |
| 486 | 503 | .local_val => @fieldParentPtr(LocalVal, "base", cur).parent, |
| 487 | 504 | .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent, |
| 488 | 505 | .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope, |
| 506 | .gen_suspend => @fieldParentPtr(GenZIR, "base", cur).parent, | |
| 507 | .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent, | |
| 508 | }; | |
| 509 | } | |
| 510 | } | |
| 511 | ||
| 512 | pub fn getSuspend(base: *Scope) ?*Scope.GenZIR { | |
| 513 | var cur = base; | |
| 514 | while (true) { | |
| 515 | cur = switch (cur.tag) { | |
| 516 | .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent, | |
| 517 | .local_val => @fieldParentPtr(LocalVal, "base", cur).parent, | |
| 518 | .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent, | |
| 519 | .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent, | |
| 520 | .gen_suspend => return @fieldParentPtr(GenZIR, "base", cur), | |
| 521 | else => return null, | |
| 522 | }; | |
| 523 | } | |
| 524 | } | |
| 525 | ||
| 526 | pub fn getNosuspend(base: *Scope) ?*Scope.Nosuspend { | |
| 527 | var cur = base; | |
| 528 | while (true) { | |
| 529 | cur = switch (cur.tag) { | |
| 530 | .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent, | |
| 531 | .local_val => @fieldParentPtr(LocalVal, "base", cur).parent, | |
| 532 | .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent, | |
| 533 | .gen_suspend => @fieldParentPtr(GenZIR, "base", cur).parent, | |
| 534 | .gen_nosuspend => return @fieldParentPtr(Nosuspend, "base", cur), | |
| 535 | else => return null, | |
| 489 | 536 | }; |
| 490 | 537 | } |
| 491 | 538 | } |
| ... | ... | @@ -507,6 +554,8 @@ pub const Scope = struct { |
| 507 | 554 | gen_zir, |
| 508 | 555 | local_val, |
| 509 | 556 | local_ptr, |
| 557 | gen_suspend, | |
| 558 | gen_nosuspend, | |
| 510 | 559 | }; |
| 511 | 560 | |
| 512 | 561 | pub const Container = struct { |
| ... | ... | @@ -740,6 +789,8 @@ pub const Scope = struct { |
| 740 | 789 | /// so they can possibly be elided later if the labeled block ends up not needing |
| 741 | 790 | /// a result location pointer. |
| 742 | 791 | labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(*zir.Inst.BinOp) = .{}, |
| 792 | /// for suspend error notes | |
| 793 | src: usize = 0, | |
| 743 | 794 | |
| 744 | 795 | pub const Label = struct { |
| 745 | 796 | token: ast.TokenIndex, |
| ... | ... | @@ -773,6 +824,16 @@ pub const Scope = struct { |
| 773 | 824 | name: []const u8, |
| 774 | 825 | ptr: *zir.Inst, |
| 775 | 826 | }; |
| 827 | ||
| 828 | pub const Nosuspend = struct { | |
| 829 | pub const base_tag: Tag = .gen_nosuspend; | |
| 830 | ||
| 831 | base: Scope = Scope{ .tag = base_tag }, | |
| 832 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`. | |
| 833 | parent: *Scope, | |
| 834 | gen_zir: *GenZIR, | |
| 835 | src: usize, | |
| 836 | }; | |
| 776 | 837 | }; |
| 777 | 838 | |
| 778 | 839 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. |
| ... | ... | @@ -1122,7 +1183,8 @@ fn astgenAndSemaFn( |
| 1122 | 1183 | const param_count = blk: { |
| 1123 | 1184 | var count: usize = 0; |
| 1124 | 1185 | var it = fn_proto.iterate(tree); |
| 1125 | while (it.next()) |_| { | |
| 1186 | while (it.next()) |param| { | |
| 1187 | if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break; | |
| 1126 | 1188 | count += 1; |
| 1127 | 1189 | } |
| 1128 | 1190 | break :blk count; |
| ... | ... | @@ -1135,6 +1197,7 @@ fn astgenAndSemaFn( |
| 1135 | 1197 | }); |
| 1136 | 1198 | const type_type_rl: astgen.ResultLoc = .{ .ty = type_type }; |
| 1137 | 1199 | |
| 1200 | var is_var_args = false; | |
| 1138 | 1201 | { |
| 1139 | 1202 | var param_type_i: usize = 0; |
| 1140 | 1203 | var it = fn_proto.iterate(tree); |
| ... | ... | @@ -1147,12 +1210,10 @@ fn astgenAndSemaFn( |
| 1147 | 1210 | "TODO implement anytype parameter", |
| 1148 | 1211 | .{}, |
| 1149 | 1212 | ), |
| 1150 | .ellipsis3 => return mod.failTok( | |
| 1151 | &fn_type_scope.base, | |
| 1152 | token, | |
| 1153 | "TODO implement var args", | |
| 1154 | .{}, | |
| 1155 | ), | |
| 1213 | .ellipsis3 => { | |
| 1214 | is_var_args = true; | |
| 1215 | break; | |
| 1216 | }, | |
| 1156 | 1217 | else => unreachable, |
| 1157 | 1218 | } |
| 1158 | 1219 | } |
| ... | ... | @@ -1234,7 +1295,13 @@ fn astgenAndSemaFn( |
| 1234 | 1295 | type_type_rl, |
| 1235 | 1296 | fn_proto.ast.return_type, |
| 1236 | 1297 | ); |
| 1237 | 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: { | |
| 1238 | 1305 | // TODO instead of enum literal type, this needs to be the |
| 1239 | 1306 | // std.builtin.CallingConvention enum. We need to implement importing other files |
| 1240 | 1307 | // and enums in order to fix this. |
| ... | ... | @@ -1243,18 +1310,31 @@ fn astgenAndSemaFn( |
| 1243 | 1310 | .ty = Type.initTag(.type), |
| 1244 | 1311 | .val = Value.initTag(.enum_literal_type), |
| 1245 | 1312 | }); |
| 1246 | const cc = try astgen.comptimeExpr(mod, &fn_type_scope.base, .{ | |
| 1313 | break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{ | |
| 1247 | 1314 | .ty = enum_lit_ty, |
| 1248 | 1315 | }, fn_proto.ast.callconv_expr); |
| 1249 | 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, .{ | |
| 1250 | 1324 | .return_type = return_type_inst, |
| 1251 | 1325 | .param_types = param_types, |
| 1252 | 1326 | .cc = cc, |
| 1253 | 1327 | }); |
| 1254 | } else try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{ | |
| 1255 | .return_type = return_type_inst, | |
| 1256 | .param_types = param_types, | |
| 1257 | }); | |
| 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 | }; | |
| 1258 | 1338 | |
| 1259 | 1339 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { |
| 1260 | 1340 | zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {}; |
| ... | ... | @@ -1287,7 +1367,12 @@ fn astgenAndSemaFn( |
| 1287 | 1367 | const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{ |
| 1288 | 1368 | .instructions = fn_type_scope.instructions.items, |
| 1289 | 1369 | }); |
| 1370 | ||
| 1290 | 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 | ||
| 1291 | 1376 | // Extern function. |
| 1292 | 1377 | var type_changed = true; |
| 1293 | 1378 | if (decl.typedValueManaged()) |tvm| { |
| ... | ... | @@ -1317,6 +1402,10 @@ fn astgenAndSemaFn( |
| 1317 | 1402 | return type_changed; |
| 1318 | 1403 | } |
| 1319 | 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 | ||
| 1320 | 1409 | const new_func = try decl_arena.allocator.create(Fn); |
| 1321 | 1410 | const fn_payload = try decl_arena.allocator.create(Value.Payload.Function); |
| 1322 | 1411 | |
| ... | ... | @@ -3295,6 +3384,9 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty |
| 3295 | 3384 | } |
| 3296 | 3385 | |
| 3297 | 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 | } | |
| 3298 | 3390 | // If the types are the same, we can return the operand. |
| 3299 | 3391 | if (dest_type.eql(inst.ty)) |
| 3300 | 3392 | return inst; |
| ... | ... | @@ -3447,6 +3539,15 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) Inn |
| 3447 | 3539 | return null; |
| 3448 | 3540 | } |
| 3449 | 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 | ||
| 3450 | 3551 | pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst { |
| 3451 | 3552 | if (ptr.ty.isConstPtr()) |
| 3452 | 3553 | return self.fail(scope, src, "cannot assign to constant", .{}); |
| ... | ... | @@ -3586,7 +3687,7 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I |
| 3586 | 3687 | } |
| 3587 | 3688 | self.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg); |
| 3588 | 3689 | }, |
| 3589 | .gen_zir => { | |
| 3690 | .gen_zir, .gen_suspend => { | |
| 3590 | 3691 | const gen_zir = scope.cast(Scope.GenZIR).?; |
| 3591 | 3692 | gen_zir.decl.analysis = .sema_failure; |
| 3592 | 3693 | gen_zir.decl.generation = self.generation; |
| ... | ... | @@ -3604,6 +3705,12 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I |
| 3604 | 3705 | gen_zir.decl.generation = self.generation; |
| 3605 | 3706 | self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg); |
| 3606 | 3707 | }, |
| 3708 | .gen_nosuspend => { | |
| 3709 | const gen_zir = scope.cast(Scope.Nosuspend).?.gen_zir; | |
| 3710 | gen_zir.decl.analysis = .sema_failure; | |
| 3711 | gen_zir.decl.generation = self.generation; | |
| 3712 | self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg); | |
| 3713 | }, | |
| 3607 | 3714 | .file => unreachable, |
| 3608 | 3715 | .container => unreachable, |
| 3609 | 3716 | } |
src/astgen.zig+110-5| ... | ... | @@ -626,10 +626,13 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 626 | 626 | .@"comptime" => return comptimeExpr(mod, scope, rl, node_datas[node].lhs), |
| 627 | 627 | .@"switch", .switch_comma => return switchExpr(mod, scope, rl, node), |
| 628 | 628 | |
| 629 | .@"nosuspend" => return nosuspendExpr(mod, scope, rl, node), | |
| 630 | .@"suspend" => return rvalue(mod, scope, rl, try suspendExpr(mod, scope, node)), | |
| 631 | .@"await" => return awaitExpr(mod, scope, rl, node), | |
| 632 | .@"resume" => return rvalue(mod, scope, rl, try resumeExpr(mod, scope, node)), | |
| 633 | ||
| 629 | 634 | .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}), |
| 630 | 635 | .@"errdefer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .errdefer", .{}), |
| 631 | .@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}), | |
| 632 | .@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}), | |
| 633 | 636 | .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), |
| 634 | 637 | |
| 635 | 638 | .array_init_one, |
| ... | ... | @@ -652,15 +655,12 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In |
| 652 | 655 | .struct_init_comma, |
| 653 | 656 | => return mod.failNode(scope, node, "TODO implement astgen.expr for struct literals", .{}), |
| 654 | 657 | |
| 655 | .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}), | |
| 656 | 658 | .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}), |
| 657 | 659 | .fn_proto_simple, |
| 658 | 660 | .fn_proto_multi, |
| 659 | 661 | .fn_proto_one, |
| 660 | 662 | .fn_proto, |
| 661 | 663 | => return mod.failNode(scope, node, "TODO implement astgen.expr for function prototypes", .{}), |
| 662 | ||
| 663 | .@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}), | |
| 664 | 664 | } |
| 665 | 665 | } |
| 666 | 666 | |
| ... | ... | @@ -766,6 +766,8 @@ fn breakExpr( |
| 766 | 766 | }, |
| 767 | 767 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 768 | 768 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| 769 | .gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent, | |
| 770 | .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent, | |
| 769 | 771 | else => if (break_label != 0) { |
| 770 | 772 | const label_name = try mod.identifierTokenString(parent_scope, break_label); |
| 771 | 773 | return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name}); |
| ... | ... | @@ -819,6 +821,8 @@ fn continueExpr( |
| 819 | 821 | }, |
| 820 | 822 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 821 | 823 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| 824 | .gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent, | |
| 825 | .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent, | |
| 822 | 826 | else => if (break_label != 0) { |
| 823 | 827 | const label_name = try mod.identifierTokenString(parent_scope, break_label); |
| 824 | 828 | return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name}); |
| ... | ... | @@ -893,6 +897,8 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn |
| 893 | 897 | }, |
| 894 | 898 | .local_val => scope = scope.cast(Scope.LocalVal).?.parent, |
| 895 | 899 | .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent, |
| 900 | .gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent, | |
| 901 | .gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent, | |
| 896 | 902 | else => return, |
| 897 | 903 | } |
| 898 | 904 | } |
| ... | ... | @@ -1100,6 +1106,8 @@ fn varDecl( |
| 1100 | 1106 | s = local_ptr.parent; |
| 1101 | 1107 | }, |
| 1102 | 1108 | .gen_zir => s = s.cast(Scope.GenZIR).?.parent, |
| 1109 | .gen_suspend => s = s.cast(Scope.GenZIR).?.parent, | |
| 1110 | .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent, | |
| 1103 | 1111 | else => break, |
| 1104 | 1112 | }; |
| 1105 | 1113 | } |
| ... | ... | @@ -3021,6 +3029,8 @@ fn identifier( |
| 3021 | 3029 | s = local_ptr.parent; |
| 3022 | 3030 | }, |
| 3023 | 3031 | .gen_zir => s = s.cast(Scope.GenZIR).?.parent, |
| 3032 | .gen_suspend => s = s.cast(Scope.GenZIR).?.parent, | |
| 3033 | .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent, | |
| 3024 | 3034 | else => break, |
| 3025 | 3035 | }; |
| 3026 | 3036 | } |
| ... | ... | @@ -3633,14 +3643,109 @@ fn callExpr( |
| 3633 | 3643 | } |
| 3634 | 3644 | |
| 3635 | 3645 | const src = token_starts[call.ast.lparen]; |
| 3646 | var modifier: std.builtin.CallOptions.Modifier = .auto; | |
| 3647 | if (call.async_token) |_| modifier = .async_kw; | |
| 3648 | ||
| 3636 | 3649 | const result = try addZIRInst(mod, scope, src, zir.Inst.Call, .{ |
| 3637 | 3650 | .func = lhs, |
| 3638 | 3651 | .args = args, |
| 3652 | .modifier = modifier, | |
| 3639 | 3653 | }, .{}); |
| 3640 | 3654 | // TODO function call with result location |
| 3641 | 3655 | return rvalue(mod, scope, rl, result); |
| 3642 | 3656 | } |
| 3643 | 3657 | |
| 3658 | fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst { | |
| 3659 | const tree = scope.tree(); | |
| 3660 | const src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]]; | |
| 3661 | ||
| 3662 | if (scope.getNosuspend()) |some| { | |
| 3663 | const msg = msg: { | |
| 3664 | const msg = try mod.errMsg(scope, src, "suspend in nosuspend block", .{}); | |
| 3665 | errdefer msg.destroy(mod.gpa); | |
| 3666 | try mod.errNote(scope, some.src, msg, "nosuspend block here", .{}); | |
| 3667 | break :msg msg; | |
| 3668 | }; | |
| 3669 | return mod.failWithOwnedErrorMsg(scope, msg); | |
| 3670 | } | |
| 3671 | ||
| 3672 | if (scope.getSuspend()) |some| { | |
| 3673 | const msg = msg: { | |
| 3674 | const msg = try mod.errMsg(scope, src, "cannot suspend inside suspend block", .{}); | |
| 3675 | errdefer msg.destroy(mod.gpa); | |
| 3676 | try mod.errNote(scope, some.src, msg, "other suspend block here", .{}); | |
| 3677 | break :msg msg; | |
| 3678 | }; | |
| 3679 | return mod.failWithOwnedErrorMsg(scope, msg); | |
| 3680 | } | |
| 3681 | ||
| 3682 | var suspend_scope: Scope.GenZIR = .{ | |
| 3683 | .base = .{ .tag = .gen_suspend }, | |
| 3684 | .parent = scope, | |
| 3685 | .decl = scope.ownerDecl().?, | |
| 3686 | .arena = scope.arena(), | |
| 3687 | .force_comptime = scope.isComptime(), | |
| 3688 | .instructions = .{}, | |
| 3689 | }; | |
| 3690 | defer suspend_scope.instructions.deinit(mod.gpa); | |
| 3691 | ||
| 3692 | const operand = tree.nodes.items(.data)[node].lhs; | |
| 3693 | if (operand != 0) { | |
| 3694 | const possibly_unused_result = try expr(mod, &suspend_scope.base, .none, operand); | |
| 3695 | if (!possibly_unused_result.tag.isNoReturn()) { | |
| 3696 | _ = try addZIRUnOp(mod, &suspend_scope.base, src, .ensure_result_used, possibly_unused_result); | |
| 3697 | } | |
| 3698 | } else { | |
| 3699 | return addZIRNoOp(mod, scope, src, .@"suspend"); | |
| 3700 | } | |
| 3701 | ||
| 3702 | const block = try addZIRInstBlock(mod, scope, src, .suspend_block, .{ | |
| 3703 | .instructions = try scope.arena().dupe(*zir.Inst, suspend_scope.instructions.items), | |
| 3704 | }); | |
| 3705 | return &block.base; | |
| 3706 | } | |
| 3707 | ||
| 3708 | fn nosuspendExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst { | |
| 3709 | const tree = scope.tree(); | |
| 3710 | var child_scope = Scope.Nosuspend{ | |
| 3711 | .parent = scope, | |
| 3712 | .gen_zir = scope.getGenZIR(), | |
| 3713 | .src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]], | |
| 3714 | }; | |
| 3715 | ||
| 3716 | return expr(mod, &child_scope.base, rl, tree.nodes.items(.data)[node].lhs); | |
| 3717 | } | |
| 3718 | ||
| 3719 | fn awaitExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst { | |
| 3720 | const tree = scope.tree(); | |
| 3721 | const src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]]; | |
| 3722 | const is_nosuspend = scope.getNosuspend() != null; | |
| 3723 | ||
| 3724 | // TODO some @asyncCall stuff | |
| 3725 | ||
| 3726 | if (scope.getSuspend()) |some| { | |
| 3727 | const msg = msg: { | |
| 3728 | const msg = try mod.errMsg(scope, src, "cannot await inside suspend block", .{}); | |
| 3729 | errdefer msg.destroy(mod.gpa); | |
| 3730 | try mod.errNote(scope, some.src, msg, "suspend block here", .{}); | |
| 3731 | break :msg msg; | |
| 3732 | }; | |
| 3733 | return mod.failWithOwnedErrorMsg(scope, msg); | |
| 3734 | } | |
| 3735 | ||
| 3736 | const operand = try expr(mod, scope, .ref, tree.nodes.items(.data)[node].lhs); | |
| 3737 | // TODO pass result location | |
| 3738 | return addZIRUnOp(mod, scope, src, if (is_nosuspend) .nosuspend_await else .@"await", operand); | |
| 3739 | } | |
| 3740 | ||
| 3741 | fn resumeExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst { | |
| 3742 | const tree = scope.tree(); | |
| 3743 | const src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]]; | |
| 3744 | ||
| 3745 | const operand = try expr(mod, scope, .ref, tree.nodes.items(.data)[node].lhs); | |
| 3746 | return addZIRUnOp(mod, scope, src, .@"resume", operand); | |
| 3747 | } | |
| 3748 | ||
| 3644 | 3749 | pub const simple_types = std.ComptimeStringMap(Value.Tag, .{ |
| 3645 | 3750 | .{ "u8", .u8_type }, |
| 3646 | 3751 | .{ "i8", .i8_type }, |
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+29-2| ... | ... | @@ -61,6 +61,8 @@ pub const Inst = struct { |
| 61 | 61 | as, |
| 62 | 62 | /// Inline assembly. |
| 63 | 63 | @"asm", |
| 64 | /// Await an async function. | |
| 65 | @"await", | |
| 64 | 66 | /// Bitwise AND. `&` |
| 65 | 67 | bit_and, |
| 66 | 68 | /// TODO delete this instruction, it has no purpose. |
| ... | ... | @@ -176,8 +178,12 @@ pub const Inst = struct { |
| 176 | 178 | @"fn", |
| 177 | 179 | /// Returns a function type, assuming unspecified calling convention. |
| 178 | 180 | fn_type, |
| 181 | /// Same as `fn_type` but the function is variadic. | |
| 182 | fn_type_var_args, | |
| 179 | 183 | /// Returns a function type, with a calling convention instruction operand. |
| 180 | 184 | fn_type_cc, |
| 185 | /// Same as `fn_type_cc` but the function is variadic. | |
| 186 | fn_type_cc_var_args, | |
| 181 | 187 | /// @import(operand) |
| 182 | 188 | import, |
| 183 | 189 | /// Integer literal. |
| ... | ... | @@ -212,6 +218,8 @@ pub const Inst = struct { |
| 212 | 218 | mul, |
| 213 | 219 | /// Twos complement wrapping integer multiplication. |
| 214 | 220 | mulwrap, |
| 221 | /// An await inside a nosuspend scope. | |
| 222 | nosuspend_await, | |
| 215 | 223 | /// Given a reference to a function and a parameter index, returns the |
| 216 | 224 | /// type of the parameter. TODO what happens when the parameter is `anytype`? |
| 217 | 225 | param_type, |
| ... | ... | @@ -226,6 +234,8 @@ pub const Inst = struct { |
| 226 | 234 | /// the memory location is in the stack frame, local to the scope containing the |
| 227 | 235 | /// instruction. |
| 228 | 236 | ref, |
| 237 | /// Resume an async function. | |
| 238 | @"resume", | |
| 229 | 239 | /// Obtains a pointer to the return value. |
| 230 | 240 | ret_ptr, |
| 231 | 241 | /// Obtains the return type of the in-scope function. |
| ... | ... | @@ -348,6 +358,11 @@ pub const Inst = struct { |
| 348 | 358 | enum_type, |
| 349 | 359 | /// Does nothing; returns a void value. |
| 350 | 360 | void_value, |
| 361 | /// Suspend an async function. | |
| 362 | @"suspend", | |
| 363 | /// Suspend an async function. | |
| 364 | /// Same as .suspend but with a block. | |
| 365 | suspend_block, | |
| 351 | 366 | /// A switch expression. |
| 352 | 367 | switchbr, |
| 353 | 368 | /// Same as `switchbr` but the target is a pointer to the value being switched on. |
| ... | ... | @@ -369,6 +384,7 @@ pub const Inst = struct { |
| 369 | 384 | .unreachable_unsafe, |
| 370 | 385 | .unreachable_safe, |
| 371 | 386 | .void_value, |
| 387 | .@"suspend", | |
| 372 | 388 | => NoOp, |
| 373 | 389 | |
| 374 | 390 | .alloc, |
| ... | ... | @@ -417,6 +433,9 @@ pub const Inst = struct { |
| 417 | 433 | .import, |
| 418 | 434 | .set_eval_branch_quota, |
| 419 | 435 | .indexable_ptr_len, |
| 436 | .@"resume", | |
| 437 | .@"await", | |
| 438 | .nosuspend_await, | |
| 420 | 439 | => UnOp, |
| 421 | 440 | |
| 422 | 441 | .add, |
| ... | ... | @@ -461,6 +480,7 @@ pub const Inst = struct { |
| 461 | 480 | .block_flat, |
| 462 | 481 | .block_comptime, |
| 463 | 482 | .block_comptime_flat, |
| 483 | .suspend_block, | |
| 464 | 484 | => Block, |
| 465 | 485 | |
| 466 | 486 | .switchbr, .switchbr_ref => SwitchBr, |
| ... | ... | @@ -486,8 +506,8 @@ pub const Inst = struct { |
| 486 | 506 | .@"export" => Export, |
| 487 | 507 | .param_type => ParamType, |
| 488 | 508 | .primitive => Primitive, |
| 489 | .fn_type => FnType, | |
| 490 | .fn_type_cc => FnTypeCc, | |
| 509 | .fn_type, .fn_type_var_args => FnType, | |
| 510 | .fn_type_cc, .fn_type_cc_var_args => FnTypeCc, | |
| 491 | 511 | .elem_ptr, .elem_val => Elem, |
| 492 | 512 | .condbr => CondBr, |
| 493 | 513 | .ptr_type => PtrType, |
| ... | ... | @@ -563,7 +583,9 @@ pub const Inst = struct { |
| 563 | 583 | .field_val_named, |
| 564 | 584 | .@"fn", |
| 565 | 585 | .fn_type, |
| 586 | .fn_type_var_args, | |
| 566 | 587 | .fn_type_cc, |
| 588 | .fn_type_cc_var_args, | |
| 567 | 589 | .int, |
| 568 | 590 | .intcast, |
| 569 | 591 | .int_type, |
| ... | ... | @@ -633,6 +655,9 @@ pub const Inst = struct { |
| 633 | 655 | .struct_type, |
| 634 | 656 | .void_value, |
| 635 | 657 | .switch_range, |
| 658 | .@"resume", | |
| 659 | .@"await", | |
| 660 | .nosuspend_await, | |
| 636 | 661 | => false, |
| 637 | 662 | |
| 638 | 663 | .@"break", |
| ... | ... | @@ -649,6 +674,8 @@ pub const Inst = struct { |
| 649 | 674 | .container_field, |
| 650 | 675 | .switchbr, |
| 651 | 676 | .switchbr_ref, |
| 677 | .@"suspend", | |
| 678 | .suspend_block, | |
| 652 | 679 | => true, |
| 653 | 680 | }; |
| 654 | 681 | } |
src/zir_sema.zig+41-17| ... | ... | @@ -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).?), |
| ... | ... | @@ -160,6 +162,11 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 160 | 162 | .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false), |
| 161 | 163 | .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr_ref).?, true), |
| 162 | 164 | .switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?), |
| 165 | .@"await" => return zirAwait(mod, scope, old_inst.castTag(.@"await").?), | |
| 166 | .nosuspend_await => return zirAwait(mod, scope, old_inst.castTag(.nosuspend_await).?), | |
| 167 | .@"resume" => return zirResume(mod, scope, old_inst.castTag(.@"resume").?), | |
| 168 | .@"suspend" => return zirSuspend(mod, scope, old_inst.castTag(.@"suspend").?), | |
| 169 | .suspend_block => return zirSuspendBlock(mod, scope, old_inst.castTag(.suspend_block).?), | |
| 163 | 170 | |
| 164 | 171 | .container_field_named, |
| 165 | 172 | .container_field_typed, |
| ... | ... | @@ -517,9 +524,11 @@ fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerErr |
| 517 | 524 | }, |
| 518 | 525 | }; |
| 519 | 526 | |
| 520 | // TODO support C-style var args | |
| 521 | 527 | const param_count = fn_ty.fnParamLen(); |
| 522 | 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 | } | |
| 523 | 532 | return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{ |
| 524 | 533 | arg_index, |
| 525 | 534 | fn_ty, |
| ... | ... | @@ -941,6 +950,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 941 | 950 | const call_params_len = inst.positionals.args.len; |
| 942 | 951 | const fn_params_len = func.ty.fnParamLen(); |
| 943 | 952 | if (func.ty.fnIsVarArgs()) { |
| 953 | assert(cc == .C); | |
| 944 | 954 | if (call_params_len < fn_params_len) { |
| 945 | 955 | // TODO add error note: declared here |
| 946 | 956 | return mod.fail( |
| ... | ... | @@ -950,7 +960,6 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 950 | 960 | .{ fn_params_len, call_params_len }, |
| 951 | 961 | ); |
| 952 | 962 | } |
| 953 | return mod.fail(scope, inst.base.src, "TODO implement support for calling var args functions", .{}); | |
| 954 | 963 | } else if (fn_params_len != call_params_len) { |
| 955 | 964 | // TODO add error note: declared here |
| 956 | 965 | return mod.fail( |
| ... | ... | @@ -969,15 +978,10 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst { |
| 969 | 978 | } |
| 970 | 979 | |
| 971 | 980 | // TODO handle function calls of generic functions |
| 972 | ||
| 973 | const fn_param_types = try mod.gpa.alloc(Type, fn_params_len); | |
| 974 | defer mod.gpa.free(fn_param_types); | |
| 975 | func.ty.fnParamTypes(fn_param_types); | |
| 976 | ||
| 977 | const casted_args = try scope.arena().alloc(*Inst, fn_params_len); | |
| 981 | const casted_args = try scope.arena().alloc(*Inst, call_params_len); | |
| 978 | 982 | for (inst.positionals.args) |src_arg, i| { |
| 979 | const uncasted_arg = try resolveInst(mod, scope, src_arg); | |
| 980 | 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); | |
| 981 | 985 | } |
| 982 | 986 | |
| 983 | 987 | const ret_type = func.ty.fnReturnType(); |
| ... | ... | @@ -1080,6 +1084,22 @@ fn zirFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst { |
| 1080 | 1084 | }); |
| 1081 | 1085 | } |
| 1082 | 1086 | |
| 1087 | fn zirAwait(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 1088 | return mod.fail(scope, inst.base.src, "TODO implement await", .{}); | |
| 1089 | } | |
| 1090 | ||
| 1091 | fn zirResume(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | |
| 1092 | return mod.fail(scope, inst.base.src, "TODO implement resume", .{}); | |
| 1093 | } | |
| 1094 | ||
| 1095 | fn zirSuspend(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { | |
| 1096 | return mod.fail(scope, inst.base.src, "TODO implement suspend", .{}); | |
| 1097 | } | |
| 1098 | ||
| 1099 | fn zirSuspendBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { | |
| 1100 | return mod.fail(scope, inst.base.src, "TODO implement suspend", .{}); | |
| 1101 | } | |
| 1102 | ||
| 1083 | 1103 | fn zirIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) InnerError!*Inst { |
| 1084 | 1104 | const tracy = trace(@src()); |
| 1085 | 1105 | defer tracy.end(); |
| ... | ... | @@ -1482,7 +1502,7 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) |
| 1482 | 1502 | return mod.constVoid(scope, unwrap.base.src); |
| 1483 | 1503 | } |
| 1484 | 1504 | |
| 1485 | 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 { | |
| 1486 | 1506 | const tracy = trace(@src()); |
| 1487 | 1507 | defer tracy.end(); |
| 1488 | 1508 | |
| ... | ... | @@ -1493,10 +1513,11 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!* |
| 1493 | 1513 | fntype.positionals.param_types, |
| 1494 | 1514 | fntype.positionals.return_type, |
| 1495 | 1515 | .Unspecified, |
| 1516 | var_args, | |
| 1496 | 1517 | ); |
| 1497 | 1518 | } |
| 1498 | 1519 | |
| 1499 | 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 { | |
| 1500 | 1521 | const tracy = trace(@src()); |
| 1501 | 1522 | defer tracy.end(); |
| 1502 | 1523 | |
| ... | ... | @@ -1513,6 +1534,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerErr |
| 1513 | 1534 | fntype.positionals.param_types, |
| 1514 | 1535 | fntype.positionals.return_type, |
| 1515 | 1536 | cc, |
| 1537 | var_args, | |
| 1516 | 1538 | ); |
| 1517 | 1539 | } |
| 1518 | 1540 | |
| ... | ... | @@ -1523,11 +1545,12 @@ fn fnTypeCommon( |
| 1523 | 1545 | zir_param_types: []*zir.Inst, |
| 1524 | 1546 | zir_return_type: *zir.Inst, |
| 1525 | 1547 | cc: std.builtin.CallingConvention, |
| 1548 | var_args: bool, | |
| 1526 | 1549 | ) InnerError!*Inst { |
| 1527 | 1550 | const return_type = try resolveType(mod, scope, zir_return_type); |
| 1528 | 1551 | |
| 1529 | 1552 | // Hot path for some common function types. |
| 1530 | if (zir_param_types.len == 0) { | |
| 1553 | if (zir_param_types.len == 0 and !var_args) { | |
| 1531 | 1554 | if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) { |
| 1532 | 1555 | return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args)); |
| 1533 | 1556 | } |
| ... | ... | @@ -1560,6 +1583,7 @@ fn fnTypeCommon( |
| 1560 | 1583 | .param_types = param_types, |
| 1561 | 1584 | .return_type = return_type, |
| 1562 | 1585 | .cc = cc, |
| 1586 | .is_var_args = var_args, | |
| 1563 | 1587 | }); |
| 1564 | 1588 | return mod.constType(scope, zir_inst.src, fn_ty); |
| 1565 | 1589 | } |
| ... | ... | @@ -2046,7 +2070,7 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In |
| 2046 | 2070 | rhs.ty.arrayLen(), |
| 2047 | 2071 | }); |
| 2048 | 2072 | } |
| 2049 | return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBitwise", .{}); | |
| 2073 | return mod.fail(scope, inst.base.src, "TODO implement support for vectors in zirBitwise", .{}); | |
| 2050 | 2074 | } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) { |
| 2051 | 2075 | return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{ |
| 2052 | 2076 | lhs.ty, |
| ... | ... | @@ -2127,7 +2151,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError! |
| 2127 | 2151 | rhs.ty.arrayLen(), |
| 2128 | 2152 | }); |
| 2129 | 2153 | } |
| 2130 | return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{}); | |
| 2154 | return mod.fail(scope, inst.base.src, "TODO implement support for vectors in zirBinOp", .{}); | |
| 2131 | 2155 | } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) { |
| 2132 | 2156 | return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{ |
| 2133 | 2157 | lhs.ty, |
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 |