| author | |
| committer | |
| log | 0a3c6dbda92931eba055c2c6447b7a4412408f17 |
| tree | 86d98cd519e628c28efe2fe9e2ff3ec86f55246d |
| parent | ca70ca7e26aaae3425dad3a2b179f544bacf45e3 |
| signature |
See #315713 files changed, 175 insertions(+), 68 deletions(-)
doc/docgen.zig+2-1| ... | ... | @@ -786,9 +786,10 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 786 | 786 | .Keyword_for, |
| 787 | 787 | .Keyword_if, |
| 788 | 788 | .Keyword_inline, |
| 789 | .Keyword_noinline, | |
| 790 | 789 | .Keyword_nakedcc, |
| 791 | 790 | .Keyword_noalias, |
| 791 | .Keyword_noasync, | |
| 792 | .Keyword_noinline, | |
| 792 | 793 | .Keyword_or, |
| 793 | 794 | .Keyword_orelse, |
| 794 | 795 | .Keyword_packed, |
src/all_types.hpp+14-5| ... | ... | @@ -758,11 +758,17 @@ struct AstNodeUnwrapOptional { |
| 758 | 758 | AstNode *expr; |
| 759 | 759 | }; |
| 760 | 760 | |
| 761 | enum CallModifier { | |
| 762 | CallModifierNone, | |
| 763 | CallModifierAsync, | |
| 764 | CallModifierNoAsync, | |
| 765 | CallModifierBuiltin, | |
| 766 | }; | |
| 767 | ||
| 761 | 768 | struct AstNodeFnCallExpr { |
| 762 | 769 | AstNode *fn_ref_expr; |
| 763 | 770 | ZigList<AstNode *> params; |
| 764 | bool is_builtin; | |
| 765 | bool is_async; | |
| 771 | CallModifier modifier; | |
| 766 | 772 | bool seen; // used by @compileLog |
| 767 | 773 | }; |
| 768 | 774 | |
| ... | ... | @@ -2730,8 +2736,10 @@ struct IrInstructionCallSrc { |
| 2730 | 2736 | ResultLoc *result_loc; |
| 2731 | 2737 | |
| 2732 | 2738 | IrInstruction *new_stack; |
| 2739 | ||
| 2733 | 2740 | FnInline fn_inline; |
| 2734 | bool is_async; | |
| 2741 | CallModifier modifier; | |
| 2742 | ||
| 2735 | 2743 | bool is_async_call_builtin; |
| 2736 | 2744 | bool is_comptime; |
| 2737 | 2745 | }; |
| ... | ... | @@ -2745,10 +2753,11 @@ struct IrInstructionCallGen { |
| 2745 | 2753 | IrInstruction **args; |
| 2746 | 2754 | IrInstruction *result_loc; |
| 2747 | 2755 | IrInstruction *frame_result_loc; |
| 2748 | ||
| 2749 | 2756 | IrInstruction *new_stack; |
| 2757 | ||
| 2750 | 2758 | FnInline fn_inline; |
| 2751 | bool is_async; | |
| 2759 | CallModifier modifier; | |
| 2760 | ||
| 2752 | 2761 | bool is_async_call_builtin; |
| 2753 | 2762 | }; |
| 2754 | 2763 |
src/analyze.cpp+10-4| ... | ... | @@ -4214,7 +4214,7 @@ void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { |
| 4214 | 4214 | add_error_note(g, msg, fn->inferred_async_node, |
| 4215 | 4215 | buf_sprintf("await here is a suspend point")); |
| 4216 | 4216 | } else if (fn->inferred_async_node->type == NodeTypeFnCallExpr && |
| 4217 | fn->inferred_async_node->data.fn_call_expr.is_builtin) | |
| 4217 | fn->inferred_async_node->data.fn_call_expr.modifier == CallModifierBuiltin) | |
| 4218 | 4218 | { |
| 4219 | 4219 | add_error_note(g, msg, fn->inferred_async_node, |
| 4220 | 4220 | buf_sprintf("@frame() causes function to be async")); |
| ... | ... | @@ -4228,8 +4228,10 @@ void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) { |
| 4228 | 4228 | // ErrorIsAsync - yes async |
| 4229 | 4229 | // ErrorSemanticAnalyzeFail - compile error emitted result is invalid |
| 4230 | 4230 | static Error analyze_callee_async(CodeGen *g, ZigFn *fn, ZigFn *callee, AstNode *call_node, |
| 4231 | bool must_not_be_async) | |
| 4231 | bool must_not_be_async, CallModifier modifier) | |
| 4232 | 4232 | { |
| 4233 | if (modifier == CallModifierNoAsync) | |
| 4234 | return ErrorNone; | |
| 4233 | 4235 | if (callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) |
| 4234 | 4236 | return ErrorNone; |
| 4235 | 4237 | if (callee->anal_state == FnAnalStateReady) { |
| ... | ... | @@ -4312,7 +4314,9 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { |
| 4312 | 4314 | // TODO function pointer call here, could be anything |
| 4313 | 4315 | continue; |
| 4314 | 4316 | } |
| 4315 | switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async)) { | |
| 4317 | switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async, | |
| 4318 | call->modifier)) | |
| 4319 | { | |
| 4316 | 4320 | case ErrorSemanticAnalyzeFail: |
| 4317 | 4321 | fn->anal_state = FnAnalStateInvalid; |
| 4318 | 4322 | return; |
| ... | ... | @@ -4329,7 +4333,9 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { |
| 4329 | 4333 | } |
| 4330 | 4334 | for (size_t i = 0; i < fn->await_list.length; i += 1) { |
| 4331 | 4335 | IrInstructionAwaitGen *await = fn->await_list.at(i); |
| 4332 | switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async)) { | |
| 4336 | switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async, | |
| 4337 | CallModifierNone)) | |
| 4338 | { | |
| 4333 | 4339 | case ErrorSemanticAnalyzeFail: |
| 4334 | 4340 | fn->anal_state = FnAnalStateInvalid; |
| 4335 | 4341 | return; |
src/ast_render.cpp+12-5| ... | ... | @@ -698,11 +698,18 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 698 | 698 | } |
| 699 | 699 | case NodeTypeFnCallExpr: |
| 700 | 700 | { |
| 701 | if (node->data.fn_call_expr.is_builtin) { | |
| 702 | fprintf(ar->f, "@"); | |
| 703 | } | |
| 704 | if (node->data.fn_call_expr.is_async) { | |
| 705 | fprintf(ar->f, "async "); | |
| 701 | switch (node->data.fn_call_expr.modifier) { | |
| 702 | case CallModifierNone: | |
| 703 | break; | |
| 704 | case CallModifierBuiltin: | |
| 705 | fprintf(ar->f, "@"); | |
| 706 | break; | |
| 707 | case CallModifierAsync: | |
| 708 | fprintf(ar->f, "async "); | |
| 709 | break; | |
| 710 | case CallModifierNoAsync: | |
| 711 | fprintf(ar->f, "noasync "); | |
| 712 | break; | |
| 706 | 713 | } |
| 707 | 714 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| 708 | 715 | bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType); |
src/codegen.cpp+47-9| ... | ... | @@ -186,6 +186,9 @@ static void generate_error_name_table(CodeGen *g); |
| 186 | 186 | static bool value_is_all_undef(CodeGen *g, ConstExprValue *const_val); |
| 187 | 187 | static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr); |
| 188 | 188 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment); |
| 189 | static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstruction *source_instr, | |
| 190 | LLVMValueRef target_frame_ptr, ZigType *result_type, ZigType *ptr_result_type, | |
| 191 | LLVMValueRef result_loc, bool non_async); | |
| 189 | 192 | |
| 190 | 193 | static void addLLVMAttr(LLVMValueRef val, LLVMAttributeIndex attr_index, const char *attr_name) { |
| 191 | 194 | unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name)); |
| ... | ... | @@ -3842,7 +3845,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3842 | 3845 | LLVMValueRef ret_ptr; |
| 3843 | 3846 | if (callee_is_async) { |
| 3844 | 3847 | if (instruction->new_stack == nullptr) { |
| 3845 | if (instruction->is_async) { | |
| 3848 | if (instruction->modifier == CallModifierAsync) { | |
| 3846 | 3849 | frame_result_loc = result_loc; |
| 3847 | 3850 | } else { |
| 3848 | 3851 | frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); |
| ... | ... | @@ -3883,7 +3886,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3883 | 3886 | } |
| 3884 | 3887 | } |
| 3885 | 3888 | } |
| 3886 | if (instruction->is_async) { | |
| 3889 | if (instruction->modifier == CallModifierAsync) { | |
| 3887 | 3890 | if (instruction->new_stack == nullptr) { |
| 3888 | 3891 | awaiter_init_val = zero; |
| 3889 | 3892 | |
| ... | ... | @@ -3908,9 +3911,15 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3908 | 3911 | // even if prefix_arg_err_ret_stack is true, let the async function do its own |
| 3909 | 3912 | // initialization. |
| 3910 | 3913 | } else { |
| 3911 | // async function called as a normal function | |
| 3912 | ||
| 3913 | awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer | |
| 3914 | if (instruction->modifier == CallModifierNoAsync && !fn_is_async(g->cur_fn)) { | |
| 3915 | // Async function called as a normal function, and calling function is not async. | |
| 3916 | // This is allowed because it was called with `noasync` which asserts that it will | |
| 3917 | // never suspend. | |
| 3918 | awaiter_init_val = zero; | |
| 3919 | } else { | |
| 3920 | // async function called as a normal function | |
| 3921 | awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer | |
| 3922 | } | |
| 3914 | 3923 | if (ret_has_bits) { |
| 3915 | 3924 | if (result_loc == nullptr) { |
| 3916 | 3925 | // return type is a scalar, but we still need a pointer to it. Use the async fn frame. |
| ... | ... | @@ -3951,7 +3960,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3951 | 3960 | LLVMValueRef ret_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start, ""); |
| 3952 | 3961 | LLVMBuildStore(g->builder, ret_ptr, ret_ptr_ptr); |
| 3953 | 3962 | } |
| 3954 | } else if (instruction->is_async) { | |
| 3963 | } else if (instruction->modifier == CallModifierAsync) { | |
| 3955 | 3964 | // Async call of blocking function |
| 3956 | 3965 | if (instruction->new_stack != nullptr) { |
| 3957 | 3966 | zig_panic("TODO @asyncCall of non-async function"); |
| ... | ... | @@ -4048,13 +4057,20 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4048 | 4057 | gen_param_values.at(arg_i)); |
| 4049 | 4058 | } |
| 4050 | 4059 | |
| 4051 | if (instruction->is_async) { | |
| 4060 | if (instruction->modifier == CallModifierAsync) { | |
| 4052 | 4061 | gen_resume(g, fn_val, frame_result_loc, ResumeIdCall); |
| 4053 | 4062 | if (instruction->new_stack != nullptr) { |
| 4054 | 4063 | return LLVMBuildBitCast(g->builder, frame_result_loc, |
| 4055 | 4064 | get_llvm_type(g, instruction->base.value.type), ""); |
| 4056 | 4065 | } |
| 4057 | 4066 | return nullptr; |
| 4067 | } else if (instruction->modifier == CallModifierNoAsync && !fn_is_async(g->cur_fn)) { | |
| 4068 | gen_resume(g, fn_val, frame_result_loc, ResumeIdCall); | |
| 4069 | ||
| 4070 | ZigType *result_type = instruction->base.value.type; | |
| 4071 | ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true); | |
| 4072 | return gen_await_early_return(g, &instruction->base, frame_result_loc, | |
| 4073 | result_type, ptr_result_type, result_loc, true); | |
| 4058 | 4074 | } else { |
| 4059 | 4075 | ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true); |
| 4060 | 4076 | |
| ... | ... | @@ -4082,7 +4098,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4082 | 4098 | if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) { |
| 4083 | 4099 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 4084 | 4100 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); |
| 4085 | } else if (instruction->is_async) { | |
| 4101 | } else if (instruction->modifier == CallModifierAsync) { | |
| 4086 | 4102 | zig_panic("TODO @asyncCall of non-async function"); |
| 4087 | 4103 | } else { |
| 4088 | 4104 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); |
| ... | ... | @@ -4107,7 +4123,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4107 | 4123 | LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); |
| 4108 | 4124 | LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type)); |
| 4109 | 4125 | return result_loc; |
| 4110 | } else if (!callee_is_async && instruction->is_async) { | |
| 4126 | } else if (!callee_is_async && instruction->modifier == CallModifierAsync) { | |
| 4111 | 4127 | LLVMBuildStore(g->builder, result, ret_ptr); |
| 4112 | 4128 | return result_loc; |
| 4113 | 4129 | } else { |
| ... | ... | @@ -7104,6 +7120,28 @@ static void do_code_gen(CodeGen *g) { |
| 7104 | 7120 | } |
| 7105 | 7121 | |
| 7106 | 7122 | if (!is_async) { |
| 7123 | // allocate async frames for noasync calls & awaits to async functions | |
| 7124 | for (size_t i = 0; i < fn_table_entry->call_list.length; i += 1) { | |
| 7125 | IrInstructionCallGen *call = fn_table_entry->call_list.at(i); | |
| 7126 | if (call->fn_entry == nullptr) | |
| 7127 | continue; | |
| 7128 | if (!fn_is_async(call->fn_entry)) | |
| 7129 | continue; | |
| 7130 | if (call->modifier != CallModifierNoAsync) | |
| 7131 | continue; | |
| 7132 | if (call->frame_result_loc != nullptr) | |
| 7133 | continue; | |
| 7134 | ZigType *callee_frame_type = get_fn_frame_type(g, call->fn_entry); | |
| 7135 | IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1); | |
| 7136 | alloca_gen->base.id = IrInstructionIdAllocaGen; | |
| 7137 | alloca_gen->base.source_node = call->base.source_node; | |
| 7138 | alloca_gen->base.scope = call->base.scope; | |
| 7139 | alloca_gen->base.value.type = get_pointer_to_type(g, callee_frame_type, false); | |
| 7140 | alloca_gen->base.ref_count = 1; | |
| 7141 | alloca_gen->name_hint = ""; | |
| 7142 | fn_table_entry->alloca_gen_list.append(alloca_gen); | |
| 7143 | call->frame_result_loc = &alloca_gen->base; | |
| 7144 | } | |
| 7107 | 7145 | // allocate temporary stack data |
| 7108 | 7146 | for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) { |
| 7109 | 7147 | IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i); |
src/ir.cpp+27-22| ... | ... | @@ -1389,7 +1389,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast |
| 1389 | 1389 | |
| 1390 | 1390 | static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1391 | 1391 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1392 | bool is_comptime, FnInline fn_inline, bool is_async, bool is_async_call_builtin, | |
| 1392 | bool is_comptime, FnInline fn_inline, CallModifier modifier, bool is_async_call_builtin, | |
| 1393 | 1393 | IrInstruction *new_stack, ResultLoc *result_loc) |
| 1394 | 1394 | { |
| 1395 | 1395 | IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node); |
| ... | ... | @@ -1399,7 +1399,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1399 | 1399 | call_instruction->fn_inline = fn_inline; |
| 1400 | 1400 | call_instruction->args = args; |
| 1401 | 1401 | call_instruction->arg_count = arg_count; |
| 1402 | call_instruction->is_async = is_async; | |
| 1402 | call_instruction->modifier = modifier; | |
| 1403 | 1403 | call_instruction->is_async_call_builtin = is_async_call_builtin; |
| 1404 | 1404 | call_instruction->new_stack = new_stack; |
| 1405 | 1405 | call_instruction->result_loc = result_loc; |
| ... | ... | @@ -1407,7 +1407,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1407 | 1407 | if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); |
| 1408 | 1408 | for (size_t i = 0; i < arg_count; i += 1) |
| 1409 | 1409 | ir_ref_instruction(args[i], irb->current_basic_block); |
| 1410 | if (is_async && new_stack != nullptr) { | |
| 1410 | if (modifier == CallModifierAsync && new_stack != nullptr) { | |
| 1411 | 1411 | // in this case the arg at the end is the return pointer |
| 1412 | 1412 | ir_ref_instruction(args[arg_count], irb->current_basic_block); |
| 1413 | 1413 | } |
| ... | ... | @@ -1418,7 +1418,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1418 | 1418 | |
| 1419 | 1419 | static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, |
| 1420 | 1420 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1421 | FnInline fn_inline, bool is_async, IrInstruction *new_stack, bool is_async_call_builtin, | |
| 1421 | FnInline fn_inline, CallModifier modifier, IrInstruction *new_stack, bool is_async_call_builtin, | |
| 1422 | 1422 | IrInstruction *result_loc, ZigType *return_type) |
| 1423 | 1423 | { |
| 1424 | 1424 | IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb, |
| ... | ... | @@ -1429,7 +1429,7 @@ static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *so |
| 1429 | 1429 | call_instruction->fn_inline = fn_inline; |
| 1430 | 1430 | call_instruction->args = args; |
| 1431 | 1431 | call_instruction->arg_count = arg_count; |
| 1432 | call_instruction->is_async = is_async; | |
| 1432 | call_instruction->modifier = modifier; | |
| 1433 | 1433 | call_instruction->is_async_call_builtin = is_async_call_builtin; |
| 1434 | 1434 | call_instruction->new_stack = new_stack; |
| 1435 | 1435 | call_instruction->result_loc = result_loc; |
| ... | ... | @@ -4412,10 +4412,10 @@ static IrInstruction *ir_gen_async_call(IrBuilder *irb, Scope *scope, AstNode *a |
| 4412 | 4412 | |
| 4413 | 4413 | args[arg_count] = ret_ptr; |
| 4414 | 4414 | |
| 4415 | bool is_async = await_node == nullptr; | |
| 4415 | CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; | |
| 4416 | 4416 | bool is_async_call_builtin = true; |
| 4417 | 4417 | IrInstruction *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, false, |
| 4418 | FnInlineAuto, is_async, is_async_call_builtin, bytes, result_loc); | |
| 4418 | FnInlineAuto, modifier, is_async_call_builtin, bytes, result_loc); | |
| 4419 | 4419 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 4420 | 4420 | } |
| 4421 | 4421 | |
| ... | ... | @@ -5302,7 +5302,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5302 | 5302 | FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; |
| 5303 | 5303 | |
| 5304 | 5304 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5305 | fn_inline, false, false, nullptr, result_loc); | |
| 5305 | fn_inline, CallModifierNone, false, nullptr, result_loc); | |
| 5306 | 5306 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 5307 | 5307 | } |
| 5308 | 5308 | case BuiltinFnIdNewStackCall: |
| ... | ... | @@ -5335,7 +5335,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5335 | 5335 | } |
| 5336 | 5336 | |
| 5337 | 5337 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5338 | FnInlineAuto, false, false, new_stack, result_loc); | |
| 5338 | FnInlineAuto, CallModifierNone, false, new_stack, result_loc); | |
| 5339 | 5339 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 5340 | 5340 | } |
| 5341 | 5341 | case BuiltinFnIdAsyncCall: |
| ... | ... | @@ -5624,7 +5624,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 5624 | 5624 | { |
| 5625 | 5625 | assert(node->type == NodeTypeFnCallExpr); |
| 5626 | 5626 | |
| 5627 | if (node->data.fn_call_expr.is_builtin) | |
| 5627 | if (node->data.fn_call_expr.modifier == CallModifierBuiltin) | |
| 5628 | 5628 | return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc); |
| 5629 | 5629 | |
| 5630 | 5630 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| ... | ... | @@ -5641,9 +5641,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 5641 | 5641 | return args[i]; |
| 5642 | 5642 | } |
| 5643 | 5643 | |
| 5644 | bool is_async = node->data.fn_call_expr.is_async; | |
| 5645 | 5644 | IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5646 | FnInlineAuto, is_async, false, nullptr, result_loc); | |
| 5645 | FnInlineAuto, node->data.fn_call_expr.modifier, false, nullptr, result_loc); | |
| 5647 | 5646 | return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); |
| 5648 | 5647 | } |
| 5649 | 5648 | |
| ... | ... | @@ -7937,7 +7936,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 7937 | 7936 | assert(node->type == NodeTypeAwaitExpr); |
| 7938 | 7937 | |
| 7939 | 7938 | AstNode *expr_node = node->data.await_expr.expr; |
| 7940 | if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.is_builtin) { | |
| 7939 | if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { | |
| 7941 | 7940 | AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; |
| 7942 | 7941 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; |
| 7943 | 7942 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); |
| ... | ... | @@ -15408,7 +15407,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc |
| 15408 | 15407 | ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_ret_type); |
| 15409 | 15408 | |
| 15410 | 15409 | IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, |
| 15411 | arg_count, casted_args, FnInlineAuto, true, casted_new_stack, | |
| 15410 | arg_count, casted_args, FnInlineAuto, CallModifierAsync, casted_new_stack, | |
| 15412 | 15411 | call_instruction->is_async_call_builtin, ret_ptr, anyframe_type); |
| 15413 | 15412 | return &call_gen->base; |
| 15414 | 15413 | } else { |
| ... | ... | @@ -15422,8 +15421,8 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc |
| 15422 | 15421 | if (type_is_invalid(result_loc->value.type)) |
| 15423 | 15422 | return ira->codegen->invalid_instruction; |
| 15424 | 15423 | return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, |
| 15425 | casted_args, FnInlineAuto, true, casted_new_stack, call_instruction->is_async_call_builtin, | |
| 15426 | result_loc, frame_type)->base; | |
| 15424 | casted_args, FnInlineAuto, CallModifierAsync, casted_new_stack, | |
| 15425 | call_instruction->is_async_call_builtin, result_loc, frame_type)->base; | |
| 15427 | 15426 | } |
| 15428 | 15427 | } |
| 15429 | 15428 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| ... | ... | @@ -16174,7 +16173,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16174 | 16173 | return ira->codegen->invalid_instruction; |
| 16175 | 16174 | |
| 16176 | 16175 | size_t impl_param_count = impl_fn_type_id->param_count; |
| 16177 | if (call_instruction->is_async) { | |
| 16176 | if (call_instruction->modifier == CallModifierAsync) { | |
| 16178 | 16177 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, |
| 16179 | 16178 | nullptr, casted_args, impl_param_count, casted_new_stack); |
| 16180 | 16179 | return ir_finish_anal(ira, result); |
| ... | ... | @@ -16201,14 +16200,17 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16201 | 16200 | result_loc = nullptr; |
| 16202 | 16201 | } |
| 16203 | 16202 | |
| 16204 | if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { | |
| 16203 | if (impl_fn_type_id->cc == CallingConventionAsync && | |
| 16204 | parent_fn_entry->inferred_async_node == nullptr && | |
| 16205 | call_instruction->modifier != CallModifierNoAsync) | |
| 16206 | { | |
| 16205 | 16207 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 16206 | 16208 | parent_fn_entry->inferred_async_fn = impl_fn; |
| 16207 | 16209 | } |
| 16208 | 16210 | |
| 16209 | 16211 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, |
| 16210 | 16212 | impl_fn, nullptr, impl_param_count, casted_args, fn_inline, |
| 16211 | false, casted_new_stack, call_instruction->is_async_call_builtin, result_loc, | |
| 16213 | call_instruction->modifier, casted_new_stack, call_instruction->is_async_call_builtin, result_loc, | |
| 16212 | 16214 | impl_fn_type_id->return_type); |
| 16213 | 16215 | |
| 16214 | 16216 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { |
| ... | ... | @@ -16325,13 +16327,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16325 | 16327 | if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type)) |
| 16326 | 16328 | return ira->codegen->invalid_instruction; |
| 16327 | 16329 | |
| 16328 | if (call_instruction->is_async) { | |
| 16330 | if (call_instruction->modifier == CallModifierAsync) { | |
| 16329 | 16331 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, |
| 16330 | 16332 | casted_args, call_param_count, casted_new_stack); |
| 16331 | 16333 | return ir_finish_anal(ira, result); |
| 16332 | 16334 | } |
| 16333 | 16335 | |
| 16334 | if (fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { | |
| 16336 | if (fn_type_id->cc == CallingConventionAsync && | |
| 16337 | parent_fn_entry->inferred_async_node == nullptr && | |
| 16338 | call_instruction->modifier != CallModifierNoAsync) | |
| 16339 | { | |
| 16335 | 16340 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 16336 | 16341 | parent_fn_entry->inferred_async_fn = fn_entry; |
| 16337 | 16342 | } |
| ... | ... | @@ -16358,7 +16363,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16358 | 16363 | } |
| 16359 | 16364 | |
| 16360 | 16365 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, |
| 16361 | call_param_count, casted_args, fn_inline, false, casted_new_stack, | |
| 16366 | call_param_count, casted_args, fn_inline, call_instruction->modifier, casted_new_stack, | |
| 16362 | 16367 | call_instruction->is_async_call_builtin, result_loc, return_type); |
| 16363 | 16368 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { |
| 16364 | 16369 | parent_fn_entry->call_list.append(new_call_instruction); |
src/ir_print.cpp+22-4| ... | ... | @@ -608,8 +608,17 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { |
| 608 | 608 | } |
| 609 | 609 | |
| 610 | 610 | static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) { |
| 611 | if (call_instruction->is_async) { | |
| 612 | fprintf(irp->f, "async "); | |
| 611 | switch (call_instruction->modifier) { | |
| 612 | case CallModifierNone: | |
| 613 | break; | |
| 614 | case CallModifierAsync: | |
| 615 | fprintf(irp->f, "async "); | |
| 616 | break; | |
| 617 | case CallModifierNoAsync: | |
| 618 | fprintf(irp->f, "noasync "); | |
| 619 | break; | |
| 620 | case CallModifierBuiltin: | |
| 621 | zig_unreachable(); | |
| 613 | 622 | } |
| 614 | 623 | if (call_instruction->fn_entry) { |
| 615 | 624 | fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); |
| ... | ... | @@ -629,8 +638,17 @@ static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instructi |
| 629 | 638 | } |
| 630 | 639 | |
| 631 | 640 | static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) { |
| 632 | if (call_instruction->is_async) { | |
| 633 | fprintf(irp->f, "async "); | |
| 641 | switch (call_instruction->modifier) { | |
| 642 | case CallModifierNone: | |
| 643 | break; | |
| 644 | case CallModifierAsync: | |
| 645 | fprintf(irp->f, "async "); | |
| 646 | break; | |
| 647 | case CallModifierNoAsync: | |
| 648 | fprintf(irp->f, "noasync "); | |
| 649 | break; | |
| 650 | case CallModifierBuiltin: | |
| 651 | zig_unreachable(); | |
| 634 | 652 | } |
| 635 | 653 | if (call_instruction->fn_entry) { |
| 636 | 654 | fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); |
src/parser.cpp+15-13| ... | ... | @@ -113,7 +113,7 @@ static AstNode *ast_parse_multiply_op(ParseContext *pc); |
| 113 | 113 | static AstNode *ast_parse_prefix_op(ParseContext *pc); |
| 114 | 114 | static AstNode *ast_parse_prefix_type_op(ParseContext *pc); |
| 115 | 115 | static AstNode *ast_parse_suffix_op(ParseContext *pc); |
| 116 | static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc); | |
| 116 | static AstNode *ast_parse_fn_call_arguments(ParseContext *pc); | |
| 117 | 117 | static AstNode *ast_parse_array_type_start(ParseContext *pc); |
| 118 | 118 | static AstNode *ast_parse_ptr_type_start(ParseContext *pc); |
| 119 | 119 | static AstNode *ast_parse_container_decl_auto(ParseContext *pc); |
| ... | ... | @@ -1403,12 +1403,14 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) { |
| 1403 | 1403 | } |
| 1404 | 1404 | |
| 1405 | 1405 | // SuffixExpr |
| 1406 | // <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments | |
| 1406 | // <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments | |
| 1407 | // / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments | |
| 1407 | 1408 | // / PrimaryTypeExpr (SuffixOp / FnCallArguments)* |
| 1408 | 1409 | static AstNode *ast_parse_suffix_expr(ParseContext *pc) { |
| 1409 | Token *async_token = eat_token_if(pc, TokenIdKeywordAsync); | |
| 1410 | if (async_token != nullptr) { | |
| 1411 | if (eat_token_if(pc, TokenIdKeywordFn) != nullptr) { | |
| 1410 | Token *async_token = eat_token(pc); | |
| 1411 | bool is_async = async_token->id == TokenIdKeywordAsync; | |
| 1412 | if (is_async || async_token->id == TokenIdKeywordNoAsync) { | |
| 1413 | if (is_async && eat_token_if(pc, TokenIdKeywordFn) != nullptr) { | |
| 1412 | 1414 | // HACK: If we see the keyword `fn`, then we assume that |
| 1413 | 1415 | // we are parsing an async fn proto, and not a call. |
| 1414 | 1416 | // We therefore put back all tokens consumed by the async |
| ... | ... | @@ -1447,24 +1449,24 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { |
| 1447 | 1449 | child = suffix; |
| 1448 | 1450 | } |
| 1449 | 1451 | |
| 1450 | // TODO: Both *_async_prefix and *_fn_call_argumnets returns an | |
| 1452 | // TODO: Both *_async_prefix and *_fn_call_arguments returns an | |
| 1451 | 1453 | // AstNode *. All we really want here is the arguments of |
| 1452 | 1454 | // the call we parse. We therefor "leak" the node for now. |
| 1453 | 1455 | // Wait till we get async rework to fix this. |
| 1454 | AstNode *args = ast_parse_fn_call_argumnets(pc); | |
| 1456 | AstNode *args = ast_parse_fn_call_arguments(pc); | |
| 1455 | 1457 | if (args == nullptr) |
| 1456 | 1458 | ast_invalid_token_error(pc, peek_token(pc)); |
| 1457 | 1459 | |
| 1458 | 1460 | assert(args->type == NodeTypeFnCallExpr); |
| 1459 | 1461 | |
| 1460 | 1462 | AstNode *res = ast_create_node(pc, NodeTypeFnCallExpr, async_token); |
| 1461 | res->data.fn_call_expr.is_async = true; | |
| 1463 | res->data.fn_call_expr.modifier = is_async ? CallModifierAsync : CallModifierNoAsync; | |
| 1462 | 1464 | res->data.fn_call_expr.seen = false; |
| 1463 | 1465 | res->data.fn_call_expr.fn_ref_expr = child; |
| 1464 | 1466 | res->data.fn_call_expr.params = args->data.fn_call_expr.params; |
| 1465 | res->data.fn_call_expr.is_builtin = false; | |
| 1466 | 1467 | return res; |
| 1467 | 1468 | } |
| 1469 | put_back_token(pc); | |
| 1468 | 1470 | |
| 1469 | 1471 | AstNode *res = ast_parse_primary_type_expr(pc); |
| 1470 | 1472 | if (res == nullptr) |
| ... | ... | @@ -1496,7 +1498,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { |
| 1496 | 1498 | continue; |
| 1497 | 1499 | } |
| 1498 | 1500 | |
| 1499 | AstNode * call = ast_parse_fn_call_argumnets(pc); | |
| 1501 | AstNode * call = ast_parse_fn_call_arguments(pc); | |
| 1500 | 1502 | if (call != nullptr) { |
| 1501 | 1503 | assert(call->type == NodeTypeFnCallExpr); |
| 1502 | 1504 | call->data.fn_call_expr.fn_ref_expr = res; |
| ... | ... | @@ -1552,7 +1554,7 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { |
| 1552 | 1554 | name = buf_create_from_str("export"); |
| 1553 | 1555 | } |
| 1554 | 1556 | |
| 1555 | AstNode *res = ast_expect(pc, ast_parse_fn_call_argumnets); | |
| 1557 | AstNode *res = ast_expect(pc, ast_parse_fn_call_arguments); | |
| 1556 | 1558 | AstNode *name_sym = ast_create_node(pc, NodeTypeSymbol, token); |
| 1557 | 1559 | name_sym->data.symbol_expr.symbol = name; |
| 1558 | 1560 | |
| ... | ... | @@ -1560,7 +1562,7 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { |
| 1560 | 1562 | res->line = at_sign->start_line; |
| 1561 | 1563 | res->column = at_sign->start_column; |
| 1562 | 1564 | res->data.fn_call_expr.fn_ref_expr = name_sym; |
| 1563 | res->data.fn_call_expr.is_builtin = true; | |
| 1565 | res->data.fn_call_expr.modifier = CallModifierBuiltin; | |
| 1564 | 1566 | return res; |
| 1565 | 1567 | } |
| 1566 | 1568 | |
| ... | ... | @@ -2672,7 +2674,7 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) { |
| 2672 | 2674 | } |
| 2673 | 2675 | |
| 2674 | 2676 | // FnCallArguments <- LPAREN ExprList RPAREN |
| 2675 | static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) { | |
| 2677 | static AstNode *ast_parse_fn_call_arguments(ParseContext *pc) { | |
| 2676 | 2678 | Token *paren = eat_token_if(pc, TokenIdLParen); |
| 2677 | 2679 | if (paren == nullptr) |
| 2678 | 2680 | return nullptr; |
src/tokenizer.cpp+4-2| ... | ... | @@ -130,9 +130,10 @@ static const struct ZigKeyword zig_keywords[] = { |
| 130 | 130 | {"for", TokenIdKeywordFor}, |
| 131 | 131 | {"if", TokenIdKeywordIf}, |
| 132 | 132 | {"inline", TokenIdKeywordInline}, |
| 133 | {"noinline", TokenIdKeywordNoInline}, | |
| 134 | 133 | {"nakedcc", TokenIdKeywordNakedCC}, |
| 135 | 134 | {"noalias", TokenIdKeywordNoAlias}, |
| 135 | {"noasync", TokenIdKeywordNoAsync}, | |
| 136 | {"noinline", TokenIdKeywordNoInline}, | |
| 136 | 137 | {"null", TokenIdKeywordNull}, |
| 137 | 138 | {"or", TokenIdKeywordOr}, |
| 138 | 139 | {"orelse", TokenIdKeywordOrElse}, |
| ... | ... | @@ -1552,9 +1553,10 @@ const char * token_name(TokenId id) { |
| 1552 | 1553 | case TokenIdKeywordFor: return "for"; |
| 1553 | 1554 | case TokenIdKeywordIf: return "if"; |
| 1554 | 1555 | case TokenIdKeywordInline: return "inline"; |
| 1555 | case TokenIdKeywordNoInline: return "noinline"; | |
| 1556 | 1556 | case TokenIdKeywordNakedCC: return "nakedcc"; |
| 1557 | 1557 | case TokenIdKeywordNoAlias: return "noalias"; |
| 1558 | case TokenIdKeywordNoAsync: return "noasync"; | |
| 1559 | case TokenIdKeywordNoInline: return "noinline"; | |
| 1558 | 1560 | case TokenIdKeywordNull: return "null"; |
| 1559 | 1561 | case TokenIdKeywordOr: return "or"; |
| 1560 | 1562 | case TokenIdKeywordOrElse: return "orelse"; |
src/tokenizer.hpp+1| ... | ... | @@ -78,6 +78,7 @@ enum TokenId { |
| 78 | 78 | TokenIdKeywordLinkSection, |
| 79 | 79 | TokenIdKeywordNakedCC, |
| 80 | 80 | TokenIdKeywordNoAlias, |
| 81 | TokenIdKeywordNoAsync, | |
| 81 | 82 | TokenIdKeywordNull, |
| 82 | 83 | TokenIdKeywordOr, |
| 83 | 84 | TokenIdKeywordOrElse, |
src/translate_c.cpp+1-1| ... | ... | @@ -253,7 +253,7 @@ static AstNode *trans_create_node_symbol_str(Context *c, const char *name) { |
| 253 | 253 | static AstNode *trans_create_node_builtin_fn_call(Context *c, Buf *name) { |
| 254 | 254 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); |
| 255 | 255 | node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, name); |
| 256 | node->data.fn_call_expr.is_builtin = true; | |
| 256 | node->data.fn_call_expr.modifier = CallModifierBuiltin; | |
| 257 | 257 | return node; |
| 258 | 258 | } |
| 259 | 259 |
std/zig/tokenizer.zig+4-2| ... | ... | @@ -36,9 +36,10 @@ pub const Token = struct { |
| 36 | 36 | Keyword{ .bytes = "for", .id = Id.Keyword_for }, |
| 37 | 37 | Keyword{ .bytes = "if", .id = Id.Keyword_if }, |
| 38 | 38 | Keyword{ .bytes = "inline", .id = Id.Keyword_inline }, |
| 39 | Keyword{ .bytes = "noinline", .id = Id.Keyword_noinline }, | |
| 40 | 39 | Keyword{ .bytes = "nakedcc", .id = Id.Keyword_nakedcc }, |
| 41 | 40 | Keyword{ .bytes = "noalias", .id = Id.Keyword_noalias }, |
| 41 | Keyword{ .bytes = "noasync", .id = Id.Keyword_noasync }, | |
| 42 | Keyword{ .bytes = "noinline", .id = Id.Keyword_noinline }, | |
| 42 | 43 | Keyword{ .bytes = "null", .id = Id.Keyword_null }, |
| 43 | 44 | Keyword{ .bytes = "or", .id = Id.Keyword_or }, |
| 44 | 45 | Keyword{ .bytes = "orelse", .id = Id.Keyword_orelse }, |
| ... | ... | @@ -167,9 +168,10 @@ pub const Token = struct { |
| 167 | 168 | Keyword_for, |
| 168 | 169 | Keyword_if, |
| 169 | 170 | Keyword_inline, |
| 170 | Keyword_noinline, | |
| 171 | 171 | Keyword_nakedcc, |
| 172 | 172 | Keyword_noalias, |
| 173 | Keyword_noasync, | |
| 174 | Keyword_noinline, | |
| 173 | 175 | Keyword_null, |
| 174 | 176 | Keyword_or, |
| 175 | 177 | Keyword_orelse, |
test/stage1/behavior/async_fn.zig+16| ... | ... | @@ -1092,3 +1092,19 @@ test "recursive call of await @asyncCall with struct return type" { |
| 1092 | 1092 | expect(res.y == 2); |
| 1093 | 1093 | expect(res.z == 3); |
| 1094 | 1094 | } |
| 1095 | ||
| 1096 | test "noasync function call" { | |
| 1097 | const S = struct { | |
| 1098 | fn doTheTest() void { | |
| 1099 | const result = noasync add(50, 100); | |
| 1100 | expect(result == 150); | |
| 1101 | } | |
| 1102 | fn add(a: i32, b: i32) i32 { | |
| 1103 | if (a > 100) { | |
| 1104 | suspend; | |
| 1105 | } | |
| 1106 | return a + b; | |
| 1107 | } | |
| 1108 | }; | |
| 1109 | S.doTheTest(); | |
| 1110 | } |