mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
stage2: fix memory management of ZIR code
* free Module.Fn ZIR code when destroying the owner Decl * unreachable_safe and unreachable_unsafe are collapsed into one ZIR instruction with a safety flag. * astgen: emit an unreachable instruction for unreachable literals * don't forget to call deinit on ZIR code * astgen: implement some builtin functions
This commit is contained in:
parent
d8692b8bdb
commit
7598a00f34
@ -224,6 +224,10 @@ pub const Decl = struct {
|
||||
const gpa = module.gpa;
|
||||
gpa.free(mem.spanZ(decl.name));
|
||||
if (decl.typedValueManaged()) |tvm| {
|
||||
if (tvm.typed_value.val.castTag(.function)) |payload| {
|
||||
const func = payload.data;
|
||||
func.deinit(gpa);
|
||||
}
|
||||
tvm.deinit(gpa);
|
||||
}
|
||||
decl.dependants.deinit(gpa);
|
||||
@ -334,7 +338,7 @@ pub const EmitH = struct {
|
||||
fwd_decl: std.ArrayListUnmanaged(u8) = .{},
|
||||
};
|
||||
|
||||
/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
|
||||
/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
|
||||
/// Extern functions do not have this data structure; they are represented by
|
||||
/// the `Decl` only, with a `Value` tag of `extern_fn`.
|
||||
pub const Fn = struct {
|
||||
@ -347,6 +351,7 @@ pub const Fn = struct {
|
||||
/// The number of parameters is determined by referring to the type.
|
||||
/// The first N elements of `extra` are indexes into `string_bytes` to
|
||||
/// a null-terminated string.
|
||||
/// This memory is managed with gpa, must be freed when the function is freed.
|
||||
zir: zir.Code,
|
||||
/// undefined unless analysis state is `success`.
|
||||
body: ir.Body,
|
||||
@ -370,6 +375,10 @@ pub const Fn = struct {
|
||||
pub fn dump(func: *Fn, mod: Module) void {
|
||||
ir.dumpFn(mod, func);
|
||||
}
|
||||
|
||||
pub fn deinit(func: *Fn, gpa: *Allocator) void {
|
||||
func.zir.deinit(gpa);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Var = struct {
|
||||
@ -1502,8 +1511,7 @@ pub const WipZirCode = struct {
|
||||
.ret_node,
|
||||
.ret_tok,
|
||||
.ret_coerce,
|
||||
.unreachable_unsafe,
|
||||
.unreachable_safe,
|
||||
.@"unreachable",
|
||||
.loop,
|
||||
.suspend_block,
|
||||
.suspend_block_one,
|
||||
@ -1521,6 +1529,7 @@ pub const WipZirCode = struct {
|
||||
pub fn deinit(wzc: *WipZirCode) void {
|
||||
wzc.instructions.deinit(wzc.gpa);
|
||||
wzc.extra.deinit(wzc.gpa);
|
||||
wzc.string_bytes.deinit(wzc.gpa);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2078,7 +2087,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
|
||||
var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
defer analysis_arena.deinit();
|
||||
|
||||
const code: zir.Code = blk: {
|
||||
var code: zir.Code = blk: {
|
||||
var wip_zir_code: WipZirCode = .{
|
||||
.decl = decl,
|
||||
.arena = &analysis_arena.allocator,
|
||||
@ -2102,6 +2111,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
|
||||
}
|
||||
break :blk code;
|
||||
};
|
||||
defer code.deinit(mod.gpa);
|
||||
|
||||
var sema: Sema = .{
|
||||
.mod = mod,
|
||||
@ -2154,17 +2164,17 @@ fn astgenAndSemaFn(
|
||||
var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
defer fn_type_scope_arena.deinit();
|
||||
|
||||
var fn_type_wip_zir_exec: WipZirCode = .{
|
||||
var fn_type_wip_zir_code: WipZirCode = .{
|
||||
.decl = decl,
|
||||
.arena = &fn_type_scope_arena.allocator,
|
||||
.gpa = mod.gpa,
|
||||
};
|
||||
defer fn_type_wip_zir_exec.deinit();
|
||||
defer fn_type_wip_zir_code.deinit();
|
||||
|
||||
var fn_type_scope: Scope.GenZir = .{
|
||||
.force_comptime = true,
|
||||
.parent = &decl.container.base,
|
||||
.zir_code = &fn_type_wip_zir_exec,
|
||||
.zir_code = &fn_type_wip_zir_code,
|
||||
};
|
||||
defer fn_type_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
@ -2317,7 +2327,8 @@ fn astgenAndSemaFn(
|
||||
errdefer decl_arena.deinit();
|
||||
const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
|
||||
|
||||
const fn_type_code = try fn_type_scope.finish();
|
||||
var fn_type_code = try fn_type_scope.finish();
|
||||
defer fn_type_code.deinit(mod.gpa);
|
||||
if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
|
||||
fn_type_code.dump(mod.gpa, "fn_type", &fn_type_scope.base, 0) catch {};
|
||||
}
|
||||
@ -2621,7 +2632,8 @@ fn astgenAndSemaVarDecl(
|
||||
init_result_loc,
|
||||
var_decl.ast.init_node,
|
||||
);
|
||||
const code = try gen_scope.finish();
|
||||
var code = try gen_scope.finish();
|
||||
defer code.deinit(mod.gpa);
|
||||
if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
|
||||
code.dump(mod.gpa, "var_init", &gen_scope.base, 0) catch {};
|
||||
}
|
||||
@ -2683,7 +2695,8 @@ fn astgenAndSemaVarDecl(
|
||||
defer type_scope.instructions.deinit(mod.gpa);
|
||||
|
||||
const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node);
|
||||
const code = try type_scope.finish();
|
||||
var code = try type_scope.finish();
|
||||
defer code.deinit(mod.gpa);
|
||||
if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
|
||||
code.dump(mod.gpa, "var_type", &type_scope.base, 0) catch {};
|
||||
}
|
||||
|
||||
15
src/Sema.zig
15
src/Sema.zig
@ -137,8 +137,7 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
|
||||
.as_node => try sema.zirAsNode(block, zir_inst),
|
||||
.@"asm" => try sema.zirAsm(block, zir_inst, false),
|
||||
.asm_volatile => try sema.zirAsm(block, zir_inst, true),
|
||||
.unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),
|
||||
.unreachable_unsafe => try sema.zirUnreachable(block, zir_inst, false),
|
||||
.@"unreachable" => try sema.zirUnreachable(block, zir_inst),
|
||||
.ret_coerce => try sema.zirRetTok(block, zir_inst, true),
|
||||
.ret_tok => try sema.zirRetTok(block, zir_inst, false),
|
||||
.ret_node => try sema.zirRetNode(block, zir_inst),
|
||||
@ -2852,17 +2851,13 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne
|
||||
return parent_block.addCondBr(src, cond, tzir_then_body, tzir_else_body);
|
||||
}
|
||||
|
||||
fn zirUnreachable(
|
||||
sema: *Sema,
|
||||
block: *Scope.Block,
|
||||
inst: zir.Inst.Index,
|
||||
safety_check: bool,
|
||||
) InnerError!*Inst {
|
||||
fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const src_node = sema.code.instructions.items(.data)[inst].node;
|
||||
const src: LazySrcLoc = .{ .node_offset = src_node };
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
|
||||
const src = inst_data.src();
|
||||
const safety_check = inst_data.safety;
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
// TODO Add compile error for @optimizeFor occurring too late in a scope.
|
||||
if (safety_check and block.wantSafety()) {
|
||||
|
||||
@ -415,10 +415,13 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
|
||||
return callExpr(mod, scope, rl, node, tree.callFull(node));
|
||||
},
|
||||
|
||||
.unreachable_literal => {
|
||||
const result = @enumToInt(zir.Const.unreachable_value);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.unreachable_literal => return gz.add(.{
|
||||
.tag = .@"unreachable",
|
||||
.data = .{ .@"unreachable" = .{
|
||||
.safety = true,
|
||||
.src_node = gz.zir_code.decl.nodeIndexToRelative(node),
|
||||
} },
|
||||
}),
|
||||
.@"return" => return ret(mod, scope, node),
|
||||
.field_access => return fieldAccess(mod, scope, rl, node),
|
||||
.float_literal => return floatLiteral(mod, scope, rl, node),
|
||||
@ -3012,10 +3015,11 @@ fn as(
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
builtin_token: ast.TokenIndex,
|
||||
src: usize,
|
||||
node: ast.Node.Index,
|
||||
lhs: ast.Node.Index,
|
||||
rhs: ast.Node.Index,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const dest_type = try typeExpr(mod, scope, lhs);
|
||||
switch (rl) {
|
||||
.none, .discard, .ref, .ty => {
|
||||
@ -3090,10 +3094,11 @@ fn bitCast(
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
builtin_token: ast.TokenIndex,
|
||||
src: usize,
|
||||
node: ast.Node.Index,
|
||||
lhs: ast.Node.Index,
|
||||
rhs: ast.Node.Index,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const dest_type = try typeExpr(mod, scope, lhs);
|
||||
switch (rl) {
|
||||
.none => {
|
||||
@ -3138,9 +3143,10 @@ fn typeOf(
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
builtin_token: ast.TokenIndex,
|
||||
src: usize,
|
||||
node: ast.Node.Index,
|
||||
params: []const ast.Node.Index,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
if (params.len < 1) {
|
||||
return mod.failTok(scope, builtin_token, "expected at least 1 argument, found 0", .{});
|
||||
}
|
||||
@ -3158,14 +3164,13 @@ fn builtinCall(
|
||||
mod: *Module,
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
call: ast.Node.Index,
|
||||
node: ast.Node.Index,
|
||||
params: []const ast.Node.Index,
|
||||
) InnerError!zir.Inst.Ref {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const tree = scope.tree();
|
||||
const main_tokens = tree.nodes.items(.main_token);
|
||||
|
||||
const builtin_token = main_tokens[call];
|
||||
const builtin_token = main_tokens[node];
|
||||
const builtin_name = tree.tokenSlice(builtin_token);
|
||||
|
||||
// We handle the different builtins manually because they have different semantics depending
|
||||
@ -3187,56 +3192,60 @@ fn builtinCall(
|
||||
}
|
||||
}
|
||||
|
||||
const gz = scope.getGenZir();
|
||||
|
||||
switch (info.tag) {
|
||||
.ptr_to_int => {
|
||||
const operand = try expr(mod, scope, .none, params[0]);
|
||||
const result = try addZIRUnOp(mod, scope, src, .ptrtoint, operand);
|
||||
return rvalue(mod, scope, rl, result);
|
||||
const result = try gz.addUnNode(.ptrtoint, operand, node);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.float_cast => {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const dest_type = try typeExpr(mod, scope, params[0]);
|
||||
const rhs = try expr(mod, scope, .none, params[1]);
|
||||
const result = try addZIRBinOp(mod, scope, src, .floatcast, dest_type, rhs);
|
||||
return rvalue(mod, scope, rl, result);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.int_cast => {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const dest_type = try typeExpr(mod, scope, params[0]);
|
||||
const rhs = try expr(mod, scope, .none, params[1]);
|
||||
const result = try addZIRBinOp(mod, scope, src, .intcast, dest_type, rhs);
|
||||
return rvalue(mod, scope, rl, result);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.breakpoint => {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const result = try addZIRNoOp(mod, scope, src, .breakpoint);
|
||||
return rvalue(mod, scope, rl, result);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.import => {
|
||||
const target = try expr(mod, scope, .none, params[0]);
|
||||
const result = try addZIRUnOp(mod, scope, src, .import, target);
|
||||
return rvalue(mod, scope, rl, result);
|
||||
const result = try gz.addUnNode(.import, target, node);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.compile_error => {
|
||||
const target = try expr(mod, scope, .none, params[0]);
|
||||
const result = try addZIRUnOp(mod, scope, src, .compile_error, target);
|
||||
return rvalue(mod, scope, rl, result);
|
||||
const result = try gz.addUnNode(.compile_error, target, node);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.set_eval_branch_quota => {
|
||||
const u32_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.u32_type),
|
||||
});
|
||||
const quota = try expr(mod, scope, .{ .ty = u32_type }, params[0]);
|
||||
const result = try addZIRUnOp(mod, scope, src, .set_eval_branch_quota, quota);
|
||||
return rvalue(mod, scope, rl, result);
|
||||
const u32_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.u32_type) };
|
||||
const quota = try expr(mod, scope, u32_rl, params[0]);
|
||||
const result = try gz.addUnNode(.set_eval_branch_quota, quota, node);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.compile_log => {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const arena = scope.arena();
|
||||
var targets = try arena.alloc(zir.Inst.Ref, params.len);
|
||||
for (params) |param, param_i|
|
||||
targets[param_i] = try expr(mod, scope, .none, param);
|
||||
const result = try addZIRInst(mod, scope, src, zir.Inst.CompileLog, .{ .to_log = targets }, .{});
|
||||
return rvalue(mod, scope, rl, result);
|
||||
return rvalue(mod, scope, rl, result, node);
|
||||
},
|
||||
.field => {
|
||||
if (true) @panic("TODO update for zir-memory-layout");
|
||||
const string_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.const_slice_u8_type),
|
||||
@ -3252,11 +3261,11 @@ fn builtinCall(
|
||||
return rvalue(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{
|
||||
.object = try expr(mod, scope, .none, params[0]),
|
||||
.field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
|
||||
}));
|
||||
}), node);
|
||||
},
|
||||
.as => return as(mod, scope, rl, builtin_token, src, params[0], params[1]),
|
||||
.bit_cast => return bitCast(mod, scope, rl, builtin_token, src, params[0], params[1]),
|
||||
.TypeOf => return typeOf(mod, scope, rl, builtin_token, src, params),
|
||||
.as => return as(mod, scope, rl, builtin_token, node, params[0], params[1]),
|
||||
.bit_cast => return bitCast(mod, scope, rl, builtin_token, node, params[0], params[1]),
|
||||
.TypeOf => return typeOf(mod, scope, rl, builtin_token, node, params),
|
||||
|
||||
.add_with_overflow,
|
||||
.align_cast,
|
||||
|
||||
33
src/main.zig
33
src/main.zig
@ -1750,15 +1750,12 @@ fn buildOutputType(
|
||||
}
|
||||
|
||||
const self_exe_path = try fs.selfExePathAlloc(arena);
|
||||
var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir|
|
||||
.{
|
||||
.path = lib_dir,
|
||||
.handle = try fs.cwd().openDir(lib_dir, .{}),
|
||||
}
|
||||
else
|
||||
introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
|
||||
fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
|
||||
};
|
||||
var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
|
||||
.path = lib_dir,
|
||||
.handle = try fs.cwd().openDir(lib_dir, .{}),
|
||||
} else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
|
||||
fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
|
||||
};
|
||||
defer zig_lib_directory.handle.close();
|
||||
|
||||
var thread_pool: ThreadPool = undefined;
|
||||
@ -2461,15 +2458,12 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
|
||||
}
|
||||
}
|
||||
|
||||
var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir|
|
||||
.{
|
||||
.path = lib_dir,
|
||||
.handle = try fs.cwd().openDir(lib_dir, .{}),
|
||||
}
|
||||
else
|
||||
introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
|
||||
fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
|
||||
};
|
||||
var zig_lib_directory: Compilation.Directory = if (override_lib_dir) |lib_dir| .{
|
||||
.path = lib_dir,
|
||||
.handle = try fs.cwd().openDir(lib_dir, .{}),
|
||||
} else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
|
||||
fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
|
||||
};
|
||||
defer zig_lib_directory.handle.close();
|
||||
|
||||
const std_special = "std" ++ fs.path.sep_str ++ "special";
|
||||
@ -3281,8 +3275,7 @@ pub const ClangArgIterator = struct {
|
||||
self.zig_equivalent = clang_arg.zig_equivalent;
|
||||
break :find_clang_arg;
|
||||
},
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
fatal("Unknown Clang option: '{s}'", .{arg});
|
||||
}
|
||||
}
|
||||
|
||||
46
src/zir.zig
46
src/zir.zig
@ -67,6 +67,13 @@ pub const Code = struct {
|
||||
return code.string_bytes[index..end :0];
|
||||
}
|
||||
|
||||
pub fn deinit(code: *Code, gpa: *Allocator) void {
|
||||
code.instructions.deinit(gpa);
|
||||
gpa.free(code.string_bytes);
|
||||
gpa.free(code.extra);
|
||||
code.* = undefined;
|
||||
}
|
||||
|
||||
/// For debugging purposes, like dumpFn but for unanalyzed zir blocks
|
||||
pub fn dump(
|
||||
code: Code,
|
||||
@ -737,15 +744,9 @@ pub const Inst = struct {
|
||||
/// of one or more params.
|
||||
/// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
|
||||
typeof_peer,
|
||||
/// Asserts control-flow will not reach this instruction. Not safety checked - the compiler
|
||||
/// will assume the correctness of this instruction.
|
||||
/// Uses the `node` union field.
|
||||
unreachable_unsafe,
|
||||
/// Asserts control-flow will not reach this instruction. In safety-checked modes,
|
||||
/// this will generate a call to the panic function unless it can be proven unreachable
|
||||
/// by the compiler.
|
||||
/// Uses the `node` union field.
|
||||
unreachable_safe,
|
||||
/// Asserts control-flow will not reach this instruction (`unreachable`).
|
||||
/// Uses the `unreachable` union field.
|
||||
@"unreachable",
|
||||
/// Bitwise XOR. `^`
|
||||
xor,
|
||||
/// Create an optional type '?T'
|
||||
@ -989,8 +990,7 @@ pub const Inst = struct {
|
||||
.ret_node,
|
||||
.ret_tok,
|
||||
.ret_coerce,
|
||||
.unreachable_unsafe,
|
||||
.unreachable_safe,
|
||||
.@"unreachable",
|
||||
.loop,
|
||||
.suspend_block,
|
||||
.suspend_block_one,
|
||||
@ -1131,6 +1131,20 @@ pub const Inst = struct {
|
||||
callee: Ref,
|
||||
param_index: u32,
|
||||
},
|
||||
@"unreachable": struct {
|
||||
/// Offset from Decl AST node index.
|
||||
/// `Tag` determines which kind of AST node this points to.
|
||||
src_node: i32,
|
||||
/// `false`: Not safety checked - the compiler will assume the
|
||||
/// correctness of this instruction.
|
||||
/// `true`: In safety-checked modes, this will generate a call
|
||||
/// to the panic function unless it can be proven unreachable by the compiler.
|
||||
safety: bool,
|
||||
|
||||
pub fn src(self: @This()) LazySrcLoc {
|
||||
return .{ .node_offset = self.src_node };
|
||||
}
|
||||
},
|
||||
|
||||
// Make sure we don't accidentally add a field to make this union
|
||||
// bigger than expected. Note that in Debug builds, Zig is allowed
|
||||
@ -1408,8 +1422,6 @@ const Writer = struct {
|
||||
.dbg_stmt_node,
|
||||
.ret_ptr,
|
||||
.ret_type,
|
||||
.unreachable_unsafe,
|
||||
.unreachable_safe,
|
||||
=> try self.writeNode(stream, inst),
|
||||
|
||||
.decl_ref,
|
||||
@ -1424,6 +1436,7 @@ const Writer = struct {
|
||||
.fn_type_cc => try self.writeFnTypeCc(stream, inst, false),
|
||||
.fn_type_var_args => try self.writeFnType(stream, inst, true),
|
||||
.fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true),
|
||||
.@"unreachable" => try self.writeUnreachable(stream, inst),
|
||||
|
||||
.enum_literal_small => try self.writeSmallStr(stream, inst),
|
||||
|
||||
@ -1612,6 +1625,13 @@ const Writer = struct {
|
||||
return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);
|
||||
}
|
||||
|
||||
fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
|
||||
const safety_str = if (inst_data.safety) "safe" else "unsafe";
|
||||
try stream.print("{s}) ", .{safety_str});
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
fn writeFnTypeCommon(
|
||||
self: *Writer,
|
||||
stream: anytype,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user