authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-10 15:20:08-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-10 15:20:08-04:00
log22428a75462e01877181501801dce4c090a87e9c
tree36affbe0da86d106bd7f6f4091dfb6e95fe461cc
parentb9d1d45dfd0f704bc762732c23aa2844f1d14e8d
signaturelock-open Commit is signed but in an unrecognized format.

fix try in an async function with error union and non-zero-bit payload


6 files changed, 187 insertions(+), 57 deletions(-)

src/all_types.hpp+11-2
......@@ -74,6 +74,7 @@ struct IrExecutable {
7474 bool invalid;
7575 bool is_inline;
7676 bool is_generic_instantiation;
77 bool need_err_code_spill;
7778};
7879
7980enum OutType {
......@@ -1384,6 +1385,7 @@ struct ZigFn {
13841385 size_t prealloc_backward_branch_quota;
13851386 AstNode **param_source_nodes;
13861387 Buf **param_names;
1388 IrInstruction *err_code_spill;
13871389
13881390 AstNode *fn_no_inline_set_node;
13891391 AstNode *fn_static_eval_set_node;
......@@ -2366,7 +2368,8 @@ enum IrInstructionId {
23662368 IrInstructionIdAwaitGen,
23672369 IrInstructionIdCoroResume,
23682370 IrInstructionIdTestCancelRequested,
2369 IrInstructionIdSpill,
2371 IrInstructionIdSpillBegin,
2372 IrInstructionIdSpillEnd,
23702373};
23712374
23722375struct IrInstruction {
......@@ -3649,13 +3652,19 @@ enum SpillId {
36493652 SpillIdRetErrCode,
36503653};
36513654
3652struct IrInstructionSpill {
3655struct IrInstructionSpillBegin {
36533656 IrInstruction base;
36543657
36553658 SpillId spill_id;
36563659 IrInstruction *operand;
36573660};
36583661
3662struct IrInstructionSpillEnd {
3663 IrInstruction base;
3664
3665 IrInstructionSpillBegin *begin;
3666};
3667
36593668enum ResultLocId {
36603669 ResultLocIdInvalid,
36613670 ResultLocIdNone,
src/analyze.cpp+12
......@@ -5190,6 +5190,18 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
51905190 }
51915191 ZigType *fn_type = get_async_fn_type(g, fn->type_entry);
51925192
5193 if (fn->analyzed_executable.need_err_code_spill) {
5194 IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
5195 alloca_gen->base.id = IrInstructionIdAllocaGen;
5196 alloca_gen->base.source_node = fn->proto_node;
5197 alloca_gen->base.scope = fn->child_scope;
5198 alloca_gen->base.value.type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
5199 alloca_gen->base.ref_count = 1;
5200 alloca_gen->name_hint = "";
5201 fn->alloca_gen_list.append(alloca_gen);
5202 fn->err_code_spill = &alloca_gen->base;
5203 }
5204
51935205 for (size_t i = 0; i < fn->call_list.length; i += 1) {
51945206 IrInstructionCallGen *call = fn->call_list.at(i);
51955207 ZigFn *callee = call->fn_entry;
src/codegen.cpp+44-31
......@@ -2274,16 +2274,16 @@ static LLVMValueRef gen_maybe_atomic_op(CodeGen *g, LLVMAtomicRMWBinOp op, LLVMV
22742274static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,
22752275 IrInstructionReturnBegin *instruction)
22762276{
2277 bool ret_type_has_bits = instruction->operand != nullptr &&
2278 type_has_bits(instruction->operand->value.type);
2279
2277 ZigType *operand_type = (instruction->operand != nullptr) ? instruction->operand->value.type : nullptr;
2278 bool operand_has_bits = (operand_type != nullptr) && type_has_bits(operand_type);
22802279 if (!fn_is_async(g->cur_fn)) {
2281 return ret_type_has_bits ? ir_llvm_value(g, instruction->operand) : nullptr;
2280 return operand_has_bits ? ir_llvm_value(g, instruction->operand) : nullptr;
22822281 }
22832282
2283 ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
2284 bool ret_type_has_bits = type_has_bits(ret_type);
22842285 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
22852286
2286 ZigType *ret_type = ret_type_has_bits ? instruction->operand->value.type : nullptr;
22872287 if (ret_type_has_bits && !handle_is_ptr(ret_type)) {
22882288 // It's a scalar, so it didn't get written to the result ptr. Do that before the atomic rmw.
22892289 LLVMBuildStore(g->builder, ir_llvm_value(g, instruction->operand), g->cur_ret_ptr);
......@@ -2333,11 +2333,11 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable,
23332333 g->cur_is_after_return = true;
23342334 LLVMBuildStore(g->builder, g->cur_async_prev_val, g->cur_async_prev_val_field_ptr);
23352335
2336 if (!ret_type_has_bits) {
2336 if (!operand_has_bits) {
23372337 return nullptr;
23382338 }
23392339
2340 return get_handle_value(g, g->cur_ret_ptr, ret_type, get_pointer_to_type(g, ret_type, true));
2340 return get_handle_value(g, g->cur_ret_ptr, operand_type, get_pointer_to_type(g, operand_type, true));
23412341}
23422342
23432343static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *instruction) {
......@@ -5113,18 +5113,6 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
51135113 return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
51145114}
51155115
5116static LLVMValueRef gen_unwrap_err_code(CodeGen *g, LLVMValueRef err_union_ptr, ZigType *ptr_type) {
5117 ZigType *err_union_type = ptr_type->data.pointer.child_type;
5118 ZigType *payload_type = err_union_type->data.error_union.payload_type;
5119 if (!type_has_bits(payload_type)) {
5120 return err_union_ptr;
5121 } else {
5122 // TODO assign undef to the payload
5123 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
5124 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
5125 }
5126}
5127
51285116static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable,
51295117 IrInstructionUnwrapErrCode *instruction)
51305118{
......@@ -5133,8 +5121,16 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
51335121
51345122 ZigType *ptr_type = instruction->err_union_ptr->value.type;
51355123 assert(ptr_type->id == ZigTypeIdPointer);
5124 ZigType *err_union_type = ptr_type->data.pointer.child_type;
5125 ZigType *payload_type = err_union_type->data.error_union.payload_type;
51365126 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr);
5137 return gen_unwrap_err_code(g, err_union_ptr, ptr_type);
5127 if (!type_has_bits(payload_type)) {
5128 return err_union_ptr;
5129 } else {
5130 // TODO assign undef to the payload
5131 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
5132 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
5133 }
51385134}
51395135
51405136static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,
......@@ -5615,21 +5611,36 @@ static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *ex
56155611 }
56165612}
56175613
5618static LLVMValueRef ir_render_spill(CodeGen *g, IrExecutable *executable, IrInstructionSpill *instruction) {
5614static LLVMValueRef ir_render_spill_begin(CodeGen *g, IrExecutable *executable,
5615 IrInstructionSpillBegin *instruction)
5616{
56195617 if (!fn_is_async(g->cur_fn))
5620 return ir_llvm_value(g, instruction->operand);
5618 return nullptr;
56215619
56225620 switch (instruction->spill_id) {
56235621 case SpillIdInvalid:
56245622 zig_unreachable();
56255623 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 }
5624 LLVMValueRef operand = ir_llvm_value(g, instruction->operand);
5625 LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill);
5626 LLVMBuildStore(g->builder, operand, ptr);
5627 return nullptr;
5628 }
5629
5630 }
5631 zig_unreachable();
5632}
5633
5634static LLVMValueRef ir_render_spill_end(CodeGen *g, IrExecutable *executable, IrInstructionSpillEnd *instruction) {
5635 if (!fn_is_async(g->cur_fn))
5636 return ir_llvm_value(g, instruction->begin->operand);
5637
5638 switch (instruction->begin->spill_id) {
5639 case SpillIdInvalid:
5640 zig_unreachable();
5641 case SpillIdRetErrCode: {
5642 LLVMValueRef ptr = ir_llvm_value(g, g->cur_fn->err_code_spill);
5643 return LLVMBuildLoad(g->builder, ptr, "");
56335644 }
56345645
56355646 }
......@@ -5891,8 +5902,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
58915902 return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction);
58925903 case IrInstructionIdTestCancelRequested:
58935904 return ir_render_test_cancel_requested(g, executable, (IrInstructionTestCancelRequested *)instruction);
5894 case IrInstructionIdSpill:
5895 return ir_render_spill(g, executable, (IrInstructionSpill *)instruction);
5905 case IrInstructionIdSpillBegin:
5906 return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction);
5907 case IrInstructionIdSpillEnd:
5908 return ir_render_spill_end(g, executable, (IrInstructionSpillEnd *)instruction);
58965909 }
58975910 zig_unreachable();
58985911}
src/ir.cpp+77-20
......@@ -1066,8 +1066,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelReques
10661066 return IrInstructionIdTestCancelRequested;
10671067}
10681068
1069static constexpr IrInstructionId ir_instruction_id(IrInstructionSpill *) {
1070 return IrInstructionIdSpill;
1069static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillBegin *) {
1070 return IrInstructionIdSpillBegin;
1071}
1072
1073static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) {
1074 return IrInstructionIdSpillEnd;
10711075}
10721076
10731077template<typename T>
......@@ -3336,15 +3340,28 @@ static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scop
33363340 return &instruction->base;
33373341}
33383342
3339static IrInstruction *ir_build_spill(IrBuilder *irb, Scope *scope, AstNode *source_node,
3343static IrInstructionSpillBegin *ir_build_spill_begin(IrBuilder *irb, Scope *scope, AstNode *source_node,
33403344 IrInstruction *operand, SpillId spill_id)
33413345{
3342 IrInstructionSpill *instruction = ir_build_instruction<IrInstructionSpill>(irb, scope, source_node);
3346 IrInstructionSpillBegin *instruction = ir_build_instruction<IrInstructionSpillBegin>(irb, scope, source_node);
3347 instruction->base.value.special = ConstValSpecialStatic;
3348 instruction->base.value.type = irb->codegen->builtin_types.entry_void;
33433349 instruction->operand = operand;
33443350 instruction->spill_id = spill_id;
33453351
33463352 ir_ref_instruction(operand, irb->current_basic_block);
33473353
3354 return instruction;
3355}
3356
3357static IrInstruction *ir_build_spill_end(IrBuilder *irb, Scope *scope, AstNode *source_node,
3358 IrInstructionSpillBegin *begin)
3359{
3360 IrInstructionSpillEnd *instruction = ir_build_instruction<IrInstructionSpillEnd>(irb, scope, source_node);
3361 instruction->begin = begin;
3362
3363 ir_ref_instruction(&begin->base, irb->current_basic_block);
3364
33483365 return &instruction->base;
33493366}
33503367
......@@ -3602,14 +3619,15 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
36023619 IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
36033620 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
36043621 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val));
3605 err_val = ir_build_return_begin(irb, scope, node, err_val);
3622 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
3623 SpillIdRetErrCode);
3624 ir_build_return_begin(irb, scope, node, err_val);
3625 err_val = ir_build_spill_end(irb, scope, node, spill_begin);
3626 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3627 result_loc_ret->base.id = ResultLocIdReturn;
3628 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3629 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
36063630 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
3607 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3608 result_loc_ret->base.id = ResultLocIdReturn;
3609 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3610 err_val = ir_build_spill(irb, scope, node, err_val, SpillIdRetErrCode);
3611 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
3612
36133631 if (irb->codegen->have_err_ret_tracing && !should_inline) {
36143632 ir_build_save_err_ret_addr(irb, scope, node);
36153633 }
......@@ -12778,8 +12796,21 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
1277812796 return ir_finish_anal(ira, result);
1277912797 }
1278012798
12799 // This cast might have been already done from IrInstructionReturnBegin but it also
12800 // might not have, in the case of `try`.
12801 IrInstruction *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type);
12802 if (type_is_invalid(casted_operand->value.type)) {
12803 AstNode *source_node = ira->explicit_return_type_source_node;
12804 if (source_node != nullptr) {
12805 ErrorMsg *msg = ira->codegen->errors.last();
12806 add_error_note(ira->codegen, msg, source_node,
12807 buf_sprintf("return type declared here"));
12808 }
12809 return ir_unreach_error(ira);
12810 }
12811
1278112812 IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
12782 instruction->base.source_node, operand);
12813 instruction->base.source_node, casted_operand);
1278312814 result->value.type = ira->codegen->builtin_types.entry_unreachable;
1278412815 return ir_finish_anal(ira, result);
1278512816}
......@@ -24742,15 +24773,38 @@ static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ir
2474224773 return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
2474324774}
2474424775
24745static IrInstruction *ir_analyze_instruction_spill(IrAnalyze *ira, IrInstructionSpill *instruction) {
24776static IrInstruction *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstructionSpillBegin *instruction) {
24777 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope))
24778 return ir_const_void(ira, &instruction->base);
24779
2474624780 IrInstruction *operand = instruction->operand->child;
2474724781 if (type_is_invalid(operand->value.type))
2474824782 return ira->codegen->invalid_instruction;
24749 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) {
24783
24784 if (!type_has_bits(operand->value.type))
24785 return ir_const_void(ira, &instruction->base);
24786
24787 ir_assert(instruction->spill_id == SpillIdRetErrCode, &instruction->base);
24788 ira->new_irb.exec->need_err_code_spill = true;
24789
24790 IrInstructionSpillBegin *result = ir_build_spill_begin(&ira->new_irb, instruction->base.scope,
24791 instruction->base.source_node, operand, instruction->spill_id);
24792 return &result->base;
24793}
24794
24795static IrInstruction *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstructionSpillEnd *instruction) {
24796 IrInstruction *operand = instruction->begin->operand->child;
24797 if (type_is_invalid(operand->value.type))
24798 return ira->codegen->invalid_instruction;
24799
24800 if (ir_should_inline(ira->new_irb.exec, instruction->base.scope) || !type_has_bits(operand->value.type))
2475024801 return operand;
24751 }
24752 IrInstruction *result = ir_build_spill(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
24753 operand, instruction->spill_id);
24802
24803 ir_assert(instruction->begin->base.child->id == IrInstructionIdSpillBegin, &instruction->base);
24804 IrInstructionSpillBegin *begin = reinterpret_cast<IrInstructionSpillBegin *>(instruction->begin->base.child);
24805
24806 IrInstruction *result = ir_build_spill_end(&ira->new_irb, instruction->base.scope,
24807 instruction->base.source_node, begin);
2475424808 result->value.type = operand->value.type;
2475524809 return result;
2475624810}
......@@ -25054,8 +25108,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2505425108 return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction);
2505525109 case IrInstructionIdTestCancelRequested:
2505625110 return ir_analyze_instruction_test_cancel_requested(ira, (IrInstructionTestCancelRequested *)instruction);
25057 case IrInstructionIdSpill:
25058 return ir_analyze_instruction_spill(ira, (IrInstructionSpill *)instruction);
25111 case IrInstructionIdSpillBegin:
25112 return ir_analyze_instruction_spill_begin(ira, (IrInstructionSpillBegin *)instruction);
25113 case IrInstructionIdSpillEnd:
25114 return ir_analyze_instruction_spill_end(ira, (IrInstructionSpillEnd *)instruction);
2505925115 }
2506025116 zig_unreachable();
2506125117}
......@@ -25193,6 +25249,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2519325249 case IrInstructionIdCoroResume:
2519425250 case IrInstructionIdAwaitSrc:
2519525251 case IrInstructionIdAwaitGen:
25252 case IrInstructionIdSpillBegin:
2519625253 return true;
2519725254
2519825255 case IrInstructionIdPhi:
......@@ -25291,7 +25348,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2529125348 case IrInstructionIdAllocaSrc:
2529225349 case IrInstructionIdAllocaGen:
2529325350 case IrInstructionIdTestCancelRequested:
25294 case IrInstructionIdSpill:
25351 case IrInstructionIdSpillEnd:
2529525352 return false;
2529625353
2529725354 case IrInstructionIdAsm:
src/ir_print.cpp+13-4
......@@ -1554,12 +1554,18 @@ 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(");
1557static void ir_print_spill_begin(IrPrint *irp, IrInstructionSpillBegin *instruction) {
1558 fprintf(irp->f, "@spillBegin(");
15591559 ir_print_other_instruction(irp, instruction->operand);
15601560 fprintf(irp->f, ")");
15611561}
15621562
1563static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) {
1564 fprintf(irp->f, "@spillEnd(");
1565 ir_print_other_instruction(irp, &instruction->begin->base);
1566 fprintf(irp->f, ")");
1567}
1568
15631569static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
15641570 ir_print_prefix(irp, instruction);
15651571 switch (instruction->id) {
......@@ -2045,8 +2051,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
20452051 case IrInstructionIdTestCancelRequested:
20462052 ir_print_test_cancel_requested(irp, (IrInstructionTestCancelRequested *)instruction);
20472053 break;
2048 case IrInstructionIdSpill:
2049 ir_print_spill(irp, (IrInstructionSpill *)instruction);
2054 case IrInstructionIdSpillBegin:
2055 ir_print_spill_begin(irp, (IrInstructionSpillBegin *)instruction);
2056 break;
2057 case IrInstructionIdSpillEnd:
2058 ir_print_spill_end(irp, (IrInstructionSpillEnd *)instruction);
20502059 break;
20512060 }
20522061 fprintf(irp->f, "\n");
test/stage1/behavior/coroutines.zig+30
......@@ -642,3 +642,33 @@ test "combining try with errdefer cancel" {
642642 };
643643 S.doTheTest();
644644}
645
646test "try in an async function with error union and non-zero-bit payload" {
647 const S = struct {
648 var frame: anyframe = undefined;
649 var ok = false;
650
651 fn doTheTest() void {
652 _ = async amain();
653 resume frame;
654 expect(ok);
655 }
656
657 fn amain() void {
658 std.testing.expectError(error.Bad, theProblem());
659 ok = true;
660 }
661
662 fn theProblem() ![]u8 {
663 frame = @frame();
664 suspend;
665 const result = try other();
666 return result;
667 }
668
669 fn other() ![]u8 {
670 return error.Bad;
671 }
672 };
673 S.doTheTest();
674}