authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-04-22 21:30:54+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-16 17:42:51-07:00
logeee8fffec70b1d3e2900970dbe836e346e499231
treeba6418a557532cbe2aee2be1045f84ff0f3ee0ce
parent5888446c03b1f77a031f5a8093488a6a2f6decb6

stage2: implement error return traces


15 files changed, 318 insertions(+), 10 deletions(-)

lib/std/builtin.zig+11
......@@ -846,5 +846,16 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn
846846 }
847847}
848848
849pub noinline fn returnError(maybe_st: ?*StackTrace) void {
850 @setCold(true);
851 const st = maybe_st orelse return;
852 addErrRetTraceAddr(st, @returnAddress());
853}
854
855pub inline fn addErrRetTraceAddr(st: *StackTrace, addr: usize) void {
856 st.instruction_addresses[st.index & (st.instruction_addresses.len - 1)] = addr;
857 st.index +%= 1;
858}
859
849860const std = @import("std.zig");
850861const root = @import("root");
src/Air.zig+8
......@@ -649,6 +649,12 @@ pub const Inst = struct {
649649 /// flush().
650650 cmp_lt_errors_len,
651651
652 /// Returns pointer to current error return trace.
653 err_return_trace,
654
655 /// Sets the operand as the current error return trace,
656 set_err_return_trace,
657
652658 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
653659 return switch (op) {
654660 .lt => .cmp_lt,
......@@ -961,6 +967,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
961967 .alloc,
962968 .ret_ptr,
963969 .arg,
970 .err_return_trace,
964971 => return datas[inst].ty,
965972
966973 .assembly,
......@@ -1048,6 +1055,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
10481055 .memcpy,
10491056 .set_union_tag,
10501057 .prefetch,
1058 .set_err_return_trace,
10511059 => return Type.void,
10521060
10531061 .ptrtoint,
src/Liveness.zig+2
......@@ -362,6 +362,7 @@ fn analyzeInst(
362362 .ret_addr,
363363 .frame_addr,
364364 .wasm_memory_size,
365 .err_return_trace,
365366 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
366367
367368 .not,
......@@ -434,6 +435,7 @@ fn analyzeInst(
434435 .round,
435436 .trunc_float,
436437 .cmp_lt_errors_len,
438 .set_err_return_trace,
437439 => {
438440 const operand = inst_datas[inst].un_op;
439441 return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
src/Module.zig+21
......@@ -1427,6 +1427,7 @@ pub const Fn = struct {
14271427 state: Analysis,
14281428 is_cold: bool = false,
14291429 is_noinline: bool = false,
1430 calls_or_awaits_errorable_fn: bool = false,
14301431
14311432 /// Any inferred error sets that this function owns, both its own inferred error set and
14321433 /// inferred error sets of any inline/comptime functions called. Not to be confused
......@@ -4838,6 +4839,9 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
48384839 };
48394840 defer sema.deinit();
48404841
4842 // reset in case case calls to errorable functions are removed.
4843 func.calls_or_awaits_errorable_fn = false;
4844
48414845 // First few indexes of extra are reserved and set at the end.
48424846 const reserved_count = @typeInfo(Air.ExtraIndex).Enum.fields.len;
48434847 try sema.air_extra.ensureTotalCapacity(gpa, reserved_count);
......@@ -4936,6 +4940,8 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
49364940 func.state = .in_progress;
49374941 log.debug("set {s} to in_progress", .{decl.name});
49384942
4943 const last_arg_index = inner_block.instructions.items.len;
4944
49394945 sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
49404946 // TODO make these unreachable instead of @panic
49414947 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
......@@ -4944,6 +4950,21 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air {
49444950 else => |e| return e,
49454951 };
49464952
4953 // If we don't get an error return trace from a caller, create our own.
4954 if (func.calls_or_awaits_errorable_fn and
4955 mod.comp.bin_file.options.error_return_tracing and
4956 !sema.fn_ret_ty.isError())
4957 {
4958 sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) {
4959 // TODO make these unreachable instead of @panic
4960 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
4961 error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
4962 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
4963 error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"),
4964 else => |e| return e,
4965 };
4966 }
4967
49474968 try wip_captures.finalize();
49484969
49494970 // Copy the block into place and mark that as the main block.
src/Sema.zig+67-8
......@@ -1411,6 +1411,38 @@ fn analyzeAsType(
14111411 return ty.copy(sema.arena);
14121412}
14131413
1414pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {
1415 var err_trace_block = block.makeSubBlock();
1416 err_trace_block.is_comptime = false;
1417 defer err_trace_block.instructions.deinit(sema.gpa);
1418
1419 const src: LazySrcLoc = .unneeded;
1420
1421 // var addrs: [err_return_trace_addr_count]usize = undefined;
1422 const err_return_trace_addr_count = 32;
1423 const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, sema.mod);
1424 const addrs_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, addr_arr_ty));
1425
1426 // var st: StackTrace = undefined;
1427 const unresolved_stack_trace_ty = try sema.getBuiltinType(&err_trace_block, src, "StackTrace");
1428 const stack_trace_ty = try sema.resolveTypeFields(&err_trace_block, src, unresolved_stack_trace_ty);
1429 const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty));
1430
1431 // st.instruction_addresses = &addrs;
1432 const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src);
1433 try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
1434
1435 // st.index = 0;
1436 const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src);
1437 const zero = try sema.addConstant(Type.usize, Value.zero);
1438 try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, zero, src, .store);
1439
1440 // @errorReturnTrace() = &st;
1441 _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr);
1442
1443 try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items);
1444}
1445
14141446/// May return Value Tags: `variable`, `undef`.
14151447/// See `resolveConstValue` for an alternative.
14161448/// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
......@@ -5236,6 +5268,13 @@ fn analyzeCall(
52365268 }
52375269
52385270 try sema.queueFullTypeResolution(func_ty_info.return_type);
5271 if (sema.owner_func != null and func_ty_info.return_type.isError()) {
5272 if (!sema.owner_func.?.calls_or_awaits_errorable_fn) {
5273 // Ensure the type exists so that backends can assume that.
5274 _ = try sema.getBuiltinType(block, call_src, "StackTrace");
5275 }
5276 sema.owner_func.?.calls_or_awaits_errorable_fn = true;
5277 }
52395278
52405279 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
52415280 args.len);
......@@ -5645,6 +5684,15 @@ fn instantiateGenericCall(
56455684
56465685 try sema.queueFullTypeResolution(new_fn_info.return_type);
56475686 }
5687
5688 if (sema.owner_func != null and new_fn_info.return_type.isError()) {
5689 if (!sema.owner_func.?.calls_or_awaits_errorable_fn) {
5690 // Ensure the type exists so that backends can assume that.
5691 _ = try sema.getBuiltinType(block, call_src, "StackTrace");
5692 }
5693 sema.owner_func.?.calls_or_awaits_errorable_fn = true;
5694 }
5695
56485696 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
56495697 runtime_args_len);
56505698 const func_inst = try block.addInst(.{
......@@ -12607,6 +12655,16 @@ fn analyzeRet(
1260712655 return always_noreturn;
1260812656 }
1260912657
12658 if (sema.fn_ret_ty.isError() and sema.mod.comp.bin_file.options.error_return_tracing) {
12659 const return_err_fn = try sema.getBuiltin(block, src, "returnError");
12660 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
12661 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
12662 const ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
12663 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
12664 const args: [1]Air.Inst.Ref = .{err_return_trace};
12665 _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args);
12666 }
12667
1261012668 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
1261112669 _ = try block.addUnOp(.ret, operand);
1261212670 return always_noreturn;
......@@ -13338,9 +13396,14 @@ fn zirErrorReturnTrace(
1333813396 const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) };
1333913397 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
1334013398 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
13341 const opt_stack_trace_ty = try Type.optional(sema.arena, stack_trace_ty);
13342 // https://github.com/ziglang/zig/issues/11259
13343 return sema.addConstant(opt_stack_trace_ty, Value.@"null");
13399 const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
13400 if (sema.owner_func != null and
13401 sema.owner_func.?.calls_or_awaits_errorable_fn and
13402 sema.mod.comp.bin_file.options.error_return_tracing)
13403 {
13404 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
13405 }
13406 return sema.addConstant(opt_ptr_stack_trace_ty, Value.@"null");
1334413407}
1334513408
1334613409fn zirFrame(
......@@ -21817,11 +21880,7 @@ fn resolvePeerTypes(
2181721880 info.data.sentinel = chosen_child_ty.sentinel();
2181821881 info.data.size = .Slice;
2181921882 info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr());
21820 info.data.pointee_type = switch (chosen_child_ty.tag()) {
21821 .array => chosen_child_ty.elemType2(),
21822 .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8),
21823 else => unreachable,
21824 };
21883 info.data.pointee_type = chosen_child_ty.elemType2();
2182521884
2182621885 const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data);
2182721886 const opt_ptr_ty = if (any_are_null)
src/arch/aarch64/CodeGen.zig+20
......@@ -718,6 +718,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
718718 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
719719 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
720720 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
721 .err_return_trace => try self.airErrReturnTrace(inst),
722 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
721723
722724 .wrap_optional => try self.airWrapOptional(inst),
723725 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -2330,6 +2332,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
23302332 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
23312333}
23322334
2335fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
2336 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2337 const result: MCValue = if (self.liveness.isUnused(inst))
2338 .dead
2339 else
2340 return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});
2341 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2342}
2343
2344fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
2345 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2346 const result: MCValue = if (self.liveness.isUnused(inst))
2347 .dead
2348 else
2349 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
2350 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2351}
2352
23332353fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
23342354 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
23352355 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/arch/arm/CodeGen.zig+20
......@@ -725,6 +725,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
725725 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
726726 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
727727 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
728 .err_return_trace => try self.airErrReturnTrace(inst),
729 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
728730
729731 .wrap_optional => try self.airWrapOptional(inst),
730732 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -1843,6 +1845,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
18431845 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
18441846}
18451847
1848fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1849 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1850 const result: MCValue = if (self.liveness.isUnused(inst))
1851 .dead
1852 else
1853 return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});
1854 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1855}
1856
1857fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1858 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1859 const result: MCValue = if (self.liveness.isUnused(inst))
1860 .dead
1861 else
1862 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
1863 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1864}
1865
18461866/// T to E!T
18471867fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void {
18481868 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
src/arch/riscv64/CodeGen.zig+20
......@@ -654,6 +654,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
654654 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
655655 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
656656 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
657 .err_return_trace => try self.airErrReturnTrace(inst),
658 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
657659
658660 .wrap_optional => try self.airWrapOptional(inst),
659661 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -1267,6 +1269,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
12671269 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
12681270}
12691271
1272fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1273 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1274 const result: MCValue = if (self.liveness.isUnused(inst))
1275 .dead
1276 else
1277 return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});
1278 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1279}
1280
1281fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1282 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1283 const result: MCValue = if (self.liveness.isUnused(inst))
1284 .dead
1285 else
1286 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
1287 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1288}
1289
12701290fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
12711291 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
12721292 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
src/arch/sparc64/CodeGen.zig+2
......@@ -630,6 +630,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
630630 .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"),
631631 .unwrap_errunion_payload_ptr=> @panic("TODO try self.airUnwrapErrPayloadPtr(inst)"),
632632 .errunion_payload_ptr_set => @panic("TODO try self.airErrUnionPayloadPtrSet(inst)"),
633 .err_return_trace => @panic("TODO try self.airErrReturnTrace(inst)"),
634 .set_err_return_trace => @panic("TODO try self.airSetErrReturnTrace(inst)"),
633635
634636 .wrap_optional => @panic("TODO try self.airWrapOptional(inst)"),
635637 .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),
src/arch/wasm/CodeGen.zig+2
......@@ -1612,6 +1612,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16121612 .atomic_store_seq_cst,
16131613 .atomic_rmw,
16141614 .tag_name,
1615 .err_return_trace,
1616 .set_err_return_trace,
16151617 => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
16161618 };
16171619}
src/arch/x86_64/CodeGen.zig+20
......@@ -749,6 +749,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
749749 .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst),
750750 .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst),
751751 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
752 .err_return_trace => try self.airErrReturnTrace(inst),
753 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
752754
753755 .wrap_optional => try self.airWrapOptional(inst),
754756 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -1855,6 +1857,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
18551857 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
18561858}
18571859
1860fn airErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1861 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1862 const result: MCValue = if (self.liveness.isUnused(inst))
1863 .dead
1864 else
1865 return self.fail("TODO implement airErrReturnTrace for {}", .{self.target.cpu.arch});
1866 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1867}
1868
1869fn airSetErrReturnTrace(self: *Self, inst: Air.Inst.Index) !void {
1870 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1871 const result: MCValue = if (self.liveness.isUnused(inst))
1872 .dead
1873 else
1874 return self.fail("TODO implement airSetErrReturnTrace for {}", .{self.target.cpu.arch});
1875 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1876}
1877
18581878fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
18591879 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
18601880 if (self.liveness.isUnused(inst)) {
src/codegen/c.zig+34
......@@ -1911,6 +1911,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
19111911 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
19121912 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
19131913 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),
1914 .err_return_trace => try airErrReturnTrace(f, inst),
1915 .set_err_return_trace => try airSetErrReturnTrace(f, inst),
19141916
19151917 .wasm_memory_size => try airWasmMemorySize(f, inst),
19161918 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
......@@ -3447,6 +3449,38 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
34473449 return local;
34483450}
34493451
3452fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
3453 if (f.liveness.isUnused(inst)) return CValue.none;
3454
3455 const un_op = f.air.instructions.items(.data)[inst].un_op;
3456 const writer = f.object.writer();
3457 const inst_ty = f.air.typeOfIndex(inst);
3458 const operand = try f.resolveInst(un_op);
3459 const local = try f.allocLocal(inst_ty, .Const);
3460
3461 try writer.writeAll(" = ");
3462
3463 _ = operand;
3464 _ = local;
3465 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
3466}
3467
3468fn airSetErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
3469 if (f.liveness.isUnused(inst)) return CValue.none;
3470
3471 const un_op = f.air.instructions.items(.data)[inst].un_op;
3472 const writer = f.object.writer();
3473 const inst_ty = f.air.typeOfIndex(inst);
3474 const operand = try f.resolveInst(un_op);
3475 const local = try f.allocLocal(inst_ty, .Const);
3476
3477 try writer.writeAll(" = ");
3478
3479 _ = operand;
3480 _ = local;
3481 return f.fail("TODO: C backend: implement airSetErrReturnTrace", .{});
3482}
3483
34503484fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
34513485 if (f.liveness.isUnused(inst))
34523486 return CValue.none;
src/codegen/llvm.zig+82-2
......@@ -636,10 +636,18 @@ pub const Object = struct {
636636 const ret_ptr = if (sret) llvm_func.getParam(0) else null;
637637 const gpa = dg.gpa;
638638
639 const err_return_tracing = fn_info.return_type.isError() and
640 dg.module.comp.bin_file.options.error_return_tracing;
641
642 const err_ret_trace = if (err_return_tracing)
643 llvm_func.getParam(@boolToInt(ret_ptr != null))
644 else
645 null;
646
639647 var args = std.ArrayList(*const llvm.Value).init(gpa);
640648 defer args.deinit();
641649
642 const param_offset: c_uint = @boolToInt(ret_ptr != null);
650 const param_offset = @as(c_uint, @boolToInt(ret_ptr != null)) + @boolToInt(err_return_tracing);
643651 for (fn_info.param_types) |param_ty| {
644652 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
645653
......@@ -711,6 +719,7 @@ pub const Object = struct {
711719 .base_line = dg.decl.src_line,
712720 .prev_dbg_line = 0,
713721 .prev_dbg_column = 0,
722 .err_ret_trace = err_ret_trace,
714723 };
715724 defer fg.deinit();
716725
......@@ -1755,6 +1764,17 @@ pub const Object = struct {
17551764 try param_di_types.append(try o.lowerDebugType(Type.void, .full));
17561765 }
17571766
1767 if (fn_info.return_type.isError() and
1768 o.module.comp.bin_file.options.error_return_tracing)
1769 {
1770 var ptr_ty_payload: Type.Payload.ElemType = .{
1771 .base = .{ .tag = .single_mut_pointer },
1772 .data = o.getStackTraceType(),
1773 };
1774 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
1775 try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));
1776 }
1777
17581778 for (fn_info.param_types) |param_ty| {
17591779 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
17601780
......@@ -1824,6 +1844,27 @@ pub const Object = struct {
18241844 "", // unique id
18251845 );
18261846 }
1847
1848 fn getStackTraceType(o: *Object) Type {
1849 const mod = o.module;
1850
1851 const std_pkg = mod.main_pkg.table.get("std").?;
1852 const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
1853
1854 const builtin_str: []const u8 = "builtin";
1855 const std_namespace = mod.declPtr(std_file.root_decl.unwrap().?).src_namespace;
1856 const builtin_decl = std_namespace.decls
1857 .getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?;
1858
1859 const stack_trace_str: []const u8 = "StackTrace";
1860 // buffer is only used for int_type, `builtin` is a struct.
1861 const builtin_ty = mod.declPtr(builtin_decl).val.toType(undefined);
1862 const builtin_namespace = builtin_ty.getNamespace().?;
1863 const stack_trace_decl = builtin_namespace.decls
1864 .getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?;
1865
1866 return mod.declPtr(stack_trace_decl).val.toType(undefined);
1867 }
18271868};
18281869
18291870pub const DeclGen = struct {
......@@ -1976,8 +2017,15 @@ pub const DeclGen = struct {
19762017 llvm_fn.addSretAttr(0, raw_llvm_ret_ty);
19772018 }
19782019
2020 const err_return_tracing = fn_info.return_type.isError() and
2021 dg.module.comp.bin_file.options.error_return_tracing;
2022
2023 if (err_return_tracing) {
2024 dg.addArgAttr(llvm_fn, @boolToInt(sret), "nonnull");
2025 }
2026
19792027 // Set parameter attributes.
1980 var llvm_param_i: c_uint = @boolToInt(sret);
2028 var llvm_param_i: c_uint = @as(c_uint, @boolToInt(sret)) + @boolToInt(err_return_tracing);
19812029 for (fn_info.param_types) |param_ty| {
19822030 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
19832031
......@@ -2435,6 +2483,17 @@ pub const DeclGen = struct {
24352483 try llvm_params.append(llvm_sret_ty.pointerType(0));
24362484 }
24372485
2486 if (fn_info.return_type.isError() and
2487 dg.module.comp.bin_file.options.error_return_tracing)
2488 {
2489 var ptr_ty_payload: Type.Payload.ElemType = .{
2490 .base = .{ .tag = .single_mut_pointer },
2491 .data = dg.object.getStackTraceType(),
2492 };
2493 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2494 try llvm_params.append(try lowerFnParamTy(dg, fn_info.cc, ptr_ty));
2495 }
2496
24382497 for (fn_info.param_types) |param_ty| {
24392498 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
24402499
......@@ -3449,6 +3508,8 @@ pub const FuncGen = struct {
34493508
34503509 llvm_func: *const llvm.Value,
34513510
3511 err_ret_trace: ?*const llvm.Value = null,
3512
34523513 /// This data structure is used to implement breaking to blocks.
34533514 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
34543515 parent_bb: *const llvm.BasicBlock,
......@@ -3678,6 +3739,8 @@ pub const FuncGen = struct {
36783739 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
36793740 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
36803741 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
3742 .err_return_trace => try self.airErrReturnTrace(inst),
3743 .set_err_return_trace => try self.airSetErrReturnTrace(inst),
36813744
36823745 .wrap_optional => try self.airWrapOptional(inst),
36833746 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
......@@ -3732,6 +3795,12 @@ pub const FuncGen = struct {
37323795 break :blk ret_ptr;
37333796 };
37343797
3798 if (fn_info.return_type.isError() and
3799 self.dg.module.comp.bin_file.options.error_return_tracing)
3800 {
3801 try llvm_args.append(self.err_ret_trace.?);
3802 }
3803
37353804 for (args) |arg| {
37363805 const param_ty = self.air.typeOf(arg);
37373806 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
......@@ -5149,6 +5218,17 @@ pub const FuncGen = struct {
51495218 return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
51505219 }
51515220
5221 fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*const llvm.Value {
5222 return self.err_ret_trace.?;
5223 }
5224
5225 fn airSetErrReturnTrace(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
5226 const un_op = self.air.instructions.items(.data)[inst].un_op;
5227 const operand = try self.resolveInst(un_op);
5228 self.err_ret_trace = operand;
5229 return null;
5230 }
5231
51525232 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
51535233 if (self.liveness.isUnused(inst)) return null;
51545234
src/print_air.zig+2
......@@ -170,6 +170,7 @@ const Writer = struct {
170170 .round,
171171 .trunc_float,
172172 .cmp_lt_errors_len,
173 .set_err_return_trace,
173174 => try w.writeUnOp(s, inst),
174175
175176 .breakpoint,
......@@ -182,6 +183,7 @@ const Writer = struct {
182183 .alloc,
183184 .ret_ptr,
184185 .arg,
186 .err_return_trace,
185187 => try w.writeTy(s, inst),
186188
187189 .not,
src/type.zig+7
......@@ -4093,6 +4093,13 @@ pub const Type = extern union {
40934093 };
40944094 }
40954095
4096 pub fn isError(ty: Type) bool {
4097 return switch (ty.zigTypeTag()) {
4098 .ErrorUnion, .ErrorSet => true,
4099 else => false,
4100 };
4101 }
4102
40964103 /// Returns whether ty, which must be an error set, includes an error `name`.
40974104 /// Might return a false negative if `ty` is an inferred error set and not fully
40984105 /// resolved yet.