authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-15 15:06:05-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-15 15:06:05-04:00
log55f5cee86b39bb2127a316f9b5d0abf532580cac
treea9bce15a8899632cf527b980c8fc27280bd9dca0
parent13b5a4bf8ca65c569e6b28ca0e41d101d12d0ff1
signaturelock-open Commit is signed but in an unrecognized format.

fix error return traces for async calls of blocking functions


5 files changed, 85 insertions(+), 23 deletions(-)

src/analyze.cpp+5
...@@ -3819,6 +3819,11 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {...@@ -3819,6 +3819,11 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
3819 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {3819 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {
3820 add_error_note(g, msg, fn->inferred_async_node,3820 add_error_note(g, msg, fn->inferred_async_node,
3821 buf_sprintf("await is a suspend point"));3821 buf_sprintf("await is a suspend point"));
3822 } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr &&
3823 fn->inferred_async_node->data.fn_call_expr.is_builtin)
3824 {
3825 add_error_note(g, msg, fn->inferred_async_node,
3826 buf_sprintf("@frame() causes function to be async"));
3822 } else {3827 } else {
3823 add_error_note(g, msg, fn->inferred_async_node,3828 add_error_note(g, msg, fn->inferred_async_node,
3824 buf_sprintf("suspends here"));3829 buf_sprintf("suspends here"));
src/codegen.cpp+37-15
...@@ -3760,6 +3760,23 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {...@@ -3760,6 +3760,23 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
3760 return LLVMBuildLoad(g->builder, prefix_ptr, "");3760 return LLVMBuildLoad(g->builder, prefix_ptr, "");
3761}3761}
37623762
3763static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) {
3764 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3765 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
3766
3767 LLVMValueRef index_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 0, "");
3768 LLVMBuildStore(g->builder, zero, index_ptr);
3769
3770 LLVMValueRef addrs_slice_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 1, "");
3771 LLVMValueRef addrs_ptr_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_ptr_index, "");
3772 LLVMValueRef indices[] = { LLVMConstNull(usize_type_ref), LLVMConstNull(usize_type_ref) };
3773 LLVMValueRef trace_field_addrs_as_ptr = LLVMBuildInBoundsGEP(g->builder, addrs_field_ptr, indices, 2, "");
3774 LLVMBuildStore(g->builder, trace_field_addrs_as_ptr, addrs_ptr_ptr);
3775
3776 LLVMValueRef addrs_len_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_len_index, "");
3777 LLVMBuildStore(g->builder, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), addrs_len_ptr);
3778}
3779
3763static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {3780static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {
3764 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;3781 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
37653782
...@@ -3900,9 +3917,24 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3900,9 +3917,24 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3900 if (first_arg_ret) {3917 if (first_arg_ret) {
3901 gen_param_values.append(ret_ptr);3918 gen_param_values.append(ret_ptr);
3902 }3919 }
3903 }3920 if (prefix_arg_err_ret_stack) {
3904 if (prefix_arg_err_ret_stack) {3921 // Set up the callee stack trace pointer pointing into the frame.
3905 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));3922 // Then we have to wire up the StackTrace pointers.
3923 // Await is responsible for merging error return traces.
3924 uint32_t trace_field_index_start = frame_index_trace_arg(g, src_return_type);
3925 LLVMValueRef callee_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3926 trace_field_index_start, "");
3927 LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3928 trace_field_index_start + 2, "");
3929 LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3930 trace_field_index_start + 3, "");
3931
3932 LLVMBuildStore(g->builder, trace_field_ptr, callee_trace_ptr_ptr);
3933
3934 gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr);
3935
3936 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
3937 }
3906 }3938 }
3907 } else {3939 } else {
3908 if (first_arg_ret) {3940 if (first_arg_ret) {
...@@ -7126,20 +7158,10 @@ static void do_code_gen(CodeGen *g) {...@@ -7126,20 +7158,10 @@ static void do_code_gen(CodeGen *g) {
71267158
7127 LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,7159 LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7128 trace_field_index_stack, "");7160 trace_field_index_stack, "");
7129 LLVMValueRef trace_field_addrs = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,7161 LLVMValueRef addrs_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr,
7130 trace_field_index_stack + 1, "");7162 trace_field_index_stack + 1, "");
71317163
7132 LLVMValueRef index_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 0, "");7164 gen_init_stack_trace(g, trace_field_ptr, addrs_field_ptr);
7133 LLVMBuildStore(g->builder, zero, index_ptr);
7134
7135 LLVMValueRef addrs_slice_ptr = LLVMBuildStructGEP(g->builder, trace_field_ptr, 1, "");
7136 LLVMValueRef addrs_ptr_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_ptr_index, "");
7137 LLVMValueRef indices[] = { LLVMConstNull(usize_type_ref), LLVMConstNull(usize_type_ref) };
7138 LLVMValueRef trace_field_addrs_as_ptr = LLVMBuildInBoundsGEP(g->builder, trace_field_addrs, indices, 2, "");
7139 LLVMBuildStore(g->builder, trace_field_addrs_as_ptr, addrs_ptr_ptr);
7140
7141 LLVMValueRef addrs_len_ptr = LLVMBuildStructGEP(g->builder, addrs_slice_ptr, slice_len_index, "");
7142 LLVMBuildStore(g->builder, LLVMConstInt(usize_type_ref, stack_trace_ptr_count, false), addrs_len_ptr);
7143 }7165 }
7144 render_async_var_decls(g, entry_block->instruction_list.at(0)->scope);7166 render_async_var_decls(g, entry_block->instruction_list.at(0)->scope);
7145 } else {7167 } else {
src/ir.cpp+4
...@@ -22078,6 +22078,10 @@ static IrInstruction *ir_analyze_instruction_frame_handle(IrAnalyze *ira, IrInst...@@ -22078,6 +22078,10 @@ static IrInstruction *ir_analyze_instruction_frame_handle(IrAnalyze *ira, IrInst
22078 ZigFn *fn = exec_fn_entry(ira->new_irb.exec);22078 ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
22079 ir_assert(fn != nullptr, &instruction->base);22079 ir_assert(fn != nullptr, &instruction->base);
2208022080
22081 if (fn->inferred_async_node == nullptr) {
22082 fn->inferred_async_node = instruction->base.source_node;
22083 }
22084
22081 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn);22085 ZigType *frame_type = get_fn_frame_type(ira->codegen, fn);
22082 ZigType *ptr_frame_type = get_pointer_to_type(ira->codegen, frame_type, false);22086 ZigType *ptr_frame_type = get_pointer_to_type(ira->codegen, frame_type, false);
2208322087
test/compile_errors.zig+12
...@@ -2,6 +2,18 @@ const tests = @import("tests.zig");...@@ -2,6 +2,18 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "@frame() causes function to be async",
7 \\export fn entry() void {
8 \\ func();
9 \\}
10 \\fn func() void {
11 \\ _ = @frame();
12 \\}
13 ,
14 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
15 "tmp.zig:5:9: note: @frame() causes function to be async",
16 );
5 cases.add(17 cases.add(
6 "invalid suspend in exported function",18 "invalid suspend in exported function",
7 \\export fn entry() void {19 \\export fn entry() void {
test/stage1/behavior/async_fn.zig+27-8
...@@ -634,17 +634,30 @@ test "returning a const error from async function" {...@@ -634,17 +634,30 @@ test "returning a const error from async function" {
634test "async/await typical usage" {634test "async/await typical usage" {
635 inline for ([_]bool{false, true}) |b1| {635 inline for ([_]bool{false, true}) |b1| {
636 inline for ([_]bool{false, true}) |b2| {636 inline for ([_]bool{false, true}) |b2| {
637 testAsyncAwaitTypicalUsage(b1, b2).doTheTest();637 inline for ([_]bool{false, true}) |b3| {
638 inline for ([_]bool{false, true}) |b4| {
639 testAsyncAwaitTypicalUsage(b1, b2, b3, b4).doTheTest();
640 }
641 }
638 }642 }
639 }643 }
640}644}
641645
642fn testAsyncAwaitTypicalUsage(comptime simulate_fail_download: bool, comptime simulate_fail_file: bool) type {646fn testAsyncAwaitTypicalUsage(
647 comptime simulate_fail_download: bool,
648 comptime simulate_fail_file: bool,
649 comptime suspend_download: bool,
650 comptime suspend_file: bool) type
651{
643 return struct {652 return struct {
644 fn doTheTest() void {653 fn doTheTest() void {
645 _ = async amainWrap();654 _ = async amainWrap();
646 resume global_file_frame;655 if (suspend_file) {
647 resume global_download_frame;656 resume global_file_frame;
657 }
658 if (suspend_download) {
659 resume global_download_frame;
660 }
648 }661 }
649 fn amainWrap() void {662 fn amainWrap() void {
650 if (amain()) |_| {663 if (amain()) |_| {
...@@ -685,20 +698,26 @@ fn testAsyncAwaitTypicalUsage(comptime simulate_fail_download: bool, comptime si...@@ -685,20 +698,26 @@ fn testAsyncAwaitTypicalUsage(comptime simulate_fail_download: bool, comptime si
685698
686 var global_download_frame: anyframe = undefined;699 var global_download_frame: anyframe = undefined;
687 fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 {700 fn fetchUrl(allocator: *std.mem.Allocator, url: []const u8) anyerror![]u8 {
688 global_download_frame = @frame();
689 const result = try std.mem.dupe(allocator, u8, "expected download text");701 const result = try std.mem.dupe(allocator, u8, "expected download text");
690 errdefer allocator.free(result);702 errdefer allocator.free(result);
691 suspend;703 if (suspend_download) {
704 suspend {
705 global_download_frame = @frame();
706 }
707 }
692 if (simulate_fail_download) return error.NoResponse;708 if (simulate_fail_download) return error.NoResponse;
693 return result;709 return result;
694 }710 }
695711
696 var global_file_frame: anyframe = undefined;712 var global_file_frame: anyframe = undefined;
697 fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 {713 fn readFile(allocator: *std.mem.Allocator, filename: []const u8) anyerror![]u8 {
698 global_file_frame = @frame();
699 const result = try std.mem.dupe(allocator, u8, "expected file text");714 const result = try std.mem.dupe(allocator, u8, "expected file text");
700 errdefer allocator.free(result);715 errdefer allocator.free(result);
701 suspend;716 if (suspend_file) {
717 suspend {
718 global_file_frame = @frame();
719 }
720 }
702 if (simulate_fail_file) return error.FileNotFound;721 if (simulate_fail_file) return error.FileNotFound;
703 return result;722 return result;
704 }723 }