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 {
23662366 IrInstructionIdAwaitGen,
23672367 IrInstructionIdCoroResume,
23682368 IrInstructionIdTestCancelRequested,
2369 IrInstructionIdSpill,
23692370};
23702371
23712372struct IrInstruction {
......@@ -3643,6 +3644,18 @@ struct IrInstructionTestCancelRequested {
36433644 IrInstruction base;
36443645};
36453646
3647enum SpillId {
3648 SpillIdInvalid,
3649 SpillIdRetErrCode,
3650};
3651
3652struct IrInstructionSpill {
3653 IrInstruction base;
3654
3655 SpillId spill_id;
3656 IrInstruction *operand;
3657};
3658
36463659enum ResultLocId {
36473660 ResultLocIdInvalid,
36483661 ResultLocIdNone,
src/codegen.cpp+36-9
......@@ -5113,17 +5113,9 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
51135113 return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
51145114}
51155115
5116static 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);
5116static LLVMValueRef gen_unwrap_err_code(CodeGen *g, LLVMValueRef err_union_ptr, ZigType *ptr_type) {
51245117 ZigType *err_union_type = ptr_type->data.pointer.child_type;
51255118 ZigType *payload_type = err_union_type->data.error_union.payload_type;
5126 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr);
51275119 if (!type_has_bits(payload_type)) {
51285120 return err_union_ptr;
51295121 } else {
......@@ -5133,6 +5125,18 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
51335125 }
51345126}
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
51365140static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,
51375141 IrInstructionUnwrapErrPayload *instruction)
51385142{
......@@ -5611,6 +5615,27 @@ static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *ex
56115615 }
56125616}
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
56145639static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
56155640 AstNode *source_node = instruction->source_node;
56165641 Scope *scope = instruction->scope;
......@@ -5866,6 +5891,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
58665891 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);
58675892 case IrInstructionIdTestCancelRequested:
58685893 return ir_render_test_cancel_requested(g, executable, (IrInstructionTestCancelRequested *)instruction);
5894 case IrInstructionIdSpill:
5895 return ir_render_spill(g, executable, (IrInstructionSpill *)instruction);
58695896 }
58705897 zig_unreachable();
58715898}
src/ir.cpp+33
......@@ -1066,6 +1066,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelReques
10661066 return IrInstructionIdTestCancelRequested;
10671067}
10681068
1069static constexpr IrInstructionId ir_instruction_id(IrInstructionSpill *) {
1070 return IrInstructionIdSpill;
1071}
1072
10691073template<typename T>
10701074static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
10711075 T *special_instruction = allocate<T>(1);
......@@ -3332,6 +3336,18 @@ static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scop
33323336 return &instruction->base;
33333337}
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
33353351static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
33363352 results[ReturnKindUnconditional] = 0;
33373353 results[ReturnKindError] = 0;
......@@ -3591,6 +3607,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
35913607 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
35923608 result_loc_ret->base.id = ResultLocIdReturn;
35933609 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3610 err_val = ir_build_spill(irb, scope, node, err_val, SpillIdRetErrCode);
35943611 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
35953612
35963613 if (irb->codegen->have_err_ret_tracing && !should_inline) {
......@@ -24725,6 +24742,19 @@ static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ir
2472524742 return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
2472624743}
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
2472824758static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {
2472924759 switch (instruction->id) {
2473024760 case IrInstructionIdInvalid:
......@@ -25024,6 +25054,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2502425054 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);
2502525055 case IrInstructionIdTestCancelRequested:
2502625056 return ir_analyze_instruction_test_cancel_requested(ira, (IrInstructionTestCancelRequested *)instruction);
25057 case IrInstructionIdSpill:
25058 return ir_analyze_instruction_spill(ira, (IrInstructionSpill *)instruction);
2502725059 }
2502825060 zig_unreachable();
2502925061}
......@@ -25259,6 +25291,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2525925291 case IrInstructionIdAllocaSrc:
2526025292 case IrInstructionIdAllocaGen:
2526125293 case IrInstructionIdTestCancelRequested:
25294 case IrInstructionIdSpill:
2526225295 return false;
2526325296
2526425297 case IrInstructionIdAsm:
src/ir_print.cpp+9
......@@ -1554,6 +1554,12 @@ static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancel
15541554 fprintf(irp->f, "@testCancelRequested()");
15551555}
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
15571563static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15581564 ir_print_prefix(irp, instruction);
15591565 switch (instruction->id) {
......@@ -2039,6 +2045,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
20392045 case IrInstructionIdTestCancelRequested:
20402046 ir_print_test_cancel_requested(irp, (IrInstructionTestCancelRequested *)instruction);
20412047 break;
2048 case IrInstructionIdSpill:
2049 ir_print_spill(irp, (IrInstructionSpill *)instruction);
2050 break;
20422051 }
20432052 fprintf(irp->f, "\n");
20442053}
test/stage1/behavior/coroutines.zig+29
......@@ -613,3 +613,32 @@ test "cancel inside an errdefer" {
613613 };
614614 S.doTheTest();
615615}
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}