authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-03 16:14:24-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-03 16:17:42-04:00
log87710a1cc2c4d0e7ecc309e430f7d33baadc5f02
tree1a5d38b2a65f0e63e463c5beb94d81c7af8a9320
parentc87920966133d3285b60ccd022282e3f53789e0c
signature Commit is signed but in an unrecognized format.

implement `@asyncCall` which supports async function pointers


8 files changed, 247 insertions(+), 61 deletions(-)

BRANCH_TODO+14-2
......@@ -1,9 +1,8 @@
1 * @asyncCall with an async function pointer
12 * compile error for error: expected anyframe->T, found 'anyframe'
23 * compile error for error: expected anyframe->T, found 'i32'
34 * await of a non async function
4 * await in single-threaded mode
55 * async call on a non async function
6 * @asyncCall with an async function pointer
76 * cancel
87 * defer and errdefer
98 * safety for double await
......@@ -21,3 +20,16 @@
2120 * compile error for copying a frame
2221 * compile error for resuming a const frame pointer
2322 * runtime safety enabling/disabling scope has to be coordinated across resume/await/calls/return
23 * await in single-threaded mode
24 * calling a generic function which is async
25 * make sure `await @asyncCall` and `await async` are handled correctly.
26 * allow @asyncCall with a real @Frame(func) (the point of this is result pointer)
27 * documentation
28 - @asyncCall
29 - @frame
30 - @Frame
31 - @frameSize
32 - coroutines section
33 - suspend
34 - resume
35 - anyframe, anyframe->T
src/all_types.hpp+3
......@@ -1503,6 +1503,7 @@ enum BuiltinFnId {
15031503 BuiltinFnIdInlineCall,
15041504 BuiltinFnIdNoInlineCall,
15051505 BuiltinFnIdNewStackCall,
1506 BuiltinFnIdAsyncCall,
15061507 BuiltinFnIdTypeId,
15071508 BuiltinFnIdShlExact,
15081509 BuiltinFnIdShrExact,
......@@ -1553,6 +1554,7 @@ enum PanicMsgId {
15531554 PanicMsgIdBadAwait,
15541555 PanicMsgIdBadReturn,
15551556 PanicMsgIdResumedAnAwaitingFn,
1557 PanicMsgIdFrameTooSmall,
15561558
15571559 PanicMsgIdCount,
15581560};
......@@ -3699,6 +3701,7 @@ static const size_t maybe_null_index = 1;
36993701static const size_t err_union_err_index = 0;
37003702static const size_t err_union_payload_index = 1;
37013703
3704// label (grep this): [coro_frame_struct_layout]
37023705static const size_t coro_fn_ptr_index = 0;
37033706static const size_t coro_awaiter_index = 1;
37043707static const size_t coro_arg_start = 2;
src/analyze.cpp+3
......@@ -5205,6 +5205,7 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
52055205 call->frame_result_loc = &alloca_gen->base;
52065206 }
52075207
5208 // label (grep this): [coro_frame_struct_layout]
52085209 ZigList<ZigType *> field_types = {};
52095210 ZigList<const char *> field_names = {};
52105211
......@@ -7525,6 +7526,7 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re
75257526 if (result_type == nullptr) {
75267527 g->anyframe_fn_type = ptr_result_type;
75277528 }
7529 // label (grep this): [coro_frame_struct_layout]
75287530 LLVMTypeRef field_types[] = {
75297531 ptr_result_type, // fn_ptr
75307532 usize_type_ref, // awaiter
......@@ -7558,6 +7560,7 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re
75587560 ZigLLVMReplaceTemporary(g->dbuilder, frame_header_di_type, replacement_di_type);
75597561 } else {
75607562 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, false);
7563 // label (grep this): [coro_frame_struct_layout]
75617564 LLVMTypeRef field_types[] = {
75627565 LLVMPointerType(fn_type, 0), // fn_ptr
75637566 usize_type_ref, // awaiter
src/codegen.cpp+79-26
......@@ -879,6 +879,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
879879 return buf_create_from_str("async function returned twice");
880880 case PanicMsgIdResumedAnAwaitingFn:
881881 return buf_create_from_str("awaiting function resumed");
882 case PanicMsgIdFrameTooSmall:
883 return buf_create_from_str("frame too small");
882884 }
883885 zig_unreachable();
884886}
......@@ -3479,7 +3481,18 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {
34793481 }
34803482}
34813483
3484static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
3485 LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type;
3486 LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0);
3487 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
3488 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
3489 LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
3490 return LLVMBuildLoad(g->builder, prefix_ptr, "");
3491}
3492
34823493static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) {
3494 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
3495
34833496 LLVMValueRef fn_val;
34843497 ZigType *fn_type;
34853498 bool callee_is_async;
......@@ -3511,34 +3524,54 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
35113524 LLVMValueRef awaiter_init_val;
35123525 LLVMValueRef ret_ptr;
35133526 if (instruction->is_async) {
3514 frame_result_loc = result_loc;
35153527 awaiter_init_val = zero;
3516 if (ret_has_bits) {
3517 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start + 1, "");
3518 }
35193528
3520 // Use the result location which is inside the frame if this is an async call.
3521 if (ret_has_bits) {
3522 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, "");
3523 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3529 if (instruction->new_stack == nullptr) {
3530 frame_result_loc = result_loc;
3531
3532 if (ret_has_bits) {
3533 // Use the result location which is inside the frame if this is an async call.
3534 ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start + 1, "");
3535 }
3536 } else {
3537 LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack);
3538 if (ir_want_runtime_safety(g, &instruction->base)) {
3539 LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, "");
3540 LLVMValueRef given_frame_len = LLVMBuildLoad(g->builder, given_len_ptr, "");
3541 LLVMValueRef actual_frame_len = gen_frame_size(g, fn_val);
3542
3543 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckFail");
3544 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FrameSizeCheckOk");
3545
3546 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntUGE, given_frame_len, actual_frame_len, "");
3547 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
3548
3549 LLVMPositionBuilderAtEnd(g->builder, fail_block);
3550 gen_safety_crash(g, PanicMsgIdFrameTooSmall);
3551
3552 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3553 }
3554 LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, "");
3555 LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, "");
3556 frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr,
3557 get_llvm_type(g, instruction->base.value.type), "");
3558
3559 if (ret_has_bits) {
3560 // Use the result location provided to the @asyncCall builtin
3561 ret_ptr = result_loc;
3562 }
35243563 }
35253564 } else if (callee_is_async) {
35263565 frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc);
35273566 awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_ret_ptr,
35283567 g->builtin_types.entry_usize->llvm_type, ""); // caller's own frame pointer
35293568 if (ret_has_bits) {
3569 // Use the call instruction's result location.
35303570 ret_ptr = result_loc;
35313571 }
3532
3533 // Use the call instruction's result location.
3534 if (ret_has_bits) {
3535 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, "");
3536 LLVMBuildStore(g->builder, result_loc, ret_ptr_ptr);
3537 }
35383572 }
35393573 if (instruction->is_async || callee_is_async) {
35403574 assert(frame_result_loc != nullptr);
3541 assert(instruction->fn_entry != nullptr);
35423575
35433576 if (prefix_arg_err_ret_stack) {
35443577 zig_panic("TODO");
......@@ -3547,6 +3580,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
35473580 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_awaiter_index, "");
35483581 LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr);
35493582
3583 if (ret_has_bits) {
3584 LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, "");
3585 LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr);
3586 }
35503587 }
35513588 if (!instruction->is_async && !callee_is_async) {
35523589 if (first_arg_ret) {
......@@ -3581,16 +3618,37 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
35813618
35823619 if (instruction->is_async || callee_is_async) {
35833620 size_t ret_2_or_0 = type_has_bits(fn_type->data.fn.fn_type_id.return_type) ? 2 : 0;
3621 size_t arg_start_i = coro_arg_start + ret_2_or_0;
3622
3623 LLVMValueRef casted_frame;
3624 if (instruction->new_stack != nullptr) {
3625 // We need the frame type to be a pointer to a struct that includes the args
3626 // label (grep this): [coro_frame_struct_layout]
3627 size_t field_count = arg_start_i + gen_param_values.length;
3628 LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count);
3629 LLVMGetStructElementTypes(LLVMGetElementType(LLVMTypeOf(frame_result_loc)), field_types);
3630 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3631 field_types[arg_start_i + arg_i] = LLVMTypeOf(gen_param_values.at(arg_i));
3632 }
3633 LLVMTypeRef frame_with_args_type = LLVMStructType(field_types, field_count, false);
3634 LLVMTypeRef ptr_frame_with_args_type = LLVMPointerType(frame_with_args_type, 0);
3635
3636 casted_frame = LLVMBuildBitCast(g->builder, frame_result_loc, ptr_frame_with_args_type, "");
3637 } else {
3638 casted_frame = frame_result_loc;
3639 }
3640
35843641 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3585 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc,
3586 coro_arg_start + ret_2_or_0 + arg_i, "");
3642 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, casted_frame, arg_start_i + arg_i, "");
35873643 LLVMBuildStore(g->builder, gen_param_values.at(arg_i), arg_ptr);
35883644 }
35893645 }
3590 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
35913646 if (instruction->is_async) {
35923647 LLVMValueRef args[] = {frame_result_loc, LLVMGetUndef(usize_type_ref)};
35933648 ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, fn_inline, "");
3649 if (instruction->new_stack != nullptr) {
3650 return frame_result_loc;
3651 }
35943652 return nullptr;
35953653 } else if (callee_is_async) {
35963654 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);
......@@ -5223,13 +5281,8 @@ static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable,
52235281static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable,
52245282 IrInstructionFrameSizeGen *instruction)
52255283{
5226 LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type;
5227 LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0);
52285284 LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn);
5229 LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
5230 LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
5231 LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
5232 return LLVMBuildLoad(g->builder, prefix_ptr, "");
5285 return gen_frame_size(g, fn_val);
52335286}
52345287
52355288static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
......@@ -7097,13 +7150,13 @@ static void define_builtin_fns(CodeGen *g) {
70977150 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);
70987151 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);
70997152 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);
7100 //Needs library support on Windows
7101 //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7153 create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
71027154 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
71037155 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
71047156 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
71057157 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
71067158 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
7159 create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX);
71077160 create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1);
71087161 create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2);
71097162 create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2);
src/ir.cpp+85-17
......@@ -1402,6 +1402,10 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s
14021402 if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block);
14031403 for (size_t i = 0; i < arg_count; i += 1)
14041404 ir_ref_instruction(args[i], irb->current_basic_block);
1405 if (is_async && new_stack != nullptr) {
1406 // in this case the arg at the end is the return pointer
1407 ir_ref_instruction(args[arg_count], irb->current_basic_block);
1408 }
14051409 if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
14061410
14071411 return &call_instruction->base;
......@@ -5203,8 +5207,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
52035207 }
52045208 case BuiltinFnIdNewStackCall:
52055209 {
5206 if (node->data.fn_call_expr.params.length == 0) {
5207 add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0"));
5210 if (node->data.fn_call_expr.params.length < 2) {
5211 add_node_error(irb->codegen, node,
5212 buf_sprintf("expected at least 2 arguments, found %" ZIG_PRI_usize,
5213 node->data.fn_call_expr.params.length));
52085214 return irb->codegen->invalid_instruction;
52095215 }
52105216
......@@ -5232,6 +5238,50 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
52325238 FnInlineAuto, false, new_stack, result_loc);
52335239 return ir_lval_wrap(irb, scope, call, lval, result_loc);
52345240 }
5241 case BuiltinFnIdAsyncCall:
5242 {
5243 size_t arg_offset = 3;
5244 if (node->data.fn_call_expr.params.length < arg_offset) {
5245 add_node_error(irb->codegen, node,
5246 buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize,
5247 arg_offset, node->data.fn_call_expr.params.length));
5248 return irb->codegen->invalid_instruction;
5249 }
5250
5251 AstNode *bytes_node = node->data.fn_call_expr.params.at(0);
5252 IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope);
5253 if (bytes == irb->codegen->invalid_instruction)
5254 return bytes;
5255
5256 AstNode *ret_ptr_node = node->data.fn_call_expr.params.at(1);
5257 IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope);
5258 if (ret_ptr == irb->codegen->invalid_instruction)
5259 return ret_ptr;
5260
5261 AstNode *fn_ref_node = node->data.fn_call_expr.params.at(2);
5262 IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
5263 if (fn_ref == irb->codegen->invalid_instruction)
5264 return fn_ref;
5265
5266 size_t arg_count = node->data.fn_call_expr.params.length - arg_offset;
5267
5268 // last "arg" is return pointer
5269 IrInstruction **args = allocate<IrInstruction*>(arg_count + 1);
5270
5271 for (size_t i = 0; i < arg_count; i += 1) {
5272 AstNode *arg_node = node->data.fn_call_expr.params.at(i + arg_offset);
5273 IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
5274 if (arg == irb->codegen->invalid_instruction)
5275 return arg;
5276 args[i] = arg;
5277 }
5278
5279 args[arg_count] = ret_ptr;
5280
5281 IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
5282 FnInlineAuto, true, bytes, result_loc);
5283 return ir_lval_wrap(irb, scope, call, lval, result_loc);
5284 }
52355285 case BuiltinFnIdTypeId:
52365286 {
52375287 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -14817,11 +14867,31 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst
1481714867}
1481814868
1481914869static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry,
14820 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count)
14870 ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,
14871 IrInstruction *casted_new_stack)
1482114872{
1482214873 if (fn_entry == nullptr) {
14823 ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required"));
14824 return ira->codegen->invalid_instruction;
14874 if (call_instruction->new_stack == nullptr) {
14875 ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required"));
14876 return ira->codegen->invalid_instruction;
14877 }
14878 // this is an @asyncCall
14879
14880 if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) {
14881 ir_add_error(ira, fn_ref,
14882 buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name)));
14883 return ira->codegen->invalid_instruction;
14884 }
14885
14886 IrInstruction *ret_ptr = call_instruction->args[call_instruction->arg_count]->child;
14887 if (type_is_invalid(ret_ptr->value.type))
14888 return ira->codegen->invalid_instruction;
14889
14890 ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_type->data.fn.fn_type_id.return_type);
14891
14892 IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref,
14893 arg_count, casted_args, FnInlineAuto, true, casted_new_stack, ret_ptr, anyframe_type);
14894 return &call_gen->base;
1482514895 }
1482614896
1482714897 ZigType *frame_type = get_coro_frame_type(ira->codegen, fn_entry);
......@@ -15559,13 +15629,13 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1555915629
1556015630 size_t impl_param_count = impl_fn_type_id->param_count;
1556115631 if (call_instruction->is_async) {
15562 zig_panic("TODO async call");
15632 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
15633 nullptr, casted_args, call_param_count, casted_new_stack);
15634 return ir_finish_anal(ira, result);
1556315635 }
1556415636
15565 if (!call_instruction->is_async) {
15566 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15567 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15568 }
15637 if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15638 parent_fn_entry->inferred_async_node = fn_ref->source_node;
1556915639 }
1557015640
1557115641 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
......@@ -15645,18 +15715,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1564515715 return ira->codegen->invalid_instruction;
1564615716 }
1564715717
15648 if (!call_instruction->is_async) {
15649 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15650 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15651 }
15652 }
15653
1565415718 if (call_instruction->is_async) {
1565515719 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,
15656 casted_args, call_param_count);
15720 casted_args, call_param_count, casted_new_stack);
1565715721 return ir_finish_anal(ira, result);
1565815722 }
1565915723
15724 if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) {
15725 parent_fn_entry->inferred_async_node = fn_ref->source_node;
15726 }
15727
1566015728 IrInstruction *result_loc;
1566115729 if (handle_is_ptr(return_type)) {
1566215730 result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
test/compile_errors.zig+12
......@@ -2,6 +2,18 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "non async function pointer passed to @asyncCall",
7 \\export fn entry() void {
8 \\ var ptr = afunc;
9 \\ var bytes: [100]u8 = undefined;
10 \\ _ = @asyncCall(&bytes, {}, ptr);
11 \\}
12 \\fn afunc() void { }
13 ,
14 "tmp.zig:4:32: error: expected async function, found 'fn() void'",
15 );
16
517 cases.add(
618 "runtime-known async function called",
719 \\export fn entry() void {
test/runtime_safety.zig+15
......@@ -1,6 +1,20 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("@asyncCall with too small a frame",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\pub fn main() void {
9 \\ var bytes: [1]u8 = undefined;
10 \\ var ptr = other;
11 \\ var frame = @asyncCall(&bytes, {}, ptr);
12 \\}
13 \\async fn other() void {
14 \\ suspend;
15 \\}
16 );
17
418 cases.addRuntimeSafety("resuming a function which is awaiting a frame",
519 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
620 \\ @import("std").os.exit(126);
......@@ -17,6 +31,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
1731 \\ suspend;
1832 \\}
1933 );
34
2035 cases.addRuntimeSafety("resuming a function which is awaiting a call",
2136 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
2237 \\ @import("std").os.exit(126);
test/stage1/behavior/coroutines.zig+36-16
......@@ -260,22 +260,42 @@ test "async function with dot syntax" {
260260 expect(S.y == 2);
261261}
262262
263//test "async fn pointer in a struct field" {
264// var data: i32 = 1;
265// const Foo = struct {
266// bar: async fn (*i32) void,
267// };
268// var foo = Foo{ .bar = simpleAsyncFn2 };
269// const p = async foo.bar(&data);
270// expect(data == 2);
271// resume p;
272// expect(data == 4);
273//}
274//async fn simpleAsyncFn2(y: *i32) void {
275// defer y.* += 2;
276// y.* += 1;
277// suspend;
278//}
263test "async fn pointer in a struct field" {
264 var data: i32 = 1;
265 const Foo = struct {
266 bar: async fn (*i32) void,
267 };
268 var foo = Foo{ .bar = simpleAsyncFn2 };
269 var bytes: [64]u8 = undefined;
270 const p = @asyncCall(&bytes, {}, foo.bar, &data);
271 comptime expect(@typeOf(p) == anyframe->void);
272 expect(data == 2);
273 resume p;
274 expect(data == 4);
275}
276async fn simpleAsyncFn2(y: *i32) void {
277 defer y.* += 2;
278 y.* += 1;
279 suspend;
280}
281
282test "@asyncCall with return type" {
283 const Foo = struct {
284 bar: async fn () i32,
285
286 async fn afunc() i32 {
287 suspend;
288 return 1234;
289 }
290 };
291 var foo = Foo{ .bar = Foo.afunc };
292 var bytes: [64]u8 = undefined;
293 var aresult: i32 = 0;
294 const frame = @asyncCall(&bytes, &aresult, foo.bar);
295 expect(aresult == 0);
296 resume frame;
297 expect(aresult == 1234);
298}
279299
280300//test "async fn with inferred error set" {
281301// const p = async failing();