@@ -3514,7 +3514,11 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
3514
3514
static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
3515
3515
assert(block_node->type == NodeTypeBlock);
3516
3516
3517
+ ZigList<IrInstruction *> incoming_values = {0};
3518
+ ZigList<IrBasicBlock *> incoming_blocks = {0};
3519
+
3517
3520
ScopeBlock *scope_block = create_block_scope(block_node, parent_scope);
3521
+
3518
3522
Scope *outer_block_scope = &scope_block->base;
3519
3523
Scope *child_scope = outer_block_scope;
3520
3524
@@ -3528,9 +3532,15 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3528
3532
return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3529
3533
}
3530
3534
3535
+ if (block_node->data.block.name != nullptr) {
3536
+ scope_block->incoming_blocks = &incoming_blocks;
3537
+ scope_block->incoming_values = &incoming_values;
3538
+ scope_block->end_block = ir_build_basic_block(irb, parent_scope, "BlockEnd");
3539
+ scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope));
3540
+ }
3541
+
3531
3542
bool is_continuation_unreachable = false;
3532
3543
IrInstruction *noreturn_return_value = nullptr;
3533
- IrInstruction *return_value = nullptr;
3534
3544
for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
3535
3545
AstNode *statement_node = block_node->data.block.statements.at(i);
3536
3546
@@ -3548,39 +3558,31 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3548
3558
// variable declarations start a new scope
3549
3559
IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
3550
3560
child_scope = decl_var_instruction->var->child_scope;
3551
- } else {
3552
- // label, defer, variable declaration will never be the result expression
3553
- if (block_node->data.block.last_statement_is_result_expression &&
3554
- i == block_node->data.block.statements.length - 1) {
3555
- // this is the result value statement
3556
- return_value = statement_value;
3557
- } else {
3558
- // there are more statements ahead of this one. this statement's value must be void
3559
- if (statement_value != irb->codegen->invalid_instruction) {
3560
- ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
3561
- }
3562
- }
3561
+ } else if (statement_value != irb->codegen->invalid_instruction) {
3562
+ // this statement's value must be void
3563
+ ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value));
3563
3564
}
3564
3565
}
3565
3566
3566
3567
if (is_continuation_unreachable) {
3567
3568
assert(noreturn_return_value != nullptr);
3568
- return noreturn_return_value;
3569
+ if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) {
3570
+ return noreturn_return_value;
3571
+ }
3572
+ } else {
3573
+ incoming_blocks.append(irb->current_basic_block);
3574
+ incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)));
3569
3575
}
3570
- // control flow falls out of block
3571
3576
3572
- if (block_node->data.block.last_statement_is_result_expression) {
3573
- // return value was determined by the last statement
3574
- assert(return_value != nullptr);
3577
+ if (block_node->data.block.name != nullptr) {
3578
+ ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3579
+ ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
3580
+ ir_set_cursor_at_end(irb, scope_block->end_block);
3581
+ return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
3575
3582
} else {
3576
- // return value is implicitly void
3577
- assert(return_value == nullptr);
3578
- return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node));
3583
+ ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3584
+ return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)));
3579
3585
}
3580
-
3581
- ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false);
3582
-
3583
- return return_value;
3584
3586
}
3585
3587
3586
3588
static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
@@ -5952,21 +5954,46 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo
5952
5954
return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval);
5953
5955
}
5954
5956
5957
+ static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) {
5958
+ IrInstruction *is_comptime;
5959
+ if (ir_should_inline(irb->exec, break_scope)) {
5960
+ is_comptime = ir_build_const_bool(irb, break_scope, node, true);
5961
+ } else {
5962
+ is_comptime = block_scope->is_comptime;
5963
+ }
5964
+
5965
+ IrInstruction *result_value;
5966
+ if (node->data.break_expr.expr) {
5967
+ result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
5968
+ if (result_value == irb->codegen->invalid_instruction)
5969
+ return irb->codegen->invalid_instruction;
5970
+ } else {
5971
+ result_value = ir_build_const_void(irb, break_scope, node);
5972
+ }
5973
+
5974
+ IrBasicBlock *dest_block = block_scope->end_block;
5975
+ ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false);
5976
+
5977
+ block_scope->incoming_blocks->append(irb->current_basic_block);
5978
+ block_scope->incoming_values->append(result_value);
5979
+ return ir_build_br(irb, break_scope, node, dest_block, is_comptime);
5980
+ }
5981
+
5955
5982
static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *node) {
5956
5983
assert(node->type == NodeTypeBreak);
5957
5984
5958
5985
// Search up the scope. We'll find one of these things first:
5959
5986
// * function definition scope or global scope => error, break outside loop
5960
5987
// * defer expression scope => error, cannot break out of defer expression
5961
5988
// * loop scope => OK
5989
+ // * (if it's a labeled break) labeled block => OK
5962
5990
5963
5991
Scope *search_scope = break_scope;
5964
5992
ScopeLoop *loop_scope;
5965
- bool saw_any_loop_scope = false;
5966
5993
for (;;) {
5967
5994
if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
5968
- if (saw_any_loop_scope ) {
5969
- add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.break_expr.name)));
5995
+ if (node->data.break_expr.name != nullptr ) {
5996
+ add_node_error(irb->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name)));
5970
5997
return irb->codegen->invalid_instruction;
5971
5998
} else {
5972
5999
add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop"));
@@ -5977,13 +6004,20 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
5977
6004
return irb->codegen->invalid_instruction;
5978
6005
} else if (search_scope->id == ScopeIdLoop) {
5979
6006
ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
5980
- saw_any_loop_scope = true;
5981
6007
if (node->data.break_expr.name == nullptr ||
5982
6008
(this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name)))
5983
6009
{
5984
6010
loop_scope = this_loop_scope;
5985
6011
break;
5986
6012
}
6013
+ } else if (search_scope->id == ScopeIdBlock) {
6014
+ ScopeBlock *this_block_scope = (ScopeBlock *)search_scope;
6015
+ if (node->data.break_expr.name != nullptr &&
6016
+ (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name)))
6017
+ {
6018
+ assert(this_block_scope->end_block != nullptr);
6019
+ return ir_gen_return_from_block(irb, break_scope, node, this_block_scope);
6020
+ }
5987
6021
}
5988
6022
search_scope = search_scope->parent;
5989
6023
}
@@ -6022,10 +6056,9 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
6022
6056
6023
6057
Scope *search_scope = continue_scope;
6024
6058
ScopeLoop *loop_scope;
6025
- bool saw_any_loop_scope = false;
6026
6059
for (;;) {
6027
6060
if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) {
6028
- if (saw_any_loop_scope ) {
6061
+ if (node->data.continue_expr.name != nullptr ) {
6029
6062
add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name)));
6030
6063
return irb->codegen->invalid_instruction;
6031
6064
} else {
@@ -6037,7 +6070,6 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
6037
6070
return irb->codegen->invalid_instruction;
6038
6071
} else if (search_scope->id == ScopeIdLoop) {
6039
6072
ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope;
6040
- saw_any_loop_scope = true;
6041
6073
if (node->data.continue_expr.name == nullptr ||
6042
6074
(this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name)))
6043
6075
{
0 commit comments