authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-06 13:35:48-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-03-06 13:35:48-08:00
log34cb5934ddd7c79fb96ffed87768764247740260
treed4ca1d9e3c6a335caf311de1383e45758f221438
parent9f722f43ac449caa0e09c1b7bb1bad0581ef323d
parent8c6e7fb2c7488faab0c41a4ea241f0110237ce91
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7910 from Vexu/stage2-async

Stage2: astgen async stuff, implement var args functions

8 files changed, 370 insertions(+), 43 deletions(-)

src/Module.zig+123-16
......@@ -370,6 +370,8 @@ pub const Scope = struct {
370370 .gen_zir => return self.cast(GenZIR).?.arena,
371371 .local_val => return self.cast(LocalVal).?.gen_zir.arena,
372372 .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,
373375 .file => unreachable,
374376 .container => unreachable,
375377 }
......@@ -385,6 +387,8 @@ pub const Scope = struct {
385387 .gen_zir => self.cast(GenZIR).?.decl,
386388 .local_val => self.cast(LocalVal).?.gen_zir.decl,
387389 .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,
388392 .file => null,
389393 .container => null,
390394 };
......@@ -396,6 +400,8 @@ pub const Scope = struct {
396400 .gen_zir => self.cast(GenZIR).?.decl,
397401 .local_val => self.cast(LocalVal).?.gen_zir.decl,
398402 .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,
399405 .file => null,
400406 .container => null,
401407 };
......@@ -410,6 +416,8 @@ pub const Scope = struct {
410416 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container,
411417 .file => return &self.cast(File).?.root_container,
412418 .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,
413421 }
414422 }
415423
......@@ -422,6 +430,8 @@ pub const Scope = struct {
422430 .gen_zir => unreachable,
423431 .local_val => unreachable,
424432 .local_ptr => unreachable,
433 .gen_suspend => unreachable,
434 .gen_nosuspend => unreachable,
425435 .file => unreachable,
426436 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),
427437 }
......@@ -436,6 +446,8 @@ pub const Scope = struct {
436446 .local_val => return &self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,
437447 .local_ptr => return &self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,
438448 .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,
439451 }
440452 }
441453
......@@ -443,9 +455,10 @@ pub const Scope = struct {
443455 pub fn getGenZIR(self: *Scope) *GenZIR {
444456 return switch (self.tag) {
445457 .block => unreachable,
446 .gen_zir => self.cast(GenZIR).?,
458 .gen_zir, .gen_suspend => self.cast(GenZIR).?,
447459 .local_val => return self.cast(LocalVal).?.gen_zir,
448460 .local_ptr => return self.cast(LocalPtr).?.gen_zir,
461 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir,
449462 .file => unreachable,
450463 .container => unreachable,
451464 };
......@@ -461,6 +474,8 @@ pub const Scope = struct {
461474 .gen_zir => unreachable,
462475 .local_val => unreachable,
463476 .local_ptr => unreachable,
477 .gen_suspend => unreachable,
478 .gen_nosuspend => unreachable,
464479 }
465480 }
466481
......@@ -472,6 +487,8 @@ pub const Scope = struct {
472487 .local_val => unreachable,
473488 .local_ptr => unreachable,
474489 .block => unreachable,
490 .gen_suspend => unreachable,
491 .gen_nosuspend => unreachable,
475492 }
476493 }
477494
......@@ -486,6 +503,36 @@ pub const Scope = struct {
486503 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
487504 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
488505 .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,
489536 };
490537 }
491538 }
......@@ -507,6 +554,8 @@ pub const Scope = struct {
507554 gen_zir,
508555 local_val,
509556 local_ptr,
557 gen_suspend,
558 gen_nosuspend,
510559 };
511560
512561 pub const Container = struct {
......@@ -740,6 +789,8 @@ pub const Scope = struct {
740789 /// so they can possibly be elided later if the labeled block ends up not needing
741790 /// a result location pointer.
742791 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(*zir.Inst.BinOp) = .{},
792 /// for suspend error notes
793 src: usize = 0,
743794
744795 pub const Label = struct {
745796 token: ast.TokenIndex,
......@@ -773,6 +824,16 @@ pub const Scope = struct {
773824 name: []const u8,
774825 ptr: *zir.Inst,
775826 };
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 };
776837};
777838
778839/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
......@@ -1122,7 +1183,8 @@ fn astgenAndSemaFn(
11221183 const param_count = blk: {
11231184 var count: usize = 0;
11241185 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;
11261188 count += 1;
11271189 }
11281190 break :blk count;
......@@ -1135,6 +1197,7 @@ fn astgenAndSemaFn(
11351197 });
11361198 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
11371199
1200 var is_var_args = false;
11381201 {
11391202 var param_type_i: usize = 0;
11401203 var it = fn_proto.iterate(tree);
......@@ -1147,12 +1210,10 @@ fn astgenAndSemaFn(
11471210 "TODO implement anytype parameter",
11481211 .{},
11491212 ),
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 },
11561217 else => unreachable,
11571218 }
11581219 }
......@@ -1234,7 +1295,13 @@ fn astgenAndSemaFn(
12341295 type_type_rl,
12351296 fn_proto.ast.return_type,
12361297 );
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: {
12381305 // TODO instead of enum literal type, this needs to be the
12391306 // std.builtin.CallingConvention enum. We need to implement importing other files
12401307 // and enums in order to fix this.
......@@ -1243,18 +1310,31 @@ fn astgenAndSemaFn(
12431310 .ty = Type.initTag(.type),
12441311 .val = Value.initTag(.enum_literal_type),
12451312 });
1246 const cc = try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
1313 break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
12471314 .ty = enum_lit_ty,
12481315 }, 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, .{
12501324 .return_type = return_type_inst,
12511325 .param_types = param_types,
12521326 .cc = cc,
12531327 });
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 };
12581338
12591339 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
12601340 zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};
......@@ -1287,7 +1367,12 @@ fn astgenAndSemaFn(
12871367 const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{
12881368 .instructions = fn_type_scope.instructions.items,
12891369 });
1370
12901371 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
12911376 // Extern function.
12921377 var type_changed = true;
12931378 if (decl.typedValueManaged()) |tvm| {
......@@ -1317,6 +1402,10 @@ fn astgenAndSemaFn(
13171402 return type_changed;
13181403 }
13191404
1405 if (fn_type.fnIsVarArgs()) {
1406 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
1407 }
1408
13201409 const new_func = try decl_arena.allocator.create(Fn);
13211410 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
13221411
......@@ -3295,6 +3384,9 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
32953384}
32963385
32973386pub 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 }
32983390 // If the types are the same, we can return the operand.
32993391 if (dest_type.eql(inst.ty))
33003392 return inst;
......@@ -3447,6 +3539,15 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) Inn
34473539 return null;
34483540}
34493541
3542pub fn coerceVarArgParam(mod: *Module, scope: *Scope, inst: *Inst) !*Inst {
3543 switch (inst.ty.zigTypeTag()) {
3544 .ComptimeInt, .ComptimeFloat => return mod.fail(scope, inst.src, "integer and float literals in var args function must be casted", .{}),
3545 else => {},
3546 }
3547 // TODO implement more of this function.
3548 return inst;
3549}
3550
34503551pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
34513552 if (ptr.ty.isConstPtr())
34523553 return self.fail(scope, src, "cannot assign to constant", .{});
......@@ -3586,7 +3687,7 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
35863687 }
35873688 self.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg);
35883689 },
3589 .gen_zir => {
3690 .gen_zir, .gen_suspend => {
35903691 const gen_zir = scope.cast(Scope.GenZIR).?;
35913692 gen_zir.decl.analysis = .sema_failure;
35923693 gen_zir.decl.generation = self.generation;
......@@ -3604,6 +3705,12 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
36043705 gen_zir.decl.generation = self.generation;
36053706 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
36063707 },
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 },
36073714 .file => unreachable,
36083715 .container => unreachable,
36093716 }
src/astgen.zig+110-5
......@@ -626,10 +626,13 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
626626 .@"comptime" => return comptimeExpr(mod, scope, rl, node_datas[node].lhs),
627627 .@"switch", .switch_comma => return switchExpr(mod, scope, rl, node),
628628
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
629634 .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),
630635 .@"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", .{}),
633636 .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
634637
635638 .array_init_one,
......@@ -652,15 +655,12 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
652655 .struct_init_comma,
653656 => return mod.failNode(scope, node, "TODO implement astgen.expr for struct literals", .{}),
654657
655 .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}),
656658 .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),
657659 .fn_proto_simple,
658660 .fn_proto_multi,
659661 .fn_proto_one,
660662 .fn_proto,
661663 => 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", .{}),
664664 }
665665}
666666
......@@ -766,6 +766,8 @@ fn breakExpr(
766766 },
767767 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
768768 .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,
769771 else => if (break_label != 0) {
770772 const label_name = try mod.identifierTokenString(parent_scope, break_label);
771773 return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});
......@@ -819,6 +821,8 @@ fn continueExpr(
819821 },
820822 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
821823 .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,
822826 else => if (break_label != 0) {
823827 const label_name = try mod.identifierTokenString(parent_scope, break_label);
824828 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
893897 },
894898 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
895899 .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,
896902 else => return,
897903 }
898904 }
......@@ -1100,6 +1106,8 @@ fn varDecl(
11001106 s = local_ptr.parent;
11011107 },
11021108 .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,
11031111 else => break,
11041112 };
11051113 }
......@@ -3021,6 +3029,8 @@ fn identifier(
30213029 s = local_ptr.parent;
30223030 },
30233031 .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,
30243034 else => break,
30253035 };
30263036 }
......@@ -3633,14 +3643,109 @@ fn callExpr(
36333643 }
36343644
36353645 const src = token_starts[call.ast.lparen];
3646 var modifier: std.builtin.CallOptions.Modifier = .auto;
3647 if (call.async_token) |_| modifier = .async_kw;
3648
36363649 const result = try addZIRInst(mod, scope, src, zir.Inst.Call, .{
36373650 .func = lhs,
36383651 .args = args,
3652 .modifier = modifier,
36393653 }, .{});
36403654 // TODO function call with result location
36413655 return rvalue(mod, scope, rl, result);
36423656}
36433657
3658fn 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
3708fn 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
3719fn 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
3741fn 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
36443749pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
36453750 .{ "u8", .u8_type },
36463751 .{ "i8", .i8_type },
src/codegen/c.zig+7-2
......@@ -215,8 +215,9 @@ pub const DeclGen = struct {
215215 try dg.renderType(w, tv.ty.fnReturnType());
216216 const decl_name = mem.span(dg.decl.name);
217217 try w.print(" {s}(", .{decl_name});
218 var param_len = tv.ty.fnParamLen();
219 if (param_len == 0)
218 const param_len = tv.ty.fnParamLen();
219 const is_var_args = tv.ty.fnIsVarArgs();
220 if (param_len == 0 and !is_var_args)
220221 try w.writeAll("void")
221222 else {
222223 var index: usize = 0;
......@@ -228,6 +229,10 @@ pub const DeclGen = struct {
228229 try w.print(" a{d}", .{index});
229230 }
230231 }
232 if (is_var_args) {
233 if (param_len != 0) try w.writeAll(", ");
234 try w.writeAll("...");
235 }
231236 try w.writeByte(')');
232237 }
233238
src/test.zig+1
......@@ -871,6 +871,7 @@ pub const TestContext = struct {
871871 "-std=c89",
872872 "-pedantic",
873873 "-Werror",
874 "-Wno-incompatible-library-redeclaration", // https://github.com/ziglang/zig/issues/875
874875 "-Wno-declaration-after-statement",
875876 "--",
876877 "-lc",
src/type.zig+46-1
......@@ -97,6 +97,8 @@ pub const Type = extern union {
9797 .@"struct", .empty_struct => return .Struct,
9898 .@"enum" => return .Enum,
9999 .@"union" => return .Union,
100
101 .var_args_param => unreachable, // can be any type
100102 }
101103 }
102104
......@@ -258,6 +260,8 @@ pub const Type = extern union {
258260 if (!a.fnParamType(i).eql(b.fnParamType(i)))
259261 return false;
260262 }
263 if (a.fnIsVarArgs() != b.fnIsVarArgs())
264 return false;
261265 return true;
262266 },
263267 .Optional => {
......@@ -323,6 +327,7 @@ pub const Type = extern union {
323327 while (i < params_len) : (i += 1) {
324328 std.hash.autoHash(&hasher, self.fnParamType(i).hash());
325329 }
330 std.hash.autoHash(&hasher, self.fnIsVarArgs());
326331 },
327332 .Optional => {
328333 var buf: Payload.ElemType = undefined;
......@@ -397,6 +402,7 @@ pub const Type = extern union {
397402 .@"anyframe",
398403 .inferred_alloc_const,
399404 .inferred_alloc_mut,
405 .var_args_param,
400406 => unreachable,
401407
402408 .array_u8,
......@@ -446,6 +452,7 @@ pub const Type = extern union {
446452 .return_type = try payload.return_type.copy(allocator),
447453 .param_types = param_types,
448454 .cc = payload.cc,
455 .is_var_args = payload.is_var_args,
449456 });
450457 },
451458 .pointer => {
......@@ -535,6 +542,7 @@ pub const Type = extern union {
535542 .comptime_int,
536543 .comptime_float,
537544 .noreturn,
545 .var_args_param,
538546 => return out_stream.writeAll(@tagName(t)),
539547
540548 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
......@@ -558,6 +566,12 @@ pub const Type = extern union {
558566 if (i != 0) try out_stream.writeAll(", ");
559567 try param_type.format("", .{}, out_stream);
560568 }
569 if (payload.is_var_args) {
570 if (payload.param_types.len != 0) {
571 try out_stream.writeAll(", ");
572 }
573 try out_stream.writeAll("...");
574 }
561575 try out_stream.writeAll(") callconv(.");
562576 try out_stream.writeAll(@tagName(payload.cc));
563577 try out_stream.writeAll(")");
......@@ -844,6 +858,7 @@ pub const Type = extern union {
844858
845859 .inferred_alloc_const => unreachable,
846860 .inferred_alloc_mut => unreachable,
861 .var_args_param => unreachable,
847862 };
848863 }
849864
......@@ -969,6 +984,7 @@ pub const Type = extern union {
969984 .inferred_alloc_const,
970985 .inferred_alloc_mut,
971986 .@"opaque",
987 .var_args_param,
972988 => unreachable,
973989 };
974990 }
......@@ -995,6 +1011,7 @@ pub const Type = extern union {
9951011 .inferred_alloc_const => unreachable,
9961012 .inferred_alloc_mut => unreachable,
9971013 .@"opaque" => unreachable,
1014 .var_args_param => unreachable,
9981015
9991016 .u8,
10001017 .i8,
......@@ -1179,6 +1196,7 @@ pub const Type = extern union {
11791196 .@"struct",
11801197 .@"union",
11811198 .@"opaque",
1199 .var_args_param,
11821200 => false,
11831201
11841202 .single_const_pointer,
......@@ -1256,6 +1274,7 @@ pub const Type = extern union {
12561274 .@"struct",
12571275 .@"union",
12581276 .@"opaque",
1277 .var_args_param,
12591278 => unreachable,
12601279
12611280 .const_slice,
......@@ -1354,6 +1373,7 @@ pub const Type = extern union {
13541373 .@"struct",
13551374 .@"union",
13561375 .@"opaque",
1376 .var_args_param,
13571377 => false,
13581378
13591379 .const_slice,
......@@ -1434,6 +1454,7 @@ pub const Type = extern union {
14341454 .@"struct",
14351455 .@"union",
14361456 .@"opaque",
1457 .var_args_param,
14371458 => false,
14381459
14391460 .single_const_pointer,
......@@ -1523,6 +1544,7 @@ pub const Type = extern union {
15231544 .@"struct",
15241545 .@"union",
15251546 .@"opaque",
1547 .var_args_param,
15261548 => false,
15271549
15281550 .pointer => {
......@@ -1607,6 +1629,7 @@ pub const Type = extern union {
16071629 .@"struct",
16081630 .@"union",
16091631 .@"opaque",
1632 .var_args_param,
16101633 => false,
16111634
16121635 .pointer => {
......@@ -1733,6 +1756,7 @@ pub const Type = extern union {
17331756 .@"struct" => unreachable,
17341757 .@"union" => unreachable,
17351758 .@"opaque" => unreachable,
1759 .var_args_param => unreachable,
17361760
17371761 .array => self.castTag(.array).?.data.elem_type,
17381762 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
......@@ -1862,6 +1886,7 @@ pub const Type = extern union {
18621886 .@"struct",
18631887 .@"union",
18641888 .@"opaque",
1889 .var_args_param,
18651890 => unreachable,
18661891
18671892 .array => self.castTag(.array).?.data.len,
......@@ -1936,6 +1961,7 @@ pub const Type = extern union {
19361961 .@"struct",
19371962 .@"union",
19381963 .@"opaque",
1964 .var_args_param,
19391965 => unreachable,
19401966
19411967 .single_const_pointer,
......@@ -2025,6 +2051,7 @@ pub const Type = extern union {
20252051 .@"struct",
20262052 .@"union",
20272053 .@"opaque",
2054 .var_args_param,
20282055 => false,
20292056
20302057 .int_signed,
......@@ -2110,6 +2137,7 @@ pub const Type = extern union {
21102137 .@"struct",
21112138 .@"union",
21122139 .@"opaque",
2140 .var_args_param,
21132141 => false,
21142142
21152143 .int_unsigned,
......@@ -2181,6 +2209,7 @@ pub const Type = extern union {
21812209 .@"struct",
21822210 .@"union",
21832211 .@"opaque",
2212 .var_args_param,
21842213 => unreachable,
21852214
21862215 .int_unsigned => .{
......@@ -2280,6 +2309,7 @@ pub const Type = extern union {
22802309 .@"struct",
22812310 .@"union",
22822311 .@"opaque",
2312 .var_args_param,
22832313 => false,
22842314
22852315 .usize,
......@@ -2400,6 +2430,7 @@ pub const Type = extern union {
24002430 .@"struct",
24012431 .@"union",
24022432 .@"opaque",
2433 .var_args_param,
24032434 => unreachable,
24042435 };
24052436 }
......@@ -2486,6 +2517,7 @@ pub const Type = extern union {
24862517 .@"struct",
24872518 .@"union",
24882519 .@"opaque",
2520 .var_args_param,
24892521 => unreachable,
24902522 }
24912523 }
......@@ -2571,6 +2603,7 @@ pub const Type = extern union {
25712603 .@"struct",
25722604 .@"union",
25732605 .@"opaque",
2606 .var_args_param,
25742607 => unreachable,
25752608 }
25762609 }
......@@ -2656,6 +2689,7 @@ pub const Type = extern union {
26562689 .@"struct",
26572690 .@"union",
26582691 .@"opaque",
2692 .var_args_param,
26592693 => unreachable,
26602694 };
26612695 }
......@@ -2738,6 +2772,7 @@ pub const Type = extern union {
27382772 .@"struct",
27392773 .@"union",
27402774 .@"opaque",
2775 .var_args_param,
27412776 => unreachable,
27422777 };
27432778 }
......@@ -2749,7 +2784,7 @@ pub const Type = extern union {
27492784 .fn_void_no_args => false,
27502785 .fn_naked_noreturn_no_args => false,
27512786 .fn_ccc_void_no_args => false,
2752 .function => false,
2787 .function => self.castTag(.function).?.data.is_var_args,
27532788
27542789 .f16,
27552790 .f32,
......@@ -2820,6 +2855,7 @@ pub const Type = extern union {
28202855 .@"struct",
28212856 .@"union",
28222857 .@"opaque",
2858 .var_args_param,
28232859 => unreachable,
28242860 };
28252861 }
......@@ -2902,6 +2938,7 @@ pub const Type = extern union {
29022938 .@"struct",
29032939 .@"union",
29042940 .@"opaque",
2941 .var_args_param,
29052942 => false,
29062943 };
29072944 }
......@@ -2962,6 +2999,7 @@ pub const Type = extern union {
29622999 .error_set,
29633000 .error_set_single,
29643001 .@"opaque",
3002 .var_args_param,
29653003 => return null,
29663004
29673005 .@"enum" => @panic("TODO onePossibleValue enum"),
......@@ -3079,6 +3117,7 @@ pub const Type = extern union {
30793117 .@"struct",
30803118 .@"union",
30813119 .@"opaque",
3120 .var_args_param,
30823121 => return false,
30833122
30843123 .c_const_pointer,
......@@ -3168,6 +3207,7 @@ pub const Type = extern union {
31683207 .pointer,
31693208 .inferred_alloc_const,
31703209 .inferred_alloc_mut,
3210 .var_args_param,
31713211 => unreachable,
31723212
31733213 .empty_struct => self.castTag(.empty_struct).?.data,
......@@ -3285,6 +3325,9 @@ pub const Type = extern union {
32853325 anyerror_void_error_union,
32863326 @"anyframe",
32873327 const_slice_u8,
3328 /// This is a special type for variadic parameters of a function call.
3329 /// Casts to it will validate that the type can be passed to a c calling convetion function.
3330 var_args_param,
32883331 /// This is a special value that tracks a set of types that have been stored
32893332 /// to an inferred allocation. It does not support most of the normal type queries.
32903333 /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.
......@@ -3373,6 +3416,7 @@ pub const Type = extern union {
33733416 .const_slice_u8,
33743417 .inferred_alloc_const,
33753418 .inferred_alloc_mut,
3419 .var_args_param,
33763420 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
33773421
33783422 .array_u8,
......@@ -3479,6 +3523,7 @@ pub const Type = extern union {
34793523 param_types: []Type,
34803524 return_type: Type,
34813525 cc: std.builtin.CallingConvention,
3526 is_var_args: bool,
34823527 },
34833528 };
34843529
src/zir.zig+29-2
......@@ -61,6 +61,8 @@ pub const Inst = struct {
6161 as,
6262 /// Inline assembly.
6363 @"asm",
64 /// Await an async function.
65 @"await",
6466 /// Bitwise AND. `&`
6567 bit_and,
6668 /// TODO delete this instruction, it has no purpose.
......@@ -176,8 +178,12 @@ pub const Inst = struct {
176178 @"fn",
177179 /// Returns a function type, assuming unspecified calling convention.
178180 fn_type,
181 /// Same as `fn_type` but the function is variadic.
182 fn_type_var_args,
179183 /// Returns a function type, with a calling convention instruction operand.
180184 fn_type_cc,
185 /// Same as `fn_type_cc` but the function is variadic.
186 fn_type_cc_var_args,
181187 /// @import(operand)
182188 import,
183189 /// Integer literal.
......@@ -212,6 +218,8 @@ pub const Inst = struct {
212218 mul,
213219 /// Twos complement wrapping integer multiplication.
214220 mulwrap,
221 /// An await inside a nosuspend scope.
222 nosuspend_await,
215223 /// Given a reference to a function and a parameter index, returns the
216224 /// type of the parameter. TODO what happens when the parameter is `anytype`?
217225 param_type,
......@@ -226,6 +234,8 @@ pub const Inst = struct {
226234 /// the memory location is in the stack frame, local to the scope containing the
227235 /// instruction.
228236 ref,
237 /// Resume an async function.
238 @"resume",
229239 /// Obtains a pointer to the return value.
230240 ret_ptr,
231241 /// Obtains the return type of the in-scope function.
......@@ -348,6 +358,11 @@ pub const Inst = struct {
348358 enum_type,
349359 /// Does nothing; returns a void value.
350360 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,
351366 /// A switch expression.
352367 switchbr,
353368 /// Same as `switchbr` but the target is a pointer to the value being switched on.
......@@ -369,6 +384,7 @@ pub const Inst = struct {
369384 .unreachable_unsafe,
370385 .unreachable_safe,
371386 .void_value,
387 .@"suspend",
372388 => NoOp,
373389
374390 .alloc,
......@@ -417,6 +433,9 @@ pub const Inst = struct {
417433 .import,
418434 .set_eval_branch_quota,
419435 .indexable_ptr_len,
436 .@"resume",
437 .@"await",
438 .nosuspend_await,
420439 => UnOp,
421440
422441 .add,
......@@ -461,6 +480,7 @@ pub const Inst = struct {
461480 .block_flat,
462481 .block_comptime,
463482 .block_comptime_flat,
483 .suspend_block,
464484 => Block,
465485
466486 .switchbr, .switchbr_ref => SwitchBr,
......@@ -486,8 +506,8 @@ pub const Inst = struct {
486506 .@"export" => Export,
487507 .param_type => ParamType,
488508 .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,
491511 .elem_ptr, .elem_val => Elem,
492512 .condbr => CondBr,
493513 .ptr_type => PtrType,
......@@ -563,7 +583,9 @@ pub const Inst = struct {
563583 .field_val_named,
564584 .@"fn",
565585 .fn_type,
586 .fn_type_var_args,
566587 .fn_type_cc,
588 .fn_type_cc_var_args,
567589 .int,
568590 .intcast,
569591 .int_type,
......@@ -633,6 +655,9 @@ pub const Inst = struct {
633655 .struct_type,
634656 .void_value,
635657 .switch_range,
658 .@"resume",
659 .@"await",
660 .nosuspend_await,
636661 => false,
637662
638663 .@"break",
......@@ -649,6 +674,8 @@ pub const Inst = struct {
649674 .container_field,
650675 .switchbr,
651676 .switchbr_ref,
677 .@"suspend",
678 .suspend_block,
652679 => true,
653680 };
654681 }
src/zir_sema.zig+41-17
......@@ -91,8 +91,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
9191 .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?),
9292 .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?),
9393 .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?),
94 .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?),
95 .fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?),
94 .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?, false),
95 .fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?, false),
96 .fn_type_var_args => return zirFnType(mod, scope, old_inst.castTag(.fn_type_var_args).?, true),
97 .fn_type_cc_var_args => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc_var_args).?, true),
9698 .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?),
9799 .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?),
98100 .floatcast => return zirFloatcast(mod, scope, old_inst.castTag(.floatcast).?),
......@@ -160,6 +162,11 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
160162 .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false),
161163 .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr_ref).?, true),
162164 .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).?),
163170
164171 .container_field_named,
165172 .container_field_typed,
......@@ -517,9 +524,11 @@ fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerErr
517524 },
518525 };
519526
520 // TODO support C-style var args
521527 const param_count = fn_ty.fnParamLen();
522528 if (arg_index >= param_count) {
529 if (fn_ty.fnIsVarArgs()) {
530 return mod.constType(scope, inst.base.src, Type.initTag(.var_args_param));
531 }
523532 return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
524533 arg_index,
525534 fn_ty,
......@@ -941,6 +950,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
941950 const call_params_len = inst.positionals.args.len;
942951 const fn_params_len = func.ty.fnParamLen();
943952 if (func.ty.fnIsVarArgs()) {
953 assert(cc == .C);
944954 if (call_params_len < fn_params_len) {
945955 // TODO add error note: declared here
946956 return mod.fail(
......@@ -950,7 +960,6 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
950960 .{ fn_params_len, call_params_len },
951961 );
952962 }
953 return mod.fail(scope, inst.base.src, "TODO implement support for calling var args functions", .{});
954963 } else if (fn_params_len != call_params_len) {
955964 // TODO add error note: declared here
956965 return mod.fail(
......@@ -969,15 +978,10 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
969978 }
970979
971980 // 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);
978982 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);
981985 }
982986
983987 const ret_type = func.ty.fnReturnType();
......@@ -1080,6 +1084,22 @@ fn zirFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
10801084 });
10811085}
10821086
1087fn zirAwait(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1088 return mod.fail(scope, inst.base.src, "TODO implement await", .{});
1089}
1090
1091fn zirResume(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1092 return mod.fail(scope, inst.base.src, "TODO implement resume", .{});
1093}
1094
1095fn zirSuspend(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
1096 return mod.fail(scope, inst.base.src, "TODO implement suspend", .{});
1097}
1098
1099fn zirSuspendBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
1100 return mod.fail(scope, inst.base.src, "TODO implement suspend", .{});
1101}
1102
10831103fn zirIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) InnerError!*Inst {
10841104 const tracy = trace(@src());
10851105 defer tracy.end();
......@@ -1482,7 +1502,7 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp)
14821502 return mod.constVoid(scope, unwrap.base.src);
14831503}
14841504
1485fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
1505fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType, var_args: bool) InnerError!*Inst {
14861506 const tracy = trace(@src());
14871507 defer tracy.end();
14881508
......@@ -1493,10 +1513,11 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*
14931513 fntype.positionals.param_types,
14941514 fntype.positionals.return_type,
14951515 .Unspecified,
1516 var_args,
14961517 );
14971518}
14981519
1499fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerError!*Inst {
1520fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args: bool) InnerError!*Inst {
15001521 const tracy = trace(@src());
15011522 defer tracy.end();
15021523
......@@ -1513,6 +1534,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerErr
15131534 fntype.positionals.param_types,
15141535 fntype.positionals.return_type,
15151536 cc,
1537 var_args,
15161538 );
15171539}
15181540
......@@ -1523,11 +1545,12 @@ fn fnTypeCommon(
15231545 zir_param_types: []*zir.Inst,
15241546 zir_return_type: *zir.Inst,
15251547 cc: std.builtin.CallingConvention,
1548 var_args: bool,
15261549) InnerError!*Inst {
15271550 const return_type = try resolveType(mod, scope, zir_return_type);
15281551
15291552 // Hot path for some common function types.
1530 if (zir_param_types.len == 0) {
1553 if (zir_param_types.len == 0 and !var_args) {
15311554 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
15321555 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
15331556 }
......@@ -1560,6 +1583,7 @@ fn fnTypeCommon(
15601583 .param_types = param_types,
15611584 .return_type = return_type,
15621585 .cc = cc,
1586 .is_var_args = var_args,
15631587 });
15641588 return mod.constType(scope, zir_inst.src, fn_ty);
15651589}
......@@ -2046,7 +2070,7 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
20462070 rhs.ty.arrayLen(),
20472071 });
20482072 }
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", .{});
20502074 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
20512075 return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
20522076 lhs.ty,
......@@ -2127,7 +2151,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
21272151 rhs.ty.arrayLen(),
21282152 });
21292153 }
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", .{});
21312155 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
21322156 return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
21332157 lhs.ty,
test/stage2/cbe.zig+13
......@@ -41,6 +41,19 @@ pub fn addCases(ctx: *TestContext) !void {
4141 , "yo!" ++ std.cstr.line_sep);
4242 }
4343
44 {
45 var case = ctx.exeFromCompiledC("var args", .{});
46
47 case.addCompareOutput(
48 \\extern fn printf(format: [*:0]const u8, ...) c_int;
49 \\
50 \\export fn main() c_int {
51 \\ _ = printf("Hello, %s!\n", "world");
52 \\ return 0;
53 \\}
54 , "Hello, world!\n");
55 }
56
4457 {
4558 var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64);
4659