From 1c8fee41c247ea60aebd1d8b0fdba4002701b1cf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 21 May 2017 10:59:09 -0400 Subject: [PATCH] add compile error for goto leaving defer expression closes #284 --- src/ir.cpp | 32 +++++++++++++++++++++++++++----- test/compile_errors.zig | 10 ++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index ad29dd8b4c..a3d0fc9558 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5982,12 +5982,34 @@ static bool ir_goto_pass2(IrBuilder *irb) { irb->current_basic_block->instruction_list.resize(goto_item->instruction_index); Buf *label_name = source_node->data.goto_expr.name; - LabelTableEntry *label = find_label(irb->exec, goto_item->scope, label_name); - if (!label) { - add_node_error(irb->codegen, source_node, - buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); - return false; + + // Search up the scope until we find one of these things: + // * A block scope with the label in it => OK + // * A defer expression scope => error, error, cannot leave defer expression + // * Top level scope => error, didn't find label + + LabelTableEntry *label; + Scope *search_scope = goto_item->scope; + for (;;) { + if (search_scope == nullptr) { + add_node_error(irb->codegen, source_node, + buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); + return false; + } else if (search_scope->id == ScopeIdBlock) { + ScopeBlock *block_scope = (ScopeBlock *)search_scope; + auto entry = block_scope->label_table.maybe_get(label_name); + if (entry) { + label = entry->value; + break; + } + } else if (search_scope->id == ScopeIdDeferExpr) { + add_node_error(irb->codegen, source_node, + buf_sprintf("cannot goto out of defer expression")); + return false; + } + search_scope = search_scope->parent; } + label->used = true; IrInstruction *is_comptime = ir_build_const_bool(irb, goto_item->scope, source_node, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 48aa35f807..f5a00d0d1a 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1882,4 +1882,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { \\} , ".tmp_source.zig:4:13: error: cannot continue out of defer expression"); + + cases.add("cannot goto out of defer expression", + \\export fn foo() { + \\ defer { + \\ goto label; + \\ }; + \\label: + \\} + , + ".tmp_source.zig:3:9: error: cannot goto out of defer expression"); }