aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig15
-rw-r--r--src/Sema.zig49
-rw-r--r--src/Zir.zig26
-rw-r--r--src/print_zir.zig9
4 files changed, 85 insertions, 14 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 3e502625db..30ed680226 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -71,6 +71,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
Zir.Inst.Ref => @enumToInt(@field(extra, field.name)),
i32 => @bitCast(u32, @field(extra, field.name)),
Zir.Inst.Call.Flags => @bitCast(u32, @field(extra, field.name)),
+ Zir.Inst.BuiltinCall.Flags => @bitCast(u32, @field(extra, field.name)),
Zir.Inst.SwitchBlock.Bits => @bitCast(u32, @field(extra, field.name)),
Zir.Inst.ExtendedFunc.Bits => @bitCast(u32, @field(extra, field.name)),
else => @compileError("bad field type"),
@@ -2213,6 +2214,14 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
slot.* = @bitCast(u32, flags);
break :b true;
},
+ .builtin_call => {
+ const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
+ const slot = &gz.astgen.extra.items[extra_index];
+ var flags = @bitCast(Zir.Inst.BuiltinCall.Flags, slot.*);
+ flags.ensure_result_used = true;
+ slot.* = @bitCast(u32, flags);
+ break :b true;
+ },
// ZIR instructions that might be a type other than `noreturn` or `void`.
.add,
@@ -2412,7 +2421,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
.atomic_load,
.atomic_rmw,
.mul_add,
- .builtin_call,
.field_parent_ptr,
.maximum,
.minimum,
@@ -7502,6 +7510,11 @@ fn builtinCall(
.options = options,
.callee = callee,
.args = args,
+ .flags = .{
+ .is_nosuspend = gz.nosuspend_node != 0,
+ .is_comptime = gz.force_comptime,
+ .ensure_result_used = false,
+ },
});
return rvalue(gz, rl, result, node);
},
diff --git a/src/Sema.zig b/src/Sema.zig
index feed4d0e8a..13a3573112 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -16097,12 +16097,12 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const args_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
const call_src = inst_data.src();
- const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index);
- var func = sema.resolveInst(extra.data.callee);
- const options = sema.resolveInst(extra.data.options);
- const args = sema.resolveInst(extra.data.args);
+ const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
+ var func = sema.resolveInst(extra.callee);
+ const options = sema.resolveInst(extra.options);
+ const args = sema.resolveInst(extra.args);
- const modifier: std.builtin.CallOptions.Modifier = modifier: {
+ const wanted_modifier: std.builtin.CallOptions.Modifier = modifier: {
const call_options_ty = try sema.getBuiltinType(block, options_src, "CallOptions");
const coerced_options = try sema.coerce(block, call_options_ty, options, options_src);
@@ -16118,6 +16118,41 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
break :modifier modifier_val.toEnum(std.builtin.CallOptions.Modifier);
};
+ const modifier: std.builtin.CallOptions.Modifier = switch (wanted_modifier) {
+ // These can be upgraded to comptime or nosuspend calls.
+ .auto, .never_tail, .no_async => m: {
+ if (extra.flags.is_comptime) {
+ break :m .compile_time;
+ }
+ if (extra.flags.is_nosuspend) {
+ break :m .no_async;
+ }
+ break :m wanted_modifier;
+ },
+ // These can be upgraded to comptime. nosuspend bit can be safely ignored.
+ .always_tail, .always_inline, .compile_time => m: {
+ if (extra.flags.is_comptime) {
+ break :m .compile_time;
+ }
+ break :m wanted_modifier;
+ },
+ .async_kw => m: {
+ if (extra.flags.is_nosuspend) {
+ return sema.fail(block, options_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{});
+ }
+ if (extra.flags.is_comptime) {
+ return sema.fail(block, options_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{});
+ }
+ break :m wanted_modifier;
+ },
+ .never_inline => m: {
+ if (extra.flags.is_comptime) {
+ return sema.fail(block, options_src, "modifier 'never_inline' cannot be used in combination with comptime function call", .{});
+ }
+ break :m wanted_modifier;
+ },
+ };
+
const args_ty = sema.typeOf(args);
if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) {
return sema.fail(block, args_src, "expected a tuple, found {}", .{args_ty.fmt(sema.mod)});
@@ -16141,8 +16176,8 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
}
}
-
- return sema.analyzeCall(block, func, func_src, call_src, modifier, false, resolved_args);
+ const ensure_result_used = extra.flags.ensure_result_used;
+ return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args);
}
fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
diff --git a/src/Zir.zig b/src/Zir.zig
index 30edd6d0e1..c722457303 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -72,6 +72,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, en
Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]),
i32 => @bitCast(i32, code.extra[i]),
Inst.Call.Flags => @bitCast(Inst.Call.Flags, code.extra[i]),
+ Inst.BuiltinCall.Flags => @bitCast(Inst.BuiltinCall.Flags, code.extra[i]),
Inst.SwitchBlock.Bits => @bitCast(Inst.SwitchBlock.Bits, code.extra[i]),
Inst.ExtendedFunc.Bits => @bitCast(Inst.ExtendedFunc.Bits, code.extra[i]),
else => @compileError("bad field type"),
@@ -280,8 +281,13 @@ pub const Inst = struct {
/// Uses the `break` union field.
break_inline,
/// Function call.
- /// Uses `pl_node`. AST node is the function call. Payload is `Call`.
+ /// Uses the `pl_node` union field with payload `Call`.
+ /// AST node is the function call.
call,
+ /// Implements the `@call` builtin.
+ /// Uses the `pl_node` union field with payload `BuiltinCall`.
+ /// AST node is the builtin call.
+ builtin_call,
/// `<`
/// Uses the `pl_node` union field. Payload is `Bin`.
cmp_lt,
@@ -916,9 +922,6 @@ pub const Inst = struct {
/// The addend communicates the type of the builtin.
/// The mulends need to be coerced to the same type.
mul_add,
- /// Implements the `@call` builtin.
- /// Uses the `pl_node` union field with payload `BuiltinCall`.
- builtin_call,
/// Implements the `@fieldParentPtr` builtin.
/// Uses the `pl_node` union field with payload `FieldParentPtr`.
field_parent_ptr,
@@ -2733,9 +2736,24 @@ pub const Inst = struct {
};
pub const BuiltinCall = struct {
+ // Note: Flags *must* come first so that unusedResultExpr
+ // can find it when it goes to modify them.
+ flags: Flags,
options: Ref,
callee: Ref,
args: Ref,
+
+ pub const Flags = packed struct {
+ is_nosuspend: bool,
+ is_comptime: bool,
+ ensure_result_used: bool,
+ _: u29 = undefined,
+
+ comptime {
+ if (@sizeOf(Flags) != 4 or @bitSizeOf(Flags) != 32)
+ @compileError("Layout of BuiltinCall.Flags needs to be updated!");
+ }
+ };
};
/// This data is stored inside extra, with two sets of trailing `Ref`:
diff --git a/src/print_zir.zig b/src/print_zir.zig
index a9d0f4690f..1f243acc30 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -365,7 +365,7 @@ const Writer = struct {
.@"export" => try self.writePlNodeExport(stream, inst),
.export_value => try self.writePlNodeExportValue(stream, inst),
- .call => try self.writePlNodeCall(stream, inst),
+ .call => try self.writeCall(stream, inst),
.block,
.block_inline,
@@ -793,6 +793,11 @@ const Writer = struct {
fn writeBuiltinCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const extra = self.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
+
+ try self.writeFlag(stream, "nodiscard ", extra.flags.ensure_result_used);
+ try self.writeFlag(stream, "nosuspend ", extra.flags.is_nosuspend);
+ try self.writeFlag(stream, "comptime ", extra.flags.is_comptime);
+
try self.writeInstRef(stream, extra.options);
try stream.writeAll(", ");
try self.writeInstRef(stream, extra.callee);
@@ -1144,7 +1149,7 @@ const Writer = struct {
try self.writeSrc(stream, src);
}
- fn writePlNodeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
+ fn writeCall(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const extra = self.code.extraData(Zir.Inst.Call, inst_data.payload_index);
const args = self.code.refSlice(extra.end, extra.data.flags.args_len);