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 {
13421342};
13431343
13441344struct ZigFn {
1345 CodeGen *codegen;
13461345 LLVMValueRef llvm_value;
13471346 const char *llvm_name;
13481347 AstNode *proto_node;
......@@ -1385,6 +1384,7 @@ struct ZigFn {
13851384
13861385 AstNode *set_cold_node;
13871386 const AstNode *inferred_async_node;
1387 ZigFn *inferred_async_fn;
13881388
13891389 ZigList<GlobalExport> export_list;
13901390 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) {
6161 return err;
6262}
6363
64ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
64ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) {
6565 Token fake_token;
6666 fake_token.start_line = node->line;
6767 fake_token.start_column = node->column;
6868 return add_token_error(g, node->owner, &fake_token, msg);
6969}
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) {
7272 Token fake_token;
7373 fake_token.start_line = node->line;
7474 fake_token.start_column = node->column;
......@@ -2656,7 +2656,6 @@ ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
26562656
26572657 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
26582658
2659 fn_entry->codegen = g;
26602659 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
26612660 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
26622661 fn_entry->analyzed_executable.fn_entry = fn_entry;
......@@ -2784,6 +2783,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
27842783 }
27852784 }
27862785 } else {
2786 fn_table_entry->inferred_async_node = inferred_async_none;
27872787 g->external_prototypes.put_unique(tld_fn->base.name, &tld_fn->base);
27882788 }
27892789
......@@ -2805,14 +2805,11 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
28052805 g->fn_defs.append(fn_table_entry);
28062806 }
28072807
2808 switch (fn_table_entry->type_entry->data.fn.fn_type_id.cc) {
2809 case CallingConventionAsync:
2810 fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
2811 break;
2812 case CallingConventionUnspecified:
2813 break;
2814 default:
2815 fn_table_entry->inferred_async_node = inferred_async_none;
2808 // if the calling convention implies that it cannot be async, we save that for later
2809 // and leave the value to be nullptr to indicate that we have not emitted possible
2810 // compile errors for improperly calling async functions.
2811 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
2812 fn_table_entry->inferred_async_node = fn_table_entry->proto_node;
28162813 }
28172814
28182815 if (scope_is_root_decls(tld_fn->base.parent_scope) &&
......@@ -3801,6 +3798,25 @@ bool fn_is_async(ZigFn *fn) {
38013798 return fn->inferred_async_node != inferred_async_none;
38023799}
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
38043820// This function resolves functions being inferred async.
38053821static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
38063822 if (fn->inferred_async_node == inferred_async_checking) {
......@@ -3816,6 +3832,13 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
38163832 return;
38173833 }
38183834 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
38193842 for (size_t i = 0; i < fn->call_list.length; i += 1) {
38203843 FnCall *call = &fn->call_list.at(i);
38213844 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) {
38283851 }
38293852 if (fn_is_async(call->callee)) {
38303853 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 }
38313863 resolve_async_fn_frame(g, fn);
38323864 return;
38333865 }
......@@ -4451,7 +4483,7 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
44514483 if (a_val->special != ConstValSpecialRuntime && b_val->special != ConstValSpecialRuntime) {
44524484 assert(a_val->special == ConstValSpecialStatic);
44534485 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)) {
44554487 return false;
44564488 }
44574489 } else {
src/analyze.hpp+2-2
......@@ -11,9 +11,9 @@
1111#include "all_types.hpp"
1212
1313void 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);
1515ErrorMsg *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);
1717void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
1818ZigType *new_type_table_entry(ZigTypeId id);
1919ZigType *get_coro_frame_type(CodeGen *g, ZigFn *fn);
test/compile_errors.zig+18
......@@ -2,6 +2,24 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub 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
523 cases.add(
624 "capture group on switch prong with incompatible payload types",
725 \\const Union = union(enum) {