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) {...@@ -6367,7 +6367,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
6367 IrInstGen *instruction = block->instruction_list.at(instr_i);6367 IrInstGen *instruction = block->instruction_list.at(instr_i);
6368 if (instruction->id == IrInstGenIdAwait ||6368 if (instruction->id == IrInstGenIdAwait ||
6369 instruction->id == IrInstGenIdVarPtr ||6369 instruction->id == IrInstGenIdVarPtr ||
6370 instruction->id == IrInstGenIdAlloca)6370 instruction->id == IrInstGenIdAlloca ||
6371 instruction->id == IrInstGenIdSpillBegin ||
6372 instruction->id == IrInstGenIdSpillEnd)
6371 {6373 {
6372 // This instruction does its own spilling specially, or otherwise doesn't need it.6374 // This instruction does its own spilling specially, or otherwise doesn't need it.
6373 continue;6375 continue;
src/codegen.cpp+22-9
...@@ -2561,7 +2561,12 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir...@@ -2561,7 +2561,12 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir
2561 LLVMBuildRet(g->builder, by_val_value);2561 LLVMBuildRet(g->builder, by_val_value);
2562 }2562 }
2563 } else if (instruction->operand == nullptr) {2563 } 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 }
2565 } else {2570 } else {
2566 LLVMValueRef value = ir_llvm_value(g, instruction->operand);2571 LLVMValueRef value = ir_llvm_value(g, instruction->operand);
2567 LLVMBuildRet(g->builder, value);2572 LLVMBuildRet(g->builder, value);
...@@ -5715,18 +5720,24 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex...@@ -5715,18 +5720,24 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex
5715 bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) &&5720 bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) &&
5716 g->errors_by_index.length > 1;5721 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
5725 ZigType *ptr_type = instruction->value->value->type;5723 ZigType *ptr_type = instruction->value->value->type;
5726 assert(ptr_type->id == ZigTypeIdPointer);5724 assert(ptr_type->id == ZigTypeIdPointer);
5727 ZigType *err_union_type = ptr_type->data.pointer.child_type;5725 ZigType *err_union_type = ptr_type->data.pointer.child_type;
5728 ZigType *payload_type = err_union_type->data.error_union.payload_type;5726 ZigType *payload_type = err_union_type->data.error_union.payload_type;
5729 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);5727 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
5730 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);5741 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
57315742
5732 if (!type_has_bits(err_union_type->data.error_union.err_set_type)) {5743 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...@@ -5741,7 +5752,6 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex
5741 } else {5752 } else {
5742 err_val = err_union_handle;5753 err_val = err_union_handle;
5743 }5754 }
5744 LLVMValueRef zero = LLVMConstNull(get_llvm_type(g, g->err_tag_type));
5745 LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");5755 LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
5746 LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");5756 LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
5747 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");5757 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
...@@ -5761,6 +5771,9 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex...@@ -5761,6 +5771,9 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutableGen *ex
5761 }5771 }
5762 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");5772 return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");
5763 } else {5773 } else {
5774 if (instruction->initializing) {
5775 gen_store_untyped(g, zero, err_union_ptr, 0, false);
5776 }
5764 return nullptr;5777 return nullptr;
5765 }5778 }
5766}5779}
src/ir.cpp+28-17
...@@ -5252,6 +5252,7 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,...@@ -5252,6 +5252,7 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
5252 return irb->codegen->invalid_inst_src;5252 return irb->codegen->invalid_inst_src;
5253 } else {5253 } else {
5254 return_value = ir_build_const_void(irb, scope, node);5254 return_value = ir_build_const_void(irb, scope, node);
5255 ir_build_end_expr(irb, scope, node, return_value, &result_loc_ret->base);
5255 }5256 }
52565257
5257 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value, result_loc_ret));5258 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,...@@ -5262,7 +5263,7 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
5262 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {5263 if (!have_err_defers && !irb->codegen->have_err_ret_tracing) {
5263 // only generate unconditional defers5264 // only generate unconditional defers
5264 ir_gen_defers_for_block(irb, scope, outer_scope, false);5265 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);
5266 result_loc_ret->base.source_instruction = result;5267 result_loc_ret->base.source_instruction = result;
5267 return result;5268 return result;
5268 }5269 }
...@@ -5271,10 +5272,6 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,...@@ -5271,10 +5272,6 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
5271 IrBasicBlockSrc *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");5272 IrBasicBlockSrc *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
5272 IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");5273 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
5278 IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);5275 IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true);
52795276
5280 IrInstSrc *is_comptime;5277 IrInstSrc *is_comptime;
...@@ -5288,22 +5285,18 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,...@@ -5288,22 +5285,18 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node,
5288 IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");5285 IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
52895286
5290 ir_set_cursor_at_end_and_append_block(irb, err_block);5287 ir_set_cursor_at_end_and_append_block(irb, err_block);
5291 if (have_err_defers) {5288 ir_gen_defers_for_block(irb, scope, outer_scope, true);
5292 ir_gen_defers_for_block(irb, scope, outer_scope, true);
5293 }
5294 if (irb->codegen->have_err_ret_tracing && !should_inline) {5289 if (irb->codegen->have_err_ret_tracing && !should_inline) {
5295 ir_build_save_err_ret_addr_src(irb, scope, node);5290 ir_build_save_err_ret_addr_src(irb, scope, node);
5296 }5291 }
5297 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);5292 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
52985293
5299 ir_set_cursor_at_end_and_append_block(irb, ok_block);5294 ir_set_cursor_at_end_and_append_block(irb, ok_block);
5300 if (have_err_defers) {5295 ir_gen_defers_for_block(irb, scope, outer_scope, false);
5301 ir_gen_defers_for_block(irb, scope, outer_scope, false);
5302 }
5303 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);5296 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
53045297
5305 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);5298 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);
5307 result_loc_ret->base.source_instruction = result;5300 result_loc_ret->base.source_instruction = result;
5308 return result;5301 return result;
5309 }5302 }
...@@ -9622,7 +9615,10 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *...@@ -9622,7 +9615,10 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
9622 }9615 }
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);
9626 if (err_union_ptr == irb->codegen->invalid_inst_src)9622 if (err_union_ptr == irb->codegen->invalid_inst_src)
9627 return irb->codegen->invalid_inst_src;9623 return irb->codegen->invalid_inst_src;
96289624
...@@ -9644,7 +9640,7 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *...@@ -9644,7 +9640,7 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
9644 is_comptime);9640 is_comptime);
96459641
9646 ir_set_cursor_at_end_and_append_block(irb, err_block);9642 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);
9648 Scope *err_scope;9644 Scope *err_scope;
9649 if (var_node) {9645 if (var_node) {
9650 assert(var_node->type == NodeTypeSymbol);9646 assert(var_node->type == NodeTypeSymbol);
...@@ -15497,6 +15493,12 @@ static IrInstGen *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira...@@ -15497,6 +15493,12 @@ static IrInstGen *ir_analyze_instruction_add_implicit_return_type(IrAnalyze *ira
15497}15493}
1549815494
15499static IrInstGen *ir_analyze_instruction_return(IrAnalyze *ira, IrInstSrcReturn *instruction) {15495static 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
15500 IrInstGen *operand = instruction->operand->child;15502 IrInstGen *operand = instruction->operand->child;
15501 if (type_is_invalid(operand->value->type))15503 if (type_is_invalid(operand->value->type))
15502 return ir_unreach_error(ira);15504 return ir_unreach_error(ira);
...@@ -29551,8 +29553,13 @@ static IrInstGen *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstSrcSp...@@ -29551,8 +29553,13 @@ static IrInstGen *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstSrcSp
29551 if (!type_has_bits(operand->value->type))29553 if (!type_has_bits(operand->value->type))
29552 return ir_const_void(ira, &instruction->base.base);29554 return ir_const_void(ira, &instruction->base.base);
2955329555
29554 ir_assert(instruction->spill_id == SpillIdRetErrCode, &instruction->base.base);29556 switch (instruction->spill_id) {
29555 ira->new_irb.exec->need_err_code_spill = true;29557 case SpillIdInvalid:
29558 zig_unreachable();
29559 case SpillIdRetErrCode:
29560 ira->new_irb.exec->need_err_code_spill = true;
29561 break;
29562 }
2955629563
29557 return ir_build_spill_begin_gen(ira, &instruction->base.base, operand, instruction->spill_id);29564 return ir_build_spill_begin_gen(ira, &instruction->base.base, operand, instruction->spill_id);
29558}29565}
...@@ -29562,8 +29569,12 @@ static IrInstGen *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstSrcSpil...@@ -29562,8 +29569,12 @@ static IrInstGen *ir_analyze_instruction_spill_end(IrAnalyze *ira, IrInstSrcSpil
29562 if (type_is_invalid(operand->value->type))29569 if (type_is_invalid(operand->value->type))
29563 return ira->codegen->invalid_inst_gen;29570 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 {
29566 return operand;29576 return operand;
29577 }
2956729578
29568 ir_assert(instruction->begin->base.child->id == IrInstGenIdSpillBegin, &instruction->base.base);29579 ir_assert(instruction->begin->base.child->id == IrInstGenIdSpillBegin, &instruction->base.base);
29569 IrInstGenSpillBegin *begin = reinterpret_cast<IrInstGenSpillBegin *>(instruction->begin->base.child);29580 IrInstGenSpillBegin *begin = reinterpret_cast<IrInstGenSpillBegin *>(instruction->begin->base.child);
test/stage1/behavior/async_fn.zig+41
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
5const expectError = std.testing.expectError;
56
6var global_x: i32 = 1;7var global_x: i32 = 1;
78
...@@ -1440,3 +1441,43 @@ test "properly spill optional payload capture value" {...@@ -1440,3 +1441,43 @@ test "properly spill optional payload capture value" {
1440 resume S.global_frame;1441 resume S.global_frame;
1441 expect(S.global_int == 1237);1442 expect(S.global_int == 1237);
1442}1443}
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}