| ... | @@ -3350,6 +3350,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3350,6 +3350,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3350 | } | 3350 | } |
| 3351 | | 3351 | |
| 3352 | bool is_continuation_unreachable = false; | 3352 | bool is_continuation_unreachable = false; |
| | 3353 | IrInstruction *noreturn_return_value = nullptr; |
| 3353 | IrInstruction *return_value = nullptr; | 3354 | IrInstruction *return_value = nullptr; |
| 3354 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { | 3355 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { |
| 3355 | AstNode *statement_node = block_node->data.block.statements.at(i); | 3356 | AstNode *statement_node = block_node->data.block.statements.at(i); |
| ... | @@ -3383,16 +3384,15 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3383,16 +3384,15 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3383 | | 3384 | |
| 3384 | // a label is an entry point | 3385 | // a label is an entry point |
| 3385 | is_continuation_unreachable = false; | 3386 | is_continuation_unreachable = false; |
| 3386 | return_value = nullptr; | | |
| 3387 | continue; | 3387 | continue; |
| 3388 | } | 3388 | } |
| 3389 | | 3389 | |
| 3390 | IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope); | 3390 | IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope); |
| 3391 | is_continuation_unreachable = instr_is_unreachable(statement_value); | 3391 | is_continuation_unreachable = instr_is_unreachable(statement_value); |
| 3392 | if (is_continuation_unreachable) | 3392 | if (is_continuation_unreachable) { |
| 3393 | return_value = statement_value; | 3393 | // keep the last noreturn statement value around in case we need to return it |
| 3394 | else | 3394 | noreturn_return_value = statement_value; |
| 3395 | return_value = nullptr; | 3395 | } |
| 3396 | if (statement_node->type == NodeTypeDefer && statement_value != irb->codegen->invalid_instruction) { | 3396 | if (statement_node->type == NodeTypeDefer && statement_value != irb->codegen->invalid_instruction) { |
| 3397 | // defer starts a new scope | 3397 | // defer starts a new scope |
| 3398 | child_scope = statement_node->data.defer.child_scope; | 3398 | child_scope = statement_node->data.defer.child_scope; |
| ... | @@ -3420,18 +3420,23 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3420,18 +3420,23 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3420 | } | 3420 | } |
| 3421 | } | 3421 | } |
| 3422 | | 3422 | |
| 3423 | if (!is_continuation_unreachable) { | 3423 | if (is_continuation_unreachable) { |
| 3424 | // control flow falls out of block | 3424 | assert(noreturn_return_value != nullptr); |
| 3425 | | 3425 | return noreturn_return_value; |
| 3426 | if (!block_node->data.block.last_statement_is_result_expression) { | 3426 | } |
| 3427 | assert(return_value == nullptr); | 3427 | // control flow falls out of block |
| 3428 | return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); | | |
| 3429 | } | | |
| 3430 | | 3428 | |
| 3431 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); | 3429 | if (block_node->data.block.last_statement_is_result_expression) { |
| | 3430 | // return value was determined by the last statement |
| | 3431 | assert(return_value != nullptr); |
| | 3432 | } else { |
| | 3433 | // return value is implicitly void |
| | 3434 | assert(return_value == nullptr); |
| | 3435 | return_value = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); |
| 3432 | } | 3436 | } |
| 3433 | | 3437 | |
| 3434 | assert(return_value != nullptr); | 3438 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| | 3439 | |
| 3435 | return return_value; | 3440 | return return_value; |
| 3436 | } | 3441 | } |
| 3437 | | 3442 | |