authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-09 21:49:40-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-09 21:49:40-04:00
logb9d1d45dfd0f704bc762732c23aa2844f1d14e8d
tree5253c503cfe54656910e5fcc5d335a1f58cf00ff
parent2e7f53f1f0d8339b8dc90ad7e0bc9963f1ec471c
signaturelock-open Commit is signed but in an unrecognized format.

fix combining try with errdefer cancel


5 files changed, 120 insertions(+), 9 deletions(-)

src/all_types.hpp+13
...@@ -2366,6 +2366,7 @@ enum IrInstructionId {...@@ -2366,6 +2366,7 @@ enum IrInstructionId {
2366 IrInstructionIdAwaitGen,2366 IrInstructionIdAwaitGen,
2367 IrInstructionIdCoroResume,2367 IrInstructionIdCoroResume,
2368 IrInstructionIdTestCancelRequested,2368 IrInstructionIdTestCancelRequested,
2369 IrInstructionIdSpill,
2369};2370};
23702371
2371struct IrInstruction {2372struct IrInstruction {
...@@ -3643,6 +3644,18 @@ struct IrInstructionTestCancelRequested {...@@ -3643,6 +3644,18 @@ struct IrInstructionTestCancelRequested {
3643 IrInstruction base;3644 IrInstruction base;
3644};3645};
36453646
3647enum SpillId {
3648 SpillIdInvalid,
3649 SpillIdRetErrCode,
3650};
3651
3652struct IrInstructionSpill {
3653 IrInstruction base;
3654
3655 SpillId spill_id;
3656 IrInstruction *operand;
3657};
3658
3646enum ResultLocId {3659enum ResultLocId {
3647 ResultLocIdInvalid,3660 ResultLocIdInvalid,
3648 ResultLocIdNone,3661 ResultLocIdNone,
src/codegen.cpp+36-9
...@@ -5113,17 +5113,9 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI...@@ -5113,17 +5113,9 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
5113 return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");5113 return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
5114}5114}
51155115
5116static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable,5116static LLVMValueRef gen_unwrap_err_code(CodeGen *g, LLVMValueRef err_union_ptr, ZigType *ptr_type) {
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);
5124 ZigType *err_union_type = ptr_type->data.pointer.child_type;5117 ZigType *err_union_type = ptr_type->data.pointer.child_type;
5125 ZigType *payload_type = err_union_type->data.error_union.payload_type;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 if (!type_has_bits(payload_type)) {5119 if (!type_has_bits(payload_type)) {
5128 return err_union_ptr;5120 return err_union_ptr;
5129 } else {5121 } else {
...@@ -5133,6 +5125,18 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab...@@ -5133,6 +5125,18 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
5133 }5125 }
5134}5126}
51355127
5128static 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
5136static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,5140static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,
5137 IrInstructionUnwrapErrPayload *instruction)5141 IrInstructionUnwrapErrPayload *instruction)
5138{5142{
...@@ -5611,6 +5615,27 @@ static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *ex...@@ -5611,6 +5615,27 @@ static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *ex
5611 }5615 }
5612}5616}
56135617
5618static 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
5614static void set_debug_location(CodeGen *g, IrInstruction *instruction) {5639static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
5615 AstNode *source_node = instruction->source_node;5640 AstNode *source_node = instruction->source_node;
5616 Scope *scope = instruction->scope;5641 Scope *scope = instruction->scope;
...@@ -5866,6 +5891,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5866,6 +5891,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5866 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);5891 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);
5867 case IrInstructionIdTestCancelRequested:5892 case IrInstructionIdTestCancelRequested:
5868 return ir_render_test_cancel_requested(g, executable, (IrInstructionTestCancelRequested *)instruction);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 zig_unreachable();5897 zig_unreachable();
5871}5898}
src/ir.cpp+33
...@@ -1066,6 +1066,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelReques...@@ -1066,6 +1066,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelReques
1066 return IrInstructionIdTestCancelRequested;1066 return IrInstructionIdTestCancelRequested;
1067}1067}
10681068
1069static constexpr IrInstructionId ir_instruction_id(IrInstructionSpill *) {
1070 return IrInstructionIdSpill;
1071}
1072
1069template<typename T>1073template<typename T>
1070static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {1074static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1071 T *special_instruction = allocate<T>(1);1075 T *special_instruction = allocate<T>(1);
...@@ -3332,6 +3336,18 @@ static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scop...@@ -3332,6 +3336,18 @@ static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scop
3332 return &instruction->base;3336 return &instruction->base;
3333}3337}
33343338
3339static 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
3335static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {3351static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
3336 results[ReturnKindUnconditional] = 0;3352 results[ReturnKindUnconditional] = 0;
3337 results[ReturnKindError] = 0;3353 results[ReturnKindError] = 0;
...@@ -3591,6 +3607,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3591,6 +3607,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3591 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);3607 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3592 result_loc_ret->base.id = ResultLocIdReturn;3608 result_loc_ret->base.id = ResultLocIdReturn;
3593 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);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 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);3611 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
35953612
3596 if (irb->codegen->have_err_ret_tracing && !should_inline) {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,6 +24742,19 @@ static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ir
24725 return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node);24742 return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
24726}24743}
2472724744
24745static 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
24728static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {24758static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
24729 switch (instruction->id) {24759 switch (instruction->id) {
24730 case IrInstructionIdInvalid:24760 case IrInstructionIdInvalid:
...@@ -25024,6 +25054,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25024,6 +25054,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25024 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);25054 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);
25025 case IrInstructionIdTestCancelRequested:25055 case IrInstructionIdTestCancelRequested:
25026 return ir_analyze_instruction_test_cancel_requested(ira, (IrInstructionTestCancelRequested *)instruction);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 zig_unreachable();25060 zig_unreachable();
25029}25061}
...@@ -25259,6 +25291,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25259,6 +25291,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25259 case IrInstructionIdAllocaSrc:25291 case IrInstructionIdAllocaSrc:
25260 case IrInstructionIdAllocaGen:25292 case IrInstructionIdAllocaGen:
25261 case IrInstructionIdTestCancelRequested:25293 case IrInstructionIdTestCancelRequested:
25294 case IrInstructionIdSpill:
25262 return false;25295 return false;
2526325296
25264 case IrInstructionIdAsm:25297 case IrInstructionIdAsm:
src/ir_print.cpp+9
...@@ -1554,6 +1554,12 @@ static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancel...@@ -1554,6 +1554,12 @@ static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancel
1554 fprintf(irp->f, "@testCancelRequested()");1554 fprintf(irp->f, "@testCancelRequested()");
1555}1555}
15561556
1557static 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
1557static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1563static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1558 ir_print_prefix(irp, instruction);1564 ir_print_prefix(irp, instruction);
1559 switch (instruction->id) {1565 switch (instruction->id) {
...@@ -2039,6 +2045,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2039,6 +2045,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2039 case IrInstructionIdTestCancelRequested:2045 case IrInstructionIdTestCancelRequested:
2040 ir_print_test_cancel_requested(irp, (IrInstructionTestCancelRequested *)instruction);2046 ir_print_test_cancel_requested(irp, (IrInstructionTestCancelRequested *)instruction);
2041 break;2047 break;
2048 case IrInstructionIdSpill:
2049 ir_print_spill(irp, (IrInstructionSpill *)instruction);
2050 break;
2042 }2051 }
2043 fprintf(irp->f, "\n");2052 fprintf(irp->f, "\n");
2044}2053}
test/stage1/behavior/coroutines.zig+29
...@@ -613,3 +613,32 @@ test "cancel inside an errdefer" {...@@ -613,3 +613,32 @@ test "cancel inside an errdefer" {
613 };613 };
614 S.doTheTest();614 S.doTheTest();
615}615}
616
617test "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}