Commit f3f838cc01

Andrew Kelley <andrew@ziglang.org>
2019-08-14 17:22:12
add compile error for await in exported function
1 parent 7799423
Changed files (2)
src/analyze.cpp
@@ -3893,18 +3893,18 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn) {
     fn->inferred_async_node = inferred_async_none;
 }
 
-static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node) {
-    ZigType *fn_type = fn_table_entry->type_entry;
+static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
+    ZigType *fn_type = fn->type_entry;
     assert(!fn_type->data.fn.is_generic);
     FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
 
-    ZigType *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
-            &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
-    fn_table_entry->src_implicit_return_type = block_return_type;
+    ZigType *block_return_type = ir_analyze(g, &fn->ir_executable,
+            &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
+    fn->src_implicit_return_type = block_return_type;
 
-    if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
+    if (type_is_invalid(block_return_type) || fn->analyzed_executable.invalid) {
         assert(g->errors.length > 0);
-        fn_table_entry->anal_state = FnAnalStateInvalid;
+        fn->anal_state = FnAnalStateInvalid;
         return;
     }
 
@@ -3912,20 +3912,20 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_typ
         ZigType *return_err_set_type = fn_type_id->return_type->data.error_union.err_set_type;
         if (return_err_set_type->data.error_set.infer_fn != nullptr) {
             ZigType *inferred_err_set_type;
-            if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorSet) {
-                inferred_err_set_type = fn_table_entry->src_implicit_return_type;
-            } else if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
-                inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
+            if (fn->src_implicit_return_type->id == ZigTypeIdErrorSet) {
+                inferred_err_set_type = fn->src_implicit_return_type;
+            } else if (fn->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
+                inferred_err_set_type = fn->src_implicit_return_type->data.error_union.err_set_type;
             } else {
                 add_node_error(g, return_type_node,
                         buf_sprintf("function with inferred error set must return at least one possible error"));
-                fn_table_entry->anal_state = FnAnalStateInvalid;
+                fn->anal_state = FnAnalStateInvalid;
                 return;
             }
 
             if (inferred_err_set_type->data.error_set.infer_fn != nullptr) {
                 if (!resolve_inferred_error_set(g, inferred_err_set_type, return_type_node)) {
-                    fn_table_entry->anal_state = FnAnalStateInvalid;
+                    fn->anal_state = FnAnalStateInvalid;
                     return;
                 }
             }
@@ -3945,12 +3945,25 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_typ
         }
     }
 
+    CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc;
+    if (cc != CallingConventionUnspecified && cc != CallingConventionAsync &&
+        fn->inferred_async_node != nullptr &&
+        fn->inferred_async_node != inferred_async_checking &&
+        fn->inferred_async_node != inferred_async_none)
+    {
+        ErrorMsg *msg = add_node_error(g, fn->proto_node,
+            buf_sprintf("function with calling convention '%s' cannot be async",
+                calling_convention_name(cc)));
+        add_async_error_notes(g, msg, fn);
+        fn->anal_state = FnAnalStateInvalid;
+    }
+
     if (g->verbose_ir) {
-        fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));
-        ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
+        fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name));
+        ir_print(g, stderr, &fn->analyzed_executable, 4);
         fprintf(stderr, "}\n");
     }
-    fn_table_entry->anal_state = FnAnalStateComplete;
+    fn->anal_state = FnAnalStateComplete;
 }
 
 static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
test/compile_errors.zig
@@ -2,6 +2,20 @@ const tests = @import("tests.zig");
 const builtin = @import("builtin");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "invalid suspend in exported function",
+        \\export fn entry() void {
+        \\    var frame = async func();
+        \\    var result = await frame;
+        \\}
+        \\fn func() void {
+        \\    suspend;
+        \\}
+    ,
+        "tmp.zig:1:1: error: function with calling convention 'ccc' cannot be async",
+        "tmp.zig:3:18: note: await is a suspend point",
+    );
+
     cases.add(
         "async function indirectly depends on its own frame",
         \\export fn entry() void {