diff --git a/src/codegen.cpp b/src/codegen.cpp index 5b87292929..15a3ca7e95 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4092,6 +4092,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr; LLVMValueRef zero = LLVMConstNull(usize_type_ref); bool need_frame_ptr_ptr_spill = false; + ZigType *anyframe_type = nullptr; LLVMValueRef frame_result_loc_uncasted = nullptr; LLVMValueRef frame_result_loc; LLVMValueRef awaiter_init_val; @@ -4134,7 +4135,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, ""); LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, ""); if (instruction->fn_entry == nullptr) { - ZigType *anyframe_type = get_any_frame_type(g, src_return_type); + anyframe_type = get_any_frame_type(g, src_return_type); frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, anyframe_type), ""); } else { ZigType *frame_type = get_fn_frame_type(g, instruction->fn_entry); @@ -4416,11 +4417,14 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, ""); frame_result_loc_uncasted = LLVMBuildLoad(g->builder, frame_ptr_ptr, ""); } - if (frame_result_loc_uncasted != nullptr && instruction->fn_entry != nullptr) { - // Instead of a spill, we do the bitcast again. The uncasted LLVM IR instruction will - // be an Alloca from the entry block, so it does not need to be spilled. - frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, - LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), ""); + if (frame_result_loc_uncasted != nullptr) { + if (instruction->fn_entry != nullptr) { + frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, + LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), ""); + } else { + frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, + get_llvm_type(g, anyframe_type), ""); + } } LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index 4316b42d9d..4bfc4f4ee4 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1372,7 +1372,7 @@ test "async function passed align(16) arg after align(8) arg" { expect(S.global_int == 99); } -test "async function call resolves target fn frame" { +test "async function call resolves target fn frame, comptime func" { const S = struct { var global_frame: anyframe = undefined; var global_int: i32 = 9; @@ -1393,3 +1393,26 @@ test "async function call resolves target fn frame" { resume S.global_frame; expect(S.global_int == 10); } + +test "async function call resolves target fn frame, runtime func" { + const S = struct { + var global_frame: anyframe = undefined; + var global_int: i32 = 9; + + fn foo() anyerror!void { + const stack_size = 1000; + var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined; + var func: async fn () anyerror!void = bar; + return await @asyncCall(&stack_frame, {}, func); + } + + fn bar() anyerror!void { + global_frame = @frame(); + suspend; + global_int += 1; + } + }; + _ = async S.foo(); + resume S.global_frame; + expect(S.global_int == 10); +}