authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-17 16:49:23-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-17 16:49:23-04:00
log66a490c27c01c958d8d20dbc289c6b2b934a724e
treeedd444dfae7eb106453f9aa0aa9ec3908c97e2f1
parent0ff396c34f93b60a000e1ee50e881a8c25122b79
signaturelock-open Commit is signed but in an unrecognized format.

detect non-async function pointer of inferred async function

closes #3075

4 files changed, 43 insertions(+), 2 deletions(-)

src/all_types.hpp+1
...@@ -1396,6 +1396,7 @@ struct ZigFn {...@@ -1396,6 +1396,7 @@ struct ZigFn {
1396 AstNode *set_cold_node;1396 AstNode *set_cold_node;
1397 const AstNode *inferred_async_node;1397 const AstNode *inferred_async_node;
1398 ZigFn *inferred_async_fn;1398 ZigFn *inferred_async_fn;
1399 AstNode *non_async_node;
13991400
1400 ZigList<GlobalExport> export_list;1401 ZigList<GlobalExport> export_list;
1401 ZigList<IrInstructionCallGen *> call_list;1402 ZigList<IrInstructionCallGen *> call_list;
src/analyze.cpp+9-2
...@@ -4144,8 +4144,15 @@ void semantic_analyze(CodeGen *g) {...@@ -4144,8 +4144,15 @@ void semantic_analyze(CodeGen *g) {
41444144
4145 // second pass over functions for detecting async4145 // second pass over functions for detecting async
4146 for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {4146 for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) {
4147 ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index);4147 ZigFn *fn = g->fn_defs.at(g->fn_defs_index);
4148 analyze_fn_async(g, fn_entry, true);4148 analyze_fn_async(g, fn, true);
4149 if (fn_is_async(fn) && fn->non_async_node != nullptr) {
4150 ErrorMsg *msg = add_node_error(g, fn->proto_node,
4151 buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name)));
4152 add_error_note(g, msg, fn->non_async_node,
4153 buf_sprintf("required to be non-async here"));
4154 add_async_error_notes(g, msg, fn);
4155 }
4149 }4156 }
4150}4157}
41514158
src/ir.cpp+18
...@@ -15160,6 +15160,20 @@ no_mem_slot:...@@ -15160,6 +15160,20 @@ no_mem_slot:
15160 return var_ptr_instruction;15160 return var_ptr_instruction;
15161}15161}
1516215162
15163// This function is called when a comptime value becomes accessible at runtime.
15164static void mark_comptime_value_escape(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *val) {
15165 ir_assert(value_is_comptime(val), source_instr);
15166 if (val->special == ConstValSpecialUndef)
15167 return;
15168
15169 if (val->type->id == ZigTypeIdFn && val->type->data.fn.fn_type_id.cc == CallingConventionUnspecified) {
15170 ir_assert(val->data.x_ptr.special == ConstPtrSpecialFunction, source_instr);
15171 if (val->data.x_ptr.data.fn.fn_entry->non_async_node == nullptr) {
15172 val->data.x_ptr.data.fn.fn_entry->non_async_node = source_instr->source_node;
15173 }
15174 }
15175}
15176
15163static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,15177static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
15164 IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const)15178 IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const)
15165{15179{
...@@ -15256,6 +15270,10 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source...@@ -15256,6 +15270,10 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
15256 break;15270 break;
15257 }15271 }
1525815272
15273 if (instr_is_comptime(value)) {
15274 mark_comptime_value_escape(ira, source_instr, &value->value);
15275 }
15276
15259 IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope,15277 IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope,
15260 source_instr->source_node, ptr, value);15278 source_instr->source_node, ptr, value);
15261 return &store_ptr->base;15279 return &store_ptr->base;
test/compile_errors.zig+15
...@@ -2,6 +2,21 @@ const tests = @import("tests.zig");...@@ -2,6 +2,21 @@ 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 "non-async function pointer eventually is inferred to become async",
7 \\export fn a() void {
8 \\ var non_async_fn: fn () void = undefined;
9 \\ non_async_fn = func;
10 \\}
11 \\fn func() void {
12 \\ suspend;
13 \\}
14 ,
15 "tmp.zig:5:1: error: 'func' cannot be async",
16 "tmp.zig:3:20: note: required to be non-async here",
17 "tmp.zig:6:5: note: suspends here",
18 );
19
5 cases.add(20 cases.add(
6 "bad alignment in @asyncCall",21 "bad alignment in @asyncCall",
7 \\export fn entry() void {22 \\export fn entry() void {