| ... | ... | @@ -3344,6 +3344,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3344 | 3344 | return ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); |
| 3345 | 3345 | } |
| 3346 | 3346 | |
| 3347 | bool is_continuation_unreachable = false; |
| 3347 | 3348 | IrInstruction *return_value = nullptr; |
| 3348 | 3349 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { |
| 3349 | 3350 | AstNode *statement_node = block_node->data.block.statements.at(i); |
| ... | ... | @@ -3367,7 +3368,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3367 | 3368 | scope_block->label_table.put(label_name, label); |
| 3368 | 3369 | } |
| 3369 | 3370 | |
| 3370 | | if (!(return_value && instr_is_unreachable(return_value))) { |
| 3371 | if (!is_continuation_unreachable) { |
| 3371 | 3372 | // fall through into new labeled basic block |
| 3372 | 3373 | IrInstruction *is_comptime = ir_mark_gen(ir_build_const_bool(irb, child_scope, statement_node, |
| 3373 | 3374 | ir_should_inline(irb->exec, child_scope))); |
| ... | ... | @@ -3375,33 +3376,58 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3375 | 3376 | } |
| 3376 | 3377 | ir_set_cursor_at_end(irb, label_block); |
| 3377 | 3378 | |
| 3378 | | return_value = nullptr; |
| 3379 | // a label is an entry point |
| 3380 | is_continuation_unreachable = false; |
| 3379 | 3381 | continue; |
| 3380 | 3382 | } |
| 3381 | 3383 | |
| 3382 | | if (return_value && instr_is_unreachable(return_value)) { |
| 3383 | | if (is_node_void_expr(statement_node)) |
| 3384 | if (is_continuation_unreachable) { |
| 3385 | // if you put a semicolon after a return statement, |
| 3386 | // then we get a void statement in the unreachable area. |
| 3387 | // this is fine. ignore any void blocks we get from this happening. |
| 3388 | if (statement_node->type == NodeTypeBlock && statement_node->data.block.statements.length == 0) |
| 3384 | 3389 | continue; |
| 3385 | 3390 | add_node_error(irb->codegen, statement_node, buf_sprintf("unreachable code")); |
| 3386 | 3391 | } |
| 3387 | 3392 | |
| 3388 | | return_value = ir_gen_node(irb, statement_node, child_scope); |
| 3389 | | if (statement_node->type == NodeTypeDefer && return_value != irb->codegen->invalid_instruction) { |
| 3393 | IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope); |
| 3394 | is_continuation_unreachable = instr_is_unreachable(statement_value); |
| 3395 | if (is_continuation_unreachable) |
| 3396 | return_value = statement_value; |
| 3397 | else |
| 3398 | return_value = nullptr; |
| 3399 | if (statement_node->type == NodeTypeDefer && statement_value != irb->codegen->invalid_instruction) { |
| 3390 | 3400 | // defer starts a new scope |
| 3391 | 3401 | child_scope = statement_node->data.defer.child_scope; |
| 3392 | 3402 | assert(child_scope); |
| 3393 | | } else if (return_value->id == IrInstructionIdDeclVar) { |
| 3403 | } else if (statement_value->id == IrInstructionIdDeclVar) { |
| 3394 | 3404 | // variable declarations start a new scope |
| 3395 | | IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)return_value; |
| 3405 | IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value; |
| 3396 | 3406 | child_scope = decl_var_instruction->var->child_scope; |
| 3407 | } else { |
| 3408 | // label, defer, variable declaration will never be the last statement |
| 3409 | if (i == block_node->data.block.statements.length - 1) { |
| 3410 | // this is the result value statement |
| 3411 | return_value = statement_value; |
| 3412 | } else { |
| 3413 | // there are more statements ahead of this one. this statement's value must be void |
| 3414 | TypeTableEntry *instruction_type = statement_value->value.type; |
| 3415 | if (instruction_type && |
| 3416 | instruction_type->id != TypeTableEntryIdInvalid && |
| 3417 | instruction_type->id != TypeTableEntryIdVoid && |
| 3418 | instruction_type->id != TypeTableEntryIdUnreachable) { |
| 3419 | add_node_error(irb->codegen, statement_node, buf_sprintf("expression valued ignored")); |
| 3420 | } |
| 3421 | } |
| 3397 | 3422 | } |
| 3398 | 3423 | } |
| 3399 | 3424 | |
| 3400 | | // labels are never the last statement |
| 3401 | 3425 | assert(return_value != nullptr); |
| 3402 | 3426 | |
| 3403 | | if (!instr_is_unreachable(return_value)) |
| 3427 | if (!is_continuation_unreachable) { |
| 3428 | // control flow falls out of block |
| 3404 | 3429 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false, false); |
| 3430 | } |
| 3405 | 3431 | |
| 3406 | 3432 | return return_value; |
| 3407 | 3433 | } |