diff --git a/src/all_types.hpp b/src/all_types.hpp index f1c699ba1..f075dd7c5 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1396,6 +1396,7 @@ struct ZigFn { AstNode *set_cold_node; const AstNode *inferred_async_node; ZigFn *inferred_async_fn; + AstNode *non_async_node; ZigList export_list; ZigList call_list; diff --git a/src/analyze.cpp b/src/analyze.cpp index 4aff6da8e..16e66a590 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4144,8 +4144,15 @@ void semantic_analyze(CodeGen *g) { // second pass over functions for detecting async for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { - ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); - analyze_fn_async(g, fn_entry, true); + ZigFn *fn = g->fn_defs.at(g->fn_defs_index); + analyze_fn_async(g, fn, true); + if (fn_is_async(fn) && fn->non_async_node != nullptr) { + ErrorMsg *msg = add_node_error(g, fn->proto_node, + buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name))); + add_error_note(g, msg, fn->non_async_node, + buf_sprintf("required to be non-async here")); + add_async_error_notes(g, msg, fn); + } } } diff --git a/src/ir.cpp b/src/ir.cpp index 51f849ce1..c37fac2f5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15160,6 +15160,20 @@ no_mem_slot: return var_ptr_instruction; } +// This function is called when a comptime value becomes accessible at runtime. +static void mark_comptime_value_escape(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *val) { + ir_assert(value_is_comptime(val), source_instr); + if (val->special == ConstValSpecialUndef) + return; + + if (val->type->id == ZigTypeIdFn && val->type->data.fn.fn_type_id.cc == CallingConventionUnspecified) { + ir_assert(val->data.x_ptr.special == ConstPtrSpecialFunction, source_instr); + if (val->data.x_ptr.data.fn.fn_entry->non_async_node == nullptr) { + val->data.x_ptr.data.fn.fn_entry->non_async_node = source_instr->source_node; + } + } +} + static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const) { @@ -15256,6 +15270,10 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source break; } + if (instr_is_comptime(value)) { + mark_comptime_value_escape(ira, source_instr, &value->value); + } + IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, ptr, value); return &store_ptr->base; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d0c12e7cf..654171f55 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,21 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "non-async function pointer eventually is inferred to become async", + \\export fn a() void { + \\ var non_async_fn: fn () void = undefined; + \\ non_async_fn = func; + \\} + \\fn func() void { + \\ suspend; + \\} + , + "tmp.zig:5:1: error: 'func' cannot be async", + "tmp.zig:3:20: note: required to be non-async here", + "tmp.zig:6:5: note: suspends here", + ); + cases.add( "bad alignment in @asyncCall", \\export fn entry() void {