| author | |
| committer | |
| log | 13b5a4bf8ca65c569e6b28ca0e41d101d12d0ff1 |
| tree | e95ccf886a1433fe68e1779cffb357595f1774b2 |
| parent | 64c293f8a4ce5fcbb506c32b989a88d982f005ce |
| signature |
24 files changed, 256 insertions(+), 806 deletions(-)
doc/docgen.zig-1| ... | ... | @@ -750,7 +750,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 750 | 750 | .Keyword_async, |
| 751 | 751 | .Keyword_await, |
| 752 | 752 | .Keyword_break, |
| 753 | .Keyword_cancel, | |
| 754 | 753 | .Keyword_catch, |
| 755 | 754 | .Keyword_comptime, |
| 756 | 755 | .Keyword_const, |
doc/langref.html.in+6-8| ... | ... | @@ -5971,7 +5971,7 @@ test "global assembly" { |
| 5971 | 5971 | {#header_open|Async Functions#} |
| 5972 | 5972 | <p> |
| 5973 | 5973 | An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation, |
| 5974 | followed by an {#syntax#}await{#endsyntax#} completion. They can also be canceled. | |
| 5974 | followed by an {#syntax#}await{#endsyntax#} completion. | |
| 5975 | 5975 | </p> |
| 5976 | 5976 | <p> |
| 5977 | 5977 | When you call a function, it creates a stack frame, |
| ... | ... | @@ -6013,11 +6013,11 @@ test "global assembly" { |
| 6013 | 6013 | <p> |
| 6014 | 6014 | The result of an async function call is a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#} |
| 6015 | 6015 | is the return type of the async function. Once a promise has been created, it must be |
| 6016 | consumed, either with {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}: | |
| 6016 | consumed with {#syntax#}await{#endsyntax#}: | |
| 6017 | 6017 | </p> |
| 6018 | 6018 | <p> |
| 6019 | 6019 | Async functions start executing when created, so in the following example, the entire |
| 6020 | async function completes before it is canceled: | |
| 6020 | TODO | |
| 6021 | 6021 | </p> |
| 6022 | 6022 | {#code_begin|test#} |
| 6023 | 6023 | const std = @import("std"); |
| ... | ... | @@ -6048,7 +6048,7 @@ fn simpleAsyncFn() void { |
| 6048 | 6048 | </p> |
| 6049 | 6049 | <p> |
| 6050 | 6050 | When an async function suspends itself, it must be sure that it will be |
| 6051 | resumed or canceled somehow, for example by registering its promise handle | |
| 6051 | resumed somehow, for example by registering its promise handle | |
| 6052 | 6052 | in an event loop. Use a suspend capture block to gain access to the |
| 6053 | 6053 | promise (TODO this is outdated): |
| 6054 | 6054 | </p> |
| ... | ... | @@ -6134,7 +6134,7 @@ async fn testResumeFromSuspend(my_result: *i32) void { |
| 6134 | 6134 | resumes the awaiter. |
| 6135 | 6135 | </p> |
| 6136 | 6136 | <p> |
| 6137 | A promise handle must be consumed exactly once after it is created, either by {#syntax#}cancel{#endsyntax#} or {#syntax#}await{#endsyntax#}. | |
| 6137 | A frame handle must be consumed exactly once after it is created with {#syntax#}await{#endsyntax#}. | |
| 6138 | 6138 | </p> |
| 6139 | 6139 | <p> |
| 6140 | 6140 | {#syntax#}await{#endsyntax#} counts as a suspend point, and therefore at every {#syntax#}await{#endsyntax#}, |
| ... | ... | @@ -9764,7 +9764,6 @@ PrimaryExpr |
| 9764 | 9764 | &lt;- AsmExpr |
| 9765 | 9765 | / IfExpr |
| 9766 | 9766 | / KEYWORD_break BreakLabel? Expr? |
| 9767 | / KEYWORD_cancel Expr | |
| 9768 | 9767 | / KEYWORD_comptime Expr |
| 9769 | 9768 | / KEYWORD_continue BreakLabel? |
| 9770 | 9769 | / KEYWORD_resume Expr |
| ... | ... | @@ -10120,7 +10119,6 @@ KEYWORD_asm &lt;- 'asm' end_of_word |
| 10120 | 10119 | KEYWORD_async &lt;- 'async' end_of_word |
| 10121 | 10120 | KEYWORD_await &lt;- 'await' end_of_word |
| 10122 | 10121 | KEYWORD_break &lt;- 'break' end_of_word |
| 10123 | KEYWORD_cancel &lt;- 'cancel' end_of_word | |
| 10124 | 10122 | KEYWORD_catch &lt;- 'catch' end_of_word |
| 10125 | 10123 | KEYWORD_comptime &lt;- 'comptime' end_of_word |
| 10126 | 10124 | KEYWORD_const &lt;- 'const' end_of_word |
| ... | ... | @@ -10165,7 +10163,7 @@ KEYWORD_volatile &lt;- 'volatile' end_of_word |
| 10165 | 10163 | KEYWORD_while &lt;- 'while' end_of_word |
| 10166 | 10164 | |
| 10167 | 10165 | keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_asm |
| 10168 | / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel | |
| 10166 | / KEYWORD_async / KEYWORD_await / KEYWORD_break | |
| 10169 | 10167 | / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue |
| 10170 | 10168 | / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer |
| 10171 | 10169 | / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false |
src-self-hosted/main.zig-3| ... | ... | @@ -467,7 +467,6 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 467 | 467 | |
| 468 | 468 | comp.start(); |
| 469 | 469 | // TODO const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color); |
| 470 | defer cancel process_build_events_handle; | |
| 471 | 470 | loop.run(); |
| 472 | 471 | } |
| 473 | 472 | |
| ... | ... | @@ -579,7 +578,6 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { |
| 579 | 578 | defer zig_compiler.deinit(); |
| 580 | 579 | |
| 581 | 580 | // TODO const handle = try async<loop.allocator> findLibCAsync(&zig_compiler); |
| 582 | defer cancel handle; | |
| 583 | 581 | |
| 584 | 582 | loop.run(); |
| 585 | 583 | } |
| ... | ... | @@ -669,7 +667,6 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 669 | 667 | // TODO &flags, |
| 670 | 668 | // TODO color, |
| 671 | 669 | // TODO ); |
| 672 | defer cancel main_handle; | |
| 673 | 670 | loop.run(); |
| 674 | 671 | return result; |
| 675 | 672 | } |
src/all_types.hpp+1-32| ... | ... | @@ -476,7 +476,6 @@ enum NodeType { |
| 476 | 476 | NodeTypeIfErrorExpr, |
| 477 | 477 | NodeTypeIfOptional, |
| 478 | 478 | NodeTypeErrorSetDecl, |
| 479 | NodeTypeCancel, | |
| 480 | 479 | NodeTypeResume, |
| 481 | 480 | NodeTypeAwaitExpr, |
| 482 | 481 | NodeTypeSuspend, |
| ... | ... | @@ -911,10 +910,6 @@ struct AstNodeBreakExpr { |
| 911 | 910 | AstNode *expr; // may be null |
| 912 | 911 | }; |
| 913 | 912 | |
| 914 | struct AstNodeCancelExpr { | |
| 915 | AstNode *expr; | |
| 916 | }; | |
| 917 | ||
| 918 | 913 | struct AstNodeResumeExpr { |
| 919 | 914 | AstNode *expr; |
| 920 | 915 | }; |
| ... | ... | @@ -1003,7 +998,6 @@ struct AstNode { |
| 1003 | 998 | AstNodeInferredArrayType inferred_array_type; |
| 1004 | 999 | AstNodeErrorType error_type; |
| 1005 | 1000 | AstNodeErrorSetDecl err_set_decl; |
| 1006 | AstNodeCancelExpr cancel_expr; | |
| 1007 | 1001 | AstNodeResumeExpr resume_expr; |
| 1008 | 1002 | AstNodeAwaitExpr await_expr; |
| 1009 | 1003 | AstNodeSuspend suspend; |
| ... | ... | @@ -1561,7 +1555,6 @@ enum PanicMsgId { |
| 1561 | 1555 | PanicMsgIdBadAwait, |
| 1562 | 1556 | PanicMsgIdBadReturn, |
| 1563 | 1557 | PanicMsgIdResumedAnAwaitingFn, |
| 1564 | PanicMsgIdResumedACancelingFn, | |
| 1565 | 1558 | PanicMsgIdFrameTooSmall, |
| 1566 | 1559 | PanicMsgIdResumedFnPendingAwait, |
| 1567 | 1560 | |
| ... | ... | @@ -1729,8 +1722,6 @@ struct CodeGen { |
| 1729 | 1722 | LLVMValueRef cur_async_switch_instr; |
| 1730 | 1723 | LLVMValueRef cur_async_resume_index_ptr; |
| 1731 | 1724 | LLVMValueRef cur_async_awaiter_ptr; |
| 1732 | LLVMValueRef cur_async_prev_val; | |
| 1733 | LLVMValueRef cur_async_prev_val_field_ptr; | |
| 1734 | 1725 | LLVMBasicBlockRef cur_preamble_llvm_block; |
| 1735 | 1726 | size_t cur_resume_block_count; |
| 1736 | 1727 | LLVMValueRef cur_err_ret_trace_val_arg; |
| ... | ... | @@ -1822,7 +1813,6 @@ struct CodeGen { |
| 1822 | 1813 | |
| 1823 | 1814 | ZigType *align_amt_type; |
| 1824 | 1815 | ZigType *stack_trace_type; |
| 1825 | ZigType *ptr_to_stack_trace_type; | |
| 1826 | 1816 | ZigType *err_tag_type; |
| 1827 | 1817 | ZigType *test_fn_type; |
| 1828 | 1818 | |
| ... | ... | @@ -1892,7 +1882,6 @@ struct CodeGen { |
| 1892 | 1882 | bool system_linker_hack; |
| 1893 | 1883 | bool reported_bad_link_libc_error; |
| 1894 | 1884 | bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl. |
| 1895 | bool cur_is_after_return; | |
| 1896 | 1885 | |
| 1897 | 1886 | //////////////////////////// Participates in Input Parameter Cache Hash |
| 1898 | 1887 | /////// Note: there is a separate cache hash for builtin.zig, when adding fields, |
| ... | ... | @@ -2235,7 +2224,6 @@ enum IrInstructionId { |
| 2235 | 2224 | IrInstructionIdCallGen, |
| 2236 | 2225 | IrInstructionIdConst, |
| 2237 | 2226 | IrInstructionIdReturn, |
| 2238 | IrInstructionIdReturnBegin, | |
| 2239 | 2227 | IrInstructionIdCast, |
| 2240 | 2228 | IrInstructionIdResizeSlice, |
| 2241 | 2229 | IrInstructionIdContainerInitList, |
| ... | ... | @@ -2345,7 +2333,6 @@ enum IrInstructionId { |
| 2345 | 2333 | IrInstructionIdExport, |
| 2346 | 2334 | IrInstructionIdErrorReturnTrace, |
| 2347 | 2335 | IrInstructionIdErrorUnion, |
| 2348 | IrInstructionIdCancel, | |
| 2349 | 2336 | IrInstructionIdAtomicRmw, |
| 2350 | 2337 | IrInstructionIdAtomicLoad, |
| 2351 | 2338 | IrInstructionIdSaveErrRetAddr, |
| ... | ... | @@ -2370,7 +2357,6 @@ enum IrInstructionId { |
| 2370 | 2357 | IrInstructionIdAwaitSrc, |
| 2371 | 2358 | IrInstructionIdAwaitGen, |
| 2372 | 2359 | IrInstructionIdResume, |
| 2373 | IrInstructionIdTestCancelRequested, | |
| 2374 | 2360 | IrInstructionIdSpillBegin, |
| 2375 | 2361 | IrInstructionIdSpillEnd, |
| 2376 | 2362 | }; |
| ... | ... | @@ -2649,12 +2635,6 @@ struct IrInstructionReturn { |
| 2649 | 2635 | IrInstruction *operand; |
| 2650 | 2636 | }; |
| 2651 | 2637 | |
| 2652 | struct IrInstructionReturnBegin { | |
| 2653 | IrInstruction base; | |
| 2654 | ||
| 2655 | IrInstruction *operand; | |
| 2656 | }; | |
| 2657 | ||
| 2658 | 2638 | enum CastOp { |
| 2659 | 2639 | CastOpNoCast, // signifies the function call expression is not a cast |
| 2660 | 2640 | CastOpNoop, // fn call expr is a cast, but does nothing |
| ... | ... | @@ -3440,12 +3420,6 @@ struct IrInstructionErrorUnion { |
| 3440 | 3420 | IrInstruction *payload; |
| 3441 | 3421 | }; |
| 3442 | 3422 | |
| 3443 | struct IrInstructionCancel { | |
| 3444 | IrInstruction base; | |
| 3445 | ||
| 3446 | IrInstruction *frame; | |
| 3447 | }; | |
| 3448 | ||
| 3449 | 3423 | struct IrInstructionAtomicRmw { |
| 3450 | 3424 | IrInstruction base; |
| 3451 | 3425 | |
| ... | ... | @@ -3647,10 +3621,6 @@ struct IrInstructionResume { |
| 3647 | 3621 | IrInstruction *frame; |
| 3648 | 3622 | }; |
| 3649 | 3623 | |
| 3650 | struct IrInstructionTestCancelRequested { | |
| 3651 | IrInstruction base; | |
| 3652 | }; | |
| 3653 | ||
| 3654 | 3624 | enum SpillId { |
| 3655 | 3625 | SpillIdInvalid, |
| 3656 | 3626 | SpillIdRetErrCode, |
| ... | ... | @@ -3756,8 +3726,7 @@ static const size_t err_union_err_index = 1; |
| 3756 | 3726 | static const size_t frame_fn_ptr_index = 0; |
| 3757 | 3727 | static const size_t frame_resume_index = 1; |
| 3758 | 3728 | static const size_t frame_awaiter_index = 2; |
| 3759 | static const size_t frame_prev_val_index = 3; | |
| 3760 | static const size_t frame_ret_start = 4; | |
| 3729 | static const size_t frame_ret_start = 3; | |
| 3761 | 3730 | |
| 3762 | 3731 | // TODO https://github.com/ziglang/zig/issues/3056 |
| 3763 | 3732 | // We require this to be a power of 2 so that we can use shifting rather than |
src/analyze.cpp+33-20| ... | ... | @@ -828,17 +828,15 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { |
| 828 | 828 | zig_unreachable(); |
| 829 | 829 | } |
| 830 | 830 | |
| 831 | ZigType *get_ptr_to_stack_trace_type(CodeGen *g) { | |
| 831 | ZigType *get_stack_trace_type(CodeGen *g) { | |
| 832 | 832 | if (g->stack_trace_type == nullptr) { |
| 833 | 833 | ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace"); |
| 834 | 834 | assert(stack_trace_type_val->type->id == ZigTypeIdMetaType); |
| 835 | 835 | |
| 836 | 836 | g->stack_trace_type = stack_trace_type_val->data.x_type; |
| 837 | 837 | assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown)); |
| 838 | ||
| 839 | g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false); | |
| 840 | 838 | } |
| 841 | return g->ptr_to_stack_trace_type; | |
| 839 | return g->stack_trace_type; | |
| 842 | 840 | } |
| 843 | 841 | |
| 844 | 842 | bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { |
| ... | ... | @@ -3035,7 +3033,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { |
| 3035 | 3033 | case NodeTypeIfErrorExpr: |
| 3036 | 3034 | case NodeTypeIfOptional: |
| 3037 | 3035 | case NodeTypeErrorSetDecl: |
| 3038 | case NodeTypeCancel: | |
| 3039 | 3036 | case NodeTypeResume: |
| 3040 | 3037 | case NodeTypeAwaitExpr: |
| 3041 | 3038 | case NodeTypeSuspend: |
| ... | ... | @@ -3822,11 +3819,9 @@ static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { |
| 3822 | 3819 | } else if (fn->inferred_async_node->type == NodeTypeAwaitExpr) { |
| 3823 | 3820 | add_error_note(g, msg, fn->inferred_async_node, |
| 3824 | 3821 | buf_sprintf("await is a suspend point")); |
| 3825 | } else if (fn->inferred_async_node->type == NodeTypeCancel) { | |
| 3826 | add_error_note(g, msg, fn->inferred_async_node, | |
| 3827 | buf_sprintf("cancel is a suspend point")); | |
| 3828 | 3822 | } else { |
| 3829 | zig_unreachable(); | |
| 3823 | add_error_note(g, msg, fn->inferred_async_node, | |
| 3824 | buf_sprintf("suspends here")); | |
| 3830 | 3825 | } |
| 3831 | 3826 | } |
| 3832 | 3827 | |
| ... | ... | @@ -5231,12 +5226,21 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5231 | 5226 | fields.append({"@fn_ptr", g->builtin_types.entry_usize, 0}); |
| 5232 | 5227 | fields.append({"@resume_index", g->builtin_types.entry_usize, 0}); |
| 5233 | 5228 | fields.append({"@awaiter", g->builtin_types.entry_usize, 0}); |
| 5234 | fields.append({"@prev_val", g->builtin_types.entry_usize, 0}); | |
| 5235 | 5229 | |
| 5236 | 5230 | fields.append({"@result_ptr_callee", ptr_return_type, 0}); |
| 5237 | 5231 | fields.append({"@result_ptr_awaiter", ptr_return_type, 0}); |
| 5238 | 5232 | fields.append({"@result", fn_type_id->return_type, 0}); |
| 5239 | 5233 | |
| 5234 | if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { | |
| 5235 | ZigType *ptr_to_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false); | |
| 5236 | fields.append({"@ptr_stack_trace_callee", ptr_to_stack_trace_type, 0}); | |
| 5237 | fields.append({"@ptr_stack_trace_awaiter", ptr_to_stack_trace_type, 0}); | |
| 5238 | ||
| 5239 | fields.append({"@stack_trace", get_stack_trace_type(g), 0}); | |
| 5240 | fields.append({"@instruction_addresses", | |
| 5241 | get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0}); | |
| 5242 | } | |
| 5243 | ||
| 5240 | 5244 | frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name), |
| 5241 | 5245 | fields.items, fields.length, target_fn_align(g->zig_target)); |
| 5242 | 5246 | frame_type->abi_size = frame_type->data.frame.locals_struct->abi_size; |
| ... | ... | @@ -5311,14 +5315,15 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5311 | 5315 | fields.append({"@fn_ptr", fn_type, 0}); |
| 5312 | 5316 | fields.append({"@resume_index", g->builtin_types.entry_usize, 0}); |
| 5313 | 5317 | fields.append({"@awaiter", g->builtin_types.entry_usize, 0}); |
| 5314 | fields.append({"@prev_val", g->builtin_types.entry_usize, 0}); | |
| 5315 | 5318 | |
| 5316 | 5319 | fields.append({"@result_ptr_callee", ptr_return_type, 0}); |
| 5317 | 5320 | fields.append({"@result_ptr_awaiter", ptr_return_type, 0}); |
| 5318 | 5321 | fields.append({"@result", fn_type_id->return_type, 0}); |
| 5319 | 5322 | |
| 5320 | 5323 | if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { |
| 5321 | fields.append({"@ptr_stack_trace", get_ptr_to_stack_trace_type(g), 0}); | |
| 5324 | ZigType *ptr_stack_trace_type = get_pointer_to_type(g, get_stack_trace_type(g), false); | |
| 5325 | fields.append({"@ptr_stack_trace_callee", ptr_stack_trace_type, 0}); | |
| 5326 | fields.append({"@ptr_stack_trace_awaiter", ptr_stack_trace_type, 0}); | |
| 5322 | 5327 | } |
| 5323 | 5328 | |
| 5324 | 5329 | for (size_t arg_i = 0; arg_i < fn_type_id->param_count; arg_i += 1) { |
| ... | ... | @@ -5337,9 +5342,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5337 | 5342 | } |
| 5338 | 5343 | |
| 5339 | 5344 | if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) { |
| 5340 | (void)get_ptr_to_stack_trace_type(g); // populate g->stack_trace_type | |
| 5341 | ||
| 5342 | fields.append({"@stack_trace", g->stack_trace_type, 0}); | |
| 5345 | fields.append({"@stack_trace", get_stack_trace_type(g), 0}); | |
| 5343 | 5346 | fields.append({"@instruction_addresses", |
| 5344 | 5347 | get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0}); |
| 5345 | 5348 | } |
| ... | ... | @@ -7553,7 +7556,7 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) { |
| 7553 | 7556 | fn_type->data.fn.gen_return_type = gen_return_type; |
| 7554 | 7557 | |
| 7555 | 7558 | if (prefix_arg_error_return_trace && !is_async) { |
| 7556 | ZigType *gen_type = get_ptr_to_stack_trace_type(g); | |
| 7559 | ZigType *gen_type = get_pointer_to_type(g, get_stack_trace_type(g), false); | |
| 7557 | 7560 | gen_param_types.append(get_llvm_type(g, gen_type)); |
| 7558 | 7561 | param_di_types.append(get_llvm_di_type(g, gen_type)); |
| 7559 | 7562 | } |
| ... | ... | @@ -7727,7 +7730,6 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re |
| 7727 | 7730 | field_types.append(ptr_fn_llvm_type); // fn_ptr |
| 7728 | 7731 | field_types.append(usize_type_ref); // resume_index |
| 7729 | 7732 | field_types.append(usize_type_ref); // awaiter |
| 7730 | field_types.append(usize_type_ref); // prev_val | |
| 7731 | 7733 | |
| 7732 | 7734 | bool have_result_type = result_type != nullptr && type_has_bits(result_type); |
| 7733 | 7735 | if (have_result_type) { |
| ... | ... | @@ -7735,7 +7737,9 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re |
| 7735 | 7737 | field_types.append(get_llvm_type(g, ptr_result_type)); // result_ptr_awaiter |
| 7736 | 7738 | field_types.append(get_llvm_type(g, result_type)); // result |
| 7737 | 7739 | if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { |
| 7738 | field_types.append(get_llvm_type(g, get_ptr_to_stack_trace_type(g))); // ptr_stack_trace | |
| 7740 | ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false); | |
| 7741 | field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_callee | |
| 7742 | field_types.append(get_llvm_type(g, ptr_stack_trace)); // ptr_stack_trace_awaiter | |
| 7739 | 7743 | } |
| 7740 | 7744 | } |
| 7741 | 7745 | LLVMStructSetBody(frame_header_type, field_types.items, field_types.length, false); |
| ... | ... | @@ -7792,14 +7796,23 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re |
| 7792 | 7796 | ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, result_type))); |
| 7793 | 7797 | |
| 7794 | 7798 | if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { |
| 7799 | ZigType *ptr_stack_trace = get_pointer_to_type(g, get_stack_trace_type(g), false); | |
| 7800 | di_element_types.append( | |
| 7801 | ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 7802 | ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_callee", | |
| 7803 | di_file, line, | |
| 7804 | 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), | |
| 7805 | 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), | |
| 7806 | 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), | |
| 7807 | ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace))); | |
| 7795 | 7808 | di_element_types.append( |
| 7796 | 7809 | ZigLLVMCreateDebugMemberType(g->dbuilder, |
| 7797 | ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace", | |
| 7810 | ZigLLVMTypeToScope(any_frame_type->llvm_di_type), "ptr_stack_trace_awaiter", | |
| 7798 | 7811 | di_file, line, |
| 7799 | 7812 | 8*LLVMABISizeOfType(g->target_data_ref, field_types.at(di_element_types.length)), |
| 7800 | 7813 | 8*LLVMABIAlignmentOfType(g->target_data_ref, field_types.at(di_element_types.length)), |
| 7801 | 7814 | 8*LLVMOffsetOfElement(g->target_data_ref, frame_header_type, di_element_types.length), |
| 7802 | ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, get_ptr_to_stack_trace_type(g)))); | |
| 7815 | ZigLLVM_DIFlags_Zero, get_llvm_di_type(g, ptr_stack_trace))); | |
| 7803 | 7816 | } |
| 7804 | 7817 | }; |
| 7805 | 7818 |
src/analyze.hpp+1-1| ... | ... | @@ -195,7 +195,7 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, Buf *symbol_name, Global |
| 195 | 195 | |
| 196 | 196 | |
| 197 | 197 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name); |
| 198 | ZigType *get_ptr_to_stack_trace_type(CodeGen *g); | |
| 198 | ZigType *get_stack_trace_type(CodeGen *g); | |
| 199 | 199 | bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node); |
| 200 | 200 | |
| 201 | 201 | ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry); |
src/ast_render.cpp-8| ... | ... | @@ -249,8 +249,6 @@ static const char *node_type_str(NodeType node_type) { |
| 249 | 249 | return "IfOptional"; |
| 250 | 250 | case NodeTypeErrorSetDecl: |
| 251 | 251 | return "ErrorSetDecl"; |
| 252 | case NodeTypeCancel: | |
| 253 | return "Cancel"; | |
| 254 | 252 | case NodeTypeResume: |
| 255 | 253 | return "Resume"; |
| 256 | 254 | case NodeTypeAwaitExpr: |
| ... | ... | @@ -1136,12 +1134,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 1136 | 1134 | fprintf(ar->f, "}"); |
| 1137 | 1135 | break; |
| 1138 | 1136 | } |
| 1139 | case NodeTypeCancel: | |
| 1140 | { | |
| 1141 | fprintf(ar->f, "cancel "); | |
| 1142 | render_node_grouped(ar, node->data.cancel_expr.expr); | |
| 1143 | break; | |
| 1144 | } | |
| 1145 | 1137 | case NodeTypeResume: |
| 1146 | 1138 | { |
| 1147 | 1139 | fprintf(ar->f, "resume "); |
src/codegen.cpp+156-256| ... | ... | @@ -28,8 +28,6 @@ enum ResumeId { |
| 28 | 28 | ResumeIdManual, |
| 29 | 29 | ResumeIdReturn, |
| 30 | 30 | ResumeIdCall, |
| 31 | ||
| 32 | ResumeIdAwaitEarlyReturn // must be last | |
| 33 | 31 | }; |
| 34 | 32 | |
| 35 | 33 | static void init_darwin_native(CodeGen *g) { |
| ... | ... | @@ -317,8 +315,9 @@ static uint32_t frame_index_trace_arg(CodeGen *g, ZigType *return_type) { |
| 317 | 315 | // label (grep this): [fn_frame_struct_layout] |
| 318 | 316 | static uint32_t frame_index_arg(CodeGen *g, ZigType *return_type) { |
| 319 | 317 | bool have_stack_trace = codegen_fn_has_err_ret_tracing_arg(g, return_type); |
| 320 | // [0] *StackTrace | |
| 321 | uint32_t trace_field_count = have_stack_trace ? 1 : 0; | |
| 318 | // [0] *StackTrace (callee's) | |
| 319 | // [1] *StackTrace (awaiter's) | |
| 320 | uint32_t trace_field_count = have_stack_trace ? 2 : 0; | |
| 322 | 321 | return frame_index_trace_arg(g, return_type) + trace_field_count; |
| 323 | 322 | } |
| 324 | 323 | |
| ... | ... | @@ -916,8 +915,6 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 916 | 915 | return buf_create_from_str("async function returned twice"); |
| 917 | 916 | case PanicMsgIdResumedAnAwaitingFn: |
| 918 | 917 | return buf_create_from_str("awaiting function resumed"); |
| 919 | case PanicMsgIdResumedACancelingFn: | |
| 920 | return buf_create_from_str("canceling function resumed"); | |
| 921 | 918 | case PanicMsgIdFrameTooSmall: |
| 922 | 919 | return buf_create_from_str("frame too small"); |
| 923 | 920 | case PanicMsgIdResumedFnPendingAwait: |
| ... | ... | @@ -946,13 +943,16 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) { |
| 946 | 943 | return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(get_llvm_type(g, str_type), 0)); |
| 947 | 944 | } |
| 948 | 945 | |
| 946 | static ZigType *ptr_to_stack_trace_type(CodeGen *g) { | |
| 947 | return get_pointer_to_type(g, get_stack_trace_type(g), false); | |
| 948 | } | |
| 949 | ||
| 949 | 950 | static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) { |
| 950 | 951 | assert(g->panic_fn != nullptr); |
| 951 | 952 | LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn); |
| 952 | 953 | LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc); |
| 953 | 954 | if (stack_trace_arg == nullptr) { |
| 954 | ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | |
| 955 | stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type)); | |
| 955 | stack_trace_arg = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); | |
| 956 | 956 | } |
| 957 | 957 | LLVMValueRef args[] = { |
| 958 | 958 | msg_arg, |
| ... | ... | @@ -1046,7 +1046,7 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { |
| 1046 | 1046 | return g->add_error_return_trace_addr_fn_val; |
| 1047 | 1047 | |
| 1048 | 1048 | LLVMTypeRef arg_types[] = { |
| 1049 | get_llvm_type(g, get_ptr_to_stack_trace_type(g)), | |
| 1049 | get_llvm_type(g, ptr_to_stack_trace_type(g)), | |
| 1050 | 1050 | g->builtin_types.entry_usize->llvm_type, |
| 1051 | 1051 | }; |
| 1052 | 1052 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); |
| ... | ... | @@ -1127,7 +1127,7 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1127 | 1127 | |
| 1128 | 1128 | LLVMTypeRef arg_types[] = { |
| 1129 | 1129 | // error return trace pointer |
| 1130 | get_llvm_type(g, get_ptr_to_stack_trace_type(g)), | |
| 1130 | get_llvm_type(g, ptr_to_stack_trace_type(g)), | |
| 1131 | 1131 | }; |
| 1132 | 1132 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false); |
| 1133 | 1133 | |
| ... | ... | @@ -1205,7 +1205,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1205 | 1205 | LLVMTypeRef fn_type_ref; |
| 1206 | 1206 | if (g->have_err_ret_tracing) { |
| 1207 | 1207 | LLVMTypeRef arg_types[] = { |
| 1208 | get_llvm_type(g, g->ptr_to_stack_trace_type), | |
| 1208 | get_llvm_type(g, get_pointer_to_type(g, get_stack_trace_type(g), false)), | |
| 1209 | 1209 | get_llvm_type(g, g->err_tag_type), |
| 1210 | 1210 | }; |
| 1211 | 1211 | fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); |
| ... | ... | @@ -1321,14 +1321,7 @@ static LLVMValueRef get_cur_err_ret_trace_val(CodeGen *g, Scope *scope) { |
| 1321 | 1321 | if (g->cur_err_ret_trace_val_stack != nullptr) { |
| 1322 | 1322 | return g->cur_err_ret_trace_val_stack; |
| 1323 | 1323 | } |
| 1324 | if (g->cur_err_ret_trace_val_arg != nullptr) { | |
| 1325 | if (fn_is_async(g->cur_fn)) { | |
| 1326 | return LLVMBuildLoad(g->builder, g->cur_err_ret_trace_val_arg, ""); | |
| 1327 | } else { | |
| 1328 | return g->cur_err_ret_trace_val_arg; | |
| 1329 | } | |
| 1330 | } | |
| 1331 | return nullptr; | |
| 1324 | return g->cur_err_ret_trace_val_arg; | |
| 1332 | 1325 | } |
| 1333 | 1326 | |
| 1334 | 1327 | static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *scope) { |
| ... | ... | @@ -1337,8 +1330,7 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc |
| 1337 | 1330 | if (g->have_err_ret_tracing) { |
| 1338 | 1331 | LLVMValueRef err_ret_trace_val = get_cur_err_ret_trace_val(g, scope); |
| 1339 | 1332 | if (err_ret_trace_val == nullptr) { |
| 1340 | ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | |
| 1341 | err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type)); | |
| 1333 | err_ret_trace_val = LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); | |
| 1342 | 1334 | } |
| 1343 | 1335 | LLVMValueRef args[] = { |
| 1344 | 1336 | err_ret_trace_val, |
| ... | ... | @@ -2044,8 +2036,8 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { |
| 2044 | 2036 | assert(g->stack_trace_type != nullptr); |
| 2045 | 2037 | |
| 2046 | 2038 | LLVMTypeRef param_types[] = { |
| 2047 | get_llvm_type(g, get_ptr_to_stack_trace_type(g)), | |
| 2048 | get_llvm_type(g, get_ptr_to_stack_trace_type(g)), | |
| 2039 | get_llvm_type(g, ptr_to_stack_trace_type(g)), | |
| 2040 | get_llvm_type(g, ptr_to_stack_trace_type(g)), | |
| 2049 | 2041 | }; |
| 2050 | 2042 | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false); |
| 2051 | 2043 | |
| ... | ... | @@ -2058,7 +2050,6 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { |
| 2058 | 2050 | addLLVMArgAttr(fn_val, (unsigned)0, "noalias"); |
| 2059 | 2051 | addLLVMArgAttr(fn_val, (unsigned)0, "writeonly"); |
| 2060 | 2052 | |
| 2061 | addLLVMArgAttr(fn_val, (unsigned)1, "nonnull"); | |
| 2062 | 2053 | addLLVMArgAttr(fn_val, (unsigned)1, "noalias"); |
| 2063 | 2054 | addLLVMArgAttr(fn_val, (unsigned)1, "readonly"); |
| 2064 | 2055 | if (g->build_mode == BuildModeDebug) { |
| ... | ... | @@ -2075,7 +2066,7 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { |
| 2075 | 2066 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 2076 | 2067 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 2077 | 2068 | |
| 2078 | // if (dest_stack_trace == null) return; | |
| 2069 | // if (dest_stack_trace == null or src_stack_trace == null) return; | |
| 2079 | 2070 | // var frame_index: usize = undefined; |
| 2080 | 2071 | // var frames_left: usize = undefined; |
| 2081 | 2072 | // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) { |
| ... | ... | @@ -2093,7 +2084,7 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { |
| 2093 | 2084 | // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len; |
| 2094 | 2085 | // } |
| 2095 | 2086 | LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return"); |
| 2096 | LLVMBasicBlockRef dest_non_null_block = LLVMAppendBasicBlock(fn_val, "DestNonNull"); | |
| 2087 | LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(fn_val, "NonNull"); | |
| 2097 | 2088 | |
| 2098 | 2089 | LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frame_index"); |
| 2099 | 2090 | LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->llvm_type, "frames_left"); |
| ... | ... | @@ -2103,9 +2094,12 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { |
| 2103 | 2094 | |
| 2104 | 2095 | LLVMValueRef null_dest_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, dest_stack_trace_ptr, |
| 2105 | 2096 | LLVMConstNull(LLVMTypeOf(dest_stack_trace_ptr)), ""); |
| 2106 | LLVMBuildCondBr(g->builder, null_dest_bit, return_block, dest_non_null_block); | |
| 2097 | LLVMValueRef null_src_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_stack_trace_ptr, | |
| 2098 | LLVMConstNull(LLVMTypeOf(src_stack_trace_ptr)), ""); | |
| 2099 | LLVMValueRef null_bit = LLVMBuildOr(g->builder, null_dest_bit, null_src_bit, ""); | |
| 2100 | LLVMBuildCondBr(g->builder, null_bit, return_block, non_null_block); | |
| 2107 | 2101 | |
| 2108 | LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block); | |
| 2102 | LLVMPositionBuilderAtEnd(g->builder, non_null_block); | |
| 2109 | 2103 | size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index; |
| 2110 | 2104 | size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index; |
| 2111 | 2105 | LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr, |
| ... | ... | @@ -2183,13 +2177,11 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut |
| 2183 | 2177 | ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1, |
| 2184 | 2178 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); |
| 2185 | 2179 | |
| 2186 | if (fn_is_async(g->cur_fn) && g->cur_fn->calls_or_awaits_errorable_fn && | |
| 2187 | codegen_fn_has_err_ret_tracing_arg(g, g->cur_fn->type_entry->data.fn.fn_type_id.return_type)) | |
| 2188 | { | |
| 2189 | LLVMValueRef dest_trace_ptr = LLVMBuildLoad(g->builder, g->cur_err_ret_trace_val_arg, ""); | |
| 2190 | LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val }; | |
| 2191 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, | |
| 2192 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 2180 | ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; | |
| 2181 | if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) { | |
| 2182 | LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, | |
| 2183 | frame_index_trace_arg(g, ret_type), ""); | |
| 2184 | LLVMBuildStore(g->builder, my_err_trace_val, trace_ptr_ptr); | |
| 2193 | 2185 | } |
| 2194 | 2186 | |
| 2195 | 2187 | return nullptr; |
| ... | ... | @@ -2201,16 +2193,9 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume |
| 2201 | 2193 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 2202 | 2194 | LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); |
| 2203 | 2195 | if (end_bb == nullptr) end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume"); |
| 2204 | LLVMValueRef ok_bit; | |
| 2205 | if (resume_id == ResumeIdAwaitEarlyReturn) { | |
| 2206 | LLVMValueRef last_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), | |
| 2207 | LLVMConstInt(usize_type_ref, ResumeIdAwaitEarlyReturn, false)); | |
| 2208 | ok_bit = LLVMBuildICmp(g->builder, LLVMIntULT, LLVMGetParam(g->cur_fn_val, 1), last_value, ""); | |
| 2209 | } else { | |
| 2210 | LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), | |
| 2211 | LLVMConstInt(usize_type_ref, resume_id, false)); | |
| 2212 | ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, ""); | |
| 2213 | } | |
| 2196 | LLVMValueRef expected_value = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), | |
| 2197 | LLVMConstInt(usize_type_ref, resume_id, false)); | |
| 2198 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, LLVMGetParam(g->cur_fn_val, 1), expected_value, ""); | |
| 2214 | 2199 | LLVMBuildCondBr(g->builder, ok_bit, end_bb, bad_resume_block); |
| 2215 | 2200 | |
| 2216 | 2201 | LLVMPositionBuilderAtEnd(g->builder, bad_resume_block); |
| ... | ... | @@ -2219,36 +2204,19 @@ static void gen_assert_resume_id(CodeGen *g, IrInstruction *source_instr, Resume |
| 2219 | 2204 | LLVMPositionBuilderAtEnd(g->builder, end_bb); |
| 2220 | 2205 | } |
| 2221 | 2206 | |
| 2222 | static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef target_frame_ptr, | |
| 2223 | ResumeId resume_id, LLVMValueRef arg_val) | |
| 2224 | { | |
| 2207 | static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef target_frame_ptr, ResumeId resume_id) { | |
| 2225 | 2208 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 2226 | 2209 | if (fn_val == nullptr) { |
| 2227 | 2210 | LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_fn_ptr_index, ""); |
| 2228 | 2211 | fn_val = LLVMBuildLoad(g->builder, fn_ptr_ptr, ""); |
| 2229 | 2212 | } |
| 2230 | if (arg_val == nullptr) { | |
| 2231 | arg_val = LLVMBuildSub(g->builder, LLVMConstAllOnes(usize_type_ref), | |
| 2232 | LLVMConstInt(usize_type_ref, resume_id, false), ""); | |
| 2233 | } else { | |
| 2234 | assert(resume_id == ResumeIdAwaitEarlyReturn); | |
| 2235 | } | |
| 2213 | LLVMValueRef arg_val = LLVMBuildSub(g->builder, LLVMConstAllOnes(usize_type_ref), | |
| 2214 | LLVMConstInt(usize_type_ref, resume_id, false), ""); | |
| 2236 | 2215 | LLVMValueRef args[] = {target_frame_ptr, arg_val}; |
| 2237 | 2216 | return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, ""); |
| 2238 | 2217 | } |
| 2239 | 2218 | |
| 2240 | static LLVMValueRef get_cur_async_prev_val(CodeGen *g) { | |
| 2241 | if (g->cur_async_prev_val != nullptr) { | |
| 2242 | return g->cur_async_prev_val; | |
| 2243 | } | |
| 2244 | g->cur_async_prev_val = LLVMBuildLoad(g->builder, g->cur_async_prev_val_field_ptr, ""); | |
| 2245 | return g->cur_async_prev_val; | |
| 2246 | } | |
| 2247 | ||
| 2248 | 2219 | static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) { |
| 2249 | // This becomes invalid when a suspend happens. | |
| 2250 | g->cur_async_prev_val = nullptr; | |
| 2251 | ||
| 2252 | 2220 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 2253 | 2221 | LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, name_hint); |
| 2254 | 2222 | size_t new_block_index = g->cur_resume_block_count; |
| ... | ... | @@ -2259,6 +2227,10 @@ static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) { |
| 2259 | 2227 | return resume_bb; |
| 2260 | 2228 | } |
| 2261 | 2229 | |
| 2230 | static void set_tail_call_if_appropriate(CodeGen *g, LLVMValueRef call_inst) { | |
| 2231 | LLVMSetTailCall(call_inst, true); | |
| 2232 | } | |
| 2233 | ||
| 2262 | 2234 | static LLVMValueRef gen_maybe_atomic_op(CodeGen *g, LLVMAtomicRMWBinOp op, LLVMValueRef ptr, LLVMValueRef val, |
| 2263 | 2235 | LLVMAtomicOrdering order) |
| 2264 | 2236 | { |
| ... | ... | @@ -2282,32 +2254,32 @@ static LLVMValueRef gen_maybe_atomic_op(CodeGen *g, LLVMAtomicRMWBinOp op, LLVMV |
| 2282 | 2254 | } |
| 2283 | 2255 | } |
| 2284 | 2256 | |
| 2285 | static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable, | |
| 2286 | IrInstructionReturnBegin *instruction) | |
| 2287 | { | |
| 2257 | static void gen_async_return(CodeGen *g, IrInstructionReturn *instruction) { | |
| 2258 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; | |
| 2259 | ||
| 2288 | 2260 | ZigType *operand_type = (instruction->operand != nullptr) ? instruction->operand->value.type : nullptr; |
| 2289 | 2261 | bool operand_has_bits = (operand_type != nullptr) && type_has_bits(operand_type); |
| 2290 | if (!fn_is_async(g->cur_fn)) { | |
| 2291 | return operand_has_bits ? ir_llvm_value(g, instruction->operand) : nullptr; | |
| 2292 | } | |
| 2262 | ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; | |
| 2263 | bool ret_type_has_bits = type_has_bits(ret_type); | |
| 2293 | 2264 | |
| 2294 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; | |
| 2295 | 2265 | if (operand_has_bits && instruction->operand != nullptr) { |
| 2296 | ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; | |
| 2297 | 2266 | bool need_store = instruction->operand->value.special != ConstValSpecialRuntime || !handle_is_ptr(ret_type); |
| 2298 | 2267 | if (need_store) { |
| 2299 | // It didn't get written to the result ptr. We do that now so that we do not have to spill | |
| 2300 | // the return operand. | |
| 2268 | // It didn't get written to the result ptr. We do that now. | |
| 2301 | 2269 | ZigType *ret_ptr_type = get_pointer_to_type(g, ret_type, true); |
| 2302 | 2270 | gen_assign_raw(g, g->cur_ret_ptr, ret_ptr_type, ir_llvm_value(g, instruction->operand)); |
| 2303 | 2271 | } |
| 2304 | 2272 | } |
| 2305 | 2273 | |
| 2306 | // Prepare to be suspended. We might end up not having to suspend though. | |
| 2307 | LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "ReturnResume"); | |
| 2274 | // Whether we tail resume the awaiter, or do an early return, we are done and will not be resumed. | |
| 2275 | if (ir_want_runtime_safety(g, &instruction->base)) { | |
| 2276 | LLVMValueRef new_resume_index = LLVMConstAllOnes(usize_type_ref); | |
| 2277 | LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr); | |
| 2278 | } | |
| 2308 | 2279 | |
| 2309 | 2280 | LLVMValueRef zero = LLVMConstNull(usize_type_ref); |
| 2310 | 2281 | LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); |
| 2282 | ||
| 2311 | 2283 | LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXor, g->cur_async_awaiter_ptr, |
| 2312 | 2284 | all_ones, LLVMAtomicOrderingAcquire); |
| 2313 | 2285 | |
| ... | ... | @@ -2316,7 +2288,6 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable, |
| 2316 | 2288 | LLVMBasicBlockRef resume_them_block = LLVMAppendBasicBlock(g->cur_fn_val, "ResumeThem"); |
| 2317 | 2289 | |
| 2318 | 2290 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_them_block, 2); |
| 2319 | LLVMBasicBlockRef switch_bb = LLVMGetInsertBlock(g->builder); | |
| 2320 | 2291 | |
| 2321 | 2292 | LLVMAddCase(switch_instr, zero, early_return_block); |
| 2322 | 2293 | LLVMAddCase(switch_instr, all_ones, bad_return_block); |
| ... | ... | @@ -2325,90 +2296,63 @@ static LLVMValueRef ir_render_return_begin(CodeGen *g, IrExecutable *executable, |
| 2325 | 2296 | LLVMPositionBuilderAtEnd(g->builder, bad_return_block); |
| 2326 | 2297 | gen_assertion(g, PanicMsgIdBadReturn, &instruction->base); |
| 2327 | 2298 | |
| 2328 | // The caller has not done an await yet. So we suspend at the return instruction, until a | |
| 2329 | // cancel or await is performed. | |
| 2299 | // There is no awaiter yet, but we're completely done. | |
| 2330 | 2300 | LLVMPositionBuilderAtEnd(g->builder, early_return_block); |
| 2331 | 2301 | LLVMBuildRetVoid(g->builder); |
| 2332 | 2302 | |
| 2333 | // Add a safety check for when getting resumed by the awaiter. | |
| 2334 | LLVMPositionBuilderAtEnd(g->builder, resume_bb); | |
| 2335 | LLVMBasicBlockRef after_resume_block = LLVMGetInsertBlock(g->builder); | |
| 2336 | gen_assert_resume_id(g, &instruction->base, ResumeIdAwaitEarlyReturn, PanicMsgIdResumedFnPendingAwait, | |
| 2337 | resume_them_block); | |
| 2338 | ||
| 2339 | // We need to resume the caller by tail calling them. | |
| 2340 | // That will happen when rendering IrInstructionReturn after running the defers/errdefers. | |
| 2341 | // We either got here from Entry (function call) or from the switch above | |
| 2342 | g->cur_async_prev_val = LLVMBuildPhi(g->builder, usize_type_ref, ""); | |
| 2343 | LLVMValueRef incoming_values[] = { LLVMGetParam(g->cur_fn_val, 1), prev_val }; | |
| 2344 | LLVMBasicBlockRef incoming_blocks[] = { after_resume_block, switch_bb }; | |
| 2345 | LLVMAddIncoming(g->cur_async_prev_val, incoming_values, incoming_blocks, 2); | |
| 2346 | ||
| 2347 | g->cur_is_after_return = true; | |
| 2348 | LLVMBuildStore(g->builder, g->cur_async_prev_val, g->cur_async_prev_val_field_ptr); | |
| 2349 | ||
| 2350 | if (!operand_has_bits) { | |
| 2351 | return nullptr; | |
| 2352 | } | |
| 2353 | ||
| 2354 | return get_handle_value(g, g->cur_ret_ptr, operand_type, get_pointer_to_type(g, operand_type, true)); | |
| 2355 | } | |
| 2356 | ||
| 2357 | static void set_tail_call_if_appropriate(CodeGen *g, LLVMValueRef call_inst) { | |
| 2358 | LLVMSetTailCall(call_inst, true); | |
| 2303 | // We need to resume the caller by tail calling them, | |
| 2304 | // but first write through the result pointer and possibly | |
| 2305 | // error return trace pointer. | |
| 2306 | LLVMPositionBuilderAtEnd(g->builder, resume_them_block); | |
| 2307 | ||
| 2308 | if (ret_type_has_bits) { | |
| 2309 | // If the awaiter result pointer is non-null, we need to copy the result to there. | |
| 2310 | LLVMBasicBlockRef copy_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResult"); | |
| 2311 | LLVMBasicBlockRef copy_end_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResultEnd"); | |
| 2312 | LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_ret_start + 1, ""); | |
| 2313 | LLVMValueRef awaiter_ret_ptr = LLVMBuildLoad(g->builder, awaiter_ret_ptr_ptr, ""); | |
| 2314 | LLVMValueRef zero_ptr = LLVMConstNull(LLVMTypeOf(awaiter_ret_ptr)); | |
| 2315 | LLVMValueRef need_copy_bit = LLVMBuildICmp(g->builder, LLVMIntNE, awaiter_ret_ptr, zero_ptr, ""); | |
| 2316 | LLVMBuildCondBr(g->builder, need_copy_bit, copy_block, copy_end_block); | |
| 2317 | ||
| 2318 | LLVMPositionBuilderAtEnd(g->builder, copy_block); | |
| 2319 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | |
| 2320 | LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, awaiter_ret_ptr, ptr_u8, ""); | |
| 2321 | LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, g->cur_ret_ptr, ptr_u8, ""); | |
| 2322 | bool is_volatile = false; | |
| 2323 | uint32_t abi_align = get_abi_alignment(g, ret_type); | |
| 2324 | LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, ret_type), false); | |
| 2325 | ZigLLVMBuildMemCpy(g->builder, | |
| 2326 | dest_ptr_casted, abi_align, | |
| 2327 | src_ptr_casted, abi_align, byte_count_val, is_volatile); | |
| 2328 | LLVMBuildBr(g->builder, copy_end_block); | |
| 2329 | ||
| 2330 | LLVMPositionBuilderAtEnd(g->builder, copy_end_block); | |
| 2331 | if (codegen_fn_has_err_ret_tracing_arg(g, ret_type)) { | |
| 2332 | LLVMValueRef awaiter_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, | |
| 2333 | frame_index_trace_arg(g, ret_type) + 1, ""); | |
| 2334 | LLVMValueRef dest_trace_ptr = LLVMBuildLoad(g->builder, awaiter_trace_ptr_ptr, ""); | |
| 2335 | LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 2336 | LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val }; | |
| 2337 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, | |
| 2338 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 2339 | } | |
| 2340 | } | |
| 2341 | ||
| 2342 | // Resume the caller by tail calling them. | |
| 2343 | ZigType *any_frame_type = get_any_frame_type(g, ret_type); | |
| 2344 | LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, prev_val, get_llvm_type(g, any_frame_type), ""); | |
| 2345 | LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn); | |
| 2346 | set_tail_call_if_appropriate(g, call_inst); | |
| 2347 | LLVMBuildRetVoid(g->builder); | |
| 2359 | 2348 | } |
| 2360 | 2349 | |
| 2361 | 2350 | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *instruction) { |
| 2362 | 2351 | if (fn_is_async(g->cur_fn)) { |
| 2363 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; | |
| 2364 | ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; | |
| 2365 | bool ret_type_has_bits = type_has_bits(ret_type); | |
| 2366 | ||
| 2367 | if (ir_want_runtime_safety(g, &instruction->base)) { | |
| 2368 | LLVMValueRef new_resume_index = LLVMConstAllOnes(usize_type_ref); | |
| 2369 | LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr); | |
| 2370 | } | |
| 2371 | ||
| 2372 | if (ret_type_has_bits) { | |
| 2373 | // If the awaiter result pointer is non-null, we need to copy the result to there. | |
| 2374 | LLVMBasicBlockRef copy_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResult"); | |
| 2375 | LLVMBasicBlockRef copy_end_block = LLVMAppendBasicBlock(g->cur_fn_val, "CopyResultEnd"); | |
| 2376 | LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_ret_start + 1, ""); | |
| 2377 | LLVMValueRef awaiter_ret_ptr = LLVMBuildLoad(g->builder, awaiter_ret_ptr_ptr, ""); | |
| 2378 | LLVMValueRef zero_ptr = LLVMConstNull(LLVMTypeOf(awaiter_ret_ptr)); | |
| 2379 | LLVMValueRef need_copy_bit = LLVMBuildICmp(g->builder, LLVMIntNE, awaiter_ret_ptr, zero_ptr, ""); | |
| 2380 | LLVMBuildCondBr(g->builder, need_copy_bit, copy_block, copy_end_block); | |
| 2381 | ||
| 2382 | LLVMPositionBuilderAtEnd(g->builder, copy_block); | |
| 2383 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | |
| 2384 | LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, awaiter_ret_ptr, ptr_u8, ""); | |
| 2385 | LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, g->cur_ret_ptr, ptr_u8, ""); | |
| 2386 | bool is_volatile = false; | |
| 2387 | uint32_t abi_align = get_abi_alignment(g, ret_type); | |
| 2388 | LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, ret_type), false); | |
| 2389 | ZigLLVMBuildMemCpy(g->builder, | |
| 2390 | dest_ptr_casted, abi_align, | |
| 2391 | src_ptr_casted, abi_align, byte_count_val, is_volatile); | |
| 2392 | LLVMBuildBr(g->builder, copy_end_block); | |
| 2393 | ||
| 2394 | LLVMPositionBuilderAtEnd(g->builder, copy_end_block); | |
| 2395 | } | |
| 2396 | ||
| 2397 | // We need to resume the caller by tail calling them. | |
| 2398 | ZigType *any_frame_type = get_any_frame_type(g, ret_type); | |
| 2399 | LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false); | |
| 2400 | LLVMValueRef mask_val = LLVMConstNot(one); | |
| 2401 | LLVMValueRef masked_prev_val = LLVMBuildAnd(g->builder, get_cur_async_prev_val(g), mask_val, ""); | |
| 2402 | LLVMValueRef their_frame_ptr = LLVMBuildIntToPtr(g->builder, masked_prev_val, | |
| 2403 | get_llvm_type(g, any_frame_type), ""); | |
| 2404 | LLVMValueRef call_inst = gen_resume(g, nullptr, their_frame_ptr, ResumeIdReturn, nullptr); | |
| 2405 | set_tail_call_if_appropriate(g, call_inst); | |
| 2406 | LLVMBuildRetVoid(g->builder); | |
| 2407 | ||
| 2408 | g->cur_is_after_return = false; | |
| 2409 | ||
| 2352 | gen_async_return(g, instruction); | |
| 2410 | 2353 | return nullptr; |
| 2411 | 2354 | } |
| 2355 | ||
| 2412 | 2356 | if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { |
| 2413 | 2357 | if (instruction->operand == nullptr) { |
| 2414 | 2358 | LLVMBuildRetVoid(g->builder); |
| ... | ... | @@ -3893,6 +3837,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3893 | 3837 | // even if prefix_arg_err_ret_stack is true, let the async function do its own |
| 3894 | 3838 | // initialization. |
| 3895 | 3839 | } else { |
| 3840 | // async function called as a normal function | |
| 3841 | ||
| 3896 | 3842 | frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); |
| 3897 | 3843 | awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer |
| 3898 | 3844 | if (ret_has_bits) { |
| ... | ... | @@ -3912,7 +3858,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3912 | 3858 | |
| 3913 | 3859 | if (prefix_arg_err_ret_stack) { |
| 3914 | 3860 | LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, |
| 3915 | frame_index_trace_arg(g, src_return_type), ""); | |
| 3861 | frame_index_trace_arg(g, src_return_type) + 1, ""); | |
| 3916 | 3862 | LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); |
| 3917 | 3863 | LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr); |
| 3918 | 3864 | } |
| ... | ... | @@ -4018,7 +3964,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4018 | 3964 | } |
| 4019 | 3965 | |
| 4020 | 3966 | if (instruction->is_async) { |
| 4021 | gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr); | |
| 3967 | gen_resume(g, fn_val, frame_result_loc, ResumeIdCall); | |
| 4022 | 3968 | if (instruction->new_stack != nullptr) { |
| 4023 | 3969 | return frame_result_loc; |
| 4024 | 3970 | } |
| ... | ... | @@ -4028,7 +3974,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4028 | 3974 | |
| 4029 | 3975 | LLVMBasicBlockRef call_bb = gen_suspend_begin(g, "CallResume"); |
| 4030 | 3976 | |
| 4031 | LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall, nullptr); | |
| 3977 | LLVMValueRef call_inst = gen_resume(g, fn_val, frame_result_loc, ResumeIdCall); | |
| 4032 | 3978 | set_tail_call_if_appropriate(g, call_inst); |
| 4033 | 3979 | LLVMBuildRetVoid(g->builder); |
| 4034 | 3980 | |
| ... | ... | @@ -4744,8 +4690,7 @@ static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *execu |
| 4744 | 4690 | { |
| 4745 | 4691 | LLVMValueRef cur_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); |
| 4746 | 4692 | if (cur_err_ret_trace_val == nullptr) { |
| 4747 | ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g); | |
| 4748 | return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type)); | |
| 4693 | return LLVMConstNull(get_llvm_type(g, ptr_to_stack_trace_type(g))); | |
| 4749 | 4694 | } |
| 4750 | 4695 | return cur_err_ret_trace_val; |
| 4751 | 4696 | } |
| ... | ... | @@ -5505,60 +5450,6 @@ static LLVMValueRef ir_render_suspend_finish(CodeGen *g, IrExecutable *executabl |
| 5505 | 5450 | return nullptr; |
| 5506 | 5451 | } |
| 5507 | 5452 | |
| 5508 | static LLVMValueRef ir_render_cancel(CodeGen *g, IrExecutable *executable, IrInstructionCancel *instruction) { | |
| 5509 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; | |
| 5510 | LLVMValueRef zero = LLVMConstNull(usize_type_ref); | |
| 5511 | LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); | |
| 5512 | LLVMValueRef one = LLVMConstInt(usize_type_ref, 1, false); | |
| 5513 | src_assert(instruction->frame->value.type->id == ZigTypeIdAnyFrame, instruction->base.source_node); | |
| 5514 | ZigType *result_type = instruction->frame->value.type->data.any_frame.result_type; | |
| 5515 | ||
| 5516 | LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame); | |
| 5517 | LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "CancelResume"); | |
| 5518 | ||
| 5519 | // supply null for the awaiter return pointer (no copy needed) | |
| 5520 | if (type_has_bits(result_type)) { | |
| 5521 | LLVMValueRef awaiter_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start + 1, ""); | |
| 5522 | LLVMBuildStore(g->builder, LLVMConstNull(LLVMGetElementType(LLVMTypeOf(awaiter_ret_ptr_ptr))), | |
| 5523 | awaiter_ret_ptr_ptr); | |
| 5524 | } | |
| 5525 | ||
| 5526 | // supply null for the error return trace pointer | |
| 5527 | if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { | |
| 5528 | LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, | |
| 5529 | frame_index_trace_arg(g, result_type), ""); | |
| 5530 | LLVMBuildStore(g->builder, LLVMConstNull(LLVMGetElementType(LLVMTypeOf(err_ret_trace_ptr_ptr))), | |
| 5531 | err_ret_trace_ptr_ptr); | |
| 5532 | } | |
| 5533 | ||
| 5534 | LLVMValueRef awaiter_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); | |
| 5535 | LLVMValueRef awaiter_ored_val = LLVMBuildOr(g->builder, awaiter_val, one, ""); | |
| 5536 | LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_awaiter_index, ""); | |
| 5537 | ||
| 5538 | LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_ored_val, | |
| 5539 | LLVMAtomicOrderingRelease); | |
| 5540 | ||
| 5541 | LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CancelSuspend"); | |
| 5542 | LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn"); | |
| 5543 | ||
| 5544 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, resume_bb, 2); | |
| 5545 | LLVMAddCase(switch_instr, zero, complete_suspend_block); | |
| 5546 | LLVMAddCase(switch_instr, all_ones, early_return_block); | |
| 5547 | ||
| 5548 | LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block); | |
| 5549 | LLVMBuildRetVoid(g->builder); | |
| 5550 | ||
| 5551 | LLVMPositionBuilderAtEnd(g->builder, early_return_block); | |
| 5552 | LLVMValueRef call_inst = gen_resume(g, nullptr, target_frame_ptr, ResumeIdAwaitEarlyReturn, awaiter_ored_val); | |
| 5553 | set_tail_call_if_appropriate(g, call_inst); | |
| 5554 | LLVMBuildRetVoid(g->builder); | |
| 5555 | ||
| 5556 | LLVMPositionBuilderAtEnd(g->builder, resume_bb); | |
| 5557 | gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedACancelingFn, nullptr); | |
| 5558 | ||
| 5559 | return nullptr; | |
| 5560 | } | |
| 5561 | ||
| 5562 | 5453 | static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwaitGen *instruction) { |
| 5563 | 5454 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 5564 | 5455 | LLVMValueRef zero = LLVMConstNull(usize_type_ref); |
| ... | ... | @@ -5568,8 +5459,9 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5568 | 5459 | |
| 5569 | 5460 | // Prepare to be suspended |
| 5570 | 5461 | LLVMBasicBlockRef resume_bb = gen_suspend_begin(g, "AwaitResume"); |
| 5462 | LLVMBasicBlockRef end_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitEnd"); | |
| 5571 | 5463 | |
| 5572 | // At this point resuming the function will do the correct thing. | |
| 5464 | // At this point resuming the function will continue from resume_bb. | |
| 5573 | 5465 | // This code is as if it is running inside the suspend block. |
| 5574 | 5466 | |
| 5575 | 5467 | // supply the awaiter return pointer |
| ... | ... | @@ -5591,15 +5483,15 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5591 | 5483 | LLVMValueRef my_err_ret_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope); |
| 5592 | 5484 | assert(my_err_ret_trace_val != nullptr); |
| 5593 | 5485 | LLVMValueRef err_ret_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, |
| 5594 | frame_index_trace_arg(g, result_type), ""); | |
| 5486 | frame_index_trace_arg(g, result_type) + 1, ""); | |
| 5595 | 5487 | LLVMBuildStore(g->builder, my_err_ret_trace_val, err_ret_trace_ptr_ptr); |
| 5596 | 5488 | } |
| 5597 | 5489 | |
| 5598 | 5490 | // caller's own frame pointer |
| 5599 | 5491 | LLVMValueRef awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); |
| 5600 | 5492 | LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_awaiter_index, ""); |
| 5601 | LLVMValueRef prev_val = LLVMBuildAtomicRMW(g->builder, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val, | |
| 5602 | LLVMAtomicOrderingRelease, g->is_single_threaded); | |
| 5493 | LLVMValueRef prev_val = gen_maybe_atomic_op(g, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val, | |
| 5494 | LLVMAtomicOrderingRelease); | |
| 5603 | 5495 | |
| 5604 | 5496 | LLVMBasicBlockRef bad_await_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadAwait"); |
| 5605 | 5497 | LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CompleteSuspend"); |
| ... | ... | @@ -5615,20 +5507,42 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5615 | 5507 | LLVMPositionBuilderAtEnd(g->builder, bad_await_block); |
| 5616 | 5508 | gen_assertion(g, PanicMsgIdBadAwait, &instruction->base); |
| 5617 | 5509 | |
| 5618 | // Early return: The async function has already completed, but it is suspending before setting the result, | |
| 5619 | // populating the error return trace if applicable, and running the defers. | |
| 5620 | // Tail resume it now, so that it can complete. | |
| 5621 | LLVMPositionBuilderAtEnd(g->builder, early_return_block); | |
| 5622 | LLVMValueRef call_inst = gen_resume(g, nullptr, target_frame_ptr, ResumeIdAwaitEarlyReturn, awaiter_init_val); | |
| 5623 | set_tail_call_if_appropriate(g, call_inst); | |
| 5624 | LLVMBuildRetVoid(g->builder); | |
| 5625 | ||
| 5626 | 5510 | // Rely on the target to resume us from suspension. |
| 5627 | 5511 | LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block); |
| 5628 | 5512 | LLVMBuildRetVoid(g->builder); |
| 5629 | 5513 | |
| 5514 | // Early return: The async function has already completed. We must copy the result and | |
| 5515 | // the error return trace if applicable. | |
| 5516 | LLVMPositionBuilderAtEnd(g->builder, early_return_block); | |
| 5517 | if (type_has_bits(result_type) && result_loc != nullptr) { | |
| 5518 | LLVMValueRef their_result_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, frame_ret_start, ""); | |
| 5519 | LLVMValueRef their_result_ptr = LLVMBuildLoad(g->builder, their_result_ptr_ptr, ""); | |
| 5520 | LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); | |
| 5521 | LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, result_loc, ptr_u8, ""); | |
| 5522 | LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, their_result_ptr, ptr_u8, ""); | |
| 5523 | bool is_volatile = false; | |
| 5524 | uint32_t abi_align = get_abi_alignment(g, result_type); | |
| 5525 | LLVMValueRef byte_count_val = LLVMConstInt(usize_type_ref, type_size(g, result_type), false); | |
| 5526 | ZigLLVMBuildMemCpy(g->builder, | |
| 5527 | dest_ptr_casted, abi_align, | |
| 5528 | src_ptr_casted, abi_align, byte_count_val, is_volatile); | |
| 5529 | } | |
| 5530 | if (codegen_fn_has_err_ret_tracing_arg(g, result_type)) { | |
| 5531 | LLVMValueRef their_trace_ptr_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, | |
| 5532 | frame_index_trace_arg(g, result_type), ""); | |
| 5533 | LLVMValueRef src_trace_ptr = LLVMBuildLoad(g->builder, their_trace_ptr_ptr, ""); | |
| 5534 | LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, instruction->base.scope); | |
| 5535 | LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; | |
| 5536 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, | |
| 5537 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 5538 | } | |
| 5539 | LLVMBuildBr(g->builder, end_bb); | |
| 5540 | ||
| 5630 | 5541 | LLVMPositionBuilderAtEnd(g->builder, resume_bb); |
| 5631 | 5542 | gen_assert_resume_id(g, &instruction->base, ResumeIdReturn, PanicMsgIdResumedAnAwaitingFn, nullptr); |
| 5543 | LLVMBuildBr(g->builder, end_bb); | |
| 5544 | ||
| 5545 | LLVMPositionBuilderAtEnd(g->builder, end_bb); | |
| 5632 | 5546 | if (type_has_bits(result_type) && result_loc != nullptr) { |
| 5633 | 5547 | return get_handle_value(g, result_loc, result_type, ptr_result_type); |
| 5634 | 5548 | } |
| ... | ... | @@ -5640,7 +5554,7 @@ static LLVMValueRef ir_render_resume(CodeGen *g, IrExecutable *executable, IrIns |
| 5640 | 5554 | ZigType *frame_type = instruction->frame->value.type; |
| 5641 | 5555 | assert(frame_type->id == ZigTypeIdAnyFrame); |
| 5642 | 5556 | |
| 5643 | gen_resume(g, nullptr, frame, ResumeIdManual, nullptr); | |
| 5557 | gen_resume(g, nullptr, frame, ResumeIdManual); | |
| 5644 | 5558 | return nullptr; |
| 5645 | 5559 | } |
| 5646 | 5560 | |
| ... | ... | @@ -5651,18 +5565,6 @@ static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable, |
| 5651 | 5565 | return gen_frame_size(g, fn_val); |
| 5652 | 5566 | } |
| 5653 | 5567 | |
| 5654 | static LLVMValueRef ir_render_test_cancel_requested(CodeGen *g, IrExecutable *executable, | |
| 5655 | IrInstructionTestCancelRequested *instruction) | |
| 5656 | { | |
| 5657 | if (!fn_is_async(g->cur_fn)) | |
| 5658 | return LLVMConstInt(LLVMInt1Type(), 0, false); | |
| 5659 | if (g->cur_is_after_return) { | |
| 5660 | return LLVMBuildTrunc(g->builder, get_cur_async_prev_val(g), LLVMInt1Type(), ""); | |
| 5661 | } else { | |
| 5662 | zig_panic("TODO"); | |
| 5663 | } | |
| 5664 | } | |
| 5665 | ||
| 5666 | 5568 | static LLVMValueRef ir_render_spill_begin(CodeGen *g, IrExecutable *executable, |
| 5667 | 5569 | IrInstructionSpillBegin *instruction) |
| 5668 | 5570 | { |
| ... | ... | @@ -5798,8 +5700,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5798 | 5700 | |
| 5799 | 5701 | case IrInstructionIdDeclVarGen: |
| 5800 | 5702 | return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); |
| 5801 | case IrInstructionIdReturnBegin: | |
| 5802 | return ir_render_return_begin(g, executable, (IrInstructionReturnBegin *)instruction); | |
| 5803 | 5703 | case IrInstructionIdReturn: |
| 5804 | 5704 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| 5805 | 5705 | case IrInstructionIdBinOp: |
| ... | ... | @@ -5918,8 +5818,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5918 | 5818 | return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction); |
| 5919 | 5819 | case IrInstructionIdErrorReturnTrace: |
| 5920 | 5820 | return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction); |
| 5921 | case IrInstructionIdCancel: | |
| 5922 | return ir_render_cancel(g, executable, (IrInstructionCancel *)instruction); | |
| 5923 | 5821 | case IrInstructionIdAtomicRmw: |
| 5924 | 5822 | return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction); |
| 5925 | 5823 | case IrInstructionIdAtomicLoad: |
| ... | ... | @@ -5952,8 +5850,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5952 | 5850 | return ir_render_frame_size(g, executable, (IrInstructionFrameSizeGen *)instruction); |
| 5953 | 5851 | case IrInstructionIdAwaitGen: |
| 5954 | 5852 | return ir_render_await(g, executable, (IrInstructionAwaitGen *)instruction); |
| 5955 | case IrInstructionIdTestCancelRequested: | |
| 5956 | return ir_render_test_cancel_requested(g, executable, (IrInstructionTestCancelRequested *)instruction); | |
| 5957 | 5853 | case IrInstructionIdSpillBegin: |
| 5958 | 5854 | return ir_render_spill_begin(g, executable, (IrInstructionSpillBegin *)instruction); |
| 5959 | 5855 | case IrInstructionIdSpillEnd: |
| ... | ... | @@ -7060,9 +6956,9 @@ static void do_code_gen(CodeGen *g) { |
| 7060 | 6956 | ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count); |
| 7061 | 6957 | err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type)); |
| 7062 | 6958 | |
| 7063 | // populate g->stack_trace_type | |
| 7064 | (void)get_ptr_to_stack_trace_type(g); | |
| 7065 | 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)); | |
| 6959 | (void)get_llvm_type(g, get_stack_trace_type(g)); | |
| 6960 | g->cur_err_ret_trace_val_stack = build_alloca(g, get_stack_trace_type(g), "error_return_trace", | |
| 6961 | get_abi_alignment(g, g->stack_trace_type)); | |
| 7066 | 6962 | } else { |
| 7067 | 6963 | g->cur_err_ret_trace_val_stack = nullptr; |
| 7068 | 6964 | } |
| ... | ... | @@ -7204,18 +7100,12 @@ static void do_code_gen(CodeGen *g) { |
| 7204 | 7100 | LLVMValueRef cur_ret_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, frame_ret_start, ""); |
| 7205 | 7101 | g->cur_ret_ptr = LLVMBuildLoad(g->builder, cur_ret_ptr_ptr, ""); |
| 7206 | 7102 | } |
| 7207 | if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { | |
| 7208 | uint32_t trace_field_index = frame_index_trace_arg(g, fn_type_id->return_type); | |
| 7209 | g->cur_err_ret_trace_val_arg = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, trace_field_index, ""); | |
| 7210 | } | |
| 7211 | 7103 | uint32_t trace_field_index_stack = UINT32_MAX; |
| 7212 | 7104 | if (codegen_fn_has_err_ret_tracing_stack(g, fn_table_entry, true)) { |
| 7213 | 7105 | trace_field_index_stack = frame_index_trace_stack(g, fn_type_id); |
| 7214 | 7106 | g->cur_err_ret_trace_val_stack = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, |
| 7215 | 7107 | trace_field_index_stack, ""); |
| 7216 | 7108 | } |
| 7217 | g->cur_async_prev_val_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, | |
| 7218 | frame_prev_val_index, ""); | |
| 7219 | 7109 | |
| 7220 | 7110 | LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, ""); |
| 7221 | 7111 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, 4); |
| ... | ... | @@ -7227,6 +7117,13 @@ static void do_code_gen(CodeGen *g) { |
| 7227 | 7117 | g->cur_resume_block_count += 1; |
| 7228 | 7118 | LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block); |
| 7229 | 7119 | if (trace_field_index_stack != UINT32_MAX) { |
| 7120 | if (codegen_fn_has_err_ret_tracing_arg(g, fn_type_id->return_type)) { | |
| 7121 | LLVMValueRef trace_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, | |
| 7122 | frame_index_trace_arg(g, fn_type_id->return_type), ""); | |
| 7123 | LLVMValueRef zero_ptr = LLVMConstNull(LLVMGetElementType(LLVMTypeOf(trace_ptr_ptr))); | |
| 7124 | LLVMBuildStore(g->builder, zero_ptr, trace_ptr_ptr); | |
| 7125 | } | |
| 7126 | ||
| 7230 | 7127 | LLVMValueRef trace_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, |
| 7231 | 7128 | trace_field_index_stack, ""); |
| 7232 | 7129 | LLVMValueRef trace_field_addrs = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, |
| ... | ... | @@ -7273,8 +7170,6 @@ static void do_code_gen(CodeGen *g) { |
| 7273 | 7170 | LLVMDumpModule(g->module); |
| 7274 | 7171 | } |
| 7275 | 7172 | |
| 7276 | // in release mode, we're sooooo confident that we've generated correct ir, | |
| 7277 | // that we skip the verify module step in order to get better performance. | |
| 7278 | 7173 | #ifndef NDEBUG |
| 7279 | 7174 | char *error = nullptr; |
| 7280 | 7175 | LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error); |
| ... | ... | @@ -10157,6 +10052,11 @@ bool codegen_fn_has_err_ret_tracing_arg(CodeGen *g, ZigType *return_type) { |
| 10157 | 10052 | } |
| 10158 | 10053 | |
| 10159 | 10054 | bool codegen_fn_has_err_ret_tracing_stack(CodeGen *g, ZigFn *fn, bool is_async) { |
| 10160 | return g->have_err_ret_tracing && fn->calls_or_awaits_errorable_fn && | |
| 10161 | (is_async || !codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type)); | |
| 10055 | if (is_async) { | |
| 10056 | return g->have_err_ret_tracing && (fn->calls_or_awaits_errorable_fn || | |
| 10057 | codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type)); | |
| 10058 | } else { | |
| 10059 | return g->have_err_ret_tracing && fn->calls_or_awaits_errorable_fn && | |
| 10060 | !codegen_fn_has_err_ret_tracing_arg(g, fn->type_entry->data.fn.fn_type_id.return_type); | |
| 10061 | } | |
| 10162 | 10062 | } |
src/ir.cpp+29-201| ... | ... | @@ -526,10 +526,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionReturn *) { |
| 526 | 526 | return IrInstructionIdReturn; |
| 527 | 527 | } |
| 528 | 528 | |
| 529 | static constexpr IrInstructionId ir_instruction_id(IrInstructionReturnBegin *) { | |
| 530 | return IrInstructionIdReturnBegin; | |
| 531 | } | |
| 532 | ||
| 533 | 529 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCast *) { |
| 534 | 530 | return IrInstructionIdCast; |
| 535 | 531 | } |
| ... | ... | @@ -974,10 +970,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnion *) { |
| 974 | 970 | return IrInstructionIdErrorUnion; |
| 975 | 971 | } |
| 976 | 972 | |
| 977 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCancel *) { | |
| 978 | return IrInstructionIdCancel; | |
| 979 | } | |
| 980 | ||
| 981 | 973 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) { |
| 982 | 974 | return IrInstructionIdAtomicRmw; |
| 983 | 975 | } |
| ... | ... | @@ -1062,10 +1054,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResume *) { |
| 1062 | 1054 | return IrInstructionIdResume; |
| 1063 | 1055 | } |
| 1064 | 1056 | |
| 1065 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelRequested *) { | |
| 1066 | return IrInstructionIdTestCancelRequested; | |
| 1067 | } | |
| 1068 | ||
| 1069 | 1057 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillBegin *) { |
| 1070 | 1058 | return IrInstructionIdSpillBegin; |
| 1071 | 1059 | } |
| ... | ... | @@ -1138,18 +1126,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou |
| 1138 | 1126 | return &return_instruction->base; |
| 1139 | 1127 | } |
| 1140 | 1128 | |
| 1141 | static IrInstruction *ir_build_return_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1142 | IrInstruction *operand) | |
| 1143 | { | |
| 1144 | IrInstructionReturnBegin *return_instruction = ir_build_instruction<IrInstructionReturnBegin>(irb, scope, source_node); | |
| 1145 | return_instruction->operand = operand; | |
| 1146 | ||
| 1147 | ir_ref_instruction(operand, irb->current_basic_block); | |
| 1148 | ||
| 1149 | return &return_instruction->base; | |
| 1150 | } | |
| 1151 | ||
| 1152 | ||
| 1153 | 1129 | static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1154 | 1130 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 1155 | 1131 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_void; |
| ... | ... | @@ -3284,16 +3260,6 @@ static IrInstruction *ir_build_suspend_finish(IrBuilder *irb, Scope *scope, AstN |
| 3284 | 3260 | return &instruction->base; |
| 3285 | 3261 | } |
| 3286 | 3262 | |
| 3287 | static IrInstruction *ir_build_cancel(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *frame) { | |
| 3288 | IrInstructionCancel *instruction = ir_build_instruction<IrInstructionCancel>(irb, scope, source_node); | |
| 3289 | instruction->base.value.type = irb->codegen->builtin_types.entry_void; | |
| 3290 | instruction->frame = frame; | |
| 3291 | ||
| 3292 | ir_ref_instruction(frame, irb->current_basic_block); | |
| 3293 | ||
| 3294 | return &instruction->base; | |
| 3295 | } | |
| 3296 | ||
| 3297 | 3263 | static IrInstruction *ir_build_await_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 3298 | 3264 | IrInstruction *frame, ResultLoc *result_loc) |
| 3299 | 3265 | { |
| ... | ... | @@ -3331,13 +3297,6 @@ static IrInstruction *ir_build_resume(IrBuilder *irb, Scope *scope, AstNode *sou |
| 3331 | 3297 | return &instruction->base; |
| 3332 | 3298 | } |
| 3333 | 3299 | |
| 3334 | static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node) { | |
| 3335 | IrInstructionTestCancelRequested *instruction = ir_build_instruction<IrInstructionTestCancelRequested>(irb, scope, source_node); | |
| 3336 | instruction->base.value.type = irb->codegen->builtin_types.entry_bool; | |
| 3337 | ||
| 3338 | return &instruction->base; | |
| 3339 | } | |
| 3340 | ||
| 3341 | 3300 | static IrInstructionSpillBegin *ir_build_spill_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 3342 | 3301 | IrInstruction *operand, SpillId spill_id) |
| 3343 | 3302 | { |
| ... | ... | @@ -3532,7 +3491,6 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3532 | 3491 | } |
| 3533 | 3492 | |
| 3534 | 3493 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value)); |
| 3535 | return_value = ir_build_return_begin(irb, scope, node, return_value); | |
| 3536 | 3494 | |
| 3537 | 3495 | size_t defer_counts[2]; |
| 3538 | 3496 | ir_count_defers(irb, scope, outer_scope, defer_counts); |
| ... | ... | @@ -3545,49 +3503,40 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3545 | 3503 | return result; |
| 3546 | 3504 | } |
| 3547 | 3505 | bool should_inline = ir_should_inline(irb->exec, scope); |
| 3548 | bool need_test_cancel = !should_inline && have_err_defers; | |
| 3549 | 3506 | |
| 3550 | 3507 | IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr"); |
| 3551 | IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, scope, "Defers"); | |
| 3552 | IrBasicBlock *ok_block = need_test_cancel ? | |
| 3553 | ir_create_basic_block(irb, scope, "ErrRetOk") : normal_defers_block; | |
| 3554 | IrBasicBlock *all_defers_block = have_err_defers ? ir_create_basic_block(irb, scope, "ErrDefers") : normal_defers_block; | |
| 3508 | IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk"); | |
| 3509 | ||
| 3510 | if (!have_err_defers) { | |
| 3511 | ir_gen_defers_for_block(irb, scope, outer_scope, false); | |
| 3512 | } | |
| 3555 | 3513 | |
| 3556 | 3514 | IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true); |
| 3557 | 3515 | |
| 3558 | IrInstruction *force_comptime = ir_build_const_bool(irb, scope, node, should_inline); | |
| 3559 | IrInstruction *err_is_comptime; | |
| 3516 | IrInstruction *is_comptime; | |
| 3560 | 3517 | if (should_inline) { |
| 3561 | err_is_comptime = force_comptime; | |
| 3518 | is_comptime = ir_build_const_bool(irb, scope, node, should_inline); | |
| 3562 | 3519 | } else { |
| 3563 | err_is_comptime = ir_build_test_comptime(irb, scope, node, is_err); | |
| 3520 | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); | |
| 3564 | 3521 | } |
| 3565 | 3522 | |
| 3566 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, err_is_comptime)); | |
| 3523 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime)); | |
| 3567 | 3524 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); |
| 3568 | 3525 | |
| 3569 | 3526 | ir_set_cursor_at_end_and_append_block(irb, err_block); |
| 3527 | if (have_err_defers) { | |
| 3528 | ir_gen_defers_for_block(irb, scope, outer_scope, true); | |
| 3529 | } | |
| 3570 | 3530 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 3571 | 3531 | ir_build_save_err_ret_addr(irb, scope, node); |
| 3572 | 3532 | } |
| 3573 | ir_build_br(irb, scope, node, all_defers_block, err_is_comptime); | |
| 3574 | ||
| 3575 | if (need_test_cancel) { | |
| 3576 | ir_set_cursor_at_end_and_append_block(irb, ok_block); | |
| 3577 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, scope, node); | |
| 3578 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_canceled, | |
| 3579 | all_defers_block, normal_defers_block, force_comptime)); | |
| 3580 | } | |
| 3533 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); | |
| 3581 | 3534 | |
| 3582 | if (all_defers_block != normal_defers_block) { | |
| 3583 | ir_set_cursor_at_end_and_append_block(irb, all_defers_block); | |
| 3584 | ir_gen_defers_for_block(irb, scope, outer_scope, true); | |
| 3585 | ir_build_br(irb, scope, node, ret_stmt_block, force_comptime); | |
| 3535 | ir_set_cursor_at_end_and_append_block(irb, ok_block); | |
| 3536 | if (have_err_defers) { | |
| 3537 | ir_gen_defers_for_block(irb, scope, outer_scope, false); | |
| 3586 | 3538 | } |
| 3587 | ||
| 3588 | ir_set_cursor_at_end_and_append_block(irb, normal_defers_block); | |
| 3589 | ir_gen_defers_for_block(irb, scope, outer_scope, false); | |
| 3590 | ir_build_br(irb, scope, node, ret_stmt_block, force_comptime); | |
| 3539 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); | |
| 3591 | 3540 | |
| 3592 | 3541 | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); |
| 3593 | 3542 | IrInstruction *result = ir_build_return(irb, scope, node, return_value); |
| ... | ... | @@ -3619,8 +3568,6 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3619 | 3568 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val)); |
| 3620 | 3569 | IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val, |
| 3621 | 3570 | SpillIdRetErrCode); |
| 3622 | ir_build_return_begin(irb, scope, node, err_val); | |
| 3623 | err_val = ir_build_spill_end(irb, scope, node, spill_begin); | |
| 3624 | 3571 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); |
| 3625 | 3572 | result_loc_ret->base.id = ResultLocIdReturn; |
| 3626 | 3573 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); |
| ... | ... | @@ -3629,6 +3576,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3629 | 3576 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 3630 | 3577 | ir_build_save_err_ret_addr(irb, scope, node); |
| 3631 | 3578 | } |
| 3579 | err_val = ir_build_spill_end(irb, scope, node, spill_begin); | |
| 3632 | 3580 | IrInstruction *ret_inst = ir_build_return(irb, scope, node, err_val); |
| 3633 | 3581 | result_loc_ret->base.source_instruction = ret_inst; |
| 3634 | 3582 | } |
| ... | ... | @@ -3847,38 +3795,10 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3847 | 3795 | return result; |
| 3848 | 3796 | |
| 3849 | 3797 | // no need for save_err_ret_addr because this cannot return error |
| 3850 | // but if it is a canceled async function we do need to run the errdefers | |
| 3798 | // only generate unconditional defers | |
| 3851 | 3799 | |
| 3852 | 3800 | ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result)); |
| 3853 | result = ir_mark_gen(ir_build_return_begin(irb, child_scope, block_node, result)); | |
| 3854 | ||
| 3855 | size_t defer_counts[2]; | |
| 3856 | ir_count_defers(irb, child_scope, outer_block_scope, defer_counts); | |
| 3857 | bool have_err_defers = defer_counts[ReturnKindError] > 0; | |
| 3858 | if (!have_err_defers) { | |
| 3859 | // only generate unconditional defers | |
| 3860 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); | |
| 3861 | return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result)); | |
| 3862 | } | |
| 3863 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, child_scope, block_node); | |
| 3864 | IrBasicBlock *all_defers_block = ir_create_basic_block(irb, child_scope, "ErrDefers"); | |
| 3865 | IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, child_scope, "Defers"); | |
| 3866 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, child_scope, "RetStmt"); | |
| 3867 | bool should_inline = ir_should_inline(irb->exec, child_scope); | |
| 3868 | IrInstruction *errdefers_is_comptime = ir_build_const_bool(irb, child_scope, block_node, | |
| 3869 | should_inline || !have_err_defers); | |
| 3870 | ir_mark_gen(ir_build_cond_br(irb, child_scope, block_node, is_canceled, | |
| 3871 | all_defers_block, normal_defers_block, errdefers_is_comptime)); | |
| 3872 | ||
| 3873 | ir_set_cursor_at_end_and_append_block(irb, all_defers_block); | |
| 3874 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, true); | |
| 3875 | ir_build_br(irb, child_scope, block_node, ret_stmt_block, errdefers_is_comptime); | |
| 3876 | ||
| 3877 | ir_set_cursor_at_end_and_append_block(irb, normal_defers_block); | |
| 3878 | 3801 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3879 | ir_build_br(irb, child_scope, block_node, ret_stmt_block, errdefers_is_comptime); | |
| 3880 | ||
| 3881 | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); | |
| 3882 | 3802 | return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result)); |
| 3883 | 3803 | } |
| 3884 | 3804 | |
| ... | ... | @@ -7930,31 +7850,6 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo |
| 7930 | 7850 | return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args); |
| 7931 | 7851 | } |
| 7932 | 7852 | |
| 7933 | static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) { | |
| 7934 | assert(node->type == NodeTypeCancel); | |
| 7935 | ||
| 7936 | ZigFn *fn_entry = exec_fn_entry(irb->exec); | |
| 7937 | if (!fn_entry) { | |
| 7938 | add_node_error(irb->codegen, node, buf_sprintf("cancel outside function definition")); | |
| 7939 | return irb->codegen->invalid_instruction; | |
| 7940 | } | |
| 7941 | ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope); | |
| 7942 | if (existing_suspend_scope) { | |
| 7943 | if (!existing_suspend_scope->reported_err) { | |
| 7944 | ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot cancel inside suspend block")); | |
| 7945 | add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here")); | |
| 7946 | existing_suspend_scope->reported_err = true; | |
| 7947 | } | |
| 7948 | return irb->codegen->invalid_instruction; | |
| 7949 | } | |
| 7950 | ||
| 7951 | IrInstruction *operand = ir_gen_node_extra(irb, node->data.cancel_expr.expr, scope, LValPtr, nullptr); | |
| 7952 | if (operand == irb->codegen->invalid_instruction) | |
| 7953 | return irb->codegen->invalid_instruction; | |
| 7954 | ||
| 7955 | return ir_build_cancel(irb, scope, node, operand); | |
| 7956 | } | |
| 7957 | ||
| 7958 | 7853 | static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 7959 | 7854 | assert(node->type == NodeTypeResume); |
| 7960 | 7855 | |
| ... | ... | @@ -8149,8 +8044,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop |
| 8149 | 8044 | return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc); |
| 8150 | 8045 | case NodeTypeErrorSetDecl: |
| 8151 | 8046 | return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc); |
| 8152 | case NodeTypeCancel: | |
| 8153 | return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval, result_loc); | |
| 8154 | 8047 | case NodeTypeResume: |
| 8155 | 8048 | return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc); |
| 8156 | 8049 | case NodeTypeAwaitExpr: |
| ... | ... | @@ -8228,7 +8121,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 8228 | 8121 | |
| 8229 | 8122 | if (!instr_is_unreachable(result)) { |
| 8230 | 8123 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result)); |
| 8231 | result = ir_mark_gen(ir_build_return_begin(irb, scope, node, result)); | |
| 8232 | 8124 | // no need for save_err_ret_addr because this cannot return error |
| 8233 | 8125 | ir_mark_gen(ir_build_return(irb, scope, result->source_node, result)); |
| 8234 | 8126 | } |
| ... | ... | @@ -8340,7 +8232,6 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec |
| 8340 | 8232 | switch (instruction->id) { |
| 8341 | 8233 | case IrInstructionIdUnwrapErrPayload: |
| 8342 | 8234 | case IrInstructionIdUnionFieldPtr: |
| 8343 | case IrInstructionIdReturnBegin: | |
| 8344 | 8235 | continue; |
| 8345 | 8236 | default: |
| 8346 | 8237 | break; |
| ... | ... | @@ -12745,17 +12636,17 @@ static IrInstruction *ir_analyze_instruction_add_implicit_return_type(IrAnalyze |
| 12745 | 12636 | return ir_const_void(ira, &instruction->base); |
| 12746 | 12637 | } |
| 12747 | 12638 | |
| 12748 | static IrInstruction *ir_analyze_instruction_return_begin(IrAnalyze *ira, IrInstructionReturnBegin *instruction) { | |
| 12639 | static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) { | |
| 12749 | 12640 | IrInstruction *operand = instruction->operand->child; |
| 12750 | 12641 | if (type_is_invalid(operand->value.type)) |
| 12751 | return ira->codegen->invalid_instruction; | |
| 12642 | return ir_unreach_error(ira); | |
| 12752 | 12643 | |
| 12753 | 12644 | if (!instr_is_comptime(operand) && handle_is_ptr(ira->explicit_return_type)) { |
| 12754 | 12645 | // result location mechanism took care of it. |
| 12755 | IrInstruction *result = ir_build_return_begin(&ira->new_irb, instruction->base.scope, | |
| 12756 | instruction->base.source_node, operand); | |
| 12757 | copy_const_val(&result->value, &operand->value, true); | |
| 12758 | return result; | |
| 12646 | IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, | |
| 12647 | instruction->base.source_node, nullptr); | |
| 12648 | result->value.type = ira->codegen->builtin_types.entry_unreachable; | |
| 12649 | return ir_finish_anal(ira, result); | |
| 12759 | 12650 | } |
| 12760 | 12651 | |
| 12761 | 12652 | IrInstruction *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type); |
| ... | ... | @@ -12777,38 +12668,6 @@ static IrInstruction *ir_analyze_instruction_return_begin(IrAnalyze *ira, IrInst |
| 12777 | 12668 | return ir_unreach_error(ira); |
| 12778 | 12669 | } |
| 12779 | 12670 | |
| 12780 | IrInstruction *result = ir_build_return_begin(&ira->new_irb, instruction->base.scope, | |
| 12781 | instruction->base.source_node, casted_operand); | |
| 12782 | copy_const_val(&result->value, &casted_operand->value, true); | |
| 12783 | return result; | |
| 12784 | } | |
| 12785 | ||
| 12786 | static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *instruction) { | |
| 12787 | IrInstruction *operand = instruction->operand->child; | |
| 12788 | if (type_is_invalid(operand->value.type)) | |
| 12789 | return ir_unreach_error(ira); | |
| 12790 | ||
| 12791 | if (!instr_is_comptime(operand) && handle_is_ptr(ira->explicit_return_type)) { | |
| 12792 | // result location mechanism took care of it. | |
| 12793 | IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, | |
| 12794 | instruction->base.source_node, nullptr); | |
| 12795 | result->value.type = ira->codegen->builtin_types.entry_unreachable; | |
| 12796 | return ir_finish_anal(ira, result); | |
| 12797 | } | |
| 12798 | ||
| 12799 | // This cast might have been already done from IrInstructionReturnBegin but it also | |
| 12800 | // might not have, in the case of `try`. | |
| 12801 | IrInstruction *casted_operand = ir_implicit_cast(ira, operand, ira->explicit_return_type); | |
| 12802 | if (type_is_invalid(casted_operand->value.type)) { | |
| 12803 | AstNode *source_node = ira->explicit_return_type_source_node; | |
| 12804 | if (source_node != nullptr) { | |
| 12805 | ErrorMsg *msg = ira->codegen->errors.last(); | |
| 12806 | add_error_note(ira->codegen, msg, source_node, | |
| 12807 | buf_sprintf("return type declared here")); | |
| 12808 | } | |
| 12809 | return ir_unreach_error(ira); | |
| 12810 | } | |
| 12811 | ||
| 12812 | 12671 | IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, |
| 12813 | 12672 | instruction->base.source_node, casted_operand); |
| 12814 | 12673 | result->value.type = ira->codegen->builtin_types.entry_unreachable; |
| ... | ... | @@ -14540,8 +14399,8 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) { |
| 14540 | 14399 | static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 14541 | 14400 | IrInstructionErrorReturnTrace *instruction) |
| 14542 | 14401 | { |
| 14402 | ZigType *ptr_to_stack_trace_type = get_pointer_to_type(ira->codegen, get_stack_trace_type(ira->codegen), false); | |
| 14543 | 14403 | if (instruction->optional == IrInstructionErrorReturnTrace::Null) { |
| 14544 | ZigType *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); | |
| 14545 | 14404 | ZigType *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type); |
| 14546 | 14405 | if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { |
| 14547 | 14406 | IrInstruction *result = ir_const(ira, &instruction->base, optional_type); |
| ... | ... | @@ -14559,7 +14418,7 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 14559 | 14418 | assert(ira->codegen->have_err_ret_tracing); |
| 14560 | 14419 | IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, |
| 14561 | 14420 | instruction->base.source_node, instruction->optional); |
| 14562 | new_instruction->value.type = get_ptr_to_stack_trace_type(ira->codegen); | |
| 14421 | new_instruction->value.type = ptr_to_stack_trace_type; | |
| 14563 | 14422 | return new_instruction; |
| 14564 | 14423 | } |
| 14565 | 14424 | } |
| ... | ... | @@ -15800,6 +15659,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15800 | 15659 | |
| 15801 | 15660 | if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { |
| 15802 | 15661 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 15662 | parent_fn_entry->inferred_async_fn = impl_fn; | |
| 15803 | 15663 | } |
| 15804 | 15664 | |
| 15805 | 15665 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, |
| ... | ... | @@ -15923,6 +15783,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15923 | 15783 | |
| 15924 | 15784 | if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { |
| 15925 | 15785 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 15786 | parent_fn_entry->inferred_async_fn = fn_entry; | |
| 15926 | 15787 | } |
| 15927 | 15788 | |
| 15928 | 15789 | IrInstruction *result_loc; |
| ... | ... | @@ -24702,21 +24563,6 @@ static IrInstruction *analyze_frame_ptr_to_anyframe_T(IrAnalyze *ira, IrInstruct |
| 24702 | 24563 | return casted_frame; |
| 24703 | 24564 | } |
| 24704 | 24565 | |
| 24705 | static IrInstruction *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) { | |
| 24706 | IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, instruction->frame->child); | |
| 24707 | if (type_is_invalid(frame->value.type)) | |
| 24708 | return ira->codegen->invalid_instruction; | |
| 24709 | ||
| 24710 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); | |
| 24711 | ir_assert(fn_entry != nullptr, &instruction->base); | |
| 24712 | ||
| 24713 | if (fn_entry->inferred_async_node == nullptr) { | |
| 24714 | fn_entry->inferred_async_node = instruction->base.source_node; | |
| 24715 | } | |
| 24716 | ||
| 24717 | return ir_build_cancel(&ira->new_irb, instruction->base.scope, instruction->base.source_node, frame); | |
| 24718 | } | |
| 24719 | ||
| 24720 | 24566 | static IrInstruction *ir_analyze_instruction_await(IrAnalyze *ira, IrInstructionAwaitSrc *instruction) { |
| 24721 | 24567 | IrInstruction *frame = analyze_frame_ptr_to_anyframe_T(ira, &instruction->base, instruction->frame->child); |
| 24722 | 24568 | if (type_is_invalid(frame->value.type)) |
| ... | ... | @@ -24772,15 +24618,6 @@ static IrInstruction *ir_analyze_instruction_resume(IrAnalyze *ira, IrInstructio |
| 24772 | 24618 | return ir_build_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame); |
| 24773 | 24619 | } |
| 24774 | 24620 | |
| 24775 | static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ira, | |
| 24776 | IrInstructionTestCancelRequested *instruction) | |
| 24777 | { | |
| 24778 | if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) { | |
| 24779 | return ir_const_bool(ira, &instruction->base, false); | |
| 24780 | } | |
| 24781 | return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node); | |
| 24782 | } | |
| 24783 | ||
| 24784 | 24621 | static IrInstruction *ir_analyze_instruction_spill_begin(IrAnalyze *ira, IrInstructionSpillBegin *instruction) { |
| 24785 | 24622 | if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) |
| 24786 | 24623 | return ir_const_void(ira, &instruction->base); |
| ... | ... | @@ -24848,8 +24685,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 24848 | 24685 | case IrInstructionIdAwaitGen: |
| 24849 | 24686 | zig_unreachable(); |
| 24850 | 24687 | |
| 24851 | case IrInstructionIdReturnBegin: | |
| 24852 | return ir_analyze_instruction_return_begin(ira, (IrInstructionReturnBegin *)instruction); | |
| 24853 | 24688 | case IrInstructionIdReturn: |
| 24854 | 24689 | return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction); |
| 24855 | 24690 | case IrInstructionIdConst: |
| ... | ... | @@ -25070,8 +24905,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25070 | 24905 | return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction); |
| 25071 | 24906 | case IrInstructionIdErrorUnion: |
| 25072 | 24907 | return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction); |
| 25073 | case IrInstructionIdCancel: | |
| 25074 | return ir_analyze_instruction_cancel(ira, (IrInstructionCancel *)instruction); | |
| 25075 | 24908 | case IrInstructionIdAtomicRmw: |
| 25076 | 24909 | return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction); |
| 25077 | 24910 | case IrInstructionIdAtomicLoad: |
| ... | ... | @@ -25114,8 +24947,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25114 | 24947 | return ir_analyze_instruction_resume(ira, (IrInstructionResume *)instruction); |
| 25115 | 24948 | case IrInstructionIdAwaitSrc: |
| 25116 | 24949 | return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction); |
| 25117 | case IrInstructionIdTestCancelRequested: | |
| 25118 | return ir_analyze_instruction_test_cancel_requested(ira, (IrInstructionTestCancelRequested *)instruction); | |
| 25119 | 24950 | case IrInstructionIdSpillBegin: |
| 25120 | 24951 | return ir_analyze_instruction_spill_begin(ira, (IrInstructionSpillBegin *)instruction); |
| 25121 | 24952 | case IrInstructionIdSpillEnd: |
| ... | ... | @@ -25209,7 +25040,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25209 | 25040 | case IrInstructionIdStorePtr: |
| 25210 | 25041 | case IrInstructionIdCallSrc: |
| 25211 | 25042 | case IrInstructionIdCallGen: |
| 25212 | case IrInstructionIdReturnBegin: | |
| 25213 | 25043 | case IrInstructionIdReturn: |
| 25214 | 25044 | case IrInstructionIdUnreachable: |
| 25215 | 25045 | case IrInstructionIdSetCold: |
| ... | ... | @@ -25235,7 +25065,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25235 | 25065 | case IrInstructionIdPtrType: |
| 25236 | 25066 | case IrInstructionIdSetAlignStack: |
| 25237 | 25067 | case IrInstructionIdExport: |
| 25238 | case IrInstructionIdCancel: | |
| 25239 | 25068 | case IrInstructionIdSaveErrRetAddr: |
| 25240 | 25069 | case IrInstructionIdAddImplicitReturnType: |
| 25241 | 25070 | case IrInstructionIdAtomicRmw: |
| ... | ... | @@ -25355,7 +25184,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25355 | 25184 | case IrInstructionIdHasDecl: |
| 25356 | 25185 | case IrInstructionIdAllocaSrc: |
| 25357 | 25186 | case IrInstructionIdAllocaGen: |
| 25358 | case IrInstructionIdTestCancelRequested: | |
| 25359 | 25187 | case IrInstructionIdSpillEnd: |
| 25360 | 25188 | return false; |
| 25361 | 25189 |
src/ir_print.cpp-24| ... | ... | @@ -64,12 +64,6 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) { |
| 64 | 64 | } |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | static void ir_print_return_begin(IrPrint *irp, IrInstructionReturnBegin *instruction) { | |
| 68 | fprintf(irp->f, "@returnBegin("); | |
| 69 | ir_print_other_instruction(irp, instruction->operand); | |
| 70 | fprintf(irp->f, ")"); | |
| 71 | } | |
| 72 | ||
| 73 | 67 | static void ir_print_return(IrPrint *irp, IrInstructionReturn *instruction) { |
| 74 | 68 | fprintf(irp->f, "return "); |
| 75 | 69 | ir_print_other_instruction(irp, instruction->operand); |
| ... | ... | @@ -1394,11 +1388,6 @@ static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruct |
| 1394 | 1388 | ir_print_other_instruction(irp, instruction->payload); |
| 1395 | 1389 | } |
| 1396 | 1390 | |
| 1397 | static void ir_print_cancel(IrPrint *irp, IrInstructionCancel *instruction) { | |
| 1398 | fprintf(irp->f, "cancel "); | |
| 1399 | ir_print_other_instruction(irp, instruction->frame); | |
| 1400 | } | |
| 1401 | ||
| 1402 | 1391 | static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instruction) { |
| 1403 | 1392 | fprintf(irp->f, "@atomicRmw("); |
| 1404 | 1393 | if (instruction->operand_type != nullptr) { |
| ... | ... | @@ -1549,10 +1538,6 @@ static void ir_print_await_gen(IrPrint *irp, IrInstructionAwaitGen *instruction) |
| 1549 | 1538 | fprintf(irp->f, ")"); |
| 1550 | 1539 | } |
| 1551 | 1540 | |
| 1552 | static void ir_print_test_cancel_requested(IrPrint *irp, IrInstructionTestCancelRequested *instruction) { | |
| 1553 | fprintf(irp->f, "@testCancelRequested()"); | |
| 1554 | } | |
| 1555 | ||
| 1556 | 1541 | static void ir_print_spill_begin(IrPrint *irp, IrInstructionSpillBegin *instruction) { |
| 1557 | 1542 | fprintf(irp->f, "@spillBegin("); |
| 1558 | 1543 | ir_print_other_instruction(irp, instruction->operand); |
| ... | ... | @@ -1570,9 +1555,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1570 | 1555 | switch (instruction->id) { |
| 1571 | 1556 | case IrInstructionIdInvalid: |
| 1572 | 1557 | zig_unreachable(); |
| 1573 | case IrInstructionIdReturnBegin: | |
| 1574 | ir_print_return_begin(irp, (IrInstructionReturnBegin *)instruction); | |
| 1575 | break; | |
| 1576 | 1558 | case IrInstructionIdReturn: |
| 1577 | 1559 | ir_print_return(irp, (IrInstructionReturn *)instruction); |
| 1578 | 1560 | break; |
| ... | ... | @@ -1966,9 +1948,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1966 | 1948 | case IrInstructionIdErrorUnion: |
| 1967 | 1949 | ir_print_error_union(irp, (IrInstructionErrorUnion *)instruction); |
| 1968 | 1950 | break; |
| 1969 | case IrInstructionIdCancel: | |
| 1970 | ir_print_cancel(irp, (IrInstructionCancel *)instruction); | |
| 1971 | break; | |
| 1972 | 1951 | case IrInstructionIdAtomicRmw: |
| 1973 | 1952 | ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction); |
| 1974 | 1953 | break; |
| ... | ... | @@ -2047,9 +2026,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 2047 | 2026 | case IrInstructionIdAwaitGen: |
| 2048 | 2027 | ir_print_await_gen(irp, (IrInstructionAwaitGen *)instruction); |
| 2049 | 2028 | break; |
| 2050 | case IrInstructionIdTestCancelRequested: | |
| 2051 | ir_print_test_cancel_requested(irp, (IrInstructionTestCancelRequested *)instruction); | |
| 2052 | break; | |
| 2053 | 2029 | case IrInstructionIdSpillBegin: |
| 2054 | 2030 | ir_print_spill_begin(irp, (IrInstructionSpillBegin *)instruction); |
| 2055 | 2031 | break; |
src/parser.cpp-12| ... | ... | @@ -1167,7 +1167,6 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) { |
| 1167 | 1167 | // <- AsmExpr |
| 1168 | 1168 | // / IfExpr |
| 1169 | 1169 | // / KEYWORD_break BreakLabel? Expr? |
| 1170 | // / KEYWORD_cancel Expr | |
| 1171 | 1170 | // / KEYWORD_comptime Expr |
| 1172 | 1171 | // / KEYWORD_continue BreakLabel? |
| 1173 | 1172 | // / KEYWORD_resume Expr |
| ... | ... | @@ -1195,14 +1194,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) { |
| 1195 | 1194 | return res; |
| 1196 | 1195 | } |
| 1197 | 1196 | |
| 1198 | Token *cancel = eat_token_if(pc, TokenIdKeywordCancel); | |
| 1199 | if (cancel != nullptr) { | |
| 1200 | AstNode *expr = ast_expect(pc, ast_parse_expr); | |
| 1201 | AstNode *res = ast_create_node(pc, NodeTypeCancel, cancel); | |
| 1202 | res->data.cancel_expr.expr = expr; | |
| 1203 | return res; | |
| 1204 | } | |
| 1205 | ||
| 1206 | 1197 | Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime); |
| 1207 | 1198 | if (comptime != nullptr) { |
| 1208 | 1199 | AstNode *expr = ast_expect(pc, ast_parse_expr); |
| ... | ... | @@ -3035,9 +3026,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 3035 | 3026 | case NodeTypeErrorSetDecl: |
| 3036 | 3027 | visit_node_list(&node->data.err_set_decl.decls, visit, context); |
| 3037 | 3028 | break; |
| 3038 | case NodeTypeCancel: | |
| 3039 | visit_field(&node->data.cancel_expr.expr, visit, context); | |
| 3040 | break; | |
| 3041 | 3029 | case NodeTypeResume: |
| 3042 | 3030 | visit_field(&node->data.resume_expr.expr, visit, context); |
| 3043 | 3031 | break; |
src/tokenizer.cpp-2| ... | ... | @@ -114,7 +114,6 @@ static const struct ZigKeyword zig_keywords[] = { |
| 114 | 114 | {"async", TokenIdKeywordAsync}, |
| 115 | 115 | {"await", TokenIdKeywordAwait}, |
| 116 | 116 | {"break", TokenIdKeywordBreak}, |
| 117 | {"cancel", TokenIdKeywordCancel}, | |
| 118 | 117 | {"catch", TokenIdKeywordCatch}, |
| 119 | 118 | {"comptime", TokenIdKeywordCompTime}, |
| 120 | 119 | {"const", TokenIdKeywordConst}, |
| ... | ... | @@ -1531,7 +1530,6 @@ const char * token_name(TokenId id) { |
| 1531 | 1530 | case TokenIdKeywordAwait: return "await"; |
| 1532 | 1531 | case TokenIdKeywordResume: return "resume"; |
| 1533 | 1532 | case TokenIdKeywordSuspend: return "suspend"; |
| 1534 | case TokenIdKeywordCancel: return "cancel"; | |
| 1535 | 1533 | case TokenIdKeywordAlign: return "align"; |
| 1536 | 1534 | case TokenIdKeywordAnd: return "and"; |
| 1537 | 1535 | case TokenIdKeywordAnyFrame: return "anyframe"; |
src/tokenizer.hpp-1| ... | ... | @@ -58,7 +58,6 @@ enum TokenId { |
| 58 | 58 | TokenIdKeywordAsync, |
| 59 | 59 | TokenIdKeywordAwait, |
| 60 | 60 | TokenIdKeywordBreak, |
| 61 | TokenIdKeywordCancel, | |
| 62 | 61 | TokenIdKeywordCatch, |
| 63 | 62 | TokenIdKeywordCompTime, |
| 64 | 63 | TokenIdKeywordConst, |
std/event/fs.zig+1-1| ... | ... | @@ -1301,7 +1301,7 @@ async fn testFsWatch(loop: *Loop) !void { |
| 1301 | 1301 | |
| 1302 | 1302 | const ev = try async watch.channel.get(); |
| 1303 | 1303 | var ev_consumed = false; |
| 1304 | defer if (!ev_consumed) cancel ev; | |
| 1304 | defer if (!ev_consumed) await ev; | |
| 1305 | 1305 | |
| 1306 | 1306 | // overwrite line 2 |
| 1307 | 1307 | const fd = try await try async openReadWrite(loop, file_path, File.default_mode); |
std/event/future.zig+1-1| ... | ... | @@ -110,7 +110,7 @@ async fn testFuture(loop: *Loop) void { |
| 110 | 110 | const b_result = await b; |
| 111 | 111 | const result = a_result + b_result; |
| 112 | 112 | |
| 113 | cancel c; | |
| 113 | await c; | |
| 114 | 114 | testing.expect(result == 12); |
| 115 | 115 | } |
| 116 | 116 |
std/event/group.zig+5-15| ... | ... | @@ -27,17 +27,6 @@ pub fn Group(comptime ReturnType: type) type { |
| 27 | 27 | }; |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | /// Cancel all the outstanding frames. Can be called even if wait was already called. | |
| 31 | pub fn deinit(self: *Self) void { | |
| 32 | while (self.frame_stack.pop()) |node| { | |
| 33 | cancel node.data; | |
| 34 | } | |
| 35 | while (self.alloc_stack.pop()) |node| { | |
| 36 | cancel node.data; | |
| 37 | self.lock.loop.allocator.destroy(node); | |
| 38 | } | |
| 39 | } | |
| 40 | ||
| 41 | 30 | /// Add a frame to the group. Thread-safe. |
| 42 | 31 | pub fn add(self: *Self, handle: anyframe->ReturnType) (error{OutOfMemory}!void) { |
| 43 | 32 | const node = try self.lock.loop.allocator.create(Stack.Node); |
| ... | ... | @@ -64,13 +53,14 @@ pub fn Group(comptime ReturnType: type) type { |
| 64 | 53 | const held = self.lock.acquire(); |
| 65 | 54 | defer held.release(); |
| 66 | 55 | |
| 56 | var result: ReturnType = {}; | |
| 57 | ||
| 67 | 58 | while (self.frame_stack.pop()) |node| { |
| 68 | 59 | if (Error == void) { |
| 69 | 60 | await node.data; |
| 70 | 61 | } else { |
| 71 | 62 | (await node.data) catch |err| { |
| 72 | self.deinit(); | |
| 73 | return err; | |
| 63 | result = err; | |
| 74 | 64 | }; |
| 75 | 65 | } |
| 76 | 66 | } |
| ... | ... | @@ -81,11 +71,11 @@ pub fn Group(comptime ReturnType: type) type { |
| 81 | 71 | await handle; |
| 82 | 72 | } else { |
| 83 | 73 | (await handle) catch |err| { |
| 84 | self.deinit(); | |
| 85 | return err; | |
| 74 | result = err; | |
| 86 | 75 | }; |
| 87 | 76 | } |
| 88 | 77 | } |
| 78 | return result; | |
| 89 | 79 | } |
| 90 | 80 | }; |
| 91 | 81 | } |
std/event/net.zig+2-6| ... | ... | @@ -54,7 +54,7 @@ pub const Server = struct { |
| 54 | 54 | self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd)); |
| 55 | 55 | |
| 56 | 56 | self.accept_frame = async Server.handler(self); |
| 57 | errdefer cancel self.accept_frame.?; | |
| 57 | errdefer await self.accept_frame.?; | |
| 58 | 58 | |
| 59 | 59 | self.listen_resume_node.handle = self.accept_frame.?; |
| 60 | 60 | try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET); |
| ... | ... | @@ -71,7 +71,7 @@ pub const Server = struct { |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | 73 | pub fn deinit(self: *Server) void { |
| 74 | if (self.accept_frame) |accept_frame| cancel accept_frame; | |
| 74 | if (self.accept_frame) |accept_frame| await accept_frame; | |
| 75 | 75 | if (self.sockfd) |sockfd| os.close(sockfd); |
| 76 | 76 | } |
| 77 | 77 | |
| ... | ... | @@ -274,13 +274,9 @@ test "listen on a port, send bytes, receive bytes" { |
| 274 | 274 | const self = @fieldParentPtr(Self, "tcp_server", tcp_server); |
| 275 | 275 | var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592 |
| 276 | 276 | defer socket.close(); |
| 277 | // TODO guarantee elision of this allocation | |
| 278 | 277 | const next_handler = errorableHandler(self, _addr, socket) catch |err| { |
| 279 | 278 | std.debug.panic("unable to handle connection: {}\n", err); |
| 280 | 279 | }; |
| 281 | suspend { | |
| 282 | cancel @frame(); | |
| 283 | } | |
| 284 | 280 | } |
| 285 | 281 | async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void { |
| 286 | 282 | const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592 |
std/zig/parse.zig-15| ... | ... | @@ -814,7 +814,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 814 | 814 | /// <- AsmExpr |
| 815 | 815 | /// / IfExpr |
| 816 | 816 | /// / KEYWORD_break BreakLabel? Expr? |
| 817 | /// / KEYWORD_cancel Expr | |
| 818 | 817 | /// / KEYWORD_comptime Expr |
| 819 | 818 | /// / KEYWORD_continue BreakLabel? |
| 820 | 819 | /// / KEYWORD_resume Expr |
| ... | ... | @@ -839,20 +838,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 839 | 838 | return &node.base; |
| 840 | 839 | } |
| 841 | 840 | |
| 842 | if (eatToken(it, .Keyword_cancel)) |token| { | |
| 843 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 844 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 845 | }); | |
| 846 | const node = try arena.create(Node.PrefixOp); | |
| 847 | node.* = Node.PrefixOp{ | |
| 848 | .base = Node{ .id = .PrefixOp }, | |
| 849 | .op_token = token, | |
| 850 | .op = Node.PrefixOp.Op.Cancel, | |
| 851 | .rhs = expr_node, | |
| 852 | }; | |
| 853 | return &node.base; | |
| 854 | } | |
| 855 | ||
| 856 | 841 | if (eatToken(it, .Keyword_comptime)) |token| { |
| 857 | 842 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ |
| 858 | 843 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, |
std/zig/parser_test.zig+2-2| ... | ... | @@ -2115,10 +2115,10 @@ test "zig fmt: async functions" { |
| 2115 | 2115 | \\ await p; |
| 2116 | 2116 | \\} |
| 2117 | 2117 | \\ |
| 2118 | \\test "suspend, resume, cancel" { | |
| 2118 | \\test "suspend, resume, await" { | |
| 2119 | 2119 | \\ const p: anyframe = async testAsyncSeq(); |
| 2120 | 2120 | \\ resume p; |
| 2121 | \\ cancel p; | |
| 2121 | \\ await p; | |
| 2122 | 2122 | \\} |
| 2123 | 2123 | \\ |
| 2124 | 2124 | ); |
std/zig/tokenizer.zig-2| ... | ... | @@ -21,7 +21,6 @@ pub const Token = struct { |
| 21 | 21 | Keyword{ .bytes = "await", .id = Id.Keyword_await }, |
| 22 | 22 | Keyword{ .bytes = "break", .id = Id.Keyword_break }, |
| 23 | 23 | Keyword{ .bytes = "catch", .id = Id.Keyword_catch }, |
| 24 | Keyword{ .bytes = "cancel", .id = Id.Keyword_cancel }, | |
| 25 | 24 | Keyword{ .bytes = "comptime", .id = Id.Keyword_comptime }, |
| 26 | 25 | Keyword{ .bytes = "const", .id = Id.Keyword_const }, |
| 27 | 26 | Keyword{ .bytes = "continue", .id = Id.Keyword_continue }, |
| ... | ... | @@ -151,7 +150,6 @@ pub const Token = struct { |
| 151 | 150 | Keyword_async, |
| 152 | 151 | Keyword_await, |
| 153 | 152 | Keyword_break, |
| 154 | Keyword_cancel, | |
| 155 | 153 | Keyword_catch, |
| 156 | 154 | Keyword_comptime, |
| 157 | 155 | Keyword_const, |
test/compile_errors.zig+5-3| ... | ... | @@ -61,13 +61,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 61 | 61 | cases.add( |
| 62 | 62 | "runtime-known async function called", |
| 63 | 63 | \\export fn entry() void { |
| 64 | \\ _ = async amain(); | |
| 65 | \\} | |
| 66 | \\fn amain() void { | |
| 64 | 67 | \\ var ptr = afunc; |
| 65 | 68 | \\ _ = ptr(); |
| 66 | 69 | \\} |
| 67 | \\ | |
| 68 | 70 | \\async fn afunc() void {} |
| 69 | 71 | , |
| 70 | "tmp.zig:3:12: error: function is not comptime-known; @asyncCall required", | |
| 72 | "tmp.zig:6:12: error: function is not comptime-known; @asyncCall required", | |
| 71 | 73 | ); |
| 72 | 74 | |
| 73 | 75 | cases.add( |
| ... | ... | @@ -3388,7 +3390,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3388 | 3390 | \\ |
| 3389 | 3391 | \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); } |
| 3390 | 3392 | , |
| 3391 | "tmp.zig:5:18: error: unable to evaluate constant expression", | |
| 3393 | "tmp.zig:5:25: error: unable to evaluate constant expression", | |
| 3392 | 3394 | "tmp.zig:2:12: note: called from here", |
| 3393 | 3395 | "tmp.zig:2:8: note: called from here", |
| 3394 | 3396 | ); |
test/stage1/behavior.zig-1| ... | ... | @@ -41,7 +41,6 @@ comptime { |
| 41 | 41 | _ = @import("behavior/bugs/920.zig"); |
| 42 | 42 | _ = @import("behavior/byteswap.zig"); |
| 43 | 43 | _ = @import("behavior/byval_arg_var.zig"); |
| 44 | _ = @import("behavior/cancel.zig"); | |
| 45 | 44 | _ = @import("behavior/cast.zig"); |
| 46 | 45 | _ = @import("behavior/const_slice_child.zig"); |
| 47 | 46 | _ = @import("behavior/defer.zig"); |
test/stage1/behavior/async_fn.zig+14-76| ... | ... | @@ -150,7 +150,7 @@ test "coroutine suspend, resume" { |
| 150 | 150 | seq('a'); |
| 151 | 151 | var f = async testAsyncSeq(); |
| 152 | 152 | seq('c'); |
| 153 | cancel f; | |
| 153 | await f; | |
| 154 | 154 | seq('g'); |
| 155 | 155 | } |
| 156 | 156 | |
| ... | ... | @@ -271,7 +271,6 @@ test "async function with dot syntax" { |
| 271 | 271 | } |
| 272 | 272 | }; |
| 273 | 273 | const p = async S.foo(); |
| 274 | // can't cancel in tests because they are non-async functions | |
| 275 | 274 | expect(S.y == 2); |
| 276 | 275 | } |
| 277 | 276 | |
| ... | ... | @@ -286,7 +285,7 @@ test "async fn pointer in a struct field" { |
| 286 | 285 | comptime expect(@typeOf(f) == anyframe->void); |
| 287 | 286 | expect(data == 2); |
| 288 | 287 | resume f; |
| 289 | expect(data == 2); | |
| 288 | expect(data == 4); | |
| 290 | 289 | _ = async doTheAwait(f); |
| 291 | 290 | expect(data == 4); |
| 292 | 291 | } |
| ... | ... | @@ -394,7 +393,6 @@ async fn printTrace(p: anyframe->(anyerror!void)) void { |
| 394 | 393 | test "break from suspend" { |
| 395 | 394 | var my_result: i32 = 1; |
| 396 | 395 | const p = async testBreakFromSuspend(&my_result); |
| 397 | // can't cancel here | |
| 398 | 396 | std.testing.expect(my_result == 2); |
| 399 | 397 | } |
| 400 | 398 | async fn testBreakFromSuspend(my_result: *i32) void { |
| ... | ... | @@ -530,45 +528,6 @@ test "call async function which has struct return type" { |
| 530 | 528 | S.doTheTest(); |
| 531 | 529 | } |
| 532 | 530 | |
| 533 | test "errdefers in scope get run when canceling async fn call" { | |
| 534 | const S = struct { | |
| 535 | var frame: anyframe = undefined; | |
| 536 | var x: u32 = 0; | |
| 537 | ||
| 538 | fn doTheTest() void { | |
| 539 | x = 9; | |
| 540 | _ = async cancelIt(); | |
| 541 | resume frame; | |
| 542 | expect(x == 6); | |
| 543 | ||
| 544 | x = 9; | |
| 545 | _ = async awaitIt(); | |
| 546 | resume frame; | |
| 547 | expect(x == 11); | |
| 548 | } | |
| 549 | ||
| 550 | fn cancelIt() void { | |
| 551 | var f = async func(); | |
| 552 | cancel f; | |
| 553 | } | |
| 554 | ||
| 555 | fn awaitIt() void { | |
| 556 | var f = async func(); | |
| 557 | await f; | |
| 558 | } | |
| 559 | ||
| 560 | fn func() void { | |
| 561 | defer x += 1; | |
| 562 | errdefer x /= 2; | |
| 563 | defer x += 1; | |
| 564 | suspend { | |
| 565 | frame = @frame(); | |
| 566 | } | |
| 567 | } | |
| 568 | }; | |
| 569 | S.doTheTest(); | |
| 570 | } | |
| 571 | ||
| 572 | 531 | test "pass string literal to async function" { |
| 573 | 532 | const S = struct { |
| 574 | 533 | var frame: anyframe = undefined; |
| ... | ... | @@ -590,7 +549,7 @@ test "pass string literal to async function" { |
| 590 | 549 | S.doTheTest(); |
| 591 | 550 | } |
| 592 | 551 | |
| 593 | test "cancel inside an errdefer" { | |
| 552 | test "await inside an errdefer" { | |
| 594 | 553 | const S = struct { |
| 595 | 554 | var frame: anyframe = undefined; |
| 596 | 555 | |
| ... | ... | @@ -601,7 +560,7 @@ test "cancel inside an errdefer" { |
| 601 | 560 | |
| 602 | 561 | fn amainWrap() !void { |
| 603 | 562 | var foo = async func(); |
| 604 | errdefer cancel foo; | |
| 563 | errdefer await foo; | |
| 605 | 564 | return error.Bad; |
| 606 | 565 | } |
| 607 | 566 | |
| ... | ... | @@ -614,35 +573,6 @@ test "cancel inside an errdefer" { |
| 614 | 573 | S.doTheTest(); |
| 615 | 574 | } |
| 616 | 575 | |
| 617 | test "combining try with errdefer cancel" { | |
| 618 | const S = struct { | |
| 619 | var frame: anyframe = undefined; | |
| 620 | var ok = false; | |
| 621 | ||
| 622 | fn doTheTest() void { | |
| 623 | _ = async amain(); | |
| 624 | resume frame; | |
| 625 | expect(ok); | |
| 626 | } | |
| 627 | ||
| 628 | fn amain() !void { | |
| 629 | var f = async func("https://example.com/"); | |
| 630 | errdefer cancel f; | |
| 631 | ||
| 632 | _ = try await f; | |
| 633 | } | |
| 634 | ||
| 635 | fn func(url: []const u8) ![]u8 { | |
| 636 | errdefer ok = true; | |
| 637 | frame = @frame(); | |
| 638 | suspend; | |
| 639 | return error.Bad; | |
| 640 | } | |
| 641 | ||
| 642 | }; | |
| 643 | S.doTheTest(); | |
| 644 | } | |
| 645 | ||
| 646 | 576 | test "try in an async function with error union and non-zero-bit payload" { |
| 647 | 577 | const S = struct { |
| 648 | 578 | var frame: anyframe = undefined; |
| ... | ... | @@ -730,14 +660,22 @@ fn testAsyncAwaitTypicalUsage(comptime simulate_fail_download: bool, comptime si |
| 730 | 660 | fn amain() !void { |
| 731 | 661 | const allocator = std.heap.direct_allocator; // TODO once we have the debug allocator, use that, so that this can detect leaks |
| 732 | 662 | var download_frame = async fetchUrl(allocator, "https://example.com/"); |
| 733 | errdefer cancel download_frame; | |
| 663 | var download_awaited = false; | |
| 664 | errdefer if (!download_awaited) { | |
| 665 | if (await download_frame) |x| allocator.free(x) else |_| {} | |
| 666 | }; | |
| 734 | 667 | |
| 735 | 668 | var file_frame = async readFile(allocator, "something.txt"); |
| 736 | errdefer cancel file_frame; | |
| 669 | var file_awaited = false; | |
| 670 | errdefer if (!file_awaited) { | |
| 671 | if (await file_frame) |x| allocator.free(x) else |_| {} | |
| 672 | }; | |
| 737 | 673 | |
| 674 | download_awaited = true; | |
| 738 | 675 | const download_text = try await download_frame; |
| 739 | 676 | defer allocator.free(download_text); |
| 740 | 677 | |
| 678 | file_awaited = true; | |
| 741 | 679 | const file_text = try await file_frame; |
| 742 | 680 | defer allocator.free(file_text); |
| 743 | 681 |
test/stage1/behavior/cancel.zig deleted-115| ... | ... | @@ -1,115 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | ||
| 4 | var defer_f1: bool = false; | |
| 5 | var defer_f2: bool = false; | |
| 6 | var defer_f3: bool = false; | |
| 7 | var f3_frame: anyframe = undefined; | |
| 8 | ||
| 9 | test "cancel forwards" { | |
| 10 | _ = async atest1(); | |
| 11 | resume f3_frame; | |
| 12 | } | |
| 13 | ||
| 14 | fn atest1() void { | |
| 15 | const p = async f1(); | |
| 16 | cancel &p; | |
| 17 | expect(defer_f1); | |
| 18 | expect(defer_f2); | |
| 19 | expect(defer_f3); | |
| 20 | } | |
| 21 | ||
| 22 | async fn f1() void { | |
| 23 | defer { | |
| 24 | defer_f1 = true; | |
| 25 | } | |
| 26 | var f2_frame = async f2(); | |
| 27 | await f2_frame; | |
| 28 | } | |
| 29 | ||
| 30 | async fn f2() void { | |
| 31 | defer { | |
| 32 | defer_f2 = true; | |
| 33 | } | |
| 34 | f3(); | |
| 35 | } | |
| 36 | ||
| 37 | async fn f3() void { | |
| 38 | f3_frame = @frame(); | |
| 39 | defer { | |
| 40 | defer_f3 = true; | |
| 41 | } | |
| 42 | suspend; | |
| 43 | } | |
| 44 | ||
| 45 | var defer_b1: bool = false; | |
| 46 | var defer_b2: bool = false; | |
| 47 | var defer_b3: bool = false; | |
| 48 | var defer_b4: bool = false; | |
| 49 | ||
| 50 | test "cancel backwards" { | |
| 51 | var b1_frame = async b1(); | |
| 52 | resume b4_handle; | |
| 53 | _ = async awaitAFrame(&b1_frame); | |
| 54 | expect(defer_b1); | |
| 55 | expect(defer_b2); | |
| 56 | expect(defer_b3); | |
| 57 | expect(defer_b4); | |
| 58 | } | |
| 59 | ||
| 60 | async fn b1() void { | |
| 61 | defer { | |
| 62 | defer_b1 = true; | |
| 63 | } | |
| 64 | b2(); | |
| 65 | } | |
| 66 | ||
| 67 | var b4_handle: anyframe->void = undefined; | |
| 68 | ||
| 69 | async fn b2() void { | |
| 70 | const b3_handle = async b3(); | |
| 71 | resume b4_handle; | |
| 72 | defer { | |
| 73 | defer_b2 = true; | |
| 74 | } | |
| 75 | const value = await b3_handle; | |
| 76 | expect(value == 1234); | |
| 77 | } | |
| 78 | ||
| 79 | async fn b3() i32 { | |
| 80 | defer { | |
| 81 | defer_b3 = true; | |
| 82 | } | |
| 83 | b4(); | |
| 84 | return 1234; | |
| 85 | } | |
| 86 | ||
| 87 | async fn b4() void { | |
| 88 | defer { | |
| 89 | defer_b4 = true; | |
| 90 | } | |
| 91 | suspend { | |
| 92 | b4_handle = @frame(); | |
| 93 | } | |
| 94 | suspend; | |
| 95 | } | |
| 96 | ||
| 97 | fn awaitAFrame(f: anyframe->void) void { | |
| 98 | await f; | |
| 99 | } | |
| 100 | ||
| 101 | test "cancel on a non-pointer" { | |
| 102 | const S = struct { | |
| 103 | fn doTheTest() void { | |
| 104 | _ = async atest(); | |
| 105 | } | |
| 106 | fn atest() void { | |
| 107 | var f = async func(); | |
| 108 | cancel f; | |
| 109 | } | |
| 110 | fn func() void { | |
| 111 | suspend; | |
| 112 | } | |
| 113 | }; | |
| 114 | S.doTheTest(); | |
| 115 | } |