| author | |
| committer | |
| log | eee8fffec70b1d3e2900970dbe836e346e499231 |
| tree | ba6418a557532cbe2aee2be1045f84ff0f3ee0ce |
| parent | 5888446c03b1f77a031f5a8093488a6a2f6decb6 |
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 | ... | @@ -846,5 +846,16 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn |
| 846 | } | 846 | } |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | pub noinline fn returnError(maybe_st: ?*StackTrace) void { | ||
| 850 | @setCold(true); | ||
| 851 | const st = maybe_st orelse return; | ||
| 852 | addErrRetTraceAddr(st, @returnAddress()); | ||
| 853 | } | ||
| 854 | |||
| 855 | pub 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 | |||
| 849 | const std = @import("std.zig"); | 860 | const std = @import("std.zig"); |
| 850 | const root = @import("root"); | 861 | const root = @import("root"); |
src/Air.zig+8| ... | @@ -649,6 +649,12 @@ pub const Inst = struct { | ... | @@ -649,6 +649,12 @@ pub const Inst = struct { |
| 649 | /// flush(). | 649 | /// flush(). |
| 650 | cmp_lt_errors_len, | 650 | cmp_lt_errors_len, |
| 651 | 651 | ||
| 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 | |||
| 652 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { | 658 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { |
| 653 | return switch (op) { | 659 | return switch (op) { |
| 654 | .lt => .cmp_lt, | 660 | .lt => .cmp_lt, |
| ... | @@ -961,6 +967,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -961,6 +967,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 961 | .alloc, | 967 | .alloc, |
| 962 | .ret_ptr, | 968 | .ret_ptr, |
| 963 | .arg, | 969 | .arg, |
| 970 | .err_return_trace, | ||
| 964 | => return datas[inst].ty, | 971 | => return datas[inst].ty, |
| 965 | 972 | ||
| 966 | .assembly, | 973 | .assembly, |
| ... | @@ -1048,6 +1055,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1048,6 +1055,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1048 | .memcpy, | 1055 | .memcpy, |
| 1049 | .set_union_tag, | 1056 | .set_union_tag, |
| 1050 | .prefetch, | 1057 | .prefetch, |
| 1058 | .set_err_return_trace, | ||
| 1051 | => return Type.void, | 1059 | => return Type.void, |
| 1052 | 1060 | ||
| 1053 | .ptrtoint, | 1061 | .ptrtoint, |
src/Liveness.zig+2| ... | @@ -362,6 +362,7 @@ fn analyzeInst( | ... | @@ -362,6 +362,7 @@ fn analyzeInst( |
| 362 | .ret_addr, | 362 | .ret_addr, |
| 363 | .frame_addr, | 363 | .frame_addr, |
| 364 | .wasm_memory_size, | 364 | .wasm_memory_size, |
| 365 | .err_return_trace, | ||
| 365 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), | 366 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), |
| 366 | 367 | ||
| 367 | .not, | 368 | .not, |
| ... | @@ -434,6 +435,7 @@ fn analyzeInst( | ... | @@ -434,6 +435,7 @@ fn analyzeInst( |
| 434 | .round, | 435 | .round, |
| 435 | .trunc_float, | 436 | .trunc_float, |
| 436 | .cmp_lt_errors_len, | 437 | .cmp_lt_errors_len, |
| 438 | .set_err_return_trace, | ||
| 437 | => { | 439 | => { |
| 438 | const operand = inst_datas[inst].un_op; | 440 | const operand = inst_datas[inst].un_op; |
| 439 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); | 441 | return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none }); |
src/Module.zig+21| ... | @@ -1427,6 +1427,7 @@ pub const Fn = struct { | ... | @@ -1427,6 +1427,7 @@ pub const Fn = struct { |
| 1427 | state: Analysis, | 1427 | state: Analysis, |
| 1428 | is_cold: bool = false, | 1428 | is_cold: bool = false, |
| 1429 | is_noinline: bool = false, | 1429 | is_noinline: bool = false, |
| 1430 | calls_or_awaits_errorable_fn: bool = false, | ||
| 1430 | 1431 | ||
| 1431 | /// Any inferred error sets that this function owns, both its own inferred error set and | 1432 | /// Any inferred error sets that this function owns, both its own inferred error set and |
| 1432 | /// inferred error sets of any inline/comptime functions called. Not to be confused | 1433 | /// 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 { | ... | @@ -4838,6 +4839,9 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 4838 | }; | 4839 | }; |
| 4839 | defer sema.deinit(); | 4840 | defer sema.deinit(); |
| 4840 | 4841 | ||
| 4842 | // reset in case case calls to errorable functions are removed. | ||
| 4843 | func.calls_or_awaits_errorable_fn = false; | ||
| 4844 | |||
| 4841 | // First few indexes of extra are reserved and set at the end. | 4845 | // First few indexes of extra are reserved and set at the end. |
| 4842 | const reserved_count = @typeInfo(Air.ExtraIndex).Enum.fields.len; | 4846 | const reserved_count = @typeInfo(Air.ExtraIndex).Enum.fields.len; |
| 4843 | try sema.air_extra.ensureTotalCapacity(gpa, reserved_count); | 4847 | try sema.air_extra.ensureTotalCapacity(gpa, reserved_count); |
| ... | @@ -4936,6 +4940,8 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -4936,6 +4940,8 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 4936 | func.state = .in_progress; | 4940 | func.state = .in_progress; |
| 4937 | log.debug("set {s} to in_progress", .{decl.name}); | 4941 | log.debug("set {s} to in_progress", .{decl.name}); |
| 4938 | 4942 | ||
| 4943 | const last_arg_index = inner_block.instructions.items.len; | ||
| 4944 | |||
| 4939 | sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) { | 4945 | sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) { |
| 4940 | // TODO make these unreachable instead of @panic | 4946 | // TODO make these unreachable instead of @panic |
| 4941 | error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"), | 4947 | error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"), |
| ... | @@ -4944,6 +4950,21 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -4944,6 +4950,21 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 4944 | else => |e| return e, | 4950 | else => |e| return e, |
| 4945 | }; | 4951 | }; |
| 4946 | 4952 | ||
| 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 | |||
| 4947 | try wip_captures.finalize(); | 4968 | try wip_captures.finalize(); |
| 4948 | 4969 | ||
| 4949 | // Copy the block into place and mark that as the main block. | 4970 | // Copy the block into place and mark that as the main block. |
src/Sema.zig+67-8| ... | @@ -1411,6 +1411,38 @@ fn analyzeAsType( | ... | @@ -1411,6 +1411,38 @@ fn analyzeAsType( |
| 1411 | return ty.copy(sema.arena); | 1411 | return ty.copy(sema.arena); |
| 1412 | } | 1412 | } |
| 1413 | 1413 | ||
| 1414 | pub 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 | |||
| 1414 | /// May return Value Tags: `variable`, `undef`. | 1446 | /// May return Value Tags: `variable`, `undef`. |
| 1415 | /// See `resolveConstValue` for an alternative. | 1447 | /// See `resolveConstValue` for an alternative. |
| 1416 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. | 1448 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. |
| ... | @@ -5236,6 +5268,13 @@ fn analyzeCall( | ... | @@ -5236,6 +5268,13 @@ fn analyzeCall( |
| 5236 | } | 5268 | } |
| 5237 | 5269 | ||
| 5238 | try sema.queueFullTypeResolution(func_ty_info.return_type); | 5270 | 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 | } | ||
| 5239 | 5278 | ||
| 5240 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + | 5279 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 5241 | args.len); | 5280 | args.len); |
| ... | @@ -5645,6 +5684,15 @@ fn instantiateGenericCall( | ... | @@ -5645,6 +5684,15 @@ fn instantiateGenericCall( |
| 5645 | 5684 | ||
| 5646 | try sema.queueFullTypeResolution(new_fn_info.return_type); | 5685 | try sema.queueFullTypeResolution(new_fn_info.return_type); |
| 5647 | } | 5686 | } |
| 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 | |||
| 5648 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + | 5696 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 5649 | runtime_args_len); | 5697 | runtime_args_len); |
| 5650 | const func_inst = try block.addInst(.{ | 5698 | const func_inst = try block.addInst(.{ |
| ... | @@ -12607,6 +12655,16 @@ fn analyzeRet( | ... | @@ -12607,6 +12655,16 @@ fn analyzeRet( |
| 12607 | return always_noreturn; | 12655 | return always_noreturn; |
| 12608 | } | 12656 | } |
| 12609 | 12657 | ||
| 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 | |||
| 12610 | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); | 12668 | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); |
| 12611 | _ = try block.addUnOp(.ret, operand); | 12669 | _ = try block.addUnOp(.ret, operand); |
| 12612 | return always_noreturn; | 12670 | return always_noreturn; |
| ... | @@ -13338,9 +13396,14 @@ fn zirErrorReturnTrace( | ... | @@ -13338,9 +13396,14 @@ fn zirErrorReturnTrace( |
| 13338 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; | 13396 | const src: LazySrcLoc = .{ .node_offset = @bitCast(i32, extended.operand) }; |
| 13339 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); | 13397 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); |
| 13340 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); | 13398 | 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); | 13399 | const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty); |
| 13342 | // https://github.com/ziglang/zig/issues/11259 | 13400 | if (sema.owner_func != null and |
| 13343 | return sema.addConstant(opt_stack_trace_ty, Value.@"null"); | 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"); | ||
| 13344 | } | 13407 | } |
| 13345 | 13408 | ||
| 13346 | fn zirFrame( | 13409 | fn zirFrame( |
| ... | @@ -21817,11 +21880,7 @@ fn resolvePeerTypes( | ... | @@ -21817,11 +21880,7 @@ fn resolvePeerTypes( |
| 21817 | info.data.sentinel = chosen_child_ty.sentinel(); | 21880 | info.data.sentinel = chosen_child_ty.sentinel(); |
| 21818 | info.data.size = .Slice; | 21881 | info.data.size = .Slice; |
| 21819 | info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr()); | 21882 | info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr()); |
| 21820 | info.data.pointee_type = switch (chosen_child_ty.tag()) { | 21883 | info.data.pointee_type = chosen_child_ty.elemType2(); |
| 21821 | .array => chosen_child_ty.elemType2(), | ||
| 21822 | .array_u8, .array_u8_sentinel_0 => Type.initTag(.u8), | ||
| 21823 | else => unreachable, | ||
| 21824 | }; | ||
| 21825 | 21884 | ||
| 21826 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); | 21885 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); |
| 21827 | const opt_ptr_ty = if (any_are_null) | 21886 | 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 { | ... | @@ -718,6 +718,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 718 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), | 718 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 719 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), | 719 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 720 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | 720 | .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), | ||
| 721 | 723 | ||
| 722 | .wrap_optional => try self.airWrapOptional(inst), | 724 | .wrap_optional => try self.airWrapOptional(inst), |
| 723 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), | 725 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | @@ -2330,6 +2332,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2330,6 +2332,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2330 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2332 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2331 | } | 2333 | } |
| 2332 | 2334 | ||
| 2335 | fn 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 | |||
| 2344 | fn 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 | |||
| 2333 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 2353 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2334 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2354 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2335 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2355 | 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 { | ... | @@ -725,6 +725,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 725 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), | 725 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 726 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), | 726 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 727 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | 727 | .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), | ||
| 728 | 730 | ||
| 729 | .wrap_optional => try self.airWrapOptional(inst), | 731 | .wrap_optional => try self.airWrapOptional(inst), |
| 730 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), | 732 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | @@ -1843,6 +1845,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1843,6 +1845,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 1843 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1845 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1844 | } | 1846 | } |
| 1845 | 1847 | ||
| 1848 | fn 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 | |||
| 1857 | fn 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 | |||
| 1846 | /// T to E!T | 1866 | /// T to E!T |
| 1847 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 1867 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1848 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1868 | 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 { | ... | @@ -654,6 +654,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 654 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), | 654 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 655 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), | 655 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 656 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | 656 | .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), | ||
| 657 | 659 | ||
| 658 | .wrap_optional => try self.airWrapOptional(inst), | 660 | .wrap_optional => try self.airWrapOptional(inst), |
| 659 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), | 661 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | @@ -1267,6 +1269,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1267,6 +1269,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 1267 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1269 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1268 | } | 1270 | } |
| 1269 | 1271 | ||
| 1272 | fn 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 | |||
| 1281 | fn 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 | |||
| 1270 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 1290 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1271 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1291 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1272 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1292 | 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 { | ... | @@ -630,6 +630,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 630 | .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"), | 630 | .unwrap_errunion_err_ptr => @panic("TODO try self.airUnwrapErrErrPtr(inst)"), |
| 631 | .unwrap_errunion_payload_ptr=> @panic("TODO try self.airUnwrapErrPayloadPtr(inst)"), | 631 | .unwrap_errunion_payload_ptr=> @panic("TODO try self.airUnwrapErrPayloadPtr(inst)"), |
| 632 | .errunion_payload_ptr_set => @panic("TODO try self.airErrUnionPayloadPtrSet(inst)"), | 632 | .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)"), | ||
| 633 | 635 | ||
| 634 | .wrap_optional => @panic("TODO try self.airWrapOptional(inst)"), | 636 | .wrap_optional => @panic("TODO try self.airWrapOptional(inst)"), |
| 635 | .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"), | 637 | .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 { | ... | @@ -1612,6 +1612,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1612 | .atomic_store_seq_cst, | 1612 | .atomic_store_seq_cst, |
| 1613 | .atomic_rmw, | 1613 | .atomic_rmw, |
| 1614 | .tag_name, | 1614 | .tag_name, |
| 1615 | .err_return_trace, | ||
| 1616 | .set_err_return_trace, | ||
| 1615 | => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), | 1617 | => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), |
| 1616 | }; | 1618 | }; |
| 1617 | } | 1619 | } |
src/arch/x86_64/CodeGen.zig+20| ... | @@ -749,6 +749,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -749,6 +749,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 749 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), | 749 | .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), |
| 750 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), | 750 | .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), |
| 751 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | 751 | .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), | ||
| 752 | 754 | ||
| 753 | .wrap_optional => try self.airWrapOptional(inst), | 755 | .wrap_optional => try self.airWrapOptional(inst), |
| 754 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), | 756 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | @@ -1855,6 +1857,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1855,6 +1857,24 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 1855 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1857 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1856 | } | 1858 | } |
| 1857 | 1859 | ||
| 1860 | fn 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 | |||
| 1869 | fn 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 | |||
| 1858 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 1878 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1859 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1879 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1860 | if (self.liveness.isUnused(inst)) { | 1880 | 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 | ... | @@ -1911,6 +1911,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1911 | .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), | 1911 | .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), |
| 1912 | .wrap_errunion_err => try airWrapErrUnionErr(f, inst), | 1912 | .wrap_errunion_err => try airWrapErrUnionErr(f, inst), |
| 1913 | .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), | 1913 | .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), | ||
| 1914 | 1916 | ||
| 1915 | .wasm_memory_size => try airWasmMemorySize(f, inst), | 1917 | .wasm_memory_size => try airWasmMemorySize(f, inst), |
| 1916 | .wasm_memory_grow => try airWasmMemoryGrow(f, inst), | 1918 | .wasm_memory_grow => try airWasmMemoryGrow(f, inst), |
| ... | @@ -3447,6 +3449,38 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3447,6 +3449,38 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3447 | return local; | 3449 | return local; |
| 3448 | } | 3450 | } |
| 3449 | 3451 | ||
| 3452 | fn 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 | |||
| 3468 | fn 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 | |||
| 3450 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { | 3484 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3451 | if (f.liveness.isUnused(inst)) | 3485 | if (f.liveness.isUnused(inst)) |
| 3452 | return CValue.none; | 3486 | return CValue.none; |
src/codegen/llvm.zig+82-2| ... | @@ -636,10 +636,18 @@ pub const Object = struct { | ... | @@ -636,10 +636,18 @@ pub const Object = struct { |
| 636 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; | 636 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; |
| 637 | const gpa = dg.gpa; | 637 | const gpa = dg.gpa; |
| 638 | 638 | ||
| 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 | |||
| 639 | var args = std.ArrayList(*const llvm.Value).init(gpa); | 647 | var args = std.ArrayList(*const llvm.Value).init(gpa); |
| 640 | defer args.deinit(); | 648 | defer args.deinit(); |
| 641 | 649 | ||
| 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); |
| 643 | for (fn_info.param_types) |param_ty| { | 651 | for (fn_info.param_types) |param_ty| { |
| 644 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 652 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 645 | 653 | ||
| ... | @@ -711,6 +719,7 @@ pub const Object = struct { | ... | @@ -711,6 +719,7 @@ pub const Object = struct { |
| 711 | .base_line = dg.decl.src_line, | 719 | .base_line = dg.decl.src_line, |
| 712 | .prev_dbg_line = 0, | 720 | .prev_dbg_line = 0, |
| 713 | .prev_dbg_column = 0, | 721 | .prev_dbg_column = 0, |
| 722 | .err_ret_trace = err_ret_trace, | ||
| 714 | }; | 723 | }; |
| 715 | defer fg.deinit(); | 724 | defer fg.deinit(); |
| 716 | 725 | ||
| ... | @@ -1755,6 +1764,17 @@ pub const Object = struct { | ... | @@ -1755,6 +1764,17 @@ pub const Object = struct { |
| 1755 | try param_di_types.append(try o.lowerDebugType(Type.void, .full)); | 1764 | try param_di_types.append(try o.lowerDebugType(Type.void, .full)); |
| 1756 | } | 1765 | } |
| 1757 | 1766 | ||
| 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 | |||
| 1758 | for (fn_info.param_types) |param_ty| { | 1778 | for (fn_info.param_types) |param_ty| { |
| 1759 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1779 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1760 | 1780 | ||
| ... | @@ -1824,6 +1844,27 @@ pub const Object = struct { | ... | @@ -1824,6 +1844,27 @@ pub const Object = struct { |
| 1824 | "", // unique id | 1844 | "", // unique id |
| 1825 | ); | 1845 | ); |
| 1826 | } | 1846 | } |
| 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 | } | ||
| 1827 | }; | 1868 | }; |
| 1828 | 1869 | ||
| 1829 | pub const DeclGen = struct { | 1870 | pub const DeclGen = struct { |
| ... | @@ -1976,8 +2017,15 @@ pub const DeclGen = struct { | ... | @@ -1976,8 +2017,15 @@ pub const DeclGen = struct { |
| 1976 | llvm_fn.addSretAttr(0, raw_llvm_ret_ty); | 2017 | llvm_fn.addSretAttr(0, raw_llvm_ret_ty); |
| 1977 | } | 2018 | } |
| 1978 | 2019 | ||
| 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 | |||
| 1979 | // Set parameter attributes. | 2027 | // 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); |
| 1981 | for (fn_info.param_types) |param_ty| { | 2029 | for (fn_info.param_types) |param_ty| { |
| 1982 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 2030 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 1983 | 2031 | ||
| ... | @@ -2435,6 +2483,17 @@ pub const DeclGen = struct { | ... | @@ -2435,6 +2483,17 @@ pub const DeclGen = struct { |
| 2435 | try llvm_params.append(llvm_sret_ty.pointerType(0)); | 2483 | try llvm_params.append(llvm_sret_ty.pointerType(0)); |
| 2436 | } | 2484 | } |
| 2437 | 2485 | ||
| 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 | |||
| 2438 | for (fn_info.param_types) |param_ty| { | 2497 | for (fn_info.param_types) |param_ty| { |
| 2439 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 2498 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2440 | 2499 | ||
| ... | @@ -3449,6 +3508,8 @@ pub const FuncGen = struct { | ... | @@ -3449,6 +3508,8 @@ pub const FuncGen = struct { |
| 3449 | 3508 | ||
| 3450 | llvm_func: *const llvm.Value, | 3509 | llvm_func: *const llvm.Value, |
| 3451 | 3510 | ||
| 3511 | err_ret_trace: ?*const llvm.Value = null, | ||
| 3512 | |||
| 3452 | /// This data structure is used to implement breaking to blocks. | 3513 | /// This data structure is used to implement breaking to blocks. |
| 3453 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { | 3514 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { |
| 3454 | parent_bb: *const llvm.BasicBlock, | 3515 | parent_bb: *const llvm.BasicBlock, |
| ... | @@ -3678,6 +3739,8 @@ pub const FuncGen = struct { | ... | @@ -3678,6 +3739,8 @@ pub const FuncGen = struct { |
| 3678 | .unwrap_errunion_err => try self.airErrUnionErr(inst, false), | 3739 | .unwrap_errunion_err => try self.airErrUnionErr(inst, false), |
| 3679 | .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), | 3740 | .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), |
| 3680 | .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), | 3741 | .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), | ||
| 3681 | 3744 | ||
| 3682 | .wrap_optional => try self.airWrapOptional(inst), | 3745 | .wrap_optional => try self.airWrapOptional(inst), |
| 3683 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), | 3746 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| ... | @@ -3732,6 +3795,12 @@ pub const FuncGen = struct { | ... | @@ -3732,6 +3795,12 @@ pub const FuncGen = struct { |
| 3732 | break :blk ret_ptr; | 3795 | break :blk ret_ptr; |
| 3733 | }; | 3796 | }; |
| 3734 | 3797 | ||
| 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 | |||
| 3735 | for (args) |arg| { | 3804 | for (args) |arg| { |
| 3736 | const param_ty = self.air.typeOf(arg); | 3805 | const param_ty = self.air.typeOf(arg); |
| 3737 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 3806 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; |
| ... | @@ -5149,6 +5218,17 @@ pub const FuncGen = struct { | ... | @@ -5149,6 +5218,17 @@ pub const FuncGen = struct { |
| 5149 | return self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | 5218 | return self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); |
| 5150 | } | 5219 | } |
| 5151 | 5220 | ||
| 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 | |||
| 5152 | fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 5232 | fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 5153 | if (self.liveness.isUnused(inst)) return null; | 5233 | if (self.liveness.isUnused(inst)) return null; |
| 5154 | 5234 |
src/print_air.zig+2| ... | @@ -170,6 +170,7 @@ const Writer = struct { | ... | @@ -170,6 +170,7 @@ const Writer = struct { |
| 170 | .round, | 170 | .round, |
| 171 | .trunc_float, | 171 | .trunc_float, |
| 172 | .cmp_lt_errors_len, | 172 | .cmp_lt_errors_len, |
| 173 | .set_err_return_trace, | ||
| 173 | => try w.writeUnOp(s, inst), | 174 | => try w.writeUnOp(s, inst), |
| 174 | 175 | ||
| 175 | .breakpoint, | 176 | .breakpoint, |
| ... | @@ -182,6 +183,7 @@ const Writer = struct { | ... | @@ -182,6 +183,7 @@ const Writer = struct { |
| 182 | .alloc, | 183 | .alloc, |
| 183 | .ret_ptr, | 184 | .ret_ptr, |
| 184 | .arg, | 185 | .arg, |
| 186 | .err_return_trace, | ||
| 185 | => try w.writeTy(s, inst), | 187 | => try w.writeTy(s, inst), |
| 186 | 188 | ||
| 187 | .not, | 189 | .not, |
src/type.zig+7| ... | @@ -4093,6 +4093,13 @@ pub const Type = extern union { | ... | @@ -4093,6 +4093,13 @@ pub const Type = extern union { |
| 4093 | }; | 4093 | }; |
| 4094 | } | 4094 | } |
| 4095 | 4095 | ||
| 4096 | pub fn isError(ty: Type) bool { | ||
| 4097 | return switch (ty.zigTypeTag()) { | ||
| 4098 | .ErrorUnion, .ErrorSet => true, | ||
| 4099 | else => false, | ||
| 4100 | }; | ||
| 4101 | } | ||
| 4102 | |||
| 4096 | /// Returns whether ty, which must be an error set, includes an error `name`. | 4103 | /// Returns whether ty, which must be an error set, includes an error `name`. |
| 4097 | /// Might return a false negative if `ty` is an inferred error set and not fully | 4104 | /// Might return a false negative if `ty` is an inferred error set and not fully |
| 4098 | /// resolved yet. | 4105 | /// resolved yet. |