| author | |
| committer | |
| log | aa2995ee395b2c1329a61513debcac6225fcb8a8 |
| tree | b96e44da1d55ee671538c775ca5aeb9d91f2c0a7 |
| parent | a43c7af3d1e41ccee73678f114bb3844febcaad6 |
See #821
Now the code works correctly, but error return traces are missing
the frames from coroutines.6 files changed, 132 insertions(+), 50 deletions(-)
src/all_types.hpp+9-1| ... | ... | @@ -1621,7 +1621,8 @@ struct CodeGen { |
| 1621 | 1621 | FnTableEntry *panic_fn; |
| 1622 | 1622 | LLVMValueRef cur_ret_ptr; |
| 1623 | 1623 | LLVMValueRef cur_fn_val; |
| 1624 | LLVMValueRef cur_err_ret_trace_val; | |
| 1624 | LLVMValueRef cur_err_ret_trace_val_arg; | |
| 1625 | LLVMValueRef cur_err_ret_trace_val_stack; | |
| 1625 | 1626 | bool c_want_stdint; |
| 1626 | 1627 | bool c_want_stdbool; |
| 1627 | 1628 | AstNode *root_export_decl; |
| ... | ... | @@ -1760,6 +1761,7 @@ enum ScopeId { |
| 1760 | 1761 | ScopeIdLoop, |
| 1761 | 1762 | ScopeIdFnDef, |
| 1762 | 1763 | ScopeIdCompTime, |
| 1764 | ScopeIdCoroPrelude, | |
| 1763 | 1765 | }; |
| 1764 | 1766 | |
| 1765 | 1767 | struct Scope { |
| ... | ... | @@ -1867,6 +1869,12 @@ struct ScopeFnDef { |
| 1867 | 1869 | FnTableEntry *fn_entry; |
| 1868 | 1870 | }; |
| 1869 | 1871 | |
| 1872 | // This scope is created to indicate that the code in the scope | |
| 1873 | // is auto-generated coroutine prelude stuff. | |
| 1874 | struct ScopeCoroPrelude { | |
| 1875 | Scope base; | |
| 1876 | }; | |
| 1877 | ||
| 1870 | 1878 | // synchronized with code in define_builtin_compile_vars |
| 1871 | 1879 | enum AtomicOrder { |
| 1872 | 1880 | AtomicOrderUnordered, |
src/analyze.cpp+7| ... | ... | @@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) { |
| 170 | 170 | return &scope->base; |
| 171 | 171 | } |
| 172 | 172 | |
| 173 | Scope *create_coro_prelude_scope(AstNode *node, Scope *parent) { | |
| 174 | ScopeCoroPrelude *scope = allocate<ScopeCoroPrelude>(1); | |
| 175 | init_scope(&scope->base, ScopeIdCoroPrelude, node, parent); | |
| 176 | return &scope->base; | |
| 177 | } | |
| 178 | ||
| 173 | 179 | ImportTableEntry *get_scope_import(Scope *scope) { |
| 174 | 180 | while (scope) { |
| 175 | 181 | if (scope->id == ScopeIdDecls) { |
| ... | ... | @@ -3592,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { |
| 3592 | 3598 | case ScopeIdCImport: |
| 3593 | 3599 | case ScopeIdLoop: |
| 3594 | 3600 | case ScopeIdCompTime: |
| 3601 | case ScopeIdCoroPrelude: | |
| 3595 | 3602 | scope = scope->parent; |
| 3596 | 3603 | continue; |
| 3597 | 3604 | case ScopeIdFnDef: |
src/analyze.hpp+1| ... | ... | @@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent); |
| 107 | 107 | ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); |
| 108 | 108 | ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); |
| 109 | 109 | Scope *create_comptime_scope(AstNode *node, Scope *parent); |
| 110 | Scope *create_coro_prelude_scope(AstNode *node, Scope *parent); | |
| 110 | 111 | |
| 111 | 112 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); |
| 112 | 113 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); |
src/codegen.cpp+50-15| ... | ... | @@ -653,6 +653,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 653 | 653 | case ScopeIdDeferExpr: |
| 654 | 654 | case ScopeIdLoop: |
| 655 | 655 | case ScopeIdCompTime: |
| 656 | case ScopeIdCoroPrelude: | |
| 656 | 657 | return get_di_scope(g, scope->parent); |
| 657 | 658 | } |
| 658 | 659 | zig_unreachable(); |
| ... | ... | @@ -1318,9 +1319,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1318 | 1319 | return fn_val; |
| 1319 | 1320 | } |
| 1320 | 1321 | |
| 1321 | static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { | |
| 1322 | static bool is_coro_prelude_scope(Scope *scope) { | |
| 1323 | while (scope != nullptr) { | |
| 1324 | if (scope->id == ScopeIdCoroPrelude) { | |
| 1325 | return true; | |
| 1326 | } else if (scope->id == ScopeIdFnDef) { | |
| 1327 | break; | |
| 1328 | } | |
| 1329 | scope = scope->parent; | |
| 1330 | } | |
| 1331 | return false; | |
| 1332 | } | |
| 1333 | ||
| 1334 | static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) { | |
| 1335 | if (!g->have_err_ret_tracing) { | |
| 1336 | return nullptr; | |
| 1337 | } | |
| 1338 | if (g->cur_fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) { | |
| 1339 | return is_coro_prelude_scope(scope) ? g->cur_err_ret_trace_val_arg : g->cur_err_ret_trace_val_stack; | |
| 1340 | } | |
| 1341 | if (g->cur_err_ret_trace_val_stack != nullptr) { | |
| 1342 | return g->cur_err_ret_trace_val_stack; | |
| 1343 | } | |
| 1344 | return g->cur_err_ret_trace_val_arg; | |
| 1345 | } | |
| 1346 | ||
| 1347 | static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { | |
| 1322 | 1348 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); |
| 1323 | LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val; | |
| 1349 | LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope); | |
| 1324 | 1350 | if (err_ret_trace_val == nullptr) { |
| 1325 | 1351 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 1326 | 1352 | err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref); |
| ... | ... | @@ -1614,7 +1640,7 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut |
| 1614 | 1640 | |
| 1615 | 1641 | LLVMValueRef return_err_fn = get_return_err_fn(g); |
| 1616 | 1642 | LLVMValueRef args[] = { |
| 1617 | g->cur_err_ret_trace_val, | |
| 1643 | get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope), | |
| 1618 | 1644 | }; |
| 1619 | 1645 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, |
| 1620 | 1646 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| ... | ... | @@ -2725,7 +2751,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2725 | 2751 | gen_param_index += 1; |
| 2726 | 2752 | } |
| 2727 | 2753 | if (prefix_arg_err_ret_stack) { |
| 2728 | gen_param_values[gen_param_index] = g->cur_err_ret_trace_val; | |
| 2754 | gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 2729 | 2755 | gen_param_index += 1; |
| 2730 | 2756 | } |
| 2731 | 2757 | if (instruction->is_async) { |
| ... | ... | @@ -3292,11 +3318,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I |
| 3292 | 3318 | static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, |
| 3293 | 3319 | IrInstructionErrorReturnTrace *instruction) |
| 3294 | 3320 | { |
| 3295 | if (g->cur_err_ret_trace_val == nullptr) { | |
| 3321 | LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 3322 | if (cur_err_ret_trace_val == nullptr) { | |
| 3296 | 3323 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 3297 | 3324 | return LLVMConstNull(ptr_to_stack_trace_type->type_ref); |
| 3298 | 3325 | } |
| 3299 | return g->cur_err_ret_trace_val; | |
| 3326 | return cur_err_ret_trace_val; | |
| 3300 | 3327 | } |
| 3301 | 3328 | |
| 3302 | 3329 | static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) { |
| ... | ... | @@ -3726,7 +3753,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3726 | 3753 | LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); |
| 3727 | 3754 | |
| 3728 | 3755 | LLVMPositionBuilderAtEnd(g->builder, err_block); |
| 3729 | gen_safety_crash_for_err(g, err_val); | |
| 3756 | gen_safety_crash_for_err(g, err_val, instruction->base.scope); | |
| 3730 | 3757 | |
| 3731 | 3758 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3732 | 3759 | } |
| ... | ... | @@ -3918,7 +3945,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec |
| 3918 | 3945 | } |
| 3919 | 3946 | |
| 3920 | 3947 | static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { |
| 3921 | gen_panic(g, ir_llvm_value(g, instruction->msg), g->cur_err_ret_trace_val); | |
| 3948 | gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); | |
| 3922 | 3949 | return nullptr; |
| 3923 | 3950 | } |
| 3924 | 3951 | |
| ... | ... | @@ -5279,9 +5306,17 @@ static void do_code_gen(CodeGen *g) { |
| 5279 | 5306 | clear_debug_source_node(g); |
| 5280 | 5307 | |
| 5281 | 5308 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); |
| 5282 | if (err_ret_trace_arg_index != UINT32_MAX) { | |
| 5283 | g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index); | |
| 5284 | } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) { | |
| 5309 | bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; | |
| 5310 | if (have_err_ret_trace_arg) { | |
| 5311 | g->cur_err_ret_trace_val_arg = LLVMGetParam(fn, err_ret_trace_arg_index); | |
| 5312 | } else { | |
| 5313 | g->cur_err_ret_trace_val_arg = nullptr; | |
| 5314 | } | |
| 5315 | ||
| 5316 | bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | |
| 5317 | bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && | |
| 5318 | (is_async || !have_err_ret_trace_arg); | |
| 5319 | if (have_err_ret_trace_stack) { | |
| 5285 | 5320 | // TODO call graph analysis to find out what this number needs to be for every function |
| 5286 | 5321 | static const size_t stack_trace_ptr_count = 30; |
| 5287 | 5322 | |
| ... | ... | @@ -5289,13 +5324,13 @@ static void do_code_gen(CodeGen *g) { |
| 5289 | 5324 | TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); |
| 5290 | 5325 | LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", |
| 5291 | 5326 | get_abi_alignment(g, array_type)); |
| 5292 | g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); | |
| 5327 | g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type)); | |
| 5293 | 5328 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; |
| 5294 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, ""); | |
| 5329 | LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, ""); | |
| 5295 | 5330 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); |
| 5296 | 5331 | |
| 5297 | 5332 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; |
| 5298 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, ""); | |
| 5333 | LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, ""); | |
| 5299 | 5334 | |
| 5300 | 5335 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; |
| 5301 | 5336 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; |
| ... | ... | @@ -5311,7 +5346,7 @@ static void do_code_gen(CodeGen *g) { |
| 5311 | 5346 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); |
| 5312 | 5347 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); |
| 5313 | 5348 | } else { |
| 5314 | g->cur_err_ret_trace_val = nullptr; | |
| 5349 | g->cur_err_ret_trace_val_stack = nullptr; | |
| 5315 | 5350 | } |
| 5316 | 5351 | |
| 5317 | 5352 | // allocate temporary stack data |
src/ir.cpp+35-34| ... | ... | @@ -6412,60 +6412,61 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6412 | 6412 | VariableTableEntry *coro_size_var; |
| 6413 | 6413 | if (is_async) { |
| 6414 | 6414 | // create the coro promise |
| 6415 | const_bool_false = ir_build_const_bool(irb, scope, node, false); | |
| 6416 | VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | |
| 6415 | Scope *coro_scope = create_coro_prelude_scope(node, scope); | |
| 6416 | const_bool_false = ir_build_const_bool(irb, coro_scope, node, false); | |
| 6417 | VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6417 | 6418 | |
| 6418 | 6419 | return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; |
| 6419 | IrInstruction *promise_init = ir_build_const_promise_init(irb, scope, node, return_type); | |
| 6420 | ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init); | |
| 6421 | IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false); | |
| 6420 | IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type); | |
| 6421 | ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init); | |
| 6422 | IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false); | |
| 6422 | 6423 | |
| 6423 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | |
| 6424 | IrInstruction *null_value = ir_build_const_null(irb, scope, node); | |
| 6425 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node, | |
| 6424 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6425 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); | |
| 6426 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, | |
| 6426 | 6427 | get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); |
| 6427 | ir_build_var_decl(irb, scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); | |
| 6428 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, scope, node, | |
| 6428 | ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); | |
| 6429 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, | |
| 6429 | 6430 | await_handle_var, false, false); |
| 6430 | 6431 | |
| 6431 | u8_ptr_type = ir_build_const_type(irb, scope, node, | |
| 6432 | u8_ptr_type = ir_build_const_type(irb, coro_scope, node, | |
| 6432 | 6433 | get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); |
| 6433 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr); | |
| 6434 | coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr); | |
| 6435 | coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | |
| 6436 | IrInstruction *coro_size = ir_build_coro_size(irb, scope, node); | |
| 6437 | ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size); | |
| 6438 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, | |
| 6434 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); | |
| 6435 | coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); | |
| 6436 | coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); | |
| 6437 | IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); | |
| 6438 | ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); | |
| 6439 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, | |
| 6439 | 6440 | ImplicitAllocatorIdArg); |
| 6440 | irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false); | |
| 6441 | ir_build_var_decl(irb, scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); | |
| 6441 | irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); | |
| 6442 | ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); | |
| 6442 | 6443 | Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); |
| 6443 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name); | |
| 6444 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr); | |
| 6445 | IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, scope, node, alloc_fn, coro_size); | |
| 6446 | IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr); | |
| 6447 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError"); | |
| 6448 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk"); | |
| 6449 | ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); | |
| 6444 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); | |
| 6445 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr); | |
| 6446 | IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size); | |
| 6447 | IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); | |
| 6448 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError"); | |
| 6449 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk"); | |
| 6450 | ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); | |
| 6450 | 6451 | |
| 6451 | 6452 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); |
| 6452 | 6453 | // we can return undefined here, because the caller passes a pointer to the error struct field |
| 6453 | 6454 | // in the error union result, and we populate it in case of allocation failure. |
| 6454 | IrInstruction *undef = ir_build_const_undefined(irb, scope, node); | |
| 6455 | ir_build_return(irb, scope, node, undef); | |
| 6455 | IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); | |
| 6456 | ir_build_return(irb, coro_scope, node, undef); | |
| 6456 | 6457 | |
| 6457 | 6458 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); |
| 6458 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, maybe_coro_mem_ptr); | |
| 6459 | irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem_ptr); | |
| 6459 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr); | |
| 6460 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); | |
| 6460 | 6461 | |
| 6461 | 6462 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 6462 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, | |
| 6463 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, | |
| 6463 | 6464 | awaiter_handle_field_name); |
| 6464 | 6465 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6465 | irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); | |
| 6466 | irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_field_name); | |
| 6466 | 6467 | result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6467 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); | |
| 6468 | ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); | |
| 6468 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name); | |
| 6469 | ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); | |
| 6469 | 6470 | |
| 6470 | 6471 | |
| 6471 | 6472 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); |
test/runtime_safety.zig+30| ... | ... | @@ -281,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 281 | 281 | \\ f.float = 12.34; |
| 282 | 282 | \\} |
| 283 | 283 | ); |
| 284 | ||
| 285 | // This case makes sure that the code compiles and runs. There is not actually a special | |
| 286 | // runtime safety check having to do specifically with error return traces across suspend points. | |
| 287 | cases.addRuntimeSafety("error return trace across suspend points", | |
| 288 | \\const std = @import("std"); | |
| 289 | \\ | |
| 290 | \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) noreturn { | |
| 291 | \\ std.os.exit(126); | |
| 292 | \\} | |
| 293 | \\ | |
| 294 | \\pub fn main() void { | |
| 295 | \\ const p = nonFailing(); | |
| 296 | \\ resume p; | |
| 297 | \\ const p2 = async<std.debug.global_allocator> printTrace(p) catch unreachable; | |
| 298 | \\ cancel p2; | |
| 299 | \\} | |
| 300 | \\ | |
| 301 | \\fn nonFailing() promise->error!void { | |
| 302 | \\ return async<std.debug.global_allocator> failing() catch unreachable; | |
| 303 | \\} | |
| 304 | \\ | |
| 305 | \\async fn failing() error!void { | |
| 306 | \\ suspend; | |
| 307 | \\ return error.Fail; | |
| 308 | \\} | |
| 309 | \\ | |
| 310 | \\async fn printTrace(p: promise->error!void) void { | |
| 311 | \\ (await p) catch unreachable; | |
| 312 | \\} | |
| 313 | ); | |
| 284 | 314 | } |