authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-24 15:30:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-24 15:30:55-07:00
log44ca5e19dc174383b1b0490e636398092711306d
tree5aafee34cee55228bdfd059313389c2a49a63001
parent5ceaae288c4f80fe5ce1449cd9d2efe0e541d629

add error for break outside loop

also fix break in nested loops

4 files changed, 35 insertions(+), 10 deletions(-)

src/analyze.cpp+12
...@@ -830,6 +830,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {...@@ -830,6 +830,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
830 context->parent = parent;830 context->parent = parent;
831 context->variable_table.init(8);831 context->variable_table.init(8);
832832
833 if (parent) {
834 context->break_allowed = parent->break_allowed || parent->next_child_break_allowed;
835 parent->next_child_break_allowed = false;
836 }
837
833 if (node && node->type == NodeTypeFnDef) {838 if (node && node->type == NodeTypeFnDef) {
834 AstNode *fn_proto_node = node->data.fn_def.fn_proto;839 AstNode *fn_proto_node = node->data.fn_def.fn_proto;
835 context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;840 context->fn_entry = fn_proto_node->codegen_node->data.fn_proto_node.fn_table_entry;
...@@ -1359,13 +1364,20 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,...@@ -1359,13 +1364,20 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
1359 TypeTableEntry *expected_type, AstNode *node)1364 TypeTableEntry *expected_type, AstNode *node)
1360{1365{
1361 analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.while_expr.condition);1366 analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.while_expr.condition);
1367
1368 context->next_child_break_allowed = true;
1362 analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body);1369 analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body);
1370
1363 return g->builtin_types.entry_void;1371 return g->builtin_types.entry_void;
1364}1372}
13651373
1366static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,1374static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1367 TypeTableEntry *expected_type, AstNode *node)1375 TypeTableEntry *expected_type, AstNode *node)
1368{1376{
1377 if (!context->break_allowed) {
1378 add_node_error(g, node,
1379 buf_sprintf("'break' expression not in loop"));
1380 }
1369 return g->builtin_types.entry_unreachable;1381 return g->builtin_types.entry_unreachable;
1370}1382}
13711383
src/analyze.hpp+3-1
...@@ -196,7 +196,7 @@ struct CodeGen {...@@ -196,7 +196,7 @@ struct CodeGen {
196 FnTableEntry *cur_fn;196 FnTableEntry *cur_fn;
197 LLVMBasicBlockRef cur_basic_block;197 LLVMBasicBlockRef cur_basic_block;
198 BlockContext *cur_block_context;198 BlockContext *cur_block_context;
199 LLVMBasicBlockRef cur_break_block;199 ZigList<LLVMBasicBlockRef> break_block_stack;
200 bool c_stdint_used;200 bool c_stdint_used;
201 AstNode *root_export_decl;201 AstNode *root_export_decl;
202 int version_major;202 int version_major;
...@@ -226,6 +226,8 @@ struct BlockContext {...@@ -226,6 +226,8 @@ struct BlockContext {
226 HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;226 HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
227 ZigList<CastNode *> cast_expr_alloca_list;227 ZigList<CastNode *> cast_expr_alloca_list;
228 ZigList<StructValExprNode *> struct_val_expr_alloca_list;228 ZigList<StructValExprNode *> struct_val_expr_alloca_list;
229 bool break_allowed;
230 bool next_child_break_allowed;
229 LLVMZigDIScope *di_scope;231 LLVMZigDIScope *di_scope;
230};232};
231233
src/codegen.cpp+7-5
...@@ -1024,10 +1024,12 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -1024,10 +1024,12 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
1024 LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);1024 LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);
10251025
1026 LLVMPositionBuilderAtEnd(g->builder, body_block);1026 LLVMPositionBuilderAtEnd(g->builder, body_block);
1027 g->cur_break_block = end_block;1027 g->break_block_stack.append(end_block);
1028 gen_expr(g, node->data.while_expr.body);1028 gen_expr(g, node->data.while_expr.body);
1029 g->cur_break_block = nullptr;1029 g->break_block_stack.pop();
1030 LLVMBuildBr(g->builder, cond_block);1030 if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
1031 LLVMBuildBr(g->builder, cond_block);
1032 }
10311033
1032 LLVMPositionBuilderAtEnd(g->builder, end_block);1034 LLVMPositionBuilderAtEnd(g->builder, end_block);
1033 return nullptr;1035 return nullptr;
...@@ -1035,10 +1037,10 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {...@@ -1035,10 +1037,10 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
10351037
1036static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {1038static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
1037 assert(node->type == NodeTypeBreak);1039 assert(node->type == NodeTypeBreak);
1038 assert(g->cur_break_block);1040 LLVMBasicBlockRef dest_block = g->break_block_stack.last();
10391041
1040 add_debug_source_node(g, node);1042 add_debug_source_node(g, node);
1041 return LLVMBuildBr(g->builder, g->cur_break_block);1043 return LLVMBuildBr(g->builder, dest_block);
1042}1044}
10431045
1044static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {1046static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
test/run_tests.cpp+13-4
...@@ -664,11 +664,14 @@ use "std.zig";...@@ -664,11 +664,14 @@ use "std.zig";
664export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {664export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
665 var i : i32 = 0;665 var i : i32 = 0;
666 while true {666 while true {
667 if i >= 4 {667 while true {
668 break;668 if i >= 4 {
669 break;
670 }
671 print_str("loop\n");
672 i += 1;
669 }673 }
670 print_str("loop\n");674 break;
671 i += 1;
672 }675 }
673 return 0;676 return 0;
674}677}
...@@ -949,6 +952,12 @@ fn f() {...@@ -949,6 +952,12 @@ fn f() {
949 };952 };
950}953}
951 )SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'");954 )SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'");
955
956 add_compile_fail_case("invalid break expression", R"SOURCE(
957fn f() {
958 break;
959}
960 )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression not in loop");
952}961}
953962
954static void print_compiler_invocation(TestCase *test_case) {963static void print_compiler_invocation(TestCase *test_case) {