diff options
| -rw-r--r-- | BRANCH_TODO | 4 | ||||
| -rw-r--r-- | src/codegen.cpp | 27 | ||||
| -rw-r--r-- | test/stage1/behavior/coroutines.zig | 42 |
3 files changed, 65 insertions, 8 deletions
diff --git a/BRANCH_TODO b/BRANCH_TODO index 6d6ae42529..92390f099f 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,3 +1,4 @@ + * struct types as the return type of an async function. make sure it works with return result locations. * compile error for error: expected anyframe->T, found 'anyframe' * compile error for error: expected anyframe->T, found 'i32' * await of a non async function @@ -15,5 +16,6 @@ * peer type resolution of *@Frame(func) and anyframe * peer type resolution of *@Frame(func) and anyframe->T when the return type matches * returning a value from within a suspend block - * struct types as the return type of an async function. make sure it works with return result locations. * make resuming inside a suspend block, with nothing after it, a must-tail call. + * make sure there are safety tests for all the new safety features (search the new PanicFnId enum values) + * error return tracing diff --git a/src/codegen.cpp b/src/codegen.cpp index f12880773b..b050e02e0a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -503,7 +503,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { // nothing to do } else if (type_is_nonnull_ptr(return_type)) { addLLVMAttr(llvm_fn, 0, "nonnull"); - } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { + } else if (!is_async && want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { // Sret pointers must not be address 0 addLLVMArgAttr(llvm_fn, 0, "nonnull"); addLLVMArgAttr(llvm_fn, 0, "sret"); @@ -3241,8 +3241,13 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, IrInstructionReturnPtr *instruction) { - src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type), - instruction->base.source_node); + if (!type_has_bits(instruction->base.value.type)) + return nullptr; + src_assert(g->cur_ret_ptr != nullptr, instruction->base.source_node); + if (fn_is_async(g->cur_fn)) { + LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_arg_start, ""); + return LLVMBuildLoad(g->builder, ptr_ptr, ""); + } return g->cur_ret_ptr; } @@ -3506,6 +3511,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (ret_has_bits) { ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start + 1, ""); } + + // Use the result location which is inside the frame if this is an async call. + if (ret_has_bits) { + LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, ""); + LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); + } } else if (callee_is_async) { frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_ret_ptr, @@ -3513,6 +3524,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (ret_has_bits) { ret_ptr = result_loc; } + + // Use the call instruction's result location. + if (ret_has_bits) { + LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, ""); + LLVMBuildStore(g->builder, result_loc, ret_ptr_ptr); + } } if (instruction->is_async || callee_is_async) { assert(frame_result_loc != nullptr); @@ -3525,10 +3542,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_awaiter_index, ""); LLVMBuildStore(g->builder, awaiter_init_val, awaiter_ptr); - if (ret_has_bits) { - LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_arg_start, ""); - LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); - } } if (!instruction->is_async && !callee_is_async) { if (first_arg_ret) { diff --git a/test/stage1/behavior/coroutines.zig b/test/stage1/behavior/coroutines.zig index b22f50c228..a1c1b7ad61 100644 --- a/test/stage1/behavior/coroutines.zig +++ b/test/stage1/behavior/coroutines.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; var global_x: i32 = 1; @@ -357,3 +358,44 @@ test "heap allocated async function frame" { }; try S.doTheTest(); } + +test "async function call return value" { + const S = struct { + var frame: anyframe = undefined; + var pt = Point{.x = 10, .y = 11 }; + + fn doTheTest() void { + expectEqual(pt.x, 10); + expectEqual(pt.y, 11); + _ = async first(); + expectEqual(pt.x, 10); + expectEqual(pt.y, 11); + resume frame; + expectEqual(pt.x, 1); + expectEqual(pt.y, 2); + } + + fn first() void { + pt = second(1, 2); + } + + fn second(x: i32, y: i32) Point { + return other(x, y); + } + + fn other(x: i32, y: i32) Point { + frame = @frame(); + suspend; + return Point{ + .x = x, + .y = y, + }; + } + + const Point = struct { + x: i32, + y: i32, + }; + }; + S.doTheTest(); +} |
