authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-09 17:19:28-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-09 17:19:28-05:00
log04ee3b01a159a25894f93d8448fb766ae545ab53
tree5f728a0597fa9c6d5203d7a7f63be466780c43f1
parent5b10d9f917ac773ca7c842d74ef44c861484670f
signaturelock-open Commit is signed but in an unrecognized format.

fix defer interfering with return value spill


4 files changed, 94 insertions(+), 27 deletions(-)

src/analyze.cpp+3-1
......@@ -6367,7 +6367,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
63676367 IrInstGen *instruction = block->instruction_list.at(instr_i);
63686368 if (instruction->id == IrInstGenIdAwait ||
63696369 instruction->id == IrInstGenIdVarPtr ||
6370 instruction->id == IrInstGenIdAlloca)
6370 instruction->id == IrInstGenIdAlloca ||
6371 instruction->id == IrInstGenIdSpillBegin ||
6372 instruction->id == IrInstGenIdSpillEnd)
63716373 {
63726374 // This instruction does its own spilling specially, or otherwise doesn't need it.
63736375 continue;
src/codegen.cpp+22-9
......@@ -2561,7 +2561,12 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir
25612561 LLVMBuildRet(g->builder, by_val_value);
25622562 }
25632563 } else if (instruction->operand == nullptr) {
2564 LLVMBuildRetVoid(g->builder);
2564 if (g->cur_ret_ptr == nullptr) {
2565 LLVMBuildRetVoid(g->builder);
2566 } else {
2567 LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, "");
2568 LLVMBuildRet(g->builder, by_val_value);
2569 }
25652570 } else {
25662571 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
25672572 LLVMBuildRet(g->builder, value);
......@@ -5715,18 +5720,24 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex
57155720 bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) &&
57165721 g->errors_by_index.length > 1;
57175722
5718 bool value_has_bits;
5719 if ((err = type_has_bits2(g, instruction->base.value->type, &value_has_bits)))
5720 codegen_report_errors_and_exit(g);
5721
5722 if (!want_safety && !value_has_bits)
5723 return nullptr;
5724
57255723 ZigType *ptr_type = instruction->value->value->type;
57265724 assert(ptr_type->id == ZigTypeIdPointer);
57275725 ZigType *err_union_type = ptr_type->data.pointer.child_type;
57285726 ZigType *payload_type = err_union_type->data.error_union.payload_type;
57295727 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
5728
5729 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type));
5730 bool value_has_bits;
5731 if ((err = type_has_bits2(g, instruction->base.value->type, &value_has_bits)))
5732 codegen_report_errors_and_exit(g);
5733 if (!want_safety && !value_has_bits) {
5734 if (instruction->initializing) {
5735 gen_store_untyped(g, zero, err_union_ptr, 0, false);
5736 }
5737 return nullptr;
5738 }
5739
5740
57305741 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
57315742
57325743 if (!type_has_bits(err_union_type->data.error_union.err_set_type)) {
......@@ -5741,7 +5752,6 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex
57415752 } else {
57425753 err_val = err_union_handle;
57435754 }
5744 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type));
57455755 LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
57465756 LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
57475757 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
......@@ -5761,6 +5771,9 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex
57615771 }
57625772 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");
57635773 } else {
5774 if (instruction->initializing) {
5775 gen_store_untyped(g, zero, err_union_ptr, 0, false);
5776 }
57645777 return nullptr;
57655778 }
57665779}
src/ir.cpp+28-17
......@@ -5252,6 +5252,7 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
52525252 return irb->codegen->invalid_inst_src;
52535253 } else {
52545254 return_value = ir_build_const_void(irb, scope, node);
5255 ir_build_end_expr(irb, scope, node, return_value, &result_loc_ret->base);
52555256 }
52565257
52575258 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value, result_loc_ret));
......@@ -5262,7 +5263,7 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
52625263 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {
52635264 // only generate unconditional defers
52645265 ir_gen_defers_for_block(irb, scope, outer_scope, false);
5265 IrInstSrc *result = ir_build_return_src(irb, scope, node, return_value);
5266 IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr);
52665267 result_loc_ret->base.source_instruction = result;
52675268 return result;
52685269 }
......@@ -5271,10 +5272,6 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
52715272 IrBasicBlockSrc *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
52725273 IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
52735274
5274 if (!have_err_defers) {
5275 ir_gen_defers_for_block(irb, scope, outer_scope, false);
5276 }
5277
52785275 IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);
52795276
52805277 IrInstSrc *is_comptime;
......@@ -5288,22 +5285,18 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
52885285 IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
52895286
52905287 ir_set_cursor_at_end_and_append_block(irb, err_block);
5291 if (have_err_defers) {
5292 ir_gen_defers_for_block(irb, scope, outer_scope, true);
5293 }
5288 ir_gen_defers_for_block(irb, scope, outer_scope, true);
52945289 if (irb->codegen->have_err_ret_tracing && !should_inline) {
52955290 ir_build_save_err_ret_addr_src(irb, scope, node);
52965291 }
52975292 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
52985293
52995294 ir_set_cursor_at_end_and_append_block(irb, ok_block);
5300 if (have_err_defers) {
5301 ir_gen_defers_for_block(irb, scope, outer_scope, false);
5302 }
5295 ir_gen_defers_for_block(irb, scope, outer_scope, false);
53035296 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
53045297
53055298 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
5306 IrInstSrc *result = ir_build_return_src(irb, scope, node, return_value);
5299 IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr);
53075300 result_loc_ret->base.source_instruction = result;
53085301 return result;
53095302 }
......@@ -9622,7 +9615,10 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
96229615 }
96239616
96249617
9625 IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr, nullptr);
9618 ScopeExpr *spill_scope = create_expr_scope(irb->codegen, op1_node, parent_scope);
9619 spill_scope->spill_harder = true;
9620
9621 IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, op1_node, &spill_scope->base, LValPtr, nullptr);
96269622 if (err_union_ptr == irb->codegen->invalid_inst_src)
96279623 return irb->codegen->invalid_inst_src;
96289624
......@@ -9644,7 +9640,7 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
96449640 is_comptime);
96459641
96469642 ir_set_cursor_at_end_and_append_block(irb, err_block);
9647 Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, parent_scope, is_comptime);
9643 Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime);
96489644 Scope *err_scope;
96499645 if (var_node) {
96509646 assert(var_node->type == NodeTypeSymbol);
......@@ -15497,6 +15493,12 @@ static IrInstGen *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira
1549715493}
1549815494
1549915495static IrInstGen *ir_analyze_instruction_return(IrAnalyze *ira, IrInstSrcReturn *instruction) {
15496 if (instruction->operand == nullptr) {
15497 // result location mechanism took care of it.
15498 IrInstGen *result = ir_build_return_gen(ira, &instruction->base.base, nullptr);
15499 return ir_finish_anal(ira, result);
15500 }
15501
1550015502 IrInstGen *operand = instruction->operand->child;
1550115503 if (type_is_invalid(operand->value->type))
1550215504 return ir_unreach_error(ira);
......@@ -29551,8 +29553,13 @@ static IrInstGen *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstSrcSp
2955129553 if (!type_has_bits(operand->value->type))
2955229554 return ir_const_void(ira, &instruction->base.base);
2955329555
29554 ir_assert(instruction->spill_id == SpillIdRetErrCode, &instruction->base.base);
29555 ira->new_irb.exec->need_err_code_spill = true;
29556 switch (instruction->spill_id) {
29557 case SpillIdInvalid:
29558 zig_unreachable();
29559 case SpillIdRetErrCode:
29560 ira->new_irb.exec->need_err_code_spill = true;
29561 break;
29562 }
2955629563
2955729564 return ir_build_spill_begin_gen(ira, &instruction->base.base, operand, instruction->spill_id);
2955829565}
......@@ -29562,8 +29569,12 @@ static IrInstGen *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstSrcSpil
2956229569 if (type_is_invalid(operand->value->type))
2956329570 return ira->codegen->invalid_inst_gen;
2956429571
29565 if (ir_should_inline(ira->old_irb.exec, instruction->base.base.scope) || !type_has_bits(operand->value->type))
29572 if (ir_should_inline(ira->old_irb.exec, instruction->base.base.scope) ||
29573 !type_has_bits(operand->value->type) ||
29574 instr_is_comptime(operand))
29575 {
2956629576 return operand;
29577 }
2956729578
2956829579 ir_assert(instruction->begin->base.child->id == IrInstGenIdSpillBegin, &instruction->base.base);
2956929580 IrInstGenSpillBegin *begin = reinterpret_cast<IrInstGenSpillBegin *>(instruction->begin->base.child);
test/stage1/behavior/async_fn.zig+41
......@@ -2,6 +2,7 @@ const std = @import("std");
22const builtin = @import("builtin");
33const expect = std.testing.expect;
44const expectEqual = std.testing.expectEqual;
5const expectError = std.testing.expectError;
56
67var global_x: i32 = 1;
78
......@@ -1440,3 +1441,43 @@ test "properly spill optional payload capture value" {
14401441 resume S.global_frame;
14411442 expect(S.global_int == 1237);
14421443}
1444
1445test "handle defer interfering with return value spill" {
1446 const S = struct {
1447 var global_frame1: anyframe = undefined;
1448 var global_frame2: anyframe = undefined;
1449 var finished = false;
1450 var baz_happened = false;
1451
1452 fn doTheTest() void {
1453 _ = async testFoo();
1454 resume global_frame1;
1455 resume global_frame2;
1456 expect(baz_happened);
1457 expect(finished);
1458 }
1459
1460 fn testFoo() void {
1461 expectError(error.Bad, foo());
1462 finished = true;
1463 }
1464
1465 fn foo() anyerror!void {
1466 defer baz();
1467 return bar() catch |err| return err;
1468 }
1469
1470 fn bar() anyerror!void {
1471 global_frame1 = @frame();
1472 suspend;
1473 return error.Bad;
1474 }
1475
1476 fn baz() void {
1477 global_frame2 = @frame();
1478 suspend;
1479 baz_happened = true;
1480 }
1481 };
1482 S.doTheTest();
1483}