From 03c1431f9c0b651f3f1853f11112edc07555883d Mon Sep 17 00:00:00 2001 From: Vexu Date: Mon, 9 Mar 2020 15:51:51 +0200 Subject: [PATCH] disallow resume and suspend in noasync scopes --- lib/std/zig/ast.zig | 1 - lib/std/zig/parse.zig | 16 ++++++++++++++-- src/ir.cpp | 44 ++++++++++++++++++++----------------------- src/parser.cpp | 9 +++++++++ 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 711806b810..5411519667 100644 --- a/lib/std/zig/ast.zig +++ b/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, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 5392c18dfe..9a574c6231 100644 --- a/lib/std/zig/parse.zig +++ b/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, }; diff --git a/src/ir.cpp b/src/ir.cpp index 6a387e12e0..50ace888cd 100644 --- a/src/ir.cpp +++ b/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) { diff --git a/src/parser.cpp b/src/parser.cpp index 7ff24db184..cdd254962e 100644 --- a/src/parser.cpp +++ b/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;