Commit 03c1431f9c

Vexu <git@vexu.eu>
2020-03-09 14:51:51
disallow resume and suspend in noasync scopes
1 parent 3618256
Changed files (4)
lib/std/zig/ast.zig
@@ -1081,7 +1081,6 @@ pub const Node = struct {
 
     pub const Noasync = struct {
         base: Node = Node{ .id = .Noasync },
-        doc_comments: ?*DocComment,
         noasync_token: TokenIndex,
         expr: *Node,
 
lib/std/zig/parse.zig
@@ -462,6 +462,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
 /// Statement
 ///     <- KEYWORD_comptime? VarDecl
 ///      / KEYWORD_comptime BlockExprStatement
+///      / KEYWORD_noasync BlockExprStatement
 ///      / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
 ///      / KEYWORD_defer BlockExprStatement
 ///      / KEYWORD_errdefer BlockExprStatement
@@ -493,6 +494,19 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
         return &node.base;
     }
 
+    if (eatToken(it, .Keyword_noasync)) |noasync_token| {
+        const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{
+            .ExpectedBlockOrAssignment = .{ .token = it.index },
+        });
+
+        const node = try arena.create(Node.Noasync);
+        node.* = .{
+            .noasync_token = noasync_token,
+            .expr = block_expr,
+        };
+        return &node.base;
+    }
+
     if (eatToken(it, .Keyword_suspend)) |suspend_token| {
         const semicolon = eatToken(it, .Semicolon);
 
@@ -898,7 +912,6 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
         });
         const node = try arena.create(Node.Noasync);
         node.* = .{
-            .doc_comments = null,
             .noasync_token = token,
             .expr = expr_node,
         };
@@ -1280,7 +1293,6 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
         const expr = (try parseTypeExpr(arena, it, tree)) orelse return null;
         const node = try arena.create(Node.Noasync);
         node.* = .{
-            .doc_comments = null,
             .noasync_token = token,
             .expr = expr,
         };
src/ir.cpp
@@ -7309,29 +7309,16 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
     zig_unreachable();
 }
 
-static bool is_noasync_scope(Scope *scope) {
-    for (;;) {
-        switch (scope->id) {
-            case ScopeIdNoAsync:
-                return true;
-            case ScopeIdDefer:
-            case ScopeIdDeferExpr:
-            case ScopeIdDecls:
-            case ScopeIdFnDef:
-            case ScopeIdCompTime:
-            case ScopeIdVarDecl:
-            case ScopeIdCImport:
-            case ScopeIdSuspend:
-                return false;
-            case ScopeIdExpr:
-            case ScopeIdTypeOf:
-            case ScopeIdBlock:
-            case ScopeIdLoop:
-            case ScopeIdRuntime:
-                scope = scope->parent;
-                continue;
-        }
+static ScopeNoAsync *get_scope_noasync(Scope *scope) {
+    while (scope) {
+        if (scope->id == ScopeIdNoAsync)
+            return (ScopeNoAsync *)scope;
+        if (scope->id == ScopeIdFnDef)
+            return nullptr;
+
+        scope = scope->parent;
     }
+    return nullptr;
 }
 
 static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval,
@@ -7342,7 +7329,7 @@ static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node,
     if (node->data.fn_call_expr.modifier == CallModifierBuiltin)
         return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc);
 
-    bool is_noasync = is_noasync_scope(scope);
+    bool is_noasync = get_scope_noasync(scope) != nullptr;
     CallModifier modifier = node->data.fn_call_expr.modifier;
     if (is_noasync) {
         if (modifier == CallModifierAsync) {
@@ -9796,6 +9783,10 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod
 
 static IrInstSrc *ir_gen_resume(IrBuilderSrc *irb, Scope *scope, AstNode *node) {
     assert(node->type == NodeTypeResume);
+    if (get_scope_noasync(scope) != nullptr) {
+        add_node_error(irb->codegen, node, buf_sprintf("resume in noasync scope"));
+        return irb->codegen->invalid_inst_src;
+    }
 
     IrInstSrc *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr);
     if (target_inst == irb->codegen->invalid_inst_src)
@@ -9809,7 +9800,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
 {
     assert(node->type == NodeTypeAwaitExpr);
 
-    bool is_noasync = is_noasync_scope(scope);
+    bool is_noasync = get_scope_noasync(scope) != nullptr;
 
     AstNode *expr_node = node->data.await_expr.expr;
     if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) {
@@ -9855,6 +9846,11 @@ static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode
         add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition"));
         return irb->codegen->invalid_inst_src;
     }
+    if (get_scope_noasync(parent_scope) != nullptr) {
+        add_node_error(irb->codegen, node, buf_sprintf("suspend in noasync scope"));
+        return irb->codegen->invalid_inst_src;
+    }
+
     ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope);
     if (existing_suspend_scope) {
         if (!existing_suspend_scope->reported_err) {
src/parser.cpp
@@ -876,6 +876,7 @@ static AstNode *ast_parse_container_field(ParseContext *pc) {
 // Statement
 //     <- KEYWORD_comptime? VarDecl
 //      / KEYWORD_comptime BlockExprStatement
+//      / KEYWORD_noasync BlockExprStatement
 //      / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
 //      / KEYWORD_defer BlockExprStatement
 //      / KEYWORD_errdefer BlockExprStatement
@@ -899,6 +900,14 @@ static AstNode *ast_parse_statement(ParseContext *pc) {
         return res;
     }
 
+    Token *noasync = eat_token_if(pc, TokenIdKeywordNoAsync);
+    if (noasync != nullptr) {
+        AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement);
+        AstNode *res = ast_create_node(pc, NodeTypeNoAsync, noasync);
+        res->data.noasync_expr.expr = statement;
+        return res;
+    }
+
     Token *suspend = eat_token_if(pc, TokenIdKeywordSuspend);
     if (suspend != nullptr) {
         AstNode *statement = nullptr;