authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-07 00:52:56-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-07 00:53:04-04:00
log7e1fcb55b3e96524ce6f5620e2e98a3e3cc56608
treeb0147340c2af1a74e84f1499133e5fbc28c162a7
parent1afbb53661e655906980668f0224804118a9862e
signaturelock-open Commit is signed but in an unrecognized format.

implement cancel

all behavior tests passing in this branch

7 files changed, 216 insertions(+), 134 deletions(-)

BRANCH_TODO+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1 * go over the commented out tests in cancel.zig1 * clean up the bitcasting of awaiter fn ptr
2 * compile error for error: expected anyframe->T, found 'anyframe'2 * compile error for error: expected anyframe->T, found 'anyframe'
3 * compile error for error: expected anyframe->T, found 'i32'3 * compile error for error: expected anyframe->T, found 'i32'
4 * await of a non async function4 * await of a non async function
src/all_types.hpp+2-1
...@@ -1556,6 +1556,7 @@ enum PanicMsgId {...@@ -1556,6 +1556,7 @@ enum PanicMsgId {
1556 PanicMsgIdBadAwait,1556 PanicMsgIdBadAwait,
1557 PanicMsgIdBadReturn,1557 PanicMsgIdBadReturn,
1558 PanicMsgIdResumedAnAwaitingFn,1558 PanicMsgIdResumedAnAwaitingFn,
1559 PanicMsgIdResumedACancelingFn,
1559 PanicMsgIdFrameTooSmall,1560 PanicMsgIdFrameTooSmall,
1560 PanicMsgIdResumedFnPendingAwait,1561 PanicMsgIdResumedFnPendingAwait,
15611562
...@@ -3432,7 +3433,7 @@ struct IrInstructionErrorUnion {...@@ -3432,7 +3433,7 @@ struct IrInstructionErrorUnion {
3432struct IrInstructionCancel {3433struct IrInstructionCancel {
3433 IrInstruction base;3434 IrInstruction base;
34343435
3435 IrInstruction *target;3436 IrInstruction *frame;
3436};3437};
34373438
3438struct IrInstructionAtomicRmw {3439struct IrInstructionAtomicRmw {
src/analyze.cpp+3
...@@ -3811,6 +3811,9 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {...@@ -3811,6 +3811,9 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
3811 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {3811 } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) {
3812 add_error_note(g, msg, fn->inferred_async_node,3812 add_error_note(g, msg, fn->inferred_async_node,
3813 buf_sprintf("await is a suspend point"));3813 buf_sprintf("await is a suspend point"));
3814 } else if (fn->inferred_async_node->type == NodeTypeCancel) {
3815 add_error_note(g, msg, fn->inferred_async_node,
3816 buf_sprintf("cancel is a suspend point"));
3814 } else {3817 } else {
3815 zig_unreachable();3818 zig_unreachable();
3816 }3819 }
src/codegen.cpp+69-40
...@@ -911,11 +911,13 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -911,11 +911,13 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
911 case PanicMsgIdBadResume:911 case PanicMsgIdBadResume:
912 return buf_create_from_str("resumed an async function which already returned");912 return buf_create_from_str("resumed an async function which already returned");
913 case PanicMsgIdBadAwait:913 case PanicMsgIdBadAwait:
914 return buf_create_from_str("async function awaited twice");914 return buf_create_from_str("async function awaited/canceled twice");
915 case PanicMsgIdBadReturn:915 case PanicMsgIdBadReturn:
916 return buf_create_from_str("async function returned twice");916 return buf_create_from_str("async function returned twice");
917 case PanicMsgIdResumedAnAwaitingFn:917 case PanicMsgIdResumedAnAwaitingFn:
918 return buf_create_from_str("awaiting function resumed");918 return buf_create_from_str("awaiting function resumed");
919 case PanicMsgIdResumedACancelingFn:
920 return buf_create_from_str("canceling function resumed");
919 case PanicMsgIdFrameTooSmall:921 case PanicMsgIdFrameTooSmall:
920 return buf_create_from_str("frame too small");922 return buf_create_from_str("frame too small");
921 case PanicMsgIdResumedFnPendingAwait:923 case PanicMsgIdResumedFnPendingAwait:
...@@ -2189,12 +2191,12 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume...@@ -2189,12 +2191,12 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume
2189 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");2191 if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume");
2190 LLVMValueRef ok_bit;2192 LLVMValueRef ok_bit;
2191 if (resume_id == ResumeIdAwaitEarlyReturn) {2193 if (resume_id == ResumeIdAwaitEarlyReturn) {
2192 LLVMValueRef last_value = LLVMBuildSub(g->builder, LLVMConstAllOnes(usize_type_ref),2194 LLVMValueRef last_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
2193 LLVMConstInt(usize_type_ref, ResumeIdAwaitEarlyReturn, false), "");2195 LLVMConstInt(usize_type_ref, ResumeIdAwaitEarlyReturn, false));
2194 ok_bit = LLVMBuildICmp(g->builder, LLVMIntULT, LLVMGetParam(g->cur_fn_val, 1), last_value, "");2196 ok_bit = LLVMBuildICmp(g->builder, LLVMIntULT, LLVMGetParam(g->cur_fn_val, 1), last_value, "");
2195 } else {2197 } else {
2196 LLVMValueRef expected_value = LLVMBuildSub(g->builder, LLVMConstAllOnes(usize_type_ref),2198 LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref),
2197 LLVMConstInt(usize_type_ref, resume_id, false), "");2199 LLVMConstInt(usize_type_ref, resume_id, false));
2198 ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, "");2200 ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, "");
2199 }2201 }
2200 LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block);2202 LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block);
...@@ -2210,11 +2212,13 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar...@@ -2210,11 +2212,13 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar
2210{2212{
2211 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;2213 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2212 if (fn_val == nullptr) {2214 if (fn_val == nullptr) {
2213 if (g->anyframe_fn_type == nullptr) {
2214 (void)get_llvm_type(g, get_any_frame_type(g, nullptr));
2215 }
2216 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, coro_fn_ptr_index, "");2215 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, coro_fn_ptr_index, "");
2217 fn_val = LLVMBuildLoad(g->builder, fn_ptr_ptr, "");2216 LLVMValueRef fn_val_typed = LLVMBuildLoad(g->builder, fn_ptr_ptr, "");
2217 LLVMValueRef as_int = LLVMBuildPtrToInt(g->builder, fn_val_typed, usize_type_ref, "");
2218 LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false);
2219 LLVMValueRef mask_val = LLVMConstNot(one);
2220 LLVMValueRef as_int_masked = LLVMBuildAnd(g->builder, as_int, mask_val, "");
2221 fn_val = LLVMBuildIntToPtr(g->builder, as_int_masked, LLVMTypeOf(fn_val_typed), "");
2218 }2222 }
2219 if (arg_val == nullptr) {2223 if (arg_val == nullptr) {
2220 arg_val = LLVMBuildSub(g->builder, LLVMConstAllOnes(usize_type_ref),2224 arg_val = LLVMBuildSub(g->builder, LLVMConstAllOnes(usize_type_ref),
...@@ -2226,6 +2230,17 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar...@@ -2226,6 +2230,17 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar
2226 return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");2230 return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
2227}2231}
22282232
2233static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) {
2234 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
2235 LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint);
2236 size_t new_block_index = g->cur_resume_block_count;
2237 g->cur_resume_block_count += 1;
2238 LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false);
2239 LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb);
2240 LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr);
2241 return resume_bb;
2242}
2243
2229static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,2244static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,
2230 IrInstructionReturnBegin *instruction)2245 IrInstructionReturnBegin *instruction)
2231{2246{
...@@ -2245,12 +2260,7 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,...@@ -2245,12 +2260,7 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,
2245 }2260 }
22462261
2247 // Prepare to be suspended. We might end up not having to suspend though.2262 // Prepare to be suspended. We might end up not having to suspend though.
2248 LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnResume");2263 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "ReturnResume");
2249 size_t new_block_index = g->cur_resume_block_count;
2250 g->cur_resume_block_count += 1;
2251 LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false);
2252 LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb);
2253 LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr);
22542264
2255 LLVMValueRef zero = LLVMConstNull(usize_type_ref);2265 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
2256 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);2266 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
...@@ -2335,7 +2345,10 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -2335,7 +2345,10 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
23352345
2336 // We need to resume the caller by tail calling them.2346 // We need to resume the caller by tail calling them.
2337 ZigType *any_frame_type = get_any_frame_type(g, ret_type);2347 ZigType *any_frame_type = get_any_frame_type(g, ret_type);
2338 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, g->cur_async_prev_val,2348 LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false);
2349 LLVMValueRef mask_val = LLVMConstNot(one);
2350 LLVMValueRef masked_prev_val = LLVMBuildAnd(g->builder, g->cur_async_prev_val, mask_val, "");
2351 LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, masked_prev_val,
2339 get_llvm_type(g, any_frame_type), "");2352 get_llvm_type(g, any_frame_type), "");
2340 LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn, nullptr);2353 LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn, nullptr);
2341 ZigLLVMSetTailCall(call_inst);2354 ZigLLVMSetTailCall(call_inst);
...@@ -3945,13 +3958,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3945,13 +3958,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3945 } else if (callee_is_async) {3958 } else if (callee_is_async) {
3946 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);3959 ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true);
39473960
3948 LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(g->cur_fn_val, "CallResume");3961 LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume");
3949 size_t new_block_index = g->cur_resume_block_count;
3950 g->cur_resume_block_count += 1;
3951 LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false);
3952 LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, call_bb);
3953
3954 LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr);
39553962
3956 LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr);3963 LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr);
3957 ZigLLVMSetTailCall(call_inst);3964 ZigLLVMSetTailCall(call_inst);
...@@ -4672,10 +4679,6 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu...@@ -4672,10 +4679,6 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu
4672 return cur_err_ret_trace_val;4679 return cur_err_ret_trace_val;
4673}4680}
46744681
4675static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {
4676 zig_panic("TODO cancel");
4677}
4678
4679static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {4682static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
4680 switch (atomic_order) {4683 switch (atomic_order) {
4681 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;4684 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
...@@ -5416,13 +5419,7 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab...@@ -5416,13 +5419,7 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab
5416static LLVMValueRef ir_render_suspend_begin(CodeGen *g, IrExecutable *executable,5419static LLVMValueRef ir_render_suspend_begin(CodeGen *g, IrExecutable *executable,
5417 IrInstructionSuspendBegin *instruction)5420 IrInstructionSuspendBegin *instruction)
5418{5421{
5419 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;5422 instruction->resume_bb = gen_suspend_begin(g, "SuspendResume");
5420 instruction->resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, "SuspendResume");
5421 size_t new_block_index = g->cur_resume_block_count;
5422 g->cur_resume_block_count += 1;
5423 LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false);
5424 LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, instruction->resume_bb);
5425 LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr);
5426 return nullptr;5423 return nullptr;
5427}5424}
54285425
...@@ -5436,6 +5433,43 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl...@@ -5436,6 +5433,43 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl
5436 return nullptr;5433 return nullptr;
5437}5434}
54385435
5436static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) {
5437 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5438 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
5439 LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref);
5440 LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false);
5441
5442 LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame);
5443 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "CancelResume");
5444
5445 LLVMValueRef awaiter_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, "");
5446 LLVMValueRef awaiter_ored_val = LLVMBuildOr(g->builder, awaiter_val, one, "");
5447 LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, coro_awaiter_index, "");
5448
5449 LLVMValueRef prev_val = LLVMBuildAtomicRMW(g->builder, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_ored_val,
5450 LLVMAtomicOrderingRelease, g->is_single_threaded);
5451
5452 LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CancelSuspend");
5453 LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn");
5454
5455 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_bb, 2);
5456 LLVMAddCase(switch_instr, zero, complete_suspend_block);
5457 LLVMAddCase(switch_instr, all_ones, early_return_block);
5458
5459 LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block);
5460 LLVMBuildRetVoid(g->builder);
5461
5462 LLVMPositionBuilderAtEnd(g->builder, early_return_block);
5463 LLVMValueRef call_inst = gen_resume(g, nullptr, target_frame_ptr, ResumeIdAwaitEarlyReturn, awaiter_ored_val);
5464 ZigLLVMSetTailCall(call_inst);
5465 LLVMBuildRetVoid(g->builder);
5466
5467 LLVMPositionBuilderAtEnd(g->builder, resume_bb);
5468 gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedACancelingFn, nullptr);
5469
5470 return nullptr;
5471}
5472
5439static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {5473static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) {
5440 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;5474 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
5441 LLVMValueRef zero = LLVMConstNull(usize_type_ref);5475 LLVMValueRef zero = LLVMConstNull(usize_type_ref);
...@@ -5444,12 +5478,7 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst...@@ -5444,12 +5478,7 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst
5444 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);5478 ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true);
54455479
5446 // Prepare to be suspended5480 // Prepare to be suspended
5447 LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitResume");5481 LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume");
5448 size_t new_block_index = g->cur_resume_block_count;
5449 g->cur_resume_block_count += 1;
5450 LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false);
5451 LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb);
5452 LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr);
54535482
5454 // At this point resuming the function will do the correct thing.5483 // At this point resuming the function will do the correct thing.
5455 // This code is as if it is running inside the suspend block.5484 // This code is as if it is running inside the suspend block.
src/ir.cpp+48-7
...@@ -3271,6 +3271,16 @@ static IrInstruction *ir_build_suspend_finish(IrBuilder *irb, Scope *scope, AstN...@@ -3271,6 +3271,16 @@ static IrInstruction *ir_build_suspend_finish(IrBuilder *irb, Scope *scope, AstN
3271 return &instruction->base;3271 return &instruction->base;
3272}3272}
32733273
3274static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) {
3275 IrInstructionCancel *instruction = ir_build_instruction<IrInstructionCancel>(irb, scope, source_node);
3276 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
3277 instruction->frame = frame;
3278
3279 ir_ref_instruction(frame, irb->current_basic_block);
3280
3281 return &instruction->base;
3282}
3283
3274static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *source_node,3284static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
3275 IrInstruction *frame, ResultLoc *result_loc)3285 IrInstruction *frame, ResultLoc *result_loc)
3276{3286{
...@@ -7820,11 +7830,26 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo...@@ -7820,11 +7830,26 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
7820static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) {7830static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) {
7821 assert(node->type == NodeTypeCancel);7831 assert(node->type == NodeTypeCancel);
78227832
7823 IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, scope);7833 ZigFn *fn_entry = exec_fn_entry(irb->exec);
7824 if (target_inst == irb->codegen->invalid_instruction)7834 if (!fn_entry) {
7835 add_node_error(irb->codegen, node, buf_sprintf("cancel outside function definition"));
7836 return irb->codegen->invalid_instruction;
7837 }
7838 ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope);
7839 if (existing_suspend_scope) {
7840 if (!existing_suspend_scope->reported_err) {
7841 ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot cancel inside suspend block"));
7842 add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here"));
7843 existing_suspend_scope->reported_err = true;
7844 }
7845 return irb->codegen->invalid_instruction;
7846 }
7847
7848 IrInstruction *operand = ir_gen_node(irb, node->data.cancel_expr.expr, scope);
7849 if (operand == irb->codegen->invalid_instruction)
7825 return irb->codegen->invalid_instruction;7850 return irb->codegen->invalid_instruction;
78267851
7827 zig_panic("TODO ir_gen_cancel");7852 return ir_build_cancel(irb, scope, node, operand);
7828}7853}
78297854
7830static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {7855static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -23781,10 +23806,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct...@@ -23781,10 +23806,6 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
23781 }23806 }
23782}23807}
2378323808
23784static IrInstruction *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
23785 zig_panic("TODO analyze cancel");
23786}
23787
23788static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {23809static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op) {
23789 ZigType *operand_type = ir_resolve_type(ira, op);23810 ZigType *operand_type = ir_resolve_type(ira, op);
23790 if (type_is_invalid(operand_type))23811 if (type_is_invalid(operand_type))
...@@ -24474,6 +24495,26 @@ static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,...@@ -24474,6 +24495,26 @@ static IrInstruction *ir_analyze_instruction_suspend_finish(IrAnalyze *ira,
24474 return ir_build_suspend_finish(&ira->new_irb, instruction->base.scope, instruction->base.source_node, begin);24495 return ir_build_suspend_finish(&ira->new_irb, instruction->base.scope, instruction->base.source_node, begin);
24475}24496}
2447624497
24498static IrInstruction *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
24499 IrInstruction *frame = instruction->frame->child;
24500 if (type_is_invalid(frame->value.type))
24501 return ira->codegen->invalid_instruction;
24502
24503 ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr);
24504 IrInstruction *casted_frame = ir_implicit_cast(ira, frame, any_frame_type);
24505 if (type_is_invalid(casted_frame->value.type))
24506 return ira->codegen->invalid_instruction;
24507
24508 ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
24509 ir_assert(fn_entry != nullptr, &instruction->base);
24510
24511 if (fn_entry->inferred_async_node == nullptr) {
24512 fn_entry->inferred_async_node = instruction->base.source_node;
24513 }
24514
24515 return ir_build_cancel(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame);
24516}
24517
24477static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {24518static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) {
24478 IrInstruction *frame_ptr = instruction->frame->child;24519 IrInstruction *frame_ptr = instruction->frame->child;
24479 if (type_is_invalid(frame_ptr->value.type))24520 if (type_is_invalid(frame_ptr->value.type))
src/ir_print.cpp+1-1
...@@ -1396,7 +1396,7 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct...@@ -1396,7 +1396,7 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct
13961396
1397static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) {1397static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) {
1398 fprintf(irp->f, "cancel ");1398 fprintf(irp->f, "cancel ");
1399 ir_print_other_instruction(irp, instruction->target);1399 ir_print_other_instruction(irp, instruction->frame);
1400}1400}
14011401
1402static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {1402static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) {
test/stage1/behavior/cancel.zig+92-84
...@@ -1,86 +1,94 @@...@@ -1,86 +1,94 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;
23
3//var defer_f1: bool = false;4var defer_f1: bool = false;
4//var defer_f2: bool = false;5var defer_f2: bool = false;
5//var defer_f3: bool = false;6var defer_f3: bool = false;
6//7var f3_frame: anyframe = undefined;
7//test "cancel forwards" {8
8// const p = async<std.heap.direct_allocator> f1() catch unreachable;9test "cancel forwards" {
9// cancel p;10 _ = async atest1();
10// std.testing.expect(defer_f1);11 resume f3_frame;
11// std.testing.expect(defer_f2);12}
12// std.testing.expect(defer_f3);13
13//}14fn atest1() void {
14//15 const p = async f1();
15//async fn f1() void {16 cancel &p;
16// defer {17 expect(defer_f1);
17// defer_f1 = true;18 expect(defer_f2);
18// }19 expect(defer_f3);
19// await (async f2() catch unreachable);20}
20//}21
21//22async fn f1() void {
22//async fn f2() void {23 defer {
23// defer {24 defer_f1 = true;
24// defer_f2 = true;25 }
25// }26 var f2_frame = async f2();
26// await (async f3() catch unreachable);27 await f2_frame;
27//}28}
28//29
29//async fn f3() void {30async fn f2() void {
30// defer {31 defer {
31// defer_f3 = true;32 defer_f2 = true;
32// }33 }
33// suspend;34 f3();
34//}35}
35//36
36//var defer_b1: bool = false;37async fn f3() void {
37//var defer_b2: bool = false;38 f3_frame = @frame();
38//var defer_b3: bool = false;39 defer {
39//var defer_b4: bool = false;40 defer_f3 = true;
40//41 }
41//test "cancel backwards" {42 suspend;
42// const p = async<std.heap.direct_allocator> b1() catch unreachable;43}
43// cancel p;44
44// std.testing.expect(defer_b1);45var defer_b1: bool = false;
45// std.testing.expect(defer_b2);46var defer_b2: bool = false;
46// std.testing.expect(defer_b3);47var defer_b3: bool = false;
47// std.testing.expect(defer_b4);48var defer_b4: bool = false;
48//}49
49//50test "cancel backwards" {
50//async fn b1() void {51 _ = async b1();
51// defer {52 resume b4_handle;
52// defer_b1 = true;53 expect(defer_b1);
53// }54 expect(defer_b2);
54// await (async b2() catch unreachable);55 expect(defer_b3);
55//}56 expect(defer_b4);
56//57}
57//var b4_handle: promise = undefined;58
58//59async fn b1() void {
59//async fn b2() void {60 defer {
60// const b3_handle = async b3() catch unreachable;61 defer_b1 = true;
61// resume b4_handle;62 }
62// cancel b4_handle;63 b2();
63// defer {64}
64// defer_b2 = true;65
65// }66var b4_handle: anyframe = undefined;
66// const value = await b3_handle;67
67// @panic("unreachable");68async fn b2() void {
68//}69 const b3_handle = async b3();
69//70 resume b4_handle;
70//async fn b3() i32 {71 defer {
71// defer {72 defer_b2 = true;
72// defer_b3 = true;73 }
73// }74 const value = await b3_handle;
74// await (async b4() catch unreachable);75 expect(value == 1234);
75// return 1234;76}
76//}77
77//78async fn b3() i32 {
78//async fn b4() void {79 defer {
79// defer {80 defer_b3 = true;
80// defer_b4 = true;81 }
81// }82 b4();
82// suspend {83 return 1234;
83// b4_handle = @handle();84}
84// }85
85// suspend;86async fn b4() void {
86//}87 defer {
88 defer_b4 = true;
89 }
90 suspend {
91 b4_handle = @frame();
92 }
93 suspend;
94}