mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 12:33:19 +00:00
Merge pull request #7910 from Vexu/stage2-async
Stage2: astgen async stuff, implement var args functions
This commit is contained in:
commit
34cb5934dd
139
src/Module.zig
139
src/Module.zig
@ -370,6 +370,8 @@ pub const Scope = struct {
|
||||
.gen_zir => return self.cast(GenZIR).?.arena,
|
||||
.local_val => return self.cast(LocalVal).?.gen_zir.arena,
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
|
||||
.gen_suspend => return self.cast(GenZIR).?.arena,
|
||||
.gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.arena,
|
||||
.file => unreachable,
|
||||
.container => unreachable,
|
||||
}
|
||||
@ -385,6 +387,8 @@ pub const Scope = struct {
|
||||
.gen_zir => self.cast(GenZIR).?.decl,
|
||||
.local_val => self.cast(LocalVal).?.gen_zir.decl,
|
||||
.local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
|
||||
.gen_suspend => return self.cast(GenZIR).?.decl,
|
||||
.gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl,
|
||||
.file => null,
|
||||
.container => null,
|
||||
};
|
||||
@ -396,6 +400,8 @@ pub const Scope = struct {
|
||||
.gen_zir => self.cast(GenZIR).?.decl,
|
||||
.local_val => self.cast(LocalVal).?.gen_zir.decl,
|
||||
.local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
|
||||
.gen_suspend => return self.cast(GenZIR).?.decl,
|
||||
.gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl,
|
||||
.file => null,
|
||||
.container => null,
|
||||
};
|
||||
@ -410,6 +416,8 @@ pub const Scope = struct {
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container,
|
||||
.file => return &self.cast(File).?.root_container,
|
||||
.container => return self.cast(Container).?,
|
||||
.gen_suspend => return self.cast(GenZIR).?.decl.container,
|
||||
.gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl.container,
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,6 +430,8 @@ pub const Scope = struct {
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.gen_suspend => unreachable,
|
||||
.gen_nosuspend => unreachable,
|
||||
.file => unreachable,
|
||||
.container => return self.cast(Container).?.fullyQualifiedNameHash(name),
|
||||
}
|
||||
@ -436,6 +446,8 @@ pub const Scope = struct {
|
||||
.local_val => return &self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,
|
||||
.local_ptr => return &self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,
|
||||
.container => return &self.cast(Container).?.file_scope.tree,
|
||||
.gen_suspend => return &self.cast(GenZIR).?.decl.container.file_scope.tree,
|
||||
.gen_nosuspend => return &self.cast(Nosuspend).?.gen_zir.decl.container.file_scope.tree,
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,9 +455,10 @@ pub const Scope = struct {
|
||||
pub fn getGenZIR(self: *Scope) *GenZIR {
|
||||
return switch (self.tag) {
|
||||
.block => unreachable,
|
||||
.gen_zir => self.cast(GenZIR).?,
|
||||
.gen_zir, .gen_suspend => self.cast(GenZIR).?,
|
||||
.local_val => return self.cast(LocalVal).?.gen_zir,
|
||||
.local_ptr => return self.cast(LocalPtr).?.gen_zir,
|
||||
.gen_nosuspend => return self.cast(Nosuspend).?.gen_zir,
|
||||
.file => unreachable,
|
||||
.container => unreachable,
|
||||
};
|
||||
@ -461,6 +474,8 @@ pub const Scope = struct {
|
||||
.gen_zir => unreachable,
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.gen_suspend => unreachable,
|
||||
.gen_nosuspend => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,6 +487,8 @@ pub const Scope = struct {
|
||||
.local_val => unreachable,
|
||||
.local_ptr => unreachable,
|
||||
.block => unreachable,
|
||||
.gen_suspend => unreachable,
|
||||
.gen_nosuspend => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,6 +503,36 @@ pub const Scope = struct {
|
||||
.local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
|
||||
.local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
|
||||
.block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope,
|
||||
.gen_suspend => @fieldParentPtr(GenZIR, "base", cur).parent,
|
||||
.gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getSuspend(base: *Scope) ?*Scope.GenZIR {
|
||||
var cur = base;
|
||||
while (true) {
|
||||
cur = switch (cur.tag) {
|
||||
.gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,
|
||||
.local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
|
||||
.local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
|
||||
.gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,
|
||||
.gen_suspend => return @fieldParentPtr(GenZIR, "base", cur),
|
||||
else => return null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getNosuspend(base: *Scope) ?*Scope.Nosuspend {
|
||||
var cur = base;
|
||||
while (true) {
|
||||
cur = switch (cur.tag) {
|
||||
.gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,
|
||||
.local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
|
||||
.local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
|
||||
.gen_suspend => @fieldParentPtr(GenZIR, "base", cur).parent,
|
||||
.gen_nosuspend => return @fieldParentPtr(Nosuspend, "base", cur),
|
||||
else => return null,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -507,6 +554,8 @@ pub const Scope = struct {
|
||||
gen_zir,
|
||||
local_val,
|
||||
local_ptr,
|
||||
gen_suspend,
|
||||
gen_nosuspend,
|
||||
};
|
||||
|
||||
pub const Container = struct {
|
||||
@ -740,6 +789,8 @@ pub const Scope = struct {
|
||||
/// so they can possibly be elided later if the labeled block ends up not needing
|
||||
/// a result location pointer.
|
||||
labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(*zir.Inst.BinOp) = .{},
|
||||
/// for suspend error notes
|
||||
src: usize = 0,
|
||||
|
||||
pub const Label = struct {
|
||||
token: ast.TokenIndex,
|
||||
@ -773,6 +824,16 @@ pub const Scope = struct {
|
||||
name: []const u8,
|
||||
ptr: *zir.Inst,
|
||||
};
|
||||
|
||||
pub const Nosuspend = struct {
|
||||
pub const base_tag: Tag = .gen_nosuspend;
|
||||
|
||||
base: Scope = Scope{ .tag = base_tag },
|
||||
/// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
|
||||
parent: *Scope,
|
||||
gen_zir: *GenZIR,
|
||||
src: usize,
|
||||
};
|
||||
};
|
||||
|
||||
/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
|
||||
@ -1122,7 +1183,8 @@ fn astgenAndSemaFn(
|
||||
const param_count = blk: {
|
||||
var count: usize = 0;
|
||||
var it = fn_proto.iterate(tree);
|
||||
while (it.next()) |_| {
|
||||
while (it.next()) |param| {
|
||||
if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;
|
||||
count += 1;
|
||||
}
|
||||
break :blk count;
|
||||
@ -1135,6 +1197,7 @@ fn astgenAndSemaFn(
|
||||
});
|
||||
const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
|
||||
|
||||
var is_var_args = false;
|
||||
{
|
||||
var param_type_i: usize = 0;
|
||||
var it = fn_proto.iterate(tree);
|
||||
@ -1147,12 +1210,10 @@ fn astgenAndSemaFn(
|
||||
"TODO implement anytype parameter",
|
||||
.{},
|
||||
),
|
||||
.ellipsis3 => return mod.failTok(
|
||||
&fn_type_scope.base,
|
||||
token,
|
||||
"TODO implement var args",
|
||||
.{},
|
||||
),
|
||||
.ellipsis3 => {
|
||||
is_var_args = true;
|
||||
break;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
@ -1234,7 +1295,13 @@ fn astgenAndSemaFn(
|
||||
type_type_rl,
|
||||
fn_proto.ast.return_type,
|
||||
);
|
||||
const fn_type_inst = if (fn_proto.ast.callconv_expr != 0) cc: {
|
||||
|
||||
const is_extern = if (fn_proto.extern_export_token) |maybe_export_token|
|
||||
token_tags[maybe_export_token] == .keyword_extern
|
||||
else
|
||||
false;
|
||||
|
||||
const cc_inst = if (fn_proto.ast.callconv_expr != 0) cc: {
|
||||
// TODO instead of enum literal type, this needs to be the
|
||||
// std.builtin.CallingConvention enum. We need to implement importing other files
|
||||
// and enums in order to fix this.
|
||||
@ -1243,18 +1310,31 @@ fn astgenAndSemaFn(
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.enum_literal_type),
|
||||
});
|
||||
const cc = try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
|
||||
break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
|
||||
.ty = enum_lit_ty,
|
||||
}, fn_proto.ast.callconv_expr);
|
||||
break :cc try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type_cc, .{
|
||||
} else if (is_extern) cc: {
|
||||
// note: https://github.com/ziglang/zig/issues/5269
|
||||
const src = token_starts[fn_proto.extern_export_token.?];
|
||||
break :cc try astgen.addZIRInst(mod, &fn_type_scope.base, src, zir.Inst.EnumLiteral, .{ .name = "C" }, .{});
|
||||
} else null;
|
||||
|
||||
const fn_type_inst = if (cc_inst) |cc| fn_type: {
|
||||
var fn_type = try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type_cc, .{
|
||||
.return_type = return_type_inst,
|
||||
.param_types = param_types,
|
||||
.cc = cc,
|
||||
});
|
||||
} else try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{
|
||||
.return_type = return_type_inst,
|
||||
.param_types = param_types,
|
||||
});
|
||||
if (is_var_args) fn_type.tag = .fn_type_cc_var_args;
|
||||
break :fn_type fn_type;
|
||||
} else fn_type: {
|
||||
var fn_type = try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{
|
||||
.return_type = return_type_inst,
|
||||
.param_types = param_types,
|
||||
});
|
||||
if (is_var_args) fn_type.tag = .fn_type_var_args;
|
||||
break :fn_type fn_type;
|
||||
};
|
||||
|
||||
if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
|
||||
zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {};
|
||||
@ -1287,7 +1367,12 @@ fn astgenAndSemaFn(
|
||||
const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{
|
||||
.instructions = fn_type_scope.instructions.items,
|
||||
});
|
||||
|
||||
if (body_node == 0) {
|
||||
if (!is_extern) {
|
||||
return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});
|
||||
}
|
||||
|
||||
// Extern function.
|
||||
var type_changed = true;
|
||||
if (decl.typedValueManaged()) |tvm| {
|
||||
@ -1317,6 +1402,10 @@ fn astgenAndSemaFn(
|
||||
return type_changed;
|
||||
}
|
||||
|
||||
if (fn_type.fnIsVarArgs()) {
|
||||
return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function is variadic", .{});
|
||||
}
|
||||
|
||||
const new_func = try decl_arena.allocator.create(Fn);
|
||||
const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
|
||||
|
||||
@ -3295,6 +3384,9 @@ pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Ty
|
||||
}
|
||||
|
||||
pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!*Inst {
|
||||
if (dest_type.tag() == .var_args_param) {
|
||||
return self.coerceVarArgParam(scope, inst);
|
||||
}
|
||||
// If the types are the same, we can return the operand.
|
||||
if (dest_type.eql(inst.ty))
|
||||
return inst;
|
||||
@ -3447,6 +3539,15 @@ pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) Inn
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn coerceVarArgParam(mod: *Module, scope: *Scope, inst: *Inst) !*Inst {
|
||||
switch (inst.ty.zigTypeTag()) {
|
||||
.ComptimeInt, .ComptimeFloat => return mod.fail(scope, inst.src, "integer and float literals in var args function must be casted", .{}),
|
||||
else => {},
|
||||
}
|
||||
// TODO implement more of this function.
|
||||
return inst;
|
||||
}
|
||||
|
||||
pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
|
||||
if (ptr.ty.isConstPtr())
|
||||
return self.fail(scope, src, "cannot assign to constant", .{});
|
||||
@ -3586,7 +3687,7 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
|
||||
}
|
||||
self.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg);
|
||||
},
|
||||
.gen_zir => {
|
||||
.gen_zir, .gen_suspend => {
|
||||
const gen_zir = scope.cast(Scope.GenZIR).?;
|
||||
gen_zir.decl.analysis = .sema_failure;
|
||||
gen_zir.decl.generation = self.generation;
|
||||
@ -3604,6 +3705,12 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
|
||||
gen_zir.decl.generation = self.generation;
|
||||
self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
|
||||
},
|
||||
.gen_nosuspend => {
|
||||
const gen_zir = scope.cast(Scope.Nosuspend).?.gen_zir;
|
||||
gen_zir.decl.analysis = .sema_failure;
|
||||
gen_zir.decl.generation = self.generation;
|
||||
self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
|
||||
},
|
||||
.file => unreachable,
|
||||
.container => unreachable,
|
||||
}
|
||||
|
||||
115
src/astgen.zig
115
src/astgen.zig
@ -626,10 +626,13 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
|
||||
.@"comptime" => return comptimeExpr(mod, scope, rl, node_datas[node].lhs),
|
||||
.@"switch", .switch_comma => return switchExpr(mod, scope, rl, node),
|
||||
|
||||
.@"nosuspend" => return nosuspendExpr(mod, scope, rl, node),
|
||||
.@"suspend" => return rvalue(mod, scope, rl, try suspendExpr(mod, scope, node)),
|
||||
.@"await" => return awaitExpr(mod, scope, rl, node),
|
||||
.@"resume" => return rvalue(mod, scope, rl, try resumeExpr(mod, scope, node)),
|
||||
|
||||
.@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}),
|
||||
.@"errdefer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .errdefer", .{}),
|
||||
.@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}),
|
||||
.@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}),
|
||||
.@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
|
||||
|
||||
.array_init_one,
|
||||
@ -652,15 +655,12 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
|
||||
.struct_init_comma,
|
||||
=> return mod.failNode(scope, node, "TODO implement astgen.expr for struct literals", .{}),
|
||||
|
||||
.@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}),
|
||||
.@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}),
|
||||
.fn_proto_simple,
|
||||
.fn_proto_multi,
|
||||
.fn_proto_one,
|
||||
.fn_proto,
|
||||
=> return mod.failNode(scope, node, "TODO implement astgen.expr for function prototypes", .{}),
|
||||
|
||||
.@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -766,6 +766,8 @@ fn breakExpr(
|
||||
},
|
||||
.local_val => scope = scope.cast(Scope.LocalVal).?.parent,
|
||||
.local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
|
||||
.gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent,
|
||||
.gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
|
||||
else => if (break_label != 0) {
|
||||
const label_name = try mod.identifierTokenString(parent_scope, break_label);
|
||||
return mod.failTok(parent_scope, break_label, "label not found: '{s}'", .{label_name});
|
||||
@ -819,6 +821,8 @@ fn continueExpr(
|
||||
},
|
||||
.local_val => scope = scope.cast(Scope.LocalVal).?.parent,
|
||||
.local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
|
||||
.gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent,
|
||||
.gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
|
||||
else => if (break_label != 0) {
|
||||
const label_name = try mod.identifierTokenString(parent_scope, break_label);
|
||||
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
|
||||
},
|
||||
.local_val => scope = scope.cast(Scope.LocalVal).?.parent,
|
||||
.local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
|
||||
.gen_suspend => scope = scope.cast(Scope.GenZIR).?.parent,
|
||||
.gen_nosuspend => scope = scope.cast(Scope.Nosuspend).?.parent,
|
||||
else => return,
|
||||
}
|
||||
}
|
||||
@ -1100,6 +1106,8 @@ fn varDecl(
|
||||
s = local_ptr.parent;
|
||||
},
|
||||
.gen_zir => s = s.cast(Scope.GenZIR).?.parent,
|
||||
.gen_suspend => s = s.cast(Scope.GenZIR).?.parent,
|
||||
.gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,
|
||||
else => break,
|
||||
};
|
||||
}
|
||||
@ -3021,6 +3029,8 @@ fn identifier(
|
||||
s = local_ptr.parent;
|
||||
},
|
||||
.gen_zir => s = s.cast(Scope.GenZIR).?.parent,
|
||||
.gen_suspend => s = s.cast(Scope.GenZIR).?.parent,
|
||||
.gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,
|
||||
else => break,
|
||||
};
|
||||
}
|
||||
@ -3633,14 +3643,109 @@ fn callExpr(
|
||||
}
|
||||
|
||||
const src = token_starts[call.ast.lparen];
|
||||
var modifier: std.builtin.CallOptions.Modifier = .auto;
|
||||
if (call.async_token) |_| modifier = .async_kw;
|
||||
|
||||
const result = try addZIRInst(mod, scope, src, zir.Inst.Call, .{
|
||||
.func = lhs,
|
||||
.args = args,
|
||||
.modifier = modifier,
|
||||
}, .{});
|
||||
// TODO function call with result location
|
||||
return rvalue(mod, scope, rl, result);
|
||||
}
|
||||
|
||||
fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]];
|
||||
|
||||
if (scope.getNosuspend()) |some| {
|
||||
const msg = msg: {
|
||||
const msg = try mod.errMsg(scope, src, "suspend in nosuspend block", .{});
|
||||
errdefer msg.destroy(mod.gpa);
|
||||
try mod.errNote(scope, some.src, msg, "nosuspend block here", .{});
|
||||
break :msg msg;
|
||||
};
|
||||
return mod.failWithOwnedErrorMsg(scope, msg);
|
||||
}
|
||||
|
||||
if (scope.getSuspend()) |some| {
|
||||
const msg = msg: {
|
||||
const msg = try mod.errMsg(scope, src, "cannot suspend inside suspend block", .{});
|
||||
errdefer msg.destroy(mod.gpa);
|
||||
try mod.errNote(scope, some.src, msg, "other suspend block here", .{});
|
||||
break :msg msg;
|
||||
};
|
||||
return mod.failWithOwnedErrorMsg(scope, msg);
|
||||
}
|
||||
|
||||
var suspend_scope: Scope.GenZIR = .{
|
||||
.base = .{ .tag = .gen_suspend },
|
||||
.parent = scope,
|
||||
.decl = scope.ownerDecl().?,
|
||||
.arena = scope.arena(),
|
||||
.force_comptime = scope.isComptime(),
|
||||
.instructions = .{},
|
||||
};
|
||||
defer suspend_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const operand = tree.nodes.items(.data)[node].lhs;
|
||||
if (operand != 0) {
|
||||
const possibly_unused_result = try expr(mod, &suspend_scope.base, .none, operand);
|
||||
if (!possibly_unused_result.tag.isNoReturn()) {
|
||||
_ = try addZIRUnOp(mod, &suspend_scope.base, src, .ensure_result_used, possibly_unused_result);
|
||||
}
|
||||
} else {
|
||||
return addZIRNoOp(mod, scope, src, .@"suspend");
|
||||
}
|
||||
|
||||
const block = try addZIRInstBlock(mod, scope, src, .suspend_block, .{
|
||||
.instructions = try scope.arena().dupe(*zir.Inst, suspend_scope.instructions.items),
|
||||
});
|
||||
return &block.base;
|
||||
}
|
||||
|
||||
fn nosuspendExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
var child_scope = Scope.Nosuspend{
|
||||
.parent = scope,
|
||||
.gen_zir = scope.getGenZIR(),
|
||||
.src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]],
|
||||
};
|
||||
|
||||
return expr(mod, &child_scope.base, rl, tree.nodes.items(.data)[node].lhs);
|
||||
}
|
||||
|
||||
fn awaitExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]];
|
||||
const is_nosuspend = scope.getNosuspend() != null;
|
||||
|
||||
// TODO some @asyncCall stuff
|
||||
|
||||
if (scope.getSuspend()) |some| {
|
||||
const msg = msg: {
|
||||
const msg = try mod.errMsg(scope, src, "cannot await inside suspend block", .{});
|
||||
errdefer msg.destroy(mod.gpa);
|
||||
try mod.errNote(scope, some.src, msg, "suspend block here", .{});
|
||||
break :msg msg;
|
||||
};
|
||||
return mod.failWithOwnedErrorMsg(scope, msg);
|
||||
}
|
||||
|
||||
const operand = try expr(mod, scope, .ref, tree.nodes.items(.data)[node].lhs);
|
||||
// TODO pass result location
|
||||
return addZIRUnOp(mod, scope, src, if (is_nosuspend) .nosuspend_await else .@"await", operand);
|
||||
}
|
||||
|
||||
fn resumeExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.tokens.items(.start)[tree.nodes.items(.main_token)[node]];
|
||||
|
||||
const operand = try expr(mod, scope, .ref, tree.nodes.items(.data)[node].lhs);
|
||||
return addZIRUnOp(mod, scope, src, .@"resume", operand);
|
||||
}
|
||||
|
||||
pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
|
||||
.{ "u8", .u8_type },
|
||||
.{ "i8", .i8_type },
|
||||
|
||||
@ -215,8 +215,9 @@ pub const DeclGen = struct {
|
||||
try dg.renderType(w, tv.ty.fnReturnType());
|
||||
const decl_name = mem.span(dg.decl.name);
|
||||
try w.print(" {s}(", .{decl_name});
|
||||
var param_len = tv.ty.fnParamLen();
|
||||
if (param_len == 0)
|
||||
const param_len = tv.ty.fnParamLen();
|
||||
const is_var_args = tv.ty.fnIsVarArgs();
|
||||
if (param_len == 0 and !is_var_args)
|
||||
try w.writeAll("void")
|
||||
else {
|
||||
var index: usize = 0;
|
||||
@ -228,6 +229,10 @@ pub const DeclGen = struct {
|
||||
try w.print(" a{d}", .{index});
|
||||
}
|
||||
}
|
||||
if (is_var_args) {
|
||||
if (param_len != 0) try w.writeAll(", ");
|
||||
try w.writeAll("...");
|
||||
}
|
||||
try w.writeByte(')');
|
||||
}
|
||||
|
||||
|
||||
@ -871,6 +871,7 @@ pub const TestContext = struct {
|
||||
"-std=c89",
|
||||
"-pedantic",
|
||||
"-Werror",
|
||||
"-Wno-incompatible-library-redeclaration", // https://github.com/ziglang/zig/issues/875
|
||||
"-Wno-declaration-after-statement",
|
||||
"--",
|
||||
"-lc",
|
||||
|
||||
47
src/type.zig
47
src/type.zig
@ -97,6 +97,8 @@ pub const Type = extern union {
|
||||
.@"struct", .empty_struct => return .Struct,
|
||||
.@"enum" => return .Enum,
|
||||
.@"union" => return .Union,
|
||||
|
||||
.var_args_param => unreachable, // can be any type
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,6 +260,8 @@ pub const Type = extern union {
|
||||
if (!a.fnParamType(i).eql(b.fnParamType(i)))
|
||||
return false;
|
||||
}
|
||||
if (a.fnIsVarArgs() != b.fnIsVarArgs())
|
||||
return false;
|
||||
return true;
|
||||
},
|
||||
.Optional => {
|
||||
@ -323,6 +327,7 @@ pub const Type = extern union {
|
||||
while (i < params_len) : (i += 1) {
|
||||
std.hash.autoHash(&hasher, self.fnParamType(i).hash());
|
||||
}
|
||||
std.hash.autoHash(&hasher, self.fnIsVarArgs());
|
||||
},
|
||||
.Optional => {
|
||||
var buf: Payload.ElemType = undefined;
|
||||
@ -397,6 +402,7 @@ pub const Type = extern union {
|
||||
.@"anyframe",
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
|
||||
.array_u8,
|
||||
@ -446,6 +452,7 @@ pub const Type = extern union {
|
||||
.return_type = try payload.return_type.copy(allocator),
|
||||
.param_types = param_types,
|
||||
.cc = payload.cc,
|
||||
.is_var_args = payload.is_var_args,
|
||||
});
|
||||
},
|
||||
.pointer => {
|
||||
@ -535,6 +542,7 @@ pub const Type = extern union {
|
||||
.comptime_int,
|
||||
.comptime_float,
|
||||
.noreturn,
|
||||
.var_args_param,
|
||||
=> return out_stream.writeAll(@tagName(t)),
|
||||
|
||||
.enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
|
||||
@ -558,6 +566,12 @@ pub const Type = extern union {
|
||||
if (i != 0) try out_stream.writeAll(", ");
|
||||
try param_type.format("", .{}, out_stream);
|
||||
}
|
||||
if (payload.is_var_args) {
|
||||
if (payload.param_types.len != 0) {
|
||||
try out_stream.writeAll(", ");
|
||||
}
|
||||
try out_stream.writeAll("...");
|
||||
}
|
||||
try out_stream.writeAll(") callconv(.");
|
||||
try out_stream.writeAll(@tagName(payload.cc));
|
||||
try out_stream.writeAll(")");
|
||||
@ -844,6 +858,7 @@ pub const Type = extern union {
|
||||
|
||||
.inferred_alloc_const => unreachable,
|
||||
.inferred_alloc_mut => unreachable,
|
||||
.var_args_param => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
@ -969,6 +984,7 @@ pub const Type = extern union {
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -995,6 +1011,7 @@ pub const Type = extern union {
|
||||
.inferred_alloc_const => unreachable,
|
||||
.inferred_alloc_mut => unreachable,
|
||||
.@"opaque" => unreachable,
|
||||
.var_args_param => unreachable,
|
||||
|
||||
.u8,
|
||||
.i8,
|
||||
@ -1179,6 +1196,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -1256,6 +1274,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
|
||||
.const_slice,
|
||||
@ -1354,6 +1373,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.const_slice,
|
||||
@ -1434,6 +1454,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -1523,6 +1544,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.pointer => {
|
||||
@ -1607,6 +1629,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.pointer => {
|
||||
@ -1733,6 +1756,7 @@ pub const Type = extern union {
|
||||
.@"struct" => unreachable,
|
||||
.@"union" => unreachable,
|
||||
.@"opaque" => unreachable,
|
||||
.var_args_param => unreachable,
|
||||
|
||||
.array => self.castTag(.array).?.data.elem_type,
|
||||
.array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
|
||||
@ -1862,6 +1886,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.castTag(.array).?.data.len,
|
||||
@ -1936,6 +1961,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -2025,6 +2051,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.int_signed,
|
||||
@ -2110,6 +2137,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.int_unsigned,
|
||||
@ -2181,6 +2209,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
|
||||
.int_unsigned => .{
|
||||
@ -2280,6 +2309,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
|
||||
.usize,
|
||||
@ -2400,6 +2430,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2486,6 +2517,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@ -2571,6 +2603,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@ -2656,6 +2689,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2738,6 +2772,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2749,7 +2784,7 @@ pub const Type = extern union {
|
||||
.fn_void_no_args => false,
|
||||
.fn_naked_noreturn_no_args => false,
|
||||
.fn_ccc_void_no_args => false,
|
||||
.function => false,
|
||||
.function => self.castTag(.function).?.data.is_var_args,
|
||||
|
||||
.f16,
|
||||
.f32,
|
||||
@ -2820,6 +2855,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2902,6 +2938,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
@ -2962,6 +2999,7 @@ pub const Type = extern union {
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> return null,
|
||||
|
||||
.@"enum" => @panic("TODO onePossibleValue enum"),
|
||||
@ -3079,6 +3117,7 @@ pub const Type = extern union {
|
||||
.@"struct",
|
||||
.@"union",
|
||||
.@"opaque",
|
||||
.var_args_param,
|
||||
=> return false,
|
||||
|
||||
.c_const_pointer,
|
||||
@ -3168,6 +3207,7 @@ pub const Type = extern union {
|
||||
.pointer,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.var_args_param,
|
||||
=> unreachable,
|
||||
|
||||
.empty_struct => self.castTag(.empty_struct).?.data,
|
||||
@ -3285,6 +3325,9 @@ pub const Type = extern union {
|
||||
anyerror_void_error_union,
|
||||
@"anyframe",
|
||||
const_slice_u8,
|
||||
/// This is a special type for variadic parameters of a function call.
|
||||
/// Casts to it will validate that the type can be passed to a c calling convetion function.
|
||||
var_args_param,
|
||||
/// This is a special value that tracks a set of types that have been stored
|
||||
/// to an inferred allocation. It does not support most of the normal type queries.
|
||||
/// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc.
|
||||
@ -3373,6 +3416,7 @@ pub const Type = extern union {
|
||||
.const_slice_u8,
|
||||
.inferred_alloc_const,
|
||||
.inferred_alloc_mut,
|
||||
.var_args_param,
|
||||
=> @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
|
||||
|
||||
.array_u8,
|
||||
@ -3479,6 +3523,7 @@ pub const Type = extern union {
|
||||
param_types: []Type,
|
||||
return_type: Type,
|
||||
cc: std.builtin.CallingConvention,
|
||||
is_var_args: bool,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
31
src/zir.zig
31
src/zir.zig
@ -61,6 +61,8 @@ pub const Inst = struct {
|
||||
as,
|
||||
/// Inline assembly.
|
||||
@"asm",
|
||||
/// Await an async function.
|
||||
@"await",
|
||||
/// Bitwise AND. `&`
|
||||
bit_and,
|
||||
/// TODO delete this instruction, it has no purpose.
|
||||
@ -176,8 +178,12 @@ pub const Inst = struct {
|
||||
@"fn",
|
||||
/// Returns a function type, assuming unspecified calling convention.
|
||||
fn_type,
|
||||
/// Same as `fn_type` but the function is variadic.
|
||||
fn_type_var_args,
|
||||
/// Returns a function type, with a calling convention instruction operand.
|
||||
fn_type_cc,
|
||||
/// Same as `fn_type_cc` but the function is variadic.
|
||||
fn_type_cc_var_args,
|
||||
/// @import(operand)
|
||||
import,
|
||||
/// Integer literal.
|
||||
@ -212,6 +218,8 @@ pub const Inst = struct {
|
||||
mul,
|
||||
/// Twos complement wrapping integer multiplication.
|
||||
mulwrap,
|
||||
/// An await inside a nosuspend scope.
|
||||
nosuspend_await,
|
||||
/// Given a reference to a function and a parameter index, returns the
|
||||
/// type of the parameter. TODO what happens when the parameter is `anytype`?
|
||||
param_type,
|
||||
@ -226,6 +234,8 @@ pub const Inst = struct {
|
||||
/// the memory location is in the stack frame, local to the scope containing the
|
||||
/// instruction.
|
||||
ref,
|
||||
/// Resume an async function.
|
||||
@"resume",
|
||||
/// Obtains a pointer to the return value.
|
||||
ret_ptr,
|
||||
/// Obtains the return type of the in-scope function.
|
||||
@ -348,6 +358,11 @@ pub const Inst = struct {
|
||||
enum_type,
|
||||
/// Does nothing; returns a void value.
|
||||
void_value,
|
||||
/// Suspend an async function.
|
||||
@"suspend",
|
||||
/// Suspend an async function.
|
||||
/// Same as .suspend but with a block.
|
||||
suspend_block,
|
||||
/// A switch expression.
|
||||
switchbr,
|
||||
/// Same as `switchbr` but the target is a pointer to the value being switched on.
|
||||
@ -369,6 +384,7 @@ pub const Inst = struct {
|
||||
.unreachable_unsafe,
|
||||
.unreachable_safe,
|
||||
.void_value,
|
||||
.@"suspend",
|
||||
=> NoOp,
|
||||
|
||||
.alloc,
|
||||
@ -417,6 +433,9 @@ pub const Inst = struct {
|
||||
.import,
|
||||
.set_eval_branch_quota,
|
||||
.indexable_ptr_len,
|
||||
.@"resume",
|
||||
.@"await",
|
||||
.nosuspend_await,
|
||||
=> UnOp,
|
||||
|
||||
.add,
|
||||
@ -461,6 +480,7 @@ pub const Inst = struct {
|
||||
.block_flat,
|
||||
.block_comptime,
|
||||
.block_comptime_flat,
|
||||
.suspend_block,
|
||||
=> Block,
|
||||
|
||||
.switchbr, .switchbr_ref => SwitchBr,
|
||||
@ -486,8 +506,8 @@ pub const Inst = struct {
|
||||
.@"export" => Export,
|
||||
.param_type => ParamType,
|
||||
.primitive => Primitive,
|
||||
.fn_type => FnType,
|
||||
.fn_type_cc => FnTypeCc,
|
||||
.fn_type, .fn_type_var_args => FnType,
|
||||
.fn_type_cc, .fn_type_cc_var_args => FnTypeCc,
|
||||
.elem_ptr, .elem_val => Elem,
|
||||
.condbr => CondBr,
|
||||
.ptr_type => PtrType,
|
||||
@ -563,7 +583,9 @@ pub const Inst = struct {
|
||||
.field_val_named,
|
||||
.@"fn",
|
||||
.fn_type,
|
||||
.fn_type_var_args,
|
||||
.fn_type_cc,
|
||||
.fn_type_cc_var_args,
|
||||
.int,
|
||||
.intcast,
|
||||
.int_type,
|
||||
@ -633,6 +655,9 @@ pub const Inst = struct {
|
||||
.struct_type,
|
||||
.void_value,
|
||||
.switch_range,
|
||||
.@"resume",
|
||||
.@"await",
|
||||
.nosuspend_await,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@ -649,6 +674,8 @@ pub const Inst = struct {
|
||||
.container_field,
|
||||
.switchbr,
|
||||
.switchbr_ref,
|
||||
.@"suspend",
|
||||
.suspend_block,
|
||||
=> true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -91,8 +91,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?),
|
||||
.@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?),
|
||||
.primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?),
|
||||
.fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?),
|
||||
.fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?),
|
||||
.fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?, false),
|
||||
.fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?, false),
|
||||
.fn_type_var_args => return zirFnType(mod, scope, old_inst.castTag(.fn_type_var_args).?, true),
|
||||
.fn_type_cc_var_args => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc_var_args).?, true),
|
||||
.intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?),
|
||||
.bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?),
|
||||
.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!
|
||||
.switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false),
|
||||
.switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr_ref).?, true),
|
||||
.switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
|
||||
.@"await" => return zirAwait(mod, scope, old_inst.castTag(.@"await").?),
|
||||
.nosuspend_await => return zirAwait(mod, scope, old_inst.castTag(.nosuspend_await).?),
|
||||
.@"resume" => return zirResume(mod, scope, old_inst.castTag(.@"resume").?),
|
||||
.@"suspend" => return zirSuspend(mod, scope, old_inst.castTag(.@"suspend").?),
|
||||
.suspend_block => return zirSuspendBlock(mod, scope, old_inst.castTag(.suspend_block).?),
|
||||
|
||||
.container_field_named,
|
||||
.container_field_typed,
|
||||
@ -517,9 +524,11 @@ fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerErr
|
||||
},
|
||||
};
|
||||
|
||||
// TODO support C-style var args
|
||||
const param_count = fn_ty.fnParamLen();
|
||||
if (arg_index >= param_count) {
|
||||
if (fn_ty.fnIsVarArgs()) {
|
||||
return mod.constType(scope, inst.base.src, Type.initTag(.var_args_param));
|
||||
}
|
||||
return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
|
||||
arg_index,
|
||||
fn_ty,
|
||||
@ -941,6 +950,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
|
||||
const call_params_len = inst.positionals.args.len;
|
||||
const fn_params_len = func.ty.fnParamLen();
|
||||
if (func.ty.fnIsVarArgs()) {
|
||||
assert(cc == .C);
|
||||
if (call_params_len < fn_params_len) {
|
||||
// TODO add error note: declared here
|
||||
return mod.fail(
|
||||
@ -950,7 +960,6 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
|
||||
.{ fn_params_len, call_params_len },
|
||||
);
|
||||
}
|
||||
return mod.fail(scope, inst.base.src, "TODO implement support for calling var args functions", .{});
|
||||
} else if (fn_params_len != call_params_len) {
|
||||
// TODO add error note: declared here
|
||||
return mod.fail(
|
||||
@ -969,15 +978,10 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
|
||||
}
|
||||
|
||||
// TODO handle function calls of generic functions
|
||||
|
||||
const fn_param_types = try mod.gpa.alloc(Type, fn_params_len);
|
||||
defer mod.gpa.free(fn_param_types);
|
||||
func.ty.fnParamTypes(fn_param_types);
|
||||
|
||||
const casted_args = try scope.arena().alloc(*Inst, fn_params_len);
|
||||
const casted_args = try scope.arena().alloc(*Inst, call_params_len);
|
||||
for (inst.positionals.args) |src_arg, i| {
|
||||
const uncasted_arg = try resolveInst(mod, scope, src_arg);
|
||||
casted_args[i] = try mod.coerce(scope, fn_param_types[i], uncasted_arg);
|
||||
// the args are already casted to the result of a param type instruction.
|
||||
casted_args[i] = try resolveInst(mod, scope, src_arg);
|
||||
}
|
||||
|
||||
const ret_type = func.ty.fnReturnType();
|
||||
@ -1080,6 +1084,22 @@ fn zirFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
|
||||
});
|
||||
}
|
||||
|
||||
fn zirAwait(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement await", .{});
|
||||
}
|
||||
|
||||
fn zirResume(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement resume", .{});
|
||||
}
|
||||
|
||||
fn zirSuspend(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement suspend", .{});
|
||||
}
|
||||
|
||||
fn zirSuspendBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement suspend", .{});
|
||||
}
|
||||
|
||||
fn zirIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
@ -1482,7 +1502,7 @@ fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp)
|
||||
return mod.constVoid(scope, unwrap.base.src);
|
||||
}
|
||||
|
||||
fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
|
||||
fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType, var_args: bool) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -1493,10 +1513,11 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*
|
||||
fntype.positionals.param_types,
|
||||
fntype.positionals.return_type,
|
||||
.Unspecified,
|
||||
var_args,
|
||||
);
|
||||
}
|
||||
|
||||
fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerError!*Inst {
|
||||
fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args: bool) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
@ -1513,6 +1534,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc) InnerErr
|
||||
fntype.positionals.param_types,
|
||||
fntype.positionals.return_type,
|
||||
cc,
|
||||
var_args,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1523,11 +1545,12 @@ fn fnTypeCommon(
|
||||
zir_param_types: []*zir.Inst,
|
||||
zir_return_type: *zir.Inst,
|
||||
cc: std.builtin.CallingConvention,
|
||||
var_args: bool,
|
||||
) InnerError!*Inst {
|
||||
const return_type = try resolveType(mod, scope, zir_return_type);
|
||||
|
||||
// Hot path for some common function types.
|
||||
if (zir_param_types.len == 0) {
|
||||
if (zir_param_types.len == 0 and !var_args) {
|
||||
if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
|
||||
return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
|
||||
}
|
||||
@ -1560,6 +1583,7 @@ fn fnTypeCommon(
|
||||
.param_types = param_types,
|
||||
.return_type = return_type,
|
||||
.cc = cc,
|
||||
.is_var_args = var_args,
|
||||
});
|
||||
return mod.constType(scope, zir_inst.src, fn_ty);
|
||||
}
|
||||
@ -2046,7 +2070,7 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
|
||||
rhs.ty.arrayLen(),
|
||||
});
|
||||
}
|
||||
return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBitwise", .{});
|
||||
return mod.fail(scope, inst.base.src, "TODO implement support for vectors in zirBitwise", .{});
|
||||
} else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
|
||||
return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
|
||||
lhs.ty,
|
||||
@ -2127,7 +2151,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
|
||||
rhs.ty.arrayLen(),
|
||||
});
|
||||
}
|
||||
return mod.fail(scope, inst.base.src, "TODO implement support for vectors in analyzeInstBinOp", .{});
|
||||
return mod.fail(scope, inst.base.src, "TODO implement support for vectors in zirBinOp", .{});
|
||||
} else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
|
||||
return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
|
||||
lhs.ty,
|
||||
|
||||
@ -41,6 +41,19 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||
, "yo!" ++ std.cstr.line_sep);
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exeFromCompiledC("var args", .{});
|
||||
|
||||
case.addCompareOutput(
|
||||
\\extern fn printf(format: [*:0]const u8, ...) c_int;
|
||||
\\
|
||||
\\export fn main() c_int {
|
||||
\\ _ = printf("Hello, %s!\n", "world");
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "Hello, world!\n");
|
||||
}
|
||||
|
||||
{
|
||||
var case = ctx.exeFromCompiledC("x86_64-linux inline assembly", linux_x64);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user