authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-20 00:31:52-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-20 00:31:52-05:00
loga06f3c74fdc0d8bf0f42427a261ab32351753fcb
treee4c73aa199982fb9885148c3339f9e0c137239b5
parent3d58d7232ab6d1fd54523182beb99c31512bc4b9

parse async fn definitions

See #727

7 files changed, 53 insertions(+), 13 deletions(-)

doc/langref.html.in+1-1
...@@ -5645,7 +5645,7 @@ UseDecl = "use" Expression ";"...@@ -5645,7 +5645,7 @@ UseDecl = "use" Expression ";"
56455645
5646ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"5646ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
56475647
5648FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr5648FnProto = option("nakedcc" | "stdcallcc" | "extern" | "async") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
56495649
5650FnDef = option("inline" | "export") FnProto Block5650FnDef = option("inline" | "export") FnProto Block
56515651
src/all_types.hpp+3
...@@ -406,6 +406,7 @@ enum CallingConvention {...@@ -406,6 +406,7 @@ enum CallingConvention {
406 CallingConventionCold,406 CallingConventionCold,
407 CallingConventionNaked,407 CallingConventionNaked,
408 CallingConventionStdcall,408 CallingConventionStdcall,
409 CallingConventionAsync,
409};410};
410411
411struct AstNodeFnProto {412struct AstNodeFnProto {
...@@ -2152,6 +2153,8 @@ struct IrInstructionCall {...@@ -2152,6 +2153,8 @@ struct IrInstructionCall {
2152 bool is_comptime;2153 bool is_comptime;
2153 LLVMValueRef tmp_ptr;2154 LLVMValueRef tmp_ptr;
2154 FnInline fn_inline;2155 FnInline fn_inline;
2156 bool is_async;
2157 IrInstruction *async_allocator;
2155};2158};
21562159
2157struct IrInstructionConst {2160struct IrInstructionConst {
src/analyze.cpp+2
...@@ -884,6 +884,7 @@ static const char *calling_convention_name(CallingConvention cc) {...@@ -884,6 +884,7 @@ static const char *calling_convention_name(CallingConvention cc) {
884 case CallingConventionCold: return "coldcc";884 case CallingConventionCold: return "coldcc";
885 case CallingConventionNaked: return "nakedcc";885 case CallingConventionNaked: return "nakedcc";
886 case CallingConventionStdcall: return "stdcallcc";886 case CallingConventionStdcall: return "stdcallcc";
887 case CallingConventionAsync: return "async";
887 }888 }
888 zig_unreachable();889 zig_unreachable();
889}890}
...@@ -895,6 +896,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {...@@ -895,6 +896,7 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
895 case CallingConventionCold: return "coldcc ";896 case CallingConventionCold: return "coldcc ";
896 case CallingConventionNaked: return "nakedcc ";897 case CallingConventionNaked: return "nakedcc ";
897 case CallingConventionStdcall: return "stdcallcc ";898 case CallingConventionStdcall: return "stdcallcc ";
899 case CallingConventionAsync: return "async ";
898 }900 }
899 zig_unreachable();901 zig_unreachable();
900}902}
src/codegen.cpp+2
...@@ -381,6 +381,8 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {...@@ -381,6 +381,8 @@ static LLVMCallConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
381 } else {381 } else {
382 return LLVMCCallConv;382 return LLVMCCallConv;
383 }383 }
384 case CallingConventionAsync:
385 return LLVMFastCallConv;
384 }386 }
385 zig_unreachable();387 zig_unreachable();
386}388}
src/ir.cpp+39-10
...@@ -986,7 +986,7 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio...@@ -986,7 +986,7 @@ static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstructio
986986
987static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,987static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
988 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,988 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
989 bool is_comptime, FnInline fn_inline)989 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
990{990{
991 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);991 IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, scope, source_node);
992 call_instruction->fn_entry = fn_entry;992 call_instruction->fn_entry = fn_entry;
...@@ -995,21 +995,25 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc...@@ -995,21 +995,25 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
995 call_instruction->fn_inline = fn_inline;995 call_instruction->fn_inline = fn_inline;
996 call_instruction->args = args;996 call_instruction->args = args;
997 call_instruction->arg_count = arg_count;997 call_instruction->arg_count = arg_count;
998 call_instruction->is_async = is_async;
999 call_instruction->async_allocator = async_allocator;
9981000
999 if (fn_ref)1001 if (fn_ref)
1000 ir_ref_instruction(fn_ref, irb->current_basic_block);1002 ir_ref_instruction(fn_ref, irb->current_basic_block);
1001 for (size_t i = 0; i < arg_count; i += 1)1003 for (size_t i = 0; i < arg_count; i += 1)
1002 ir_ref_instruction(args[i], irb->current_basic_block);1004 ir_ref_instruction(args[i], irb->current_basic_block);
1005 if (async_allocator)
1006 ir_ref_instruction(async_allocator, irb->current_basic_block);
10031007
1004 return &call_instruction->base;1008 return &call_instruction->base;
1005}1009}
10061010
1007static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,1011static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
1008 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,1012 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
1009 bool is_comptime, FnInline fn_inline)1013 bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator)
1010{1014{
1011 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,1015 IrInstruction *new_instruction = ir_build_call(irb, old_instruction->scope,
1012 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline);1016 old_instruction->source_node, fn_entry, fn_ref, arg_count, args, is_comptime, fn_inline, is_async, async_allocator);
1013 ir_link_new_instruction(new_instruction, old_instruction);1017 ir_link_new_instruction(new_instruction, old_instruction);
1014 return new_instruction;1018 return new_instruction;
1015}1019}
...@@ -3754,7 +3758,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -3754,7 +3758,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
3754 }3758 }
3755 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;3759 FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
37563760
3757 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline);3761 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr);
3758 }3762 }
3759 case BuiltinFnIdTypeId:3763 case BuiltinFnIdTypeId:
3760 {3764 {
...@@ -3888,11 +3892,17 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node...@@ -3888,11 +3892,17 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node
3888 return args[i];3892 return args[i];
3889 }3893 }
38903894
3891 if (node->data.fn_call_expr.is_async) {3895 bool is_async = node->data.fn_call_expr.is_async;
3892 zig_panic("TODO ir_gen_fn_call for async fn calls");3896 IrInstruction *async_allocator = nullptr;
3897 if (is_async) {
3898 if (node->data.fn_call_expr.async_allocator) {
3899 async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
3900 if (async_allocator == irb->codegen->invalid_instruction)
3901 return async_allocator;
3902 }
3893 }3903 }
38943904
3895 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto);3905 return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator);
3896}3906}
38973907
3898static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {3908static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -10584,6 +10594,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -10584,6 +10594,11 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
10584 buf_sprintf("exported function must specify calling convention"));10594 buf_sprintf("exported function must specify calling convention"));
10585 add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));10595 add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
10586 } break;10596 } break;
10597 case CallingConventionAsync: {
10598 ErrorMsg *msg = ir_add_error(ira, target,
10599 buf_sprintf("exported function cannot be async"));
10600 add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
10601 } break;
10587 case CallingConventionC:10602 case CallingConventionC:
10588 case CallingConventionNaked:10603 case CallingConventionNaked:
10589 case CallingConventionCold:10604 case CallingConventionCold:
...@@ -10963,6 +10978,13 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10963,6 +10978,13 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
10963 }10978 }
10964 return ira->codegen->builtin_types.entry_invalid;10979 return ira->codegen->builtin_types.entry_invalid;
10965 }10980 }
10981 if (fn_type_id->cc == CallingConventionAsync && !call_instruction->is_async) {
10982 ErrorMsg *msg = ir_add_error(ira, fn_ref, buf_sprintf("must use async keyword to call async function"));
10983 if (fn_proto_node) {
10984 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("declared here"));
10985 }
10986 return ira->codegen->builtin_types.entry_invalid;
10987 }
1096610988
1096710989
10968 if (fn_type_id->is_var_args) {10990 if (fn_type_id->is_var_args) {
...@@ -11258,7 +11280,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -11258,7 +11280,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1125811280
11259 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;11281 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
11260 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,11282 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
11261 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline);11283 impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, false, nullptr);
1126211284
11263 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;11285 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
11264 ir_add_alloca(ira, new_call_instruction, return_type);11286 ir_add_alloca(ira, new_call_instruction, return_type);
...@@ -11324,12 +11346,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -11324,12 +11346,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1132411346
11325 assert(next_arg_index == call_param_count);11347 assert(next_arg_index == call_param_count);
1132611348
11349 if (call_instruction->is_async) {
11350 zig_panic("TODO handle async fn call");
11351 }
11352
11327 TypeTableEntry *return_type = fn_type_id->return_type;11353 TypeTableEntry *return_type = fn_type_id->return_type;
11328 if (type_is_invalid(return_type))11354 if (type_is_invalid(return_type))
11329 return ira->codegen->builtin_types.entry_invalid;11355 return ira->codegen->builtin_types.entry_invalid;
1133011356
11331 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,11357 IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
11332 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline);11358 fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr);
1133311359
11334 ir_add_alloca(ira, new_call_instruction, return_type);11360 ir_add_alloca(ira, new_call_instruction, return_type);
11335 return ir_finish_anal(ira, return_type);11361 return ir_finish_anal(ira, return_type);
...@@ -16491,7 +16517,10 @@ static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruc...@@ -16491,7 +16517,10 @@ static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruc
16491}16517}
1649216518
16493static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {16519static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructionCancel *instruction) {
16494 IrInstruction *casted_target = ir_implicit_cast(ira, instruction->target->other, ira->codegen->builtin_types.entry_promise);16520 IrInstruction *target_inst = instruction->target->other;
16521 if (type_is_invalid(target_inst->value.type))
16522 return ira->codegen->builtin_types.entry_invalid;
16523 IrInstruction *casted_target = ir_implicit_cast(ira, target_inst, ira->codegen->builtin_types.entry_promise);
16495 if (type_is_invalid(casted_target->value.type))16524 if (type_is_invalid(casted_target->value.type))
16496 return ira->codegen->builtin_types.entry_invalid;16525 return ira->codegen->builtin_types.entry_invalid;
1649716526
src/parser.cpp+5-1
...@@ -2333,7 +2333,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand...@@ -2333,7 +2333,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
2333}2333}
23342334
2335/*2335/*
2336FnProto = option("nakedcc" | "stdcallcc" | "extern") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr2336FnProto = option("nakedcc" | "stdcallcc" | "extern" | "async") "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
2337*/2337*/
2338static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {2338static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
2339 Token *first_token = &pc->tokens->at(*token_index);2339 Token *first_token = &pc->tokens->at(*token_index);
...@@ -2345,6 +2345,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m...@@ -2345,6 +2345,10 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
2345 *token_index += 1;2345 *token_index += 1;
2346 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);2346 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2347 cc = CallingConventionNaked;2347 cc = CallingConventionNaked;
2348 } else if (first_token->id == TokenIdKeywordAsync) {
2349 *token_index += 1;
2350 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
2351 cc = CallingConventionAsync;
2348 } else if (first_token->id == TokenIdKeywordStdcallCC) {2352 } else if (first_token->id == TokenIdKeywordStdcallCC) {
2349 *token_index += 1;2353 *token_index += 1;
2350 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);2354 fn_token = ast_eat_token(pc, token_index, TokenIdKeywordFn);
std/mem.zig+1-1
...@@ -124,7 +124,7 @@ pub const Allocator = struct {...@@ -124,7 +124,7 @@ pub const Allocator = struct {
124 return self.allocator.allocFn(self.allocator, byte_count, alignment);124 return self.allocator.allocFn(self.allocator, byte_count, alignment);
125 }125 }
126126
127 fn free(self: &const AsyncAllocator, old_mem: []u8) {127 fn free(self: &const AsyncAllocator, old_mem: []u8) void {
128 return self.allocator.freeFn(self.allocator, old_mem);128 return self.allocator.freeFn(self.allocator, old_mem);
129 }129 }
130 };130 };