Commit 44ca5e19dc
Changed files (4)
src/analyze.cpp
@@ -830,6 +830,11 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
context->parent = parent;
context->variable_table.init(8);
+ if (parent) {
+ context->break_allowed = parent->break_allowed || parent->next_child_break_allowed;
+ parent->next_child_break_allowed = false;
+ }
+
if (node && node->type == NodeTypeFnDef) {
AstNode *fn_proto_node = node->data.fn_def.fn_proto;
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,
TypeTableEntry *expected_type, AstNode *node)
{
analyze_expression(g, import, context, g->builtin_types.entry_bool, node->data.while_expr.condition);
+
+ context->next_child_break_allowed = true;
analyze_expression(g, import, context, g->builtin_types.entry_void, node->data.while_expr.body);
+
return g->builtin_types.entry_void;
}
static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
+ if (!context->break_allowed) {
+ add_node_error(g, node,
+ buf_sprintf("'break' expression not in loop"));
+ }
return g->builtin_types.entry_unreachable;
}
src/analyze.hpp
@@ -196,7 +196,7 @@ struct CodeGen {
FnTableEntry *cur_fn;
LLVMBasicBlockRef cur_basic_block;
BlockContext *cur_block_context;
- LLVMBasicBlockRef cur_break_block;
+ ZigList<LLVMBasicBlockRef> break_block_stack;
bool c_stdint_used;
AstNode *root_export_decl;
int version_major;
@@ -226,6 +226,8 @@ struct BlockContext {
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
ZigList<CastNode *> cast_expr_alloca_list;
ZigList<StructValExprNode *> struct_val_expr_alloca_list;
+ bool break_allowed;
+ bool next_child_break_allowed;
LLVMZigDIScope *di_scope;
};
src/codegen.cpp
@@ -1024,10 +1024,12 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);
LLVMPositionBuilderAtEnd(g->builder, body_block);
- g->cur_break_block = end_block;
+ g->break_block_stack.append(end_block);
gen_expr(g, node->data.while_expr.body);
- g->cur_break_block = nullptr;
- LLVMBuildBr(g->builder, cond_block);
+ g->break_block_stack.pop();
+ if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
+ LLVMBuildBr(g->builder, cond_block);
+ }
LLVMPositionBuilderAtEnd(g->builder, end_block);
return nullptr;
@@ -1035,10 +1037,10 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeBreak);
- assert(g->cur_break_block);
+ LLVMBasicBlockRef dest_block = g->break_block_stack.last();
add_debug_source_node(g, node);
- return LLVMBuildBr(g->builder, g->cur_break_block);
+ return LLVMBuildBr(g->builder, dest_block);
}
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
test/run_tests.cpp
@@ -664,11 +664,14 @@ use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
var i : i32 = 0;
while true {
- if i >= 4 {
- break;
+ while true {
+ if i >= 4 {
+ break;
+ }
+ print_str("loop\n");
+ i += 1;
}
- print_str("loop\n");
- i += 1;
+ break;
}
return 0;
}
@@ -949,6 +952,12 @@ fn f() {
};
}
)SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'");
+
+ add_compile_fail_case("invalid break expression", R"SOURCE(
+fn f() {
+ break;
+}
+ )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression not in loop");
}
static void print_compiler_invocation(TestCase *test_case) {