mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
stage2: add runtime safety for unwrapping error
This commit is contained in:
parent
e369752430
commit
ab4ec35b8b
4 changed files with 139 additions and 22 deletions
|
|
@ -198,19 +198,17 @@ comptime {
|
|||
const __trunctfxf2 = @import("compiler_rt/trunc_f80.zig").__trunctfxf2;
|
||||
@export(__trunctfxf2, .{ .name = "__trunctfxf2", .linkage = linkage });
|
||||
|
||||
if (builtin.zig_backend == .stage1) { // TODO
|
||||
switch (arch) {
|
||||
.i386,
|
||||
.x86_64,
|
||||
=> {
|
||||
const zig_probe_stack = @import("compiler_rt/stack_probe.zig").zig_probe_stack;
|
||||
@export(zig_probe_stack, .{
|
||||
.name = "__zig_probe_stack",
|
||||
.linkage = linkage,
|
||||
});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
switch (arch) {
|
||||
.i386,
|
||||
.x86_64,
|
||||
=> {
|
||||
const zig_probe_stack = @import("compiler_rt/stack_probe.zig").zig_probe_stack;
|
||||
@export(zig_probe_stack, .{
|
||||
.name = "__zig_probe_stack",
|
||||
.linkage = linkage,
|
||||
});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
const __unordsf2 = @import("compiler_rt/compareXf2.zig").__unordsf2;
|
||||
|
|
|
|||
|
|
@ -846,6 +846,10 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
|
|||
}
|
||||
}
|
||||
|
||||
pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {
|
||||
std.debug.panicExtra(st, "attempt to unwrap error: {s}", .{@errorName(err)});
|
||||
}
|
||||
|
||||
pub noinline fn returnError(maybe_st: ?*StackTrace) void {
|
||||
@setCold(true);
|
||||
const st = maybe_st orelse return;
|
||||
|
|
|
|||
|
|
@ -856,6 +856,33 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
|||
catch_token + 2
|
||||
else
|
||||
null;
|
||||
|
||||
var rhs = node_datas[node].rhs;
|
||||
while (true) switch (node_tags[rhs]) {
|
||||
.grouped_expression => rhs = node_datas[rhs].lhs,
|
||||
.unreachable_literal => {
|
||||
if (payload_token != null and mem.eql(u8, tree.tokenSlice(payload_token.?), "_")) {
|
||||
return astgen.failTok(payload_token.?, "discard of error capture; omit it instead", .{});
|
||||
} else if (payload_token != null) {
|
||||
return astgen.failTok(payload_token.?, "unused capture", .{});
|
||||
}
|
||||
const lhs = node_datas[node].lhs;
|
||||
|
||||
const operand = try reachableExpr(gz, scope, switch (rl) {
|
||||
.ref => .ref,
|
||||
else => .none,
|
||||
}, lhs, lhs);
|
||||
const result = try gz.addUnNode(switch (rl) {
|
||||
.ref => .err_union_payload_safe_ptr,
|
||||
else => .err_union_payload_safe,
|
||||
}, operand, node);
|
||||
switch (rl) {
|
||||
.none, .coerced_ty, .discard, .ref => return result,
|
||||
else => return rvalue(gz, rl, result, lhs),
|
||||
}
|
||||
},
|
||||
else => break,
|
||||
};
|
||||
switch (rl) {
|
||||
.ref => return orelseCatchExpr(
|
||||
gz,
|
||||
|
|
|
|||
106
src/Sema.zig
106
src/Sema.zig
|
|
@ -6248,8 +6248,7 @@ fn zirErrUnionPayload(
|
|||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
if (safety_check and block.wantSafety()) {
|
||||
const is_non_err = try block.addUnOp(.is_err, operand);
|
||||
try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
|
||||
try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
|
||||
}
|
||||
const result_ty = operand_ty.errorUnionPayload();
|
||||
return block.addTyOp(.unwrap_errunion_payload, result_ty, operand);
|
||||
|
|
@ -6330,8 +6329,7 @@ fn analyzeErrUnionPayloadPtr(
|
|||
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
if (safety_check and block.wantSafety()) {
|
||||
const is_non_err = try block.addUnOp(.is_err, operand);
|
||||
try sema.addSafetyCheck(block, is_non_err, .unwrap_errunion);
|
||||
try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
|
||||
}
|
||||
const air_tag: Air.Inst.Tag = if (initializing)
|
||||
.errunion_payload_ptr_set
|
||||
|
|
@ -13400,6 +13398,10 @@ fn zirErrorReturnTrace(
|
|||
extended: Zir.Inst.Extended.InstData,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
|
||||
return sema.getErrorReturnTrace(block, src);
|
||||
}
|
||||
|
||||
fn getErrorReturnTrace(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!Air.Inst.Ref {
|
||||
const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
|
||||
const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
|
||||
const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
|
||||
|
|
@ -16852,7 +16854,6 @@ fn explainWhyTypeIsComptime(
|
|||
pub const PanicId = enum {
|
||||
unreach,
|
||||
unwrap_null,
|
||||
unwrap_errunion,
|
||||
cast_to_null,
|
||||
incorrect_alignment,
|
||||
invalid_error_code,
|
||||
|
|
@ -16962,12 +16963,100 @@ fn panicWithMsg(
|
|||
try Type.optional(arena, ptr_stack_trace_ty),
|
||||
Value.@"null",
|
||||
);
|
||||
const args = try arena.create([2]Air.Inst.Ref);
|
||||
args.* = .{ msg_inst, null_stack_trace };
|
||||
_ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, args);
|
||||
const args: [2]Air.Inst.Ref = .{ msg_inst, null_stack_trace };
|
||||
_ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args);
|
||||
return always_noreturn;
|
||||
}
|
||||
|
||||
fn panicUnwrapError(
|
||||
sema: *Sema,
|
||||
parent_block: *Block,
|
||||
src: LazySrcLoc,
|
||||
operand: Air.Inst.Ref,
|
||||
unwrap_err_tag: Air.Inst.Tag,
|
||||
is_non_err_tag: Air.Inst.Tag,
|
||||
) !void {
|
||||
const ok = try parent_block.addUnOp(is_non_err_tag, operand);
|
||||
const gpa = sema.gpa;
|
||||
|
||||
var fail_block: Block = .{
|
||||
.parent = parent_block,
|
||||
.sema = sema,
|
||||
.src_decl = parent_block.src_decl,
|
||||
.namespace = parent_block.namespace,
|
||||
.wip_capture_scope = parent_block.wip_capture_scope,
|
||||
.instructions = .{},
|
||||
.inlining = parent_block.inlining,
|
||||
.is_comptime = parent_block.is_comptime,
|
||||
};
|
||||
|
||||
defer fail_block.instructions.deinit(gpa);
|
||||
|
||||
{
|
||||
const this_feature_is_implemented_in_the_backend =
|
||||
sema.mod.comp.bin_file.options.object_format == .c or
|
||||
sema.mod.comp.bin_file.options.use_llvm;
|
||||
|
||||
if (!this_feature_is_implemented_in_the_backend) {
|
||||
// TODO implement this feature in all the backends and then delete this branch
|
||||
_ = try fail_block.addNoOp(.breakpoint);
|
||||
_ = try fail_block.addNoOp(.unreach);
|
||||
} else {
|
||||
const panic_fn = try sema.getBuiltin(&fail_block, src, "panicUnwrapError");
|
||||
const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
|
||||
const err_return_trace = try sema.getErrorReturnTrace(&fail_block, src);
|
||||
const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
|
||||
_ = try sema.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args);
|
||||
}
|
||||
}
|
||||
|
||||
try parent_block.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
|
||||
1 + // The main block only needs space for the cond_br.
|
||||
@typeInfo(Air.CondBr).Struct.fields.len +
|
||||
1 + // The ok branch of the cond_br only needs space for the br.
|
||||
fail_block.instructions.items.len);
|
||||
|
||||
try sema.air_instructions.ensureUnusedCapacity(gpa, 3);
|
||||
const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
|
||||
const cond_br_inst = block_inst + 1;
|
||||
const br_inst = cond_br_inst + 1;
|
||||
sema.air_instructions.appendAssumeCapacity(.{
|
||||
.tag = .block,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = .void_type,
|
||||
.payload = sema.addExtraAssumeCapacity(Air.Block{
|
||||
.body_len = 1,
|
||||
}),
|
||||
} },
|
||||
});
|
||||
sema.air_extra.appendAssumeCapacity(cond_br_inst);
|
||||
|
||||
sema.air_instructions.appendAssumeCapacity(.{
|
||||
.tag = .cond_br,
|
||||
.data = .{ .pl_op = .{
|
||||
.operand = ok,
|
||||
.payload = sema.addExtraAssumeCapacity(Air.CondBr{
|
||||
.then_body_len = 1,
|
||||
.else_body_len = @intCast(u32, fail_block.instructions.items.len),
|
||||
}),
|
||||
} },
|
||||
});
|
||||
sema.air_extra.appendAssumeCapacity(br_inst);
|
||||
sema.air_extra.appendSliceAssumeCapacity(fail_block.instructions.items);
|
||||
|
||||
sema.air_instructions.appendAssumeCapacity(.{
|
||||
.tag = .br,
|
||||
.data = .{ .br = .{
|
||||
.block_inst = block_inst,
|
||||
.operand = .void_value,
|
||||
} },
|
||||
});
|
||||
|
||||
parent_block.instructions.appendAssumeCapacity(block_inst);
|
||||
}
|
||||
|
||||
fn safetyPanic(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
|
|
@ -16977,7 +17066,6 @@ fn safetyPanic(
|
|||
const msg = switch (panic_id) {
|
||||
.unreach => "reached unreachable code",
|
||||
.unwrap_null => "attempt to use null value",
|
||||
.unwrap_errunion => "unreachable error occurred",
|
||||
.cast_to_null => "cast causes pointer to be null",
|
||||
.incorrect_alignment => "incorrect alignment",
|
||||
.invalid_error_code => "invalid error code",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue