| author | |
| committer | |
| log | b9d1d45dfd0f704bc762732c23aa2844f1d14e8d |
| tree | 5253c503cfe54656910e5fcc5d335a1f58cf00ff |
| parent | 2e7f53f1f0d8339b8dc90ad7e0bc9963f1ec471c |
| signature | Commit is signed but in an unrecognized format. |
5 files changed, 120 insertions(+), 9 deletions(-)
src/all_types.hpp+13| ... | ... | @@ -2366,6 +2366,7 @@ enum IrInstructionId { |
| 2366 | 2366 | IrInstructionIdAwaitGen, |
| 2367 | 2367 | IrInstructionIdCoroResume, |
| 2368 | 2368 | IrInstructionIdTestCancelRequested, |
| 2369 | IrInstructionIdSpill, | |
| 2369 | 2370 | }; |
| 2370 | 2371 | |
| 2371 | 2372 | struct IrInstruction { |
| ... | ... | @@ -3643,6 +3644,18 @@ struct IrInstructionTestCancelRequested { |
| 3643 | 3644 | IrInstruction base; |
| 3644 | 3645 | }; |
| 3645 | 3646 | |
| 3647 | enum SpillId { | |
| 3648 | SpillIdInvalid, | |
| 3649 | SpillIdRetErrCode, | |
| 3650 | }; | |
| 3651 | ||
| 3652 | struct IrInstructionSpill { | |
| 3653 | IrInstruction base; | |
| 3654 | ||
| 3655 | SpillId spill_id; | |
| 3656 | IrInstruction *operand; | |
| 3657 | }; | |
| 3658 | ||
| 3646 | 3659 | enum ResultLocId { |
| 3647 | 3660 | ResultLocIdInvalid, |
| 3648 | 3661 | ResultLocIdNone, |
src/codegen.cpp+36-9| ... | ... | @@ -5113,17 +5113,9 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI |
| 5113 | 5113 | return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, ""); |
| 5114 | 5114 | } |
| 5115 | 5115 | |
| 5116 | static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, | |
| 5117 | IrInstructionUnwrapErrCode *instruction) | |
| 5118 | { | |
| 5119 | if (instruction->base.value.special != ConstValSpecialRuntime) | |
| 5120 | return nullptr; | |
| 5121 | ||
| 5122 | ZigType *ptr_type = instruction->err_union_ptr->value.type; | |
| 5123 | assert(ptr_type->id == ZigTypeIdPointer); | |
| 5116 | static LLVMValueRef gen_unwrap_err_code(CodeGen *g, LLVMValueRef err_union_ptr, ZigType *ptr_type) { | |
| 5124 | 5117 | ZigType *err_union_type = ptr_type->data.pointer.child_type; |
| 5125 | 5118 | ZigType *payload_type = err_union_type->data.error_union.payload_type; |
| 5126 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr); | |
| 5127 | 5119 | if (!type_has_bits(payload_type)) { |
| 5128 | 5120 | return err_union_ptr; |
| 5129 | 5121 | } else { |
| ... | ... | @@ -5133,6 +5125,18 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab |
| 5133 | 5125 | } |
| 5134 | 5126 | } |
| 5135 | 5127 | |
| 5128 | static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, | |
| 5129 | IrInstructionUnwrapErrCode *instruction) | |
| 5130 | { | |
| 5131 | if (instruction->base.value.special != ConstValSpecialRuntime) | |
| 5132 | return nullptr; | |
| 5133 | ||
| 5134 | ZigType *ptr_type = instruction->err_union_ptr->value.type; | |
| 5135 | assert(ptr_type->id == ZigTypeIdPointer); | |
| 5136 | LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr); | |
| 5137 | return gen_unwrap_err_code(g, err_union_ptr, ptr_type); | |
| 5138 | } | |
| 5139 | ||
| 5136 | 5140 | static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, |
| 5137 | 5141 | IrInstructionUnwrapErrPayload *instruction) |
| 5138 | 5142 | { |
| ... | ... | @@ -5611,6 +5615,27 @@ static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *ex |
| 5611 | 5615 | } |
| 5612 | 5616 | } |
| 5613 | 5617 | |
| 5618 | static LLVMValueRef ir_render_spill(CodeGen *g, IrExecutable *executable, IrInstructionSpill *instruction) { | |
| 5619 | if (!fn_is_async(g->cur_fn)) | |
| 5620 | return ir_llvm_value(g, instruction->operand); | |
| 5621 | ||
| 5622 | switch (instruction->spill_id) { | |
| 5623 | case SpillIdInvalid: | |
| 5624 | zig_unreachable(); | |
| 5625 | case SpillIdRetErrCode: { | |
| 5626 | LLVMValueRef ret_ptr = LLVMBuildLoad(g->builder, g->cur_ret_ptr, ""); | |
| 5627 | ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; | |
| 5628 | if (ret_type->id == ZigTypeIdErrorUnion) { | |
| 5629 | return gen_unwrap_err_code(g, ret_ptr, get_pointer_to_type(g, ret_type, true)); | |
| 5630 | } else { | |
| 5631 | zig_unreachable(); | |
| 5632 | } | |
| 5633 | } | |
| 5634 | ||
| 5635 | } | |
| 5636 | zig_unreachable(); | |
| 5637 | } | |
| 5638 | ||
| 5614 | 5639 | static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 5615 | 5640 | AstNode *source_node = instruction->source_node; |
| 5616 | 5641 | Scope *scope = instruction->scope; |
| ... | ... | @@ -5866,6 +5891,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5866 | 5891 | return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction); |
| 5867 | 5892 | case IrInstructionIdTestCancelRequested: |
| 5868 | 5893 | return ir_render_test_cancel_requested(g, executable, (IrInstructionTestCancelRequested *)instruction); |
| 5894 | case IrInstructionIdSpill: | |
| 5895 | return ir_render_spill(g, executable, (IrInstructionSpill *)instruction); | |
| 5869 | 5896 | } |
| 5870 | 5897 | zig_unreachable(); |
| 5871 | 5898 | } |
src/ir.cpp+33| ... | ... | @@ -1066,6 +1066,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelReques |
| 1066 | 1066 | return IrInstructionIdTestCancelRequested; |
| 1067 | 1067 | } |
| 1068 | 1068 | |
| 1069 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSpill *) { | |
| 1070 | return IrInstructionIdSpill; | |
| 1071 | } | |
| 1072 | ||
| 1069 | 1073 | template<typename T> |
| 1070 | 1074 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1071 | 1075 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -3332,6 +3336,18 @@ static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scop |
| 3332 | 3336 | return &instruction->base; |
| 3333 | 3337 | } |
| 3334 | 3338 | |
| 3339 | static IrInstruction *ir_build_spill(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 3340 | IrInstruction *operand, SpillId spill_id) | |
| 3341 | { | |
| 3342 | IrInstructionSpill *instruction = ir_build_instruction<IrInstructionSpill>(irb, scope, source_node); | |
| 3343 | instruction->operand = operand; | |
| 3344 | instruction->spill_id = spill_id; | |
| 3345 | ||
| 3346 | ir_ref_instruction(operand, irb->current_basic_block); | |
| 3347 | ||
| 3348 | return &instruction->base; | |
| 3349 | } | |
| 3350 | ||
| 3335 | 3351 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 3336 | 3352 | results[ReturnKindUnconditional] = 0; |
| 3337 | 3353 | results[ReturnKindError] = 0; |
| ... | ... | @@ -3591,6 +3607,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3591 | 3607 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); |
| 3592 | 3608 | result_loc_ret->base.id = ResultLocIdReturn; |
| 3593 | 3609 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); |
| 3610 | err_val = ir_build_spill(irb, scope, node, err_val, SpillIdRetErrCode); | |
| 3594 | 3611 | ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); |
| 3595 | 3612 | |
| 3596 | 3613 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| ... | ... | @@ -24725,6 +24742,19 @@ static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ir |
| 24725 | 24742 | return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node); |
| 24726 | 24743 | } |
| 24727 | 24744 | |
| 24745 | static IrInstruction *ir_analyze_instruction_spill(IrAnalyze *ira, IrInstructionSpill *instruction) { | |
| 24746 | IrInstruction *operand = instruction->operand->child; | |
| 24747 | if (type_is_invalid(operand->value.type)) | |
| 24748 | return ira->codegen->invalid_instruction; | |
| 24749 | if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) { | |
| 24750 | return operand; | |
| 24751 | } | |
| 24752 | IrInstruction *result = ir_build_spill(&ira->new_irb, instruction->base.scope, instruction->base.source_node, | |
| 24753 | operand, instruction->spill_id); | |
| 24754 | result->value.type = operand->value.type; | |
| 24755 | return result; | |
| 24756 | } | |
| 24757 | ||
| 24728 | 24758 | static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { |
| 24729 | 24759 | switch (instruction->id) { |
| 24730 | 24760 | case IrInstructionIdInvalid: |
| ... | ... | @@ -25024,6 +25054,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25024 | 25054 | return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction); |
| 25025 | 25055 | case IrInstructionIdTestCancelRequested: |
| 25026 | 25056 | return ir_analyze_instruction_test_cancel_requested(ira, (IrInstructionTestCancelRequested *)instruction); |
| 25057 | case IrInstructionIdSpill: | |
| 25058 | return ir_analyze_instruction_spill(ira, (IrInstructionSpill *)instruction); | |
| 25027 | 25059 | } |
| 25028 | 25060 | zig_unreachable(); |
| 25029 | 25061 | } |
| ... | ... | @@ -25259,6 +25291,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25259 | 25291 | case IrInstructionIdAllocaSrc: |
| 25260 | 25292 | case IrInstructionIdAllocaGen: |
| 25261 | 25293 | case IrInstructionIdTestCancelRequested: |
| 25294 | case IrInstructionIdSpill: | |
| 25262 | 25295 | return false; |
| 25263 | 25296 | |
| 25264 | 25297 | case IrInstructionIdAsm: |
src/ir_print.cpp+9| ... | ... | @@ -1554,6 +1554,12 @@ static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancel |
| 1554 | 1554 | fprintf(irp->f, "@testCancelRequested()"); |
| 1555 | 1555 | } |
| 1556 | 1556 | |
| 1557 | static void ir_print_spill(IrPrint *irp, IrInstructionSpill *instruction) { | |
| 1558 | fprintf(irp->f, "@spill("); | |
| 1559 | ir_print_other_instruction(irp, instruction->operand); | |
| 1560 | fprintf(irp->f, ")"); | |
| 1561 | } | |
| 1562 | ||
| 1557 | 1563 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1558 | 1564 | ir_print_prefix(irp, instruction); |
| 1559 | 1565 | switch (instruction->id) { |
| ... | ... | @@ -2039,6 +2045,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 2039 | 2045 | case IrInstructionIdTestCancelRequested: |
| 2040 | 2046 | ir_print_test_cancel_requested(irp, (IrInstructionTestCancelRequested *)instruction); |
| 2041 | 2047 | break; |
| 2048 | case IrInstructionIdSpill: | |
| 2049 | ir_print_spill(irp, (IrInstructionSpill *)instruction); | |
| 2050 | break; | |
| 2042 | 2051 | } |
| 2043 | 2052 | fprintf(irp->f, "\n"); |
| 2044 | 2053 | } |
test/stage1/behavior/coroutines.zig+29| ... | ... | @@ -613,3 +613,32 @@ test "cancel inside an errdefer" { |
| 613 | 613 | }; |
| 614 | 614 | S.doTheTest(); |
| 615 | 615 | } |
| 616 | ||
| 617 | test "combining try with errdefer cancel" { | |
| 618 | const S = struct { | |
| 619 | var frame: anyframe = undefined; | |
| 620 | var ok = false; | |
| 621 | ||
| 622 | fn doTheTest() void { | |
| 623 | _ = async amain(); | |
| 624 | resume frame; | |
| 625 | expect(ok); | |
| 626 | } | |
| 627 | ||
| 628 | fn amain() !void { | |
| 629 | var f = async func("https://example.com/"); | |
| 630 | errdefer cancel f; | |
| 631 | ||
| 632 | _ = try await f; | |
| 633 | } | |
| 634 | ||
| 635 | fn func(url: []const u8) ![]u8 { | |
| 636 | errdefer ok = true; | |
| 637 | frame = @frame(); | |
| 638 | suspend; | |
| 639 | return error.Bad; | |
| 640 | } | |
| 641 | ||
| 642 | }; | |
| 643 | S.doTheTest(); | |
| 644 | } |