Commit 66a490c27c
Changed files (4)
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<GlobalExport> export_list;
ZigList<IrInstructionCallGen *> call_list;
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);
+ }
}
}
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;
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 {