Commit 34a7e6fdb3

Andrew Kelley <superjoe30@gmail.com>
2016-02-06 09:13:47
codegen: return respects unconditional defer
See #110
1 parent ec33e5a
src/all_types.hpp
@@ -1159,14 +1159,6 @@ struct ErrorTableEntry {
     AstNode *decl_node;
 };
 
-enum BlockExitPath {
-    BlockExitPathFallthrough,
-    BlockExitPathReturn,
-    BlockExitPathGoto,
-
-    BlockExitPathCount,
-};
-
 struct BlockContext {
     // One of: NodeTypeFnDef, NodeTypeBlock, NodeTypeRoot, NodeTypeDefer, NodeTypeVariableDeclaration
     AstNode *node;
@@ -1186,7 +1178,6 @@ struct BlockContext {
 
     LLVMZigDIScope *di_scope;
     Buf *c_import_buf;
-    bool block_exit_paths[BlockExitPathCount];
 };
 
 enum CIntType {
src/analyze.cpp
@@ -4545,9 +4545,6 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
         normalize_parent_ptrs(node);
     }
 
-    // TODO follow the blocks to their parents, loop over all of them, set them all to true
-    context->block_exit_paths[BlockExitPathReturn] = true;
-
     TypeTableEntry *expected_return_type = get_return_type(context);
 
     switch (node->data.return_expr.kind) {
src/codegen.cpp
@@ -1593,7 +1593,19 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
     return phi;
 }
 
+static void gen_defers_for_block(CodeGen *g, BlockContext *inner_block, BlockContext *outer_block) {
+    while (inner_block != outer_block) {
+        if (inner_block->node->type == NodeTypeDefer) {
+            gen_expr(g, inner_block->node->data.defer.expr);
+        }
+        inner_block = inner_block->parent;
+    }
+}
+
 static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value) {
+    gen_defers_for_block(g, source_node->block_context,
+            source_node->block_context->fn_entry->fn_def_node->block_context);
+
     TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
     if (handle_is_ptr(return_type)) {
         assert(g->cur_ret_ptr);
@@ -1615,7 +1627,9 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
 
     switch (node->data.return_expr.kind) {
         case ReturnKindUnconditional:
-            return gen_return(g, node, value);
+            {
+                return gen_return(g, node, value);
+            }
         case ReturnKindError:
             {
                 assert(value_type->id == TypeTableEntryIdErrorUnion);
@@ -1820,13 +1834,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
         return nullptr;
     }
 
-    BlockContext *block_context = block_node->data.block.nested_block;
-    while (block_context != block_node->data.block.child_block) {
-        if (block_context->node->type == NodeTypeDefer) {
-            gen_expr(g, block_context->node->data.defer.expr);
-        }
-        block_context = block_context->parent;
-    }
+    gen_defers_for_block(g, block_node->data.block.nested_block, block_node->data.block.child_block);
 
     if (implicit_return_type) {
         return gen_return(g, block_node, return_value);
test/run_tests.cpp
@@ -1532,6 +1532,19 @@ pub fn main(args: [][]u8) -> %void {
 }
     )SOURCE", "before\nafter\ndefer3\ndefer2\ndefer1\n");
 
+
+    add_simple_case("defer with return", R"SOURCE(
+import "std.zig";
+pub fn main(args: [][]u8) -> %void {
+    %%stdout.printf("before\n");
+    defer %%stdout.printf("defer1\n");
+    defer %%stdout.printf("defer2\n");
+    if (args.len == 1) return;
+    defer %%stdout.printf("defer3\n");
+    %%stdout.printf("after\n");
+}
+    )SOURCE", "before\ndefer2\ndefer1\n");
+
 }