Commit 1c8fee41c2

Andrew Kelley <superjoe30@gmail.com>
2017-05-21 16:59:09
add compile error for goto leaving defer expression
closes #284
1 parent 9f3cca8
Changed files (2)
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,
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");
 }