diff --git a/src/codegen.cpp b/src/codegen.cpp index 1c677389c..5b8729292 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4059,6 +4059,8 @@ static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMV } static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrInstGenCall *instruction) { + Error err; + LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; LLVMValueRef fn_val; @@ -4089,6 +4091,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn ZigList gen_param_types = {}; 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; LLVMValueRef frame_result_loc_uncasted = nullptr; LLVMValueRef frame_result_loc; LLVMValueRef awaiter_init_val; @@ -4127,14 +4130,17 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn LLVMPositionBuilderAtEnd(g->builder, ok_block); } + need_frame_ptr_ptr_spill = true; 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); frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, anyframe_type), ""); } else { - ZigType *ptr_frame_type = get_pointer_to_type(g, - get_fn_frame_type(g, instruction->fn_entry), false); + ZigType *frame_type = get_fn_frame_type(g, instruction->fn_entry); + if ((err = type_resolve(g, frame_type, ResolveStatusLLVMFull))) + codegen_report_errors_and_exit(g); + ZigType *ptr_frame_type = get_pointer_to_type(g, frame_type, false); frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, ptr_frame_type), ""); } @@ -4405,6 +4411,11 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn } } + if (need_frame_ptr_ptr_spill) { + LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); + 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. diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index aa0f1f04e..4316b42d9 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -1371,3 +1371,25 @@ test "async function passed align(16) arg after align(8) arg" { resume S.global_frame; expect(S.global_int == 99); } + +test "async function call resolves target fn frame" { + 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; + return await @asyncCall(&stack_frame, {}, bar); + } + + fn bar() anyerror!void { + global_frame = @frame(); + suspend; + global_int += 1; + } + }; + _ = async S.foo(); + resume S.global_frame; + expect(S.global_int == 10); +}