Commit 24048b2af6
Changed files (7)
src/all_types.hpp
@@ -642,9 +642,11 @@ struct AstNodeBoolLiteral {
};
struct AstNodeBreakExpr {
+ bool is_inline; // TODO
};
struct AstNodeContinueExpr {
+ bool is_inline; // TODO
};
struct AstNodeArrayType {
@@ -1233,11 +1235,21 @@ struct LabelTableEntry {
bool used;
};
+enum ScopeId {
+ ScopeIdDecls,
+ ScopeIdBlock,
+ ScopeIdDefer,
+ ScopeIdVarDecl,
+ ScopeIdCImport,
+ ScopeIdLoop,
+ ScopeIdFnDef,
+};
+
struct Scope {
- AstNode *node;
+ ScopeId id;
+ AstNode *source_node;
- // if the scope has a parent, this is it. Every scope has a parent except
- // ScopeIdGlobal
+ // if the scope has a parent, this is it
Scope *parent;
ZigLLVMDIScope *di_scope;
@@ -1293,6 +1305,7 @@ struct ScopeCImport {
// This scope is created for a loop such as for or while in order to
// make break and continue statements work.
// NodeTypeForExpr or NodeTypeWhileExpr
+// TODO I think we can get rid of this
struct ScopeLoop {
Scope base;
};
src/analyze.cpp
@@ -130,15 +130,16 @@ ScopeDecls *get_container_scope(TypeTableEntry *type_entry) {
return *get_container_scope_ptr(type_entry);
}
-void init_scope(Scope *dest, AstNode *node, Scope *parent) {
- dest->node = node;
+void init_scope(Scope *dest, ScopeId id, AstNode *source_node, Scope *parent) {
+ dest->id = id;
+ dest->source_node = source_node;
dest->parent = parent;
}
static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import) {
assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl);
ScopeDecls *scope = allocate<ScopeDecls>(1);
- init_scope(&scope->base, node, parent);
+ init_scope(&scope->base, ScopeIdDecls, node, parent);
scope->decl_table.init(4);
scope->container_type = container_type;
scope->import = import;
@@ -148,7 +149,7 @@ static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEnt
Scope *create_block_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeBlock);
ScopeBlock *scope = allocate<ScopeBlock>(1);
- init_scope(&scope->base, node, parent);
+ init_scope(&scope->base, ScopeIdBlock, node, parent);
scope->label_table.init(1);
return &scope->base;
}
@@ -156,14 +157,13 @@ Scope *create_block_scope(AstNode *node, Scope *parent) {
Scope *create_defer_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeDefer);
ScopeDefer *scope = allocate<ScopeDefer>(1);
- init_scope(&scope->base, node, parent);
+ init_scope(&scope->base, ScopeIdDefer, node, parent);
return &scope->base;
}
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
- assert(node->type == NodeTypeVariableDeclaration || node->type == NodeTypeParamDecl);
ScopeVarDecl *scope = allocate<ScopeVarDecl>(1);
- init_scope(&scope->base, node, parent);
+ init_scope(&scope->base, ScopeIdVarDecl, node, parent);
scope->var = var;
return &scope->base;
}
@@ -171,7 +171,7 @@ Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) {
Scope *create_cimport_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeFnCallExpr);
ScopeCImport *scope = allocate<ScopeCImport>(1);
- init_scope(&scope->base, node, parent);
+ init_scope(&scope->base, ScopeIdCImport, node, parent);
buf_resize(&scope->c_import_buf, 0);
return &scope->base;
}
@@ -179,21 +179,21 @@ Scope *create_cimport_scope(AstNode *node, Scope *parent) {
Scope *create_loop_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeWhileExpr || node->type == NodeTypeForExpr);
ScopeLoop *scope = allocate<ScopeLoop>(1);
- init_scope(&scope->base, node, parent);
+ init_scope(&scope->base, ScopeIdLoop, node, parent);
return &scope->base;
}
ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry) {
assert(node->type == NodeTypeFnDef);
ScopeFnDef *scope = allocate<ScopeFnDef>(1);
- init_scope(&scope->base, node, parent);
+ init_scope(&scope->base, ScopeIdFnDef, node, parent);
scope->fn_entry = fn_entry;
return scope;
}
ImportTableEntry *get_scope_import(Scope *scope) {
while (scope) {
- if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) {
+ if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
assert(decls_scope->import);
return decls_scope->import;
@@ -1991,9 +1991,7 @@ bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *
Tld *find_decl(Scope *scope, Buf *name) {
while (scope) {
- if (scope->node->type == NodeTypeRoot ||
- scope->node->type == NodeTypeContainerDecl)
- {
+ if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
auto entry = decls_scope->decl_table.maybe_get(name);
if (entry)
@@ -2006,15 +2004,11 @@ Tld *find_decl(Scope *scope, Buf *name) {
VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) {
while (scope) {
- if (scope->node->type == NodeTypeVariableDeclaration ||
- scope->node->type == NodeTypeParamDecl)
- {
+ if (scope->id == ScopeIdVarDecl) {
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
if (buf_eql_buf(name, &var_scope->var->name))
return var_scope->var;
- } else if (scope->node->type == NodeTypeRoot ||
- scope->node->type == NodeTypeContainerDecl)
- {
+ } else if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
auto entry = decls_scope->decl_table.maybe_get(name);
if (entry) {
@@ -2034,7 +2028,7 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *scope, Buf *name) {
FnTableEntry *scope_fn_entry(Scope *scope) {
while (scope) {
- if (scope->node->type == NodeTypeFnDef) {
+ if (scope->id == ScopeIdFnDef) {
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
return fn_scope->fn_entry;
}
src/ast_render.cpp
@@ -364,6 +364,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
case NodeTypeSwitchProng:
case NodeTypeSwitchRange:
case NodeTypeLabel:
+ case NodeTypeStructValueField:
zig_unreachable();
case NodeTypeRoot:
for (size_t i = 0; i < node->data.root.top_level_decls.length; i += 1) {
@@ -602,9 +603,30 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
case NodeTypeContainerInitExpr:
render_node_ungrouped(ar, node->data.container_init_expr.type);
- fprintf(ar->f, "{");
- assert(node->data.container_init_expr.entries.length == 0);
+ if (node->data.container_init_expr.kind == ContainerInitKindStruct) {
+ fprintf(ar->f, "{\n");
+ ar->indent += ar->indent_size;
+ } else {
+ fprintf(ar->f, "{");
+ }
+ for (size_t i = 0; i < node->data.container_init_expr.entries.length; i += 1) {
+ AstNode *entry = node->data.container_init_expr.entries.at(i);
+ if (entry->type == NodeTypeStructValueField) {
+ Buf *name = entry->data.struct_val_field.name;
+ AstNode *expr = entry->data.struct_val_field.expr;
+ fprintf(ar->f, ".%s = ", buf_ptr(name));
+ render_node_grouped(ar, expr);
+ fprintf(ar->f, ",\n");
+ } else {
+ if (i != 0)
+ fprintf(ar->f, ", ");
+ render_node_grouped(ar, entry);
+ }
+ }
fprintf(ar->f, "}");
+ if (node->data.container_init_expr.kind == ContainerInitKindStruct) {
+ ar->indent -= ar->indent_size;
+ }
break;
case NodeTypeArrayType:
{
@@ -788,7 +810,40 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
case NodeTypeGoto:
{
- fprintf(ar->f, "goto %s", buf_ptr(node->data.goto_expr.name));
+ const char *inline_str = node->data.goto_expr.is_inline ? "inline " : "";
+ fprintf(ar->f, "%sgoto %s", inline_str, buf_ptr(node->data.goto_expr.name));
+ break;
+ }
+ case NodeTypeForExpr:
+ {
+ const char *inline_str = node->data.for_expr.is_inline ? "inline " : "";
+ fprintf(ar->f, "%sfor (", inline_str);
+ render_node_grouped(ar, node->data.for_expr.array_expr);
+ fprintf(ar->f, ") ");
+ if (node->data.for_expr.elem_node) {
+ fprintf(ar->f, "|");
+ if (node->data.for_expr.elem_is_ptr)
+ fprintf(ar->f, "*");
+ render_node_grouped(ar, node->data.for_expr.elem_node);
+ if (node->data.for_expr.index_node) {
+ fprintf(ar->f, ", ");
+ render_node_grouped(ar, node->data.for_expr.index_node);
+ }
+ fprintf(ar->f, "| ");
+ }
+ render_node_grouped(ar, node->data.for_expr.body);
+ break;
+ }
+ case NodeTypeBreak:
+ {
+ const char *inline_str = node->data.break_expr.is_inline ? "inline " : "";
+ fprintf(ar->f, "%sbreak", inline_str);
+ break;
+ }
+ case NodeTypeContinue:
+ {
+ const char *inline_str = node->data.continue_expr.is_inline ? "inline " : "";
+ fprintf(ar->f, "%scontinue", inline_str);
break;
}
case NodeTypeFnDecl:
@@ -797,12 +852,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
case NodeTypeUnwrapErrorExpr:
case NodeTypeSliceExpr:
case NodeTypeStructField:
- case NodeTypeStructValueField:
case NodeTypeUse:
case NodeTypeZeroesLiteral:
- case NodeTypeForExpr:
- case NodeTypeBreak:
- case NodeTypeContinue:
zig_panic("TODO more ast rendering");
}
}
src/codegen.cpp
@@ -277,40 +277,55 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
if (scope->di_scope)
return scope->di_scope;
- if (scope->node->type == NodeTypeFnDef) {
- assert(scope->parent);
- ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
- FnTableEntry *fn_table_entry = fn_scope->fn_entry;
- unsigned line_number = fn_table_entry->proto_node->line + 1;
- unsigned scope_line = line_number;
- bool is_definition = fn_table_entry->fn_def_node != nullptr;
- unsigned flags = 0;
- bool is_optimized = g->is_release_build;
- ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
- get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "",
- scope->node->owner->di_file, line_number,
- fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage,
- is_definition, scope_line, flags, is_optimized, nullptr);
-
- scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
- ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram);
- } else if (scope->node->type == NodeTypeRoot) {
- scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file);
- } else if (scope->node->type == NodeTypeContainerDecl) {
- ScopeDecls *decls_scope = (ScopeDecls *)scope;
- assert(decls_scope->container_type);
- scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
- } else {
- assert(scope->parent);
- ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
- get_di_scope(g, scope->parent),
- scope->node->owner->di_file,
- scope->node->line + 1,
- scope->node->column + 1);
- scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
+ ImportTableEntry *import = get_scope_import(scope);
+ switch (scope->id) {
+ case ScopeIdCImport:
+ zig_unreachable();
+ case ScopeIdFnDef:
+ {
+ assert(scope->parent);
+ ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
+ FnTableEntry *fn_table_entry = fn_scope->fn_entry;
+ unsigned line_number = fn_table_entry->proto_node->line + 1;
+ unsigned scope_line = line_number;
+ bool is_definition = fn_table_entry->fn_def_node != nullptr;
+ unsigned flags = 0;
+ bool is_optimized = g->is_release_build;
+ ZigLLVMDISubprogram *subprogram = ZigLLVMCreateFunction(g->dbuilder,
+ get_di_scope(g, scope->parent), buf_ptr(&fn_table_entry->symbol_name), "",
+ import->di_file, line_number,
+ fn_table_entry->type_entry->di_type, fn_table_entry->internal_linkage,
+ is_definition, scope_line, flags, is_optimized, nullptr);
+
+ scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
+ ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram);
+ return scope->di_scope;
+ }
+ case ScopeIdDecls:
+ if (scope->parent) {
+ ScopeDecls *decls_scope = (ScopeDecls *)scope;
+ assert(decls_scope->container_type);
+ scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
+ } else {
+ scope->di_scope = ZigLLVMFileToScope(import->di_file);
+ }
+ return scope->di_scope;
+ case ScopeIdBlock:
+ case ScopeIdDefer:
+ case ScopeIdVarDecl:
+ case ScopeIdLoop:
+ {
+ assert(scope->parent);
+ ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
+ get_di_scope(g, scope->parent),
+ import->di_file,
+ scope->source_node->line + 1,
+ scope->source_node->column + 1);
+ scope->di_scope = ZigLLVMLexicalBlockToScope(di_block);
+ return scope->di_scope;
+ }
}
-
- return scope->di_scope;
+ zig_unreachable();
}
static void clear_debug_source_node(CodeGen *g) {
@@ -400,11 +415,11 @@ static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
// TODO memoize
Scope *scope = instruction->scope;
while (scope) {
- if (scope->node->type == NodeTypeBlock) {
+ if (scope->id == ScopeIdBlock) {
ScopeBlock *block_scope = (ScopeBlock *)scope;
if (block_scope->safety_set_node)
return !block_scope->safety_off;
- } else if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) {
+ } else if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
if (decls_scope->safety_set_node)
return !decls_scope->safety_off;
src/ir.cpp
@@ -18,12 +18,17 @@ struct IrExecContext {
size_t mem_slot_count;
};
+struct LoopStackItem {
+ IrBasicBlock *break_block;
+ IrBasicBlock *continue_block;
+ bool is_inline;
+};
+
struct IrBuilder {
CodeGen *codegen;
IrExecutable *exec;
IrBasicBlock *current_basic_block;
- ZigList<IrBasicBlock *> break_block_stack;
- ZigList<IrBasicBlock *> continue_block_stack;
+ ZigList<LoopStackItem> loop_stack;
};
struct IrAnalyze {
@@ -1241,13 +1246,17 @@ static void ir_gen_defers_for_block(IrBuilder *irb, Scope *parent_scope, Scope *
bool gen_error_defers, bool gen_maybe_defers)
{
while (inner_scope != outer_scope) {
- if (inner_scope->node->type == NodeTypeDefer &&
- ((inner_scope->node->data.defer.kind == ReturnKindUnconditional) ||
- (gen_error_defers && inner_scope->node->data.defer.kind == ReturnKindError) ||
- (gen_maybe_defers && inner_scope->node->data.defer.kind == ReturnKindMaybe)))
- {
- AstNode *defer_expr_node = inner_scope->node->data.defer.expr;
- ir_gen_node(irb, defer_expr_node, parent_scope);
+ if (inner_scope->id == ScopeIdDefer) {
+ assert(inner_scope->source_node->type == NodeTypeDefer);
+ ReturnKind defer_kind = inner_scope->source_node->data.defer.kind;
+ if (defer_kind == ReturnKindUnconditional ||
+ (gen_error_defers && defer_kind == ReturnKindError) ||
+ (gen_maybe_defers && defer_kind == ReturnKindMaybe))
+ {
+ AstNode *defer_expr_node = inner_scope->source_node->data.defer.expr;
+ ir_gen_node(irb, defer_expr_node, parent_scope);
+ }
+
}
inner_scope = inner_scope->parent;
}
@@ -2070,11 +2079,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end(irb, body_block);
- irb->break_block_stack.append(end_block);
- irb->continue_block_stack.append(continue_block);
+ LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
+ loop_stack_item->break_block = end_block;
+ loop_stack_item->continue_block = continue_block;
+ loop_stack_item->is_inline = is_inline;
ir_gen_node(irb, node->data.while_expr.body, scope);
- irb->break_block_stack.pop();
- irb->continue_block_stack.pop();
+ irb->loop_stack.pop();
ir_build_br(irb, scope, node, continue_block, is_inline);
ir_set_cursor_at_end(irb, end_block);
@@ -2096,9 +2106,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
}
assert(elem_node->type == NodeTypeSymbol);
- IrInstruction *array_val = ir_gen_node(irb, array_node, parent_scope);
- if (array_val == irb->codegen->invalid_instruction)
- return array_val;
+ IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPurposeAddressOf);
+ if (array_val_ptr == irb->codegen->invalid_instruction)
+ return array_val_ptr;
+
+ IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
IrInstruction *array_type = ir_build_typeof(irb, parent_scope, array_node, array_val);
IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_type);
@@ -2155,7 +2167,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ir_build_cond_br(irb, child_scope, node, cond, body_block, end_block, is_inline);
ir_set_cursor_at_end(irb, body_block);
- IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val, index_val, true);
+ IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, true);
IrInstruction *elem_val;
if (node->data.for_expr.elem_is_ptr) {
elem_val = elem_ptr;
@@ -2164,11 +2176,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
}
ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val);
- irb->break_block_stack.append(end_block);
- irb->continue_block_stack.append(continue_block);
+ LoopStackItem *loop_stack_item = irb->loop_stack.add_one();
+ loop_stack_item->break_block = end_block;
+ loop_stack_item->continue_block = continue_block;
+ loop_stack_item->is_inline = is_inline;
ir_gen_node(irb, body_node, child_scope);
- irb->break_block_stack.pop();
- irb->continue_block_stack.pop();
+ irb->loop_stack.pop();
ir_build_br(irb, child_scope, node, continue_block, is_inline);
@@ -2195,14 +2208,14 @@ static IrInstruction *ir_gen_this_literal(IrBuilder *irb, Scope *scope, AstNode
return ir_build_const_fn(irb, scope, node, fn_entry);
}
- if (scope->node->type == NodeTypeContainerDecl) {
+ if (scope->id == ScopeIdDecls) {
ScopeDecls *decls_scope = (ScopeDecls *)scope;
TypeTableEntry *container_type = decls_scope->container_type;
assert(container_type);
return ir_build_const_type(irb, scope, node, container_type);
}
- if (scope->node->type == NodeTypeBlock)
+ if (scope->id == ScopeIdBlock)
return ir_build_const_scope(irb, scope, node, scope);
zig_unreachable();
@@ -2246,8 +2259,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
return ir_build_array_type(irb, scope, node, size_value, child_type);
} else {
- IrInstruction *child_type = ir_gen_node_extra(irb, child_type_node,
- scope, LValPurposeAddressOf);
+ IrInstruction *child_type = ir_gen_node(irb, child_type_node, scope);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
@@ -2575,7 +2587,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name) {
while (scope) {
- if (scope->node->type == NodeTypeBlock) {
+ if (scope->id == ScopeIdBlock) {
ScopeBlock *block_scope = (ScopeBlock *)scope;
auto entry = block_scope->label_table.maybe_get(name);
if (entry)
@@ -2589,7 +2601,7 @@ static LabelTableEntry *find_label(IrExecutable *exec, Scope *scope, Buf *name)
static ScopeBlock *find_block_scope(IrExecutable *exec, Scope *scope) {
while (scope) {
- if (scope->node->type == NodeTypeBlock)
+ if (scope->id == ScopeIdBlock)
return (ScopeBlock *)scope;
scope = scope->parent;
}
@@ -2637,6 +2649,36 @@ static IrInstruction *ir_gen_goto(IrBuilder *irb, Scope *scope, AstNode *node) {
return ir_build_unreachable(irb, scope, node);
}
+static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *scope, AstNode *node) {
+ assert(node->type == NodeTypeBreak);
+
+ if (irb->loop_stack.length == 0) {
+ add_node_error(irb->codegen, node,
+ buf_sprintf("'break' expression outside loop"));
+ return irb->codegen->invalid_instruction;
+ }
+
+ bool is_inline = ir_should_inline(irb) || node->data.break_expr.is_inline;
+ LoopStackItem *loop_stack_item = &irb->loop_stack.last();
+ IrBasicBlock *dest_block = loop_stack_item->break_block;
+ return ir_build_br(irb, scope, node, dest_block, is_inline);
+}
+
+static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *scope, AstNode *node) {
+ assert(node->type == NodeTypeContinue);
+
+ if (irb->loop_stack.length == 0) {
+ add_node_error(irb->codegen, node,
+ buf_sprintf("'continue' expression outside loop"));
+ return irb->codegen->invalid_instruction;
+ }
+
+ bool is_inline = ir_should_inline(irb) || node->data.continue_expr.is_inline;
+ LoopStackItem *loop_stack_item = &irb->loop_stack.last();
+ IrBasicBlock *dest_block = loop_stack_item->continue_block;
+ return ir_build_br(irb, scope, node, dest_block, is_inline);
+}
+
static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LValPurpose lval) {
if (lval == LValPurposeNone)
return value;
@@ -2712,11 +2754,13 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
return ir_lval_wrap(irb, scope, ir_gen_goto(irb, scope, node), lval);
case NodeTypeTypeLiteral:
return ir_lval_wrap(irb, scope, ir_gen_type_literal(irb, scope, node), lval);
+ case NodeTypeBreak:
+ return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval);
+ case NodeTypeContinue:
+ return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);
case NodeTypeUnwrapErrorExpr:
case NodeTypeDefer:
case NodeTypeSliceExpr:
- case NodeTypeBreak:
- case NodeTypeContinue:
case NodeTypeCharLiteral:
case NodeTypeZeroesLiteral:
case NodeTypeErrorType:
@@ -7704,87 +7748,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
// }
//}
//
-//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-// assert(node->type == NodeTypeWhileExpr);
-//
-// AstNode **condition_node = &node->data.while_expr.condition;
-// AstNode *while_body_node = node->data.while_expr.body;
-// AstNode **continue_expr_node = &node->data.while_expr.continue_expr;
-//
-// TypeTableEntry *condition_type = analyze_expression(g, import, context,
-// g->builtin_types.entry_bool, *condition_node);
-//
-// if (*continue_expr_node) {
-// analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node);
-// }
-//
-// BlockContext *child_context = new_block_context(node, context);
-// child_context->parent_loop_node = node;
-//
-// analyze_expression(g, import, child_context, g->builtin_types.entry_void, while_body_node);
-//
-//
-// TypeTableEntry *expr_return_type = g->builtin_types.entry_void;
-//
-// if (condition_type->id == TypeTableEntryIdInvalid) {
-// expr_return_type = g->builtin_types.entry_invalid;
-// } else {
-// // if the condition is a simple constant expression and there are no break statements
-// // then the return type is unreachable
-// ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val;
-// if (const_val->ok) {
-// if (const_val->data.x_bool) {
-// node->data.while_expr.condition_always_true = true;
-// if (!node->data.while_expr.contains_break) {
-// expr_return_type = g->builtin_types.entry_unreachable;
-// }
-// }
-// }
-// }
-//
-// return expr_return_type;
-//}
-//
-//static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-// assert(node->type == NodeTypeBreak);
-//
-// AstNode *loop_node = context->parent_loop_node;
-// if (loop_node) {
-// 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"));
-// }
-// return g->builtin_types.entry_unreachable;
-//}
-//
-//static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *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;
-//}
-//
//static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
// TypeTableEntry *expected_type, AstNode *node)
//{
@@ -8592,22 +8555,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
// }
//}
//
-//static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeBreak);
-// LLVMBasicBlockRef dest_block = g->break_block_stack.last();
-//
-// set_debug_source_node(g, node);
-// return LLVMBuildBr(g->builder, dest_block);
-//}
-
-//static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeContinue);
-// LLVMBasicBlockRef dest_block = g->continue_block_stack.last();
-//
-// set_debug_source_node(g, node);
-// return LLVMBuildBr(g->builder, dest_block);
-//}
-//
//static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
// bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr)
//{
src/ir_print.cpp
@@ -104,7 +104,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
}
case TypeTableEntryIdBlock:
{
- AstNode *node = const_val->data.x_block->node;
+ AstNode *node = const_val->data.x_block->source_node;
fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1);
return;
}
test/self_hosted2.zig
@@ -139,6 +139,20 @@ fn testFnWithInlineArgs() {
}
+fn testContinueInForLoop() {
+ const array = []i32 {1, 2, 3, 4, 5};
+ var sum : i32 = 0;
+ for (array) |x| {
+ sum += x;
+ if (x < 3) {
+ continue;
+ }
+ break;
+ }
+ assert(sum == 6);
+}
+
+
fn assert(ok: bool) {
if (!ok)
@unreachable();
@@ -158,6 +172,7 @@ fn runAllTests() {
testCompileTimeFib();
testCompileTimeGenericEval();
testFnWithInlineArgs();
+ testContinueInForLoop();
}
export nakedcc fn _start() -> unreachable {