Commit ee1a4f4c1d
Changed files (6)
src/all_types.hpp
@@ -3037,7 +3037,8 @@ struct IrInstructionMergeErrRetTraces {
IrInstruction base;
IrInstruction *coro_promise_ptr;
- IrInstruction *err_ret_trace_ptr;
+ IrInstruction *src_err_ret_trace_ptr;
+ IrInstruction *dest_err_ret_trace_ptr;
};
struct IrInstructionMarkErrRetTracePtr {
@@ -3058,13 +3059,16 @@ static const size_t err_union_payload_index = 1;
// TODO call graph analysis to find out what this number needs to be for every function
static const size_t stack_trace_ptr_count = 30;
+// these belong to the async function
+#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
+#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
+#define RESULT_FIELD_NAME "result"
#define ASYNC_ALLOC_FIELD_NAME "allocFn"
#define ASYNC_FREE_FIELD_NAME "freeFn"
#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
-#define RESULT_FIELD_NAME "result"
+// these point to data belonging to the awaiter
+#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
#define RESULT_PTR_FIELD_NAME "result_ptr"
-#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
-#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
enum FloatMode {
src/analyze.cpp
@@ -474,6 +474,7 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
field_names.append(RESULT_FIELD_NAME);
field_names.append(RESULT_PTR_FIELD_NAME);
if (g->have_err_ret_tracing) {
+ field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
field_names.append(ERR_RET_TRACE_FIELD_NAME);
field_names.append(RETURN_ADDRESSES_FIELD_NAME);
}
@@ -483,7 +484,7 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
field_types.append(return_type);
field_types.append(result_ptr_type);
if (g->have_err_ret_tracing) {
- get_ptr_to_stack_trace_type(g);
+ field_types.append(get_ptr_to_stack_trace_type(g));
field_types.append(g->stack_trace_type);
field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
}
src/codegen.cpp
@@ -4383,8 +4383,8 @@ static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *exe
{
assert(g->have_err_ret_tracing);
- LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->err_ret_trace_ptr);
- LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope);
+ LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr);
+ LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr);
LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
src/ir.cpp
@@ -2708,14 +2708,16 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
}
static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *coro_promise_ptr, IrInstruction *err_ret_trace_ptr)
+ IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
{
IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
instruction->coro_promise_ptr = coro_promise_ptr;
- instruction->err_ret_trace_ptr = err_ret_trace_ptr;
+ instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
+ instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
- ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
+ ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
+ ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
return &instruction->base;
}
@@ -6115,6 +6117,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);
+ if (irb->codegen->have_err_ret_tracing) {
+ IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
+ Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
+ IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
+ ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
+ }
+
Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
awaiter_handle_field_name);
@@ -6144,8 +6153,9 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
- IrInstruction *err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name);
- ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr);
+ IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name);
+ IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
+ ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
@@ -6402,6 +6412,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_id;
IrInstruction *u8_ptr_type;
IrInstruction *const_bool_false;
+ IrInstruction *coro_promise_ptr;
+ IrInstruction *err_ret_trace_ptr;
TypeTableEntry *return_type;
Buf *result_ptr_field_name;
VariableTableEntry *coro_size_var;
@@ -6417,7 +6429,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
// TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
- IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
+ coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
@@ -6471,7 +6483,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name);
Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
- IrInstruction *err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
+ err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
// coordinate with builtin.zig
@@ -6536,6 +6548,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
}
+ if (irb->codegen->have_err_ret_tracing) {
+ Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
+ IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
+ IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
+ ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
+ }
ir_build_br(irb, scope, node, check_free_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
@@ -13098,6 +13116,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
{
if (!is_slice(bare_struct_type)) {
ScopeDecls *container_scope = get_container_scope(bare_struct_type);
+ assert(container_scope != nullptr);
auto entry = container_scope->decl_table.maybe_get(field_name);
Tld *tld = entry ? entry->value : nullptr;
if (tld && tld->id == TldIdFn) {
@@ -17948,12 +17967,16 @@ static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ir
return out_val->type;
}
- IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->other;
- if (type_is_invalid(err_ret_trace_ptr->value.type))
+ IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->other;
+ if (type_is_invalid(src_err_ret_trace_ptr->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->other;
+ if (type_is_invalid(dest_err_ret_trace_ptr->value.type))
return ira->codegen->builtin_types.entry_invalid;
IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, coro_promise_ptr, err_ret_trace_ptr);
+ instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
ir_link_new_instruction(result, &instruction->base);
result->value.type = ira->codegen->builtin_types.entry_void;
return result->value.type;
src/ir_print.cpp
@@ -1192,7 +1192,9 @@ static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRet
fprintf(irp->f, "@mergeErrRetTraces(");
ir_print_other_instruction(irp, instruction->coro_promise_ptr);
fprintf(irp->f, ",");
- ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
+ ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
+ fprintf(irp->f, ",");
+ ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
fprintf(irp->f, ")");
}
test/cases/coroutines.zig
@@ -191,13 +191,20 @@ async fn failing() !void {
return error.Fail;
}
-test "error return trace across suspend points" {
+test "error return trace across suspend points - early return" {
const p = nonFailing();
resume p;
const p2 = try async<std.debug.global_allocator> printTrace(p);
cancel p2;
}
+test "error return trace across suspend points - async return" {
+ const p = nonFailing();
+ const p2 = try async<std.debug.global_allocator> printTrace(p);
+ resume p;
+ cancel p2;
+}
+
fn nonFailing() promise->error!void {
return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
}