| author | |
| committer | |
| log | 32642ac9cb00b59fef97c1888e0424b0eb4db784 |
| tree | 11fc77184d633811f0a78289d0feb7c663175f08 |
| parent | fdadab40c61a6f70a65472cc95ccd5ba52c01772 |
See #514 files changed, 47 insertions(+), 9 deletions(-)
src/all_types.hpp+2| ... | ... | @@ -474,6 +474,7 @@ struct AstNodeWhileExpr { |
| 474 | 474 | // populated by semantic analyzer |
| 475 | 475 | bool condition_always_true; |
| 476 | 476 | bool contains_break; |
| 477 | bool contains_continue; | |
| 477 | 478 | Expr resolved_expr; |
| 478 | 479 | BlockContext *block_context; |
| 479 | 480 | }; |
| ... | ... | @@ -486,6 +487,7 @@ struct AstNodeForExpr { |
| 486 | 487 | |
| 487 | 488 | // populated by semantic analyzer |
| 488 | 489 | bool contains_break; |
| 490 | bool contains_continue; | |
| 489 | 491 | Expr resolved_expr; |
| 490 | 492 | VariableTableEntry *elem_var; |
| 491 | 493 | VariableTableEntry *index_var; |
src/analyze.cpp+18-3| ... | ... | @@ -3354,6 +3354,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl |
| 3354 | 3354 | } |
| 3355 | 3355 | |
| 3356 | 3356 | BlockContext *child_context = new_block_context(node, context); |
| 3357 | child_context->parent_loop_node = node; | |
| 3357 | 3358 | |
| 3358 | 3359 | AstNode *elem_var_node = node->data.for_expr.elem_node; |
| 3359 | 3360 | elem_var_node->block_context = child_context; |
| ... | ... | @@ -3385,8 +3386,13 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, |
| 3385 | 3386 | |
| 3386 | 3387 | AstNode *loop_node = context->parent_loop_node; |
| 3387 | 3388 | if (loop_node) { |
| 3388 | assert(loop_node->type == NodeTypeWhileExpr); | |
| 3389 | loop_node->data.while_expr.contains_break = true; | |
| 3389 | if (loop_node->type == NodeTypeWhileExpr) { | |
| 3390 | loop_node->data.while_expr.contains_break = true; | |
| 3391 | } else if (loop_node->type == NodeTypeForExpr) { | |
| 3392 | loop_node->data.for_expr.contains_break = true; | |
| 3393 | } else { | |
| 3394 | zig_unreachable(); | |
| 3395 | } | |
| 3390 | 3396 | } else { |
| 3391 | 3397 | add_node_error(g, node, buf_sprintf("'break' expression outside loop")); |
| 3392 | 3398 | } |
| ... | ... | @@ -3396,7 +3402,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, |
| 3396 | 3402 | static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 3397 | 3403 | TypeTableEntry *expected_type, AstNode *node) |
| 3398 | 3404 | { |
| 3399 | if (!context->parent_loop_node) { | |
| 3405 | AstNode *loop_node = context->parent_loop_node; | |
| 3406 | if (loop_node) { | |
| 3407 | if (loop_node->type == NodeTypeWhileExpr) { | |
| 3408 | loop_node->data.while_expr.contains_continue = true; | |
| 3409 | } else if (loop_node->type == NodeTypeForExpr) { | |
| 3410 | loop_node->data.for_expr.contains_continue = true; | |
| 3411 | } else { | |
| 3412 | zig_unreachable(); | |
| 3413 | } | |
| 3414 | } else { | |
| 3400 | 3415 | add_node_error(g, node, buf_sprintf("'continue' expression outside loop")); |
| 3401 | 3416 | } |
| 3402 | 3417 | return g->builtin_types.entry_unreachable; |
src/codegen.cpp+9-4| ... | ... | @@ -2089,6 +2089,7 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) { |
| 2089 | 2089 | LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond"); |
| 2090 | 2090 | LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody"); |
| 2091 | 2091 | LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd"); |
| 2092 | LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForContinue"); | |
| 2092 | 2093 | |
| 2093 | 2094 | LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr); |
| 2094 | 2095 | add_debug_source_node(g, node); |
| ... | ... | @@ -2122,17 +2123,21 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) { |
| 2122 | 2123 | gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val, |
| 2123 | 2124 | elem_var->type, child_type); |
| 2124 | 2125 | g->break_block_stack.append(end_block); |
| 2125 | g->continue_block_stack.append(cond_block); | |
| 2126 | g->continue_block_stack.append(continue_block); | |
| 2126 | 2127 | gen_expr(g, node->data.for_expr.body); |
| 2127 | 2128 | g->break_block_stack.pop(); |
| 2128 | 2129 | g->continue_block_stack.pop(); |
| 2129 | 2130 | if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) { |
| 2130 | 2131 | add_debug_source_node(g, node); |
| 2131 | LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, ""); | |
| 2132 | LLVMBuildStore(g->builder, new_index_val, index_ptr); | |
| 2133 | LLVMBuildBr(g->builder, cond_block); | |
| 2132 | LLVMBuildBr(g->builder, continue_block); | |
| 2134 | 2133 | } |
| 2135 | 2134 | |
| 2135 | LLVMPositionBuilderAtEnd(g->builder, continue_block); | |
| 2136 | add_debug_source_node(g, node); | |
| 2137 | LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, ""); | |
| 2138 | LLVMBuildStore(g->builder, new_index_val, index_ptr); | |
| 2139 | LLVMBuildBr(g->builder, cond_block); | |
| 2140 | ||
| 2136 | 2141 | LLVMPositionBuilderAtEnd(g->builder, end_block); |
| 2137 | 2142 | return nullptr; |
| 2138 | 2143 | } |
test/self_hosted.zig+18-2| ... | ... | @@ -52,17 +52,33 @@ error SecondError; |
| 52 | 52 | #attribute("test") |
| 53 | 53 | fn constant_enum_with_payload() { |
| 54 | 54 | should_be_empty(AnEnumWithPayload.Empty); |
| 55 | should_be_13(AnEnumWithPayload.Full(13)); | |
| 55 | should_be_not_empty(AnEnumWithPayload.Full(13)); | |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | 58 | fn should_be_empty(x: AnEnumWithPayload) { |
| 59 | 59 | if (x != AnEnumWithPayload.Empty) unreachable{} |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | fn should_be_13(x: AnEnumWithPayload) { | |
| 62 | fn should_be_not_empty(x: AnEnumWithPayload) { | |
| 63 | if (x == AnEnumWithPayload.Empty) unreachable{} | |
| 63 | 64 | } |
| 64 | 65 | |
| 65 | 66 | enum AnEnumWithPayload { |
| 66 | 67 | Empty, |
| 67 | 68 | Full: i32, |
| 68 | 69 | } |
| 70 | ||
| 71 | ||
| 72 | #attribute("test") | |
| 73 | fn continue_in_for_loop() { | |
| 74 | const array = []i32 {1, 2, 3, 4, 5}; | |
| 75 | var sum : i32 = 0; | |
| 76 | for (x, array) { | |
| 77 | sum += x; | |
| 78 | if (x < 3) { | |
| 79 | continue; | |
| 80 | } | |
| 81 | break; | |
| 82 | } | |
| 83 | if (sum != 6) unreachable{} | |
| 84 | } |