Commit 32642ac9cb
Changed files (4)
src/all_types.hpp
@@ -474,6 +474,7 @@ struct AstNodeWhileExpr {
// populated by semantic analyzer
bool condition_always_true;
bool contains_break;
+ bool contains_continue;
Expr resolved_expr;
BlockContext *block_context;
};
@@ -486,6 +487,7 @@ struct AstNodeForExpr {
// populated by semantic analyzer
bool contains_break;
+ bool contains_continue;
Expr resolved_expr;
VariableTableEntry *elem_var;
VariableTableEntry *index_var;
src/analyze.cpp
@@ -3354,6 +3354,7 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
}
BlockContext *child_context = new_block_context(node, context);
+ child_context->parent_loop_node = node;
AstNode *elem_var_node = node->data.for_expr.elem_node;
elem_var_node->block_context = child_context;
@@ -3385,8 +3386,13 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
AstNode *loop_node = context->parent_loop_node;
if (loop_node) {
- assert(loop_node->type == NodeTypeWhileExpr);
- loop_node->data.while_expr.contains_break = true;
+ if (loop_node->type == NodeTypeWhileExpr) {
+ loop_node->data.while_expr.contains_break = true;
+ } else if (loop_node->type == NodeTypeForExpr) {
+ loop_node->data.for_expr.contains_break = true;
+ } else {
+ zig_unreachable();
+ }
} else {
add_node_error(g, node, buf_sprintf("'break' expression outside loop"));
}
@@ -3396,7 +3402,16 @@ static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import,
static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
- if (!context->parent_loop_node) {
+ AstNode *loop_node = context->parent_loop_node;
+ if (loop_node) {
+ if (loop_node->type == NodeTypeWhileExpr) {
+ loop_node->data.while_expr.contains_continue = true;
+ } else if (loop_node->type == NodeTypeForExpr) {
+ loop_node->data.for_expr.contains_continue = true;
+ } else {
+ zig_unreachable();
+ }
+ } else {
add_node_error(g, node, buf_sprintf("'continue' expression outside loop"));
}
return g->builtin_types.entry_unreachable;
src/codegen.cpp
@@ -2089,6 +2089,7 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");
LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");
LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");
+ LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForContinue");
LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr);
add_debug_source_node(g, node);
@@ -2122,17 +2123,21 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val,
elem_var->type, child_type);
g->break_block_stack.append(end_block);
- g->continue_block_stack.append(cond_block);
+ g->continue_block_stack.append(continue_block);
gen_expr(g, node->data.for_expr.body);
g->break_block_stack.pop();
g->continue_block_stack.pop();
if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {
add_debug_source_node(g, node);
- LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");
- LLVMBuildStore(g->builder, new_index_val, index_ptr);
- LLVMBuildBr(g->builder, cond_block);
+ LLVMBuildBr(g->builder, continue_block);
}
+ LLVMPositionBuilderAtEnd(g->builder, continue_block);
+ add_debug_source_node(g, node);
+ LLVMValueRef new_index_val = LLVMBuildAdd(g->builder, index_val, one_const, "");
+ LLVMBuildStore(g->builder, new_index_val, index_ptr);
+ LLVMBuildBr(g->builder, cond_block);
+
LLVMPositionBuilderAtEnd(g->builder, end_block);
return nullptr;
}
test/self_hosted.zig
@@ -52,17 +52,33 @@ error SecondError;
#attribute("test")
fn constant_enum_with_payload() {
should_be_empty(AnEnumWithPayload.Empty);
- should_be_13(AnEnumWithPayload.Full(13));
+ should_be_not_empty(AnEnumWithPayload.Full(13));
}
fn should_be_empty(x: AnEnumWithPayload) {
if (x != AnEnumWithPayload.Empty) unreachable{}
}
-fn should_be_13(x: AnEnumWithPayload) {
+fn should_be_not_empty(x: AnEnumWithPayload) {
+ if (x == AnEnumWithPayload.Empty) unreachable{}
}
enum AnEnumWithPayload {
Empty,
Full: i32,
}
+
+
+#attribute("test")
+fn continue_in_for_loop() {
+ const array = []i32 {1, 2, 3, 4, 5};
+ var sum : i32 = 0;
+ for (x, array) {
+ sum += x;
+ if (x < 3) {
+ continue;
+ }
+ break;
+ }
+ if (sum != 6) unreachable{}
+}