From 1c8fee41c247ea60aebd1d8b0fdba4002701b1cf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 21 May 2017 10:59:09 -0400 Subject: add compile error for goto leaving defer expression closes #284 --- src/ir.cpp | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'src/ir.cpp') 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, -- cgit v1.2.3