From 34a7e6fdb362cb7be1067b7d1fc110eb2f323c51 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 6 Feb 2016 01:13:47 -0700 Subject: [PATCH] codegen: return respects unconditional defer See #110 --- src/all_types.hpp | 9 --------- src/analyze.cpp | 3 --- src/codegen.cpp | 24 ++++++++++++++++-------- test/run_tests.cpp | 13 +++++++++++++ 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index d627b36c37..9b5fc79575 100644 --- a/src/all_types.hpp +++ b/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 { diff --git a/src/analyze.cpp b/src/analyze.cpp index 1bf0ca06ec..03e5ad1899 100644 --- a/src/analyze.cpp +++ b/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) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 2be63327fb..4cab9fa13d 100644 --- a/src/codegen.cpp +++ b/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); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 26c6a287f0..50fa09f5a9 100644 --- a/test/run_tests.cpp +++ b/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"); + }