authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-23 19:35:41-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-23 19:35:41-04:00
log19ee4957502c704312646f75544e968b618aa807
treec3b70d7f17138de258e7b6e46be0872e7357adc1
parent7e9760de10e05a4c2a7bae4c4bb945351b9ae0cb
signature Commit is signed but in an unrecognized format.

add error for function with ccc indirectly calling async function


4 files changed, 65 insertions(+), 15 deletions(-)

src/all_types.hpp+1-1
...@@ -1342,7 +1342,6 @@ struct FnCall {...@@ -1342,7 +1342,6 @@ struct FnCall {
1342};1342};
13431343
1344struct ZigFn {1344struct ZigFn {
1345 CodeGen *codegen;
1346 LLVMValueRef llvm_value;1345 LLVMValueRef llvm_value;
1347 const char *llvm_name;1346 const char *llvm_name;
1348 AstNode *proto_node;1347 AstNode *proto_node;
...@@ -1385,6 +1384,7 @@ struct ZigFn {...@@ -1385,6 +1384,7 @@ struct ZigFn {
13851384
1386 AstNode *set_cold_node;1385 AstNode *set_cold_node;
1387 const AstNode *inferred_async_node;1386 const AstNode *inferred_async_node;
1387 ZigFn *inferred_async_fn;
13881388
1389 ZigList<GlobalExport> export_list;1389 ZigList<GlobalExport> export_list;
1390 ZigList<FnCall> call_list;1390 ZigList<FnCall> call_list;
src/analyze.cpp+44-12
...@@ -61,14 +61,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {...@@ -61,14 +61,14 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) {
61 return err;61 return err;
62}62}
6363
64ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {64ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) {
65 Token fake_token;65 Token fake_token;
66 fake_token.start_line = node->line;66 fake_token.start_line = node->line;
67 fake_token.start_column = node->column;67 fake_token.start_column = node->column;
68 return add_token_error(g, node->owner, &fake_token, msg);68 return add_token_error(g, node->owner, &fake_token, msg);
69}69}
7070
71ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {71ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg) {
72 Token fake_token;72 Token fake_token;
73 fake_token.start_line = node->line;73 fake_token.start_line = node->line;
74 fake_token.start_column = node->column;74 fake_token.start_column = node->column;
...@@ -2656,7 +2656,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {...@@ -2656,7 +2656,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
26562656
2657 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;2657 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
26582658
2659 fn_entry->codegen = g;
2660 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;2659 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
2661 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;2660 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
2662 fn_entry->analyzed_executable.fn_entry = fn_entry;2661 fn_entry->analyzed_executable.fn_entry = fn_entry;
...@@ -2784,6 +2783,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2784,6 +2783,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2784 }2783 }
2785 }2784 }
2786 } else {2785 } else {
2786 fn_table_entry->inferred_async_node = inferred_async_none;
2787 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);2787 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
2788 }2788 }
27892789
...@@ -2805,14 +2805,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2805,14 +2805,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2805 g->fn_defs.append(fn_table_entry);2805 g->fn_defs.append(fn_table_entry);
2806 }2806 }
28072807
2808 switch (fn_table_entry->type_entry->data.fn.fn_type_id.cc) {2808 // if the calling convention implies that it cannot be async, we save that for later
2809 case CallingConventionAsync:2809 // and leave the value to be nullptr to indicate that we have not emitted possible
2810 fn_table_entry->inferred_async_node = fn_table_entry->proto_node;2810 // compile errors for improperly calling async functions.
2811 break;2811 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
2812 case CallingConventionUnspecified:2812 fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
2813 break;
2814 default:
2815 fn_table_entry->inferred_async_node = inferred_async_none;
2816 }2813 }
28172814
2818 if (scope_is_root_decls(tld_fn->base.parent_scope) &&2815 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
...@@ -3801,6 +3798,25 @@ bool fn_is_async(ZigFn *fn) {...@@ -3801,6 +3798,25 @@ bool fn_is_async(ZigFn *fn) {
3801 return fn->inferred_async_node != inferred_async_none;3798 return fn->inferred_async_node != inferred_async_none;
3802}3799}
38033800
3801static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
3802 assert(fn->inferred_async_node != nullptr);
3803 assert(fn->inferred_async_node != inferred_async_checking);
3804 assert(fn->inferred_async_node != inferred_async_none);
3805 if (fn->inferred_async_fn != nullptr) {
3806 ErrorMsg *new_msg = add_error_note(g, msg, fn->inferred_async_node,
3807 buf_sprintf("async function call here"));
3808 return add_async_error_notes(g, new_msg, fn->inferred_async_fn);
3809 } else if (fn->inferred_async_node->type == NodeTypeFnProto) {
3810 add_error_note(g, msg, fn->inferred_async_node,
3811 buf_sprintf("async calling convention here"));
3812 } else if (fn->inferred_async_node->type == NodeTypeSuspend) {
3813 add_error_note(g, msg, fn->inferred_async_node,
3814 buf_sprintf("suspends here"));
3815 } else {
3816 zig_unreachable();
3817 }
3818}
3819
3804// This function resolves functions being inferred async.3820// This function resolves functions being inferred async.
3805static void analyze_fn_async(CodeGen *g, ZigFn *fn) {3821static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
3806 if (fn->inferred_async_node == inferred_async_checking) {3822 if (fn->inferred_async_node == inferred_async_checking) {
...@@ -3816,6 +3832,13 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {...@@ -3816,6 +3832,13 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
3816 return;3832 return;
3817 }3833 }
3818 fn->inferred_async_node = inferred_async_checking;3834 fn->inferred_async_node = inferred_async_checking;
3835
3836 bool must_not_be_async = false;
3837 if (fn->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified) {
3838 must_not_be_async = true;
3839 fn->inferred_async_node = inferred_async_none;
3840 }
3841
3819 for (size_t i = 0; i < fn->call_list.length; i += 1) {3842 for (size_t i = 0; i < fn->call_list.length; i += 1) {
3820 FnCall *call = &fn->call_list.at(i);3843 FnCall *call = &fn->call_list.at(i);
3821 if (call->callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)3844 if (call->callee->type_entry->data.fn.fn_type_id.cc != CallingConventionUnspecified)
...@@ -3828,6 +3851,15 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {...@@ -3828,6 +3851,15 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
3828 }3851 }
3829 if (fn_is_async(call->callee)) {3852 if (fn_is_async(call->callee)) {
3830 fn->inferred_async_node = call->source_node;3853 fn->inferred_async_node = call->source_node;
3854 fn->inferred_async_fn = call->callee;
3855 if (must_not_be_async) {
3856 ErrorMsg *msg = add_node_error(g, fn->proto_node,
3857 buf_sprintf("function with calling convention '%s' cannot be async",
3858 calling_convention_name(fn->type_entry->data.fn.fn_type_id.cc)));
3859 add_async_error_notes(g, msg, fn);
3860 fn->anal_state = FnAnalStateInvalid;
3861 return;
3862 }
3831 resolve_async_fn_frame(g, fn);3863 resolve_async_fn_frame(g, fn);
3832 return;3864 return;
3833 }3865 }
...@@ -4451,7 +4483,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {...@@ -4451,7 +4483,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
4451 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {4483 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
4452 assert(a_val->special == ConstValSpecialStatic);4484 assert(a_val->special == ConstValSpecialStatic);
4453 assert(b_val->special == ConstValSpecialStatic);4485 assert(b_val->special == ConstValSpecialStatic);
4454 if (!const_values_equal(a->fn_entry->codegen, a_val, b_val)) {4486 if (!const_values_equal(a->codegen, a_val, b_val)) {
4455 return false;4487 return false;
4456 }4488 }
4457 } else {4489 } else {
src/analyze.hpp+2-2
...@@ -11,9 +11,9 @@...@@ -11,9 +11,9 @@
11#include "all_types.hpp"11#include "all_types.hpp"
1212
13void semantic_analyze(CodeGen *g);13void semantic_analyze(CodeGen *g);
14ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);14ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg);
15ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);15ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg);
16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);16ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg);
17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);17void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
18ZigType *new_type_table_entry(ZigTypeId id);18ZigType *new_type_table_entry(ZigTypeId id);
19ZigType *get_coro_frame_type(CodeGen *g, ZigFn *fn);19ZigType *get_coro_frame_type(CodeGen *g, ZigFn *fn);
test/compile_errors.zig+18
...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");...@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "function with ccc indirectly calling async function",
7 \\export fn entry() void {
8 \\ foo();
9 \\}
10 \\fn foo() void {
11 \\ bar();
12 \\}
13 \\fn bar() void {
14 \\ suspend;
15 \\}
16 ,
17 "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
18 "tmp.zig:2:8: note: async function call here",
19 "tmp.zig:5:8: note: async function call here",
20 "tmp.zig:8:5: note: suspends here",
21 );
22
5 cases.add(23 cases.add(
6 "capture group on switch prong with incompatible payload types",24 "capture group on switch prong with incompatible payload types",
7 \\const Union = union(enum) {25 \\const Union = union(enum) {