| 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,7 +1621,8 @@ struct CodeGen { |
| 1621 | FnTableEntry *panic_fn; | 1621 | FnTableEntry *panic_fn; |
| 1622 | LLVMValueRef cur_ret_ptr; | 1622 | LLVMValueRef cur_ret_ptr; |
| 1623 | LLVMValueRef cur_fn_val; | 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 | bool c_want_stdint; | 1626 | bool c_want_stdint; |
| 1626 | bool c_want_stdbool; | 1627 | bool c_want_stdbool; |
| 1627 | AstNode *root_export_decl; | 1628 | AstNode *root_export_decl; |
| ... | @@ -1760,6 +1761,7 @@ enum ScopeId { | ... | @@ -1760,6 +1761,7 @@ enum ScopeId { |
| 1760 | ScopeIdLoop, | 1761 | ScopeIdLoop, |
| 1761 | ScopeIdFnDef, | 1762 | ScopeIdFnDef, |
| 1762 | ScopeIdCompTime, | 1763 | ScopeIdCompTime, |
| 1764 | ScopeIdCoroPrelude, | ||
| 1763 | }; | 1765 | }; |
| 1764 | 1766 | ||
| 1765 | struct Scope { | 1767 | struct Scope { |
| ... | @@ -1867,6 +1869,12 @@ struct ScopeFnDef { | ... | @@ -1867,6 +1869,12 @@ struct ScopeFnDef { |
| 1867 | FnTableEntry *fn_entry; | 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 | // synchronized with code in define_builtin_compile_vars | 1878 | // synchronized with code in define_builtin_compile_vars |
| 1871 | enum AtomicOrder { | 1879 | enum AtomicOrder { |
| 1872 | AtomicOrderUnordered, | 1880 | AtomicOrderUnordered, |
src/analyze.cpp+7| ... | @@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) { | ... | @@ -170,6 +170,12 @@ Scope *create_comptime_scope(AstNode *node, Scope *parent) { |
| 170 | return &scope->base; | 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 | ImportTableEntry *get_scope_import(Scope *scope) { | 179 | ImportTableEntry *get_scope_import(Scope *scope) { |
| 174 | while (scope) { | 180 | while (scope) { |
| 175 | if (scope->id == ScopeIdDecls) { | 181 | if (scope->id == ScopeIdDecls) { |
| ... | @@ -3592,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { | ... | @@ -3592,6 +3598,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) { |
| 3592 | case ScopeIdCImport: | 3598 | case ScopeIdCImport: |
| 3593 | case ScopeIdLoop: | 3599 | case ScopeIdLoop: |
| 3594 | case ScopeIdCompTime: | 3600 | case ScopeIdCompTime: |
| 3601 | case ScopeIdCoroPrelude: | ||
| 3595 | scope = scope->parent; | 3602 | scope = scope->parent; |
| 3596 | continue; | 3603 | continue; |
| 3597 | case ScopeIdFnDef: | 3604 | case ScopeIdFnDef: |
src/analyze.hpp+1| ... | @@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent); | ... | @@ -107,6 +107,7 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent); |
| 107 | ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); | 107 | ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); |
| 108 | ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); | 108 | ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); |
| 109 | Scope *create_comptime_scope(AstNode *node, Scope *parent); | 109 | Scope *create_comptime_scope(AstNode *node, Scope *parent); |
| 110 | Scope *create_coro_prelude_scope(AstNode *node, Scope *parent); | ||
| 110 | 111 | ||
| 111 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); | 112 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); |
| 112 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); | 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,6 +653,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 653 | case ScopeIdDeferExpr: | 653 | case ScopeIdDeferExpr: |
| 654 | case ScopeIdLoop: | 654 | case ScopeIdLoop: |
| 655 | case ScopeIdCompTime: | 655 | case ScopeIdCompTime: |
| 656 | case ScopeIdCoroPrelude: | ||
| 656 | return get_di_scope(g, scope->parent); | 657 | return get_di_scope(g, scope->parent); |
| 657 | } | 658 | } |
| 658 | zig_unreachable(); | 659 | zig_unreachable(); |
| ... | @@ -1318,9 +1319,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { | ... | @@ -1318,9 +1319,34 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1318 | return fn_val; | 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 | LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g); | 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 | if (err_ret_trace_val == nullptr) { | 1350 | if (err_ret_trace_val == nullptr) { |
| 1325 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | 1351 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 1326 | err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref); | 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,7 +1640,7 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut |
| 1614 | 1640 | ||
| 1615 | LLVMValueRef return_err_fn = get_return_err_fn(g); | 1641 | LLVMValueRef return_err_fn = get_return_err_fn(g); |
| 1616 | LLVMValueRef args[] = { | 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 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, | 1645 | LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1, |
| 1620 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | 1646 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| ... | @@ -2725,7 +2751,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -2725,7 +2751,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 2725 | gen_param_index += 1; | 2751 | gen_param_index += 1; |
| 2726 | } | 2752 | } |
| 2727 | if (prefix_arg_err_ret_stack) { | 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 | gen_param_index += 1; | 2755 | gen_param_index += 1; |
| 2730 | } | 2756 | } |
| 2731 | if (instruction->is_async) { | 2757 | if (instruction->is_async) { |
| ... | @@ -3292,11 +3318,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I | ... | @@ -3292,11 +3318,12 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I |
| 3292 | static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, | 3318 | static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable, |
| 3293 | IrInstructionErrorReturnTrace *instruction) | 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 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | 3323 | TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); |
| 3297 | return LLVMConstNull(ptr_to_stack_trace_type->type_ref); | 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 | static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) { | 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,7 +3753,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu |
| 3726 | LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); | 3753 | LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); |
| 3727 | 3754 | ||
| 3728 | LLVMPositionBuilderAtEnd(g->builder, err_block); | 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 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | 3758 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 3732 | } | 3759 | } |
| ... | @@ -3918,7 +3945,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec | ... | @@ -3918,7 +3945,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec |
| 3918 | } | 3945 | } |
| 3919 | 3946 | ||
| 3920 | static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { | 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 | return nullptr; | 3949 | return nullptr; |
| 3923 | } | 3950 | } |
| 3924 | 3951 | ||
| ... | @@ -5279,9 +5306,17 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5279,9 +5306,17 @@ static void do_code_gen(CodeGen *g) { |
| 5279 | clear_debug_source_node(g); | 5306 | clear_debug_source_node(g); |
| 5280 | 5307 | ||
| 5281 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); | 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) { | 5309 | bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; |
| 5283 | g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index); | 5310 | if (have_err_ret_trace_arg) { |
| 5284 | } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) { | 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 | // TODO call graph analysis to find out what this number needs to be for every function | 5320 | // TODO call graph analysis to find out what this number needs to be for every function |
| 5286 | static const size_t stack_trace_ptr_count = 30; | 5321 | static const size_t stack_trace_ptr_count = 30; |
| 5287 | 5322 | ||
| ... | @@ -5289,13 +5324,13 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5289,13 +5324,13 @@ static void do_code_gen(CodeGen *g) { |
| 5289 | TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); | 5324 | TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count); |
| 5290 | LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", | 5325 | LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", |
| 5291 | get_abi_alignment(g, array_type)); | 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 | size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; | 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 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); | 5330 | gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false); |
| 5296 | 5331 | ||
| 5297 | size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; | 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 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; | 5335 | TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry; |
| 5301 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | 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,7 +5346,7 @@ static void do_code_gen(CodeGen *g) { |
| 5311 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); | 5346 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, ""); |
| 5312 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | 5347 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); |
| 5313 | } else { | 5348 | } else { |
| 5314 | g->cur_err_ret_trace_val = nullptr; | 5349 | g->cur_err_ret_trace_val_stack = nullptr; |
| 5315 | } | 5350 | } |
| 5316 | 5351 | ||
| 5317 | // allocate temporary stack data | 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,60 +6412,61 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6412 | VariableTableEntry *coro_size_var; | 6412 | VariableTableEntry *coro_size_var; |
| 6413 | if (is_async) { | 6413 | if (is_async) { |
| 6414 | // create the coro promise | 6414 | // create the coro promise |
| 6415 | const_bool_false = ir_build_const_bool(irb, scope, node, false); | 6415 | Scope *coro_scope = create_coro_prelude_scope(node, scope); |
| 6416 | VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | 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 | return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; | 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 | IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type); |
| 6420 | ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init); | 6421 | ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init); |
| 6421 | IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false); | 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 | VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 6424 | IrInstruction *null_value = ir_build_const_null(irb, scope, node); | 6425 | IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); |
| 6425 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, scope, node, | 6426 | IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, |
| 6426 | get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); | 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 | ir_build_var_decl(irb, coro_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, | 6429 | irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, |
| 6429 | await_handle_var, false, false); | 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 | get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); | 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 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr); |
| 6434 | coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr); | 6435 | coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); |
| 6435 | coro_size_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); | 6436 | coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); |
| 6436 | IrInstruction *coro_size = ir_build_coro_size(irb, scope, node); | 6437 | IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); |
| 6437 | ir_build_var_decl(irb, scope, node, coro_size_var, nullptr, nullptr, coro_size); | 6438 | ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); |
| 6438 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, | 6439 | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, |
| 6439 | ImplicitAllocatorIdArg); | 6440 | ImplicitAllocatorIdArg); |
| 6440 | irb->exec->coro_allocator_var = ir_create_var(irb, node, scope, nullptr, true, true, true, const_bool_false); | 6441 | irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_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); | 6442 | ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); |
| 6442 | Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); | 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_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name); |
| 6444 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr); | 6445 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_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 *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size); |
| 6446 | IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, scope, node, maybe_coro_mem_ptr); | 6447 | IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); |
| 6447 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError"); | 6448 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError"); |
| 6448 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk"); | 6449 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk"); |
| 6449 | ir_build_cond_br(irb, scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false); | 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 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); | 6452 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); |
| 6452 | // we can return undefined here, because the caller passes a pointer to the error struct field | 6453 | // we can return undefined here, because the caller passes a pointer to the error struct field |
| 6453 | // in the error union result, and we populate it in case of allocation failure. | 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 | IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); |
| 6455 | ir_build_return(irb, scope, node, undef); | 6456 | ir_build_return(irb, coro_scope, node, undef); |
| 6456 | 6457 | ||
| 6457 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); | 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 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_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); | 6460 | irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr); |
| 6460 | 6461 | ||
| 6461 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); | 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 | awaiter_handle_field_name); | 6464 | awaiter_handle_field_name); |
| 6464 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); | 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 | result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); | 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 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_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); | 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 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); | 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,4 +281,34 @@ pub fn addCases(cases: &tests.CompareOutputContext) void { |
| 281 | \\ f.float = 12.34; | 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 | } |