move "unreachable code" error from stage1 to stage2

* AstGen: implement "unreachable code" error for blocks. This works at
   the statement level.
 * stage1: remove the "unreachable code" error implementation, which
   means removing the `is_gen` field from IrInstSrc. This is one small
   step towards a smaller memory footprint for stage1. The benefits
   won't be realized until a future commit because this flag took
   advantage of padding.

There may be a regression here with "union has no associated enum"
error, and there is a regression with the following code:

```zig
const a = noreturn;
```

A future commit will address these regressions.
This commit is contained in:
Andrew Kelley 2021-06-23 18:19:17 -07:00
parent d84b386f60
commit 125b85d737
6 changed files with 109 additions and 105 deletions

View File

@ -247,7 +247,6 @@ pub const Utf8View = struct {
} else |err| switch (err) {
error.InvalidUtf8 => {
@compileError("invalid utf8");
unreachable;
},
}
}

View File

@ -1570,7 +1570,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
const defer_scope = scope.cast(Scope.Defer).?;
scope = defer_scope.parent;
const expr_node = node_datas[defer_scope.defer_node].rhs;
try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
_ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
},
.defer_error => scope = scope.cast(Scope.Defer).?.parent,
.top => unreachable,
@ -1623,7 +1623,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)
const defer_scope = scope.cast(Scope.Defer).?;
scope = defer_scope.parent;
const expr_node = node_datas[defer_scope.defer_node].rhs;
try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
_ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node);
},
.defer_error => scope = scope.cast(Scope.Defer).?.parent,
.namespace => break,
@ -1785,8 +1785,23 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa);
defer block_arena.deinit();
var noreturn_src_node: ast.Node.Index = 0;
var scope = parent_scope;
for (statements) |statement| {
if (noreturn_src_node != 0) {
return astgen.failNodeNotes(
statement,
"unreachable code",
.{},
&[_]u32{
try astgen.errNoteNode(
noreturn_src_node,
"control flow is diverted here",
.{},
),
},
);
}
switch (node_tags[statement]) {
// zig fmt: off
.global_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.globalVarDecl(statement)),
@ -1814,7 +1829,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
.assign_mul => try assignOp(gz, scope, statement, .mul),
.assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap),
else => try unusedResultExpr(gz, scope, statement),
else => noreturn_src_node = try unusedResultExpr(gz, scope, statement),
// zig fmt: on
}
}
@ -1823,11 +1838,14 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod
try checkUsed(gz, parent_scope, scope);
}
fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!void {
/// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`.
/// Otherwise returns 0.
fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!ast.Node.Index {
try emitDbgNode(gz, statement);
// We need to emit an error if the result is not `noreturn` or `void`, but
// we want to avoid adding the ZIR instruction if possible for performance.
const maybe_unused_result = try expr(gz, scope, .none, statement);
var noreturn_src_node: ast.Node.Index = 0;
const elide_check = if (gz.refToIndex(maybe_unused_result)) |inst| b: {
// Note that this array becomes invalid after appending more items to it
// in the above while loop.
@ -2061,15 +2079,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.extended,
=> break :b false,
// ZIR instructions that are always either `noreturn` or `void`.
.breakpoint,
.fence,
.dbg_stmt,
.ensure_result_used,
.ensure_result_non_error,
.@"export",
.set_eval_branch_quota,
.ensure_err_payload_void,
// ZIR instructions that are always `noreturn`.
.@"break",
.break_inline,
.condbr,
@ -2078,16 +2088,30 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
.ret_node,
.ret_coerce,
.@"unreachable",
.repeat,
.repeat_inline,
.panic,
=> {
noreturn_src_node = statement;
break :b true;
},
// ZIR instructions that are always `void`.
.breakpoint,
.fence,
.dbg_stmt,
.ensure_result_used,
.ensure_result_non_error,
.@"export",
.set_eval_branch_quota,
.ensure_err_payload_void,
.store,
.store_node,
.store_to_block_ptr,
.store_to_inferred_ptr,
.resolve_inferred_alloc,
.repeat,
.repeat_inline,
.validate_struct_init_ptr,
.validate_array_init_ptr,
.panic,
.set_align_stack,
.set_cold,
.set_float_mode,
@ -2097,15 +2121,19 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
} else switch (maybe_unused_result) {
.none => unreachable,
.void_value,
.unreachable_value,
=> true,
.unreachable_value => b: {
noreturn_src_node = statement;
break :b true;
},
.void_value => true,
else => false,
};
if (!elide_check) {
_ = try gz.addUnNode(.ensure_result_used, maybe_unused_result, statement);
}
return noreturn_src_node;
}
fn genDefers(
@ -2132,7 +2160,7 @@ fn genDefers(
const prev_in_defer = gz.in_defer;
gz.in_defer = true;
defer gz.in_defer = prev_in_defer;
try unusedResultExpr(gz, defer_scope.parent, expr_node);
_ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
},
.defer_error => {
const defer_scope = scope.cast(Scope.Defer).?;
@ -2142,7 +2170,7 @@ fn genDefers(
const prev_in_defer = gz.in_defer;
gz.in_defer = true;
defer gz.in_defer = prev_in_defer;
try unusedResultExpr(gz, defer_scope.parent, expr_node);
_ = try unusedResultExpr(gz, defer_scope.parent, expr_node);
},
.namespace => unreachable,
.top => unreachable,

View File

@ -2733,9 +2733,6 @@ struct IrInstSrc {
IrInst base;
IrInstSrcId id;
// true if this instruction was generated by zig and not from user code
// this matters for the "unreachable code" compile error
bool is_gen;
bool is_noreturn;
// When analyzing IR, instructions that point to this instruction in the "old ir"

View File

@ -2557,7 +2557,6 @@ static IrInstSrc *ir_build_reset_result(Stage1AstGen *ag, Scope *scope, AstNode
{
IrInstSrcResetResult *instruction = ir_build_instruction<IrInstSrcResetResult>(ag, scope, source_node);
instruction->result_loc = result_loc;
instruction->base.is_gen = true;
return &instruction->base;
}
@ -2737,7 +2736,6 @@ static IrInstSrc *ir_build_alloca_src(Stage1AstGen *ag, Scope *scope, AstNode *s
IrInstSrc *align, const char *name_hint, IrInstSrc *is_comptime)
{
IrInstSrcAlloca *instruction = ir_build_instruction<IrInstSrcAlloca>(ag, scope, source_node);
instruction->base.is_gen = true;
instruction->align = align;
instruction->name_hint = name_hint;
instruction->is_comptime = is_comptime;
@ -2752,7 +2750,6 @@ static IrInstSrc *ir_build_end_expr(Stage1AstGen *ag, Scope *scope, AstNode *sou
IrInstSrc *value, ResultLoc *result_loc)
{
IrInstSrcEndExpr *instruction = ir_build_instruction<IrInstSrcEndExpr>(ag, scope, source_node);
instruction->base.is_gen = true;
instruction->value = value;
instruction->result_loc = result_loc;
@ -2885,11 +2882,6 @@ static void ir_count_defers(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_s
}
}
static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) {
instruction->is_gen = true;
return instruction;
}
static bool astgen_defers_for_block(Stage1AstGen *ag, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, IrInstSrc *err_value) {
Scope *scope = inner_scope;
if (is_noreturn != nullptr) *is_noreturn = false;
@ -2948,8 +2940,8 @@ static bool astgen_defers_for_block(Stage1AstGen *ag, Scope *inner_scope, Scope
if (defer_expr_value->is_noreturn) {
if (is_noreturn != nullptr) *is_noreturn = true;
} else {
ir_mark_gen(ir_build_check_statement_is_void(ag, defer_expr_scope, defer_expr_node,
defer_expr_value));
ir_build_check_statement_is_void(ag, defer_expr_scope, defer_expr_node,
defer_expr_value);
}
scope = scope->parent;
continue;
@ -3047,7 +3039,7 @@ static IrInstSrc *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, L
ir_build_end_expr(ag, scope, node, return_value, &result_loc_ret->base);
}
ir_mark_gen(ir_build_add_implicit_return_type(ag, scope, node, return_value, result_loc_ret));
ir_build_add_implicit_return_type(ag, scope, node, return_value, result_loc_ret);
size_t defer_counts[2];
ir_count_defers(ag, scope, outer_scope, defer_counts);
@ -3074,7 +3066,7 @@ static IrInstSrc *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, L
is_comptime = ir_build_test_comptime(ag, scope, node, is_err);
}
ir_mark_gen(ir_build_cond_br(ag, scope, node, is_err, err_block, ok_block, is_comptime));
ir_build_cond_br(ag, scope, node, is_err, err_block, ok_block, is_comptime);
Stage1ZirBasicBlock *ret_stmt_block = ir_create_basic_block(ag, scope, "RetStmt");
ir_set_cursor_at_end_and_append_block(ag, err_block);
@ -3112,12 +3104,12 @@ static IrInstSrc *astgen_return(Stage1AstGen *ag, Scope *scope, AstNode *node, L
} else {
is_comptime = ir_build_test_comptime(ag, scope, node, is_err_val);
}
ir_mark_gen(ir_build_cond_br(ag, scope, node, is_err_val, return_block, continue_block, is_comptime));
ir_build_cond_br(ag, scope, node, is_err_val, return_block, continue_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, return_block);
IrInstSrc *err_val_ptr = ir_build_unwrap_err_code_src(ag, scope, node, err_union_ptr);
IrInstSrc *err_val = ir_build_load_ptr(ag, scope, node, err_val_ptr);
ir_mark_gen(ir_build_add_implicit_return_type(ag, scope, node, err_val, nullptr));
ir_build_add_implicit_return_type(ag, scope, node, err_val, nullptr);
IrInstSrcSpillBegin *spill_begin = ir_build_spill_begin_src(ag, scope, node, err_val,
SpillIdRetErrCode);
ResultLocReturn *result_loc_ret = heap::c_allocator.create<ResultLocReturn>();
@ -3338,7 +3330,7 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
child_scope = decl_var_instruction->var->child_scope;
} else if (!is_continuation_unreachable) {
// this statement's value must be void
ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, statement_node, statement_value));
ir_build_check_statement_is_void(ag, child_scope, statement_node, statement_value);
}
}
@ -3364,7 +3356,7 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
return ir_expr_wrap(ag, parent_scope, phi, result_loc);
} else {
incoming_blocks.append(ag->current_basic_block);
IrInstSrc *else_expr_result = ir_mark_gen(ir_build_const_void(ag, parent_scope, block_node));
IrInstSrc *else_expr_result = ir_build_const_void(ag, parent_scope, block_node);
if (scope_block->peer_parent != nullptr) {
ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent);
@ -3387,13 +3379,13 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
IrInstSrc *result;
if (block_node->data.block.name != nullptr) {
ir_mark_gen(ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime));
ir_build_br(ag, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime);
ir_set_cursor_at_end_and_append_block(ag, scope_block->end_block);
IrInstSrc *phi = ir_build_phi(ag, parent_scope, block_node, incoming_blocks.length,
incoming_blocks.items, incoming_values.items, scope_block->peer_parent);
result = ir_expr_wrap(ag, parent_scope, phi, result_loc);
} else {
IrInstSrc *void_inst = ir_mark_gen(ir_build_const_void(ag, child_scope, block_node));
IrInstSrc *void_inst = ir_build_const_void(ag, child_scope, block_node);
result = ir_lval_wrap(ag, parent_scope, void_inst, lval, result_loc);
}
if (!is_return_from_fn)
@ -3402,14 +3394,14 @@ static IrInstSrc *astgen_block(Stage1AstGen *ag, Scope *parent_scope, AstNode *b
// no need for save_err_ret_addr because this cannot return error
// only generate unconditional defers
ir_mark_gen(ir_build_add_implicit_return_type(ag, child_scope, block_node, result, nullptr));
ir_build_add_implicit_return_type(ag, child_scope, block_node, result, nullptr);
ResultLocReturn *result_loc_ret = heap::c_allocator.create<ResultLocReturn>();
result_loc_ret->base.id = ResultLocIdReturn;
ir_build_reset_result(ag, parent_scope, block_node, &result_loc_ret->base);
ir_mark_gen(ir_build_end_expr(ag, parent_scope, block_node, result, &result_loc_ret->base));
ir_build_end_expr(ag, parent_scope, block_node, result, &result_loc_ret->base);
if (!astgen_defers_for_block(ag, child_scope, outer_block_scope, nullptr, nullptr))
return ag->codegen->invalid_inst_src;
return ir_mark_gen(ir_build_return_src(ag, child_scope, result->base.source_node, result));
return ir_build_return_src(ag, child_scope, result->base.source_node, result);
}
static IrInstSrc *astgen_bin_op_id(Stage1AstGen *ag, Scope *scope, AstNode *node, IrBinOp op_id) {
@ -3628,7 +3620,7 @@ static IrInstSrc *astgen_orelse(Stage1AstGen *ag, Scope *parent_scope, AstNode *
return ag->codegen->invalid_inst_src;
Stage1ZirBasicBlock *after_null_block = ag->current_basic_block;
if (!instr_is_unreachable(null_result))
ir_mark_gen(ir_build_br(ag, parent_scope, node, end_block, is_comptime));
ir_build_br(ag, parent_scope, node, end_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, ok_block);
IrInstSrc *unwrapped_ptr = ir_build_optional_unwrap_ptr(ag, parent_scope, node, maybe_ptr, false);
@ -5395,7 +5387,7 @@ static IrInstSrc *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNode *n
return ag->codegen->invalid_inst_src;
Stage1ZirBasicBlock *after_then_block = ag->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, else_block);
IrInstSrc *else_expr_result;
@ -5409,7 +5401,7 @@ static IrInstSrc *astgen_if_bool_expr(Stage1AstGen *ag, Scope *scope, AstNode *n
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, endif_block);
IrInstSrc **incoming_values = heap::c_allocator.allocate<IrInstSrc *>(2);
@ -5954,12 +5946,11 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
IrInstSrc *is_err = ir_build_test_err_src(ag, scope, node->data.while_expr.condition, err_val_ptr,
true, false);
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, scope, node));
IrInstSrc *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node);
IrInstSrc *cond_br_inst;
if (!instr_is_unreachable(is_err)) {
cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_err,
else_block, body_block, is_comptime);
cond_br_inst->is_gen = true;
} else {
// for the purposes of the source instruction to ir_build_result_peers
cond_br_inst = ag->current_basic_block->instruction_list.last();
@ -6005,8 +5996,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
}
if (!instr_is_unreachable(body_result)) {
ir_mark_gen(ir_build_check_statement_is_void(ag, payload_scope, node->data.while_expr.body, body_result));
ir_mark_gen(ir_build_br(ag, payload_scope, node, continue_block, is_comptime));
ir_build_check_statement_is_void(ag, payload_scope, node->data.while_expr.body, body_result);
ir_build_br(ag, payload_scope, node, continue_block, is_comptime);
}
if (continue_expr_node) {
@ -6015,8 +6006,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (expr_result == ag->codegen->invalid_inst_src)
return expr_result;
if (!instr_is_unreachable(expr_result)) {
ir_mark_gen(ir_build_check_statement_is_void(ag, payload_scope, continue_expr_node, expr_result));
ir_mark_gen(ir_build_br(ag, payload_scope, node, cond_block, is_comptime));
ir_build_check_statement_is_void(ag, payload_scope, continue_expr_node, expr_result);
ir_build_br(ag, payload_scope, node, cond_block, is_comptime);
}
}
@ -6041,7 +6032,7 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(ag, scope, node, end_block, is_comptime));
ir_build_br(ag, scope, node, end_block, is_comptime);
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
if (else_result) {
@ -6075,12 +6066,11 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
IrInstSrc *maybe_val = ir_build_load_ptr(ag, scope, node->data.while_expr.condition, maybe_val_ptr);
IrInstSrc *is_non_null = ir_build_test_non_null_src(ag, scope, node->data.while_expr.condition, maybe_val);
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, scope, node));
IrInstSrc *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node);
IrInstSrc *cond_br_inst;
if (!instr_is_unreachable(is_non_null)) {
cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, is_non_null,
body_block, else_block, is_comptime);
cond_br_inst->is_gen = true;
} else {
// for the purposes of the source instruction to ir_build_result_peers
cond_br_inst = ag->current_basic_block->instruction_list.last();
@ -6123,8 +6113,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
}
if (!instr_is_unreachable(body_result)) {
ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, node->data.while_expr.body, body_result));
ir_mark_gen(ir_build_br(ag, child_scope, node, continue_block, is_comptime));
ir_build_check_statement_is_void(ag, child_scope, node->data.while_expr.body, body_result);
ir_build_br(ag, child_scope, node, continue_block, is_comptime);
}
if (continue_expr_node) {
@ -6133,8 +6123,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (expr_result == ag->codegen->invalid_inst_src)
return expr_result;
if (!instr_is_unreachable(expr_result)) {
ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, continue_expr_node, expr_result));
ir_mark_gen(ir_build_br(ag, child_scope, node, cond_block, is_comptime));
ir_build_check_statement_is_void(ag, child_scope, continue_expr_node, expr_result);
ir_build_br(ag, child_scope, node, cond_block, is_comptime);
}
}
@ -6151,7 +6141,7 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(ag, scope, node, end_block, is_comptime));
ir_build_br(ag, scope, node, end_block, is_comptime);
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
@ -6175,12 +6165,11 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (cond_val == ag->codegen->invalid_inst_src)
return cond_val;
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, scope, node));
IrInstSrc *void_else_result = else_node ? nullptr : ir_build_const_void(ag, scope, node);
IrInstSrc *cond_br_inst;
if (!instr_is_unreachable(cond_val)) {
cond_br_inst = ir_build_cond_br(ag, scope, node->data.while_expr.condition, cond_val,
body_block, else_block, is_comptime);
cond_br_inst->is_gen = true;
} else {
// for the purposes of the source instruction to ir_build_result_peers
cond_br_inst = ag->current_basic_block->instruction_list.last();
@ -6219,8 +6208,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
}
if (!instr_is_unreachable(body_result)) {
ir_mark_gen(ir_build_check_statement_is_void(ag, scope, node->data.while_expr.body, body_result));
ir_mark_gen(ir_build_br(ag, scope, node, continue_block, is_comptime));
ir_build_check_statement_is_void(ag, scope, node->data.while_expr.body, body_result);
ir_build_br(ag, scope, node, continue_block, is_comptime);
}
if (continue_expr_node) {
@ -6229,8 +6218,8 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (expr_result == ag->codegen->invalid_inst_src)
return expr_result;
if (!instr_is_unreachable(expr_result)) {
ir_mark_gen(ir_build_check_statement_is_void(ag, scope, continue_expr_node, expr_result));
ir_mark_gen(ir_build_br(ag, scope, node, cond_block, is_comptime));
ir_build_check_statement_is_void(ag, scope, continue_expr_node, expr_result);
ir_build_br(ag, scope, node, cond_block, is_comptime);
}
}
@ -6248,7 +6237,7 @@ static IrInstSrc *astgen_while_expr(Stage1AstGen *ag, Scope *scope, AstNode *nod
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(ag, scope, node, end_block, is_comptime));
ir_build_br(ag, scope, node, end_block, is_comptime);
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
@ -6332,9 +6321,9 @@ static IrInstSrc *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode
IrInstSrc *index_val = ir_build_load_ptr(ag, &spill_scope->base, node, index_ptr);
IrInstSrc *cond = ir_build_bin_op(ag, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
Stage1ZirBasicBlock *after_cond_block = ag->current_basic_block;
IrInstSrc *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(ag, parent_scope, node));
IrInstSrc *cond_br_inst = ir_mark_gen(ir_build_cond_br(ag, parent_scope, node, cond,
body_block, else_block, is_comptime));
IrInstSrc *void_else_value = else_node ? nullptr : ir_build_const_void(ag, parent_scope, node);
IrInstSrc *cond_br_inst = ir_build_cond_br(ag, parent_scope, node, cond,
body_block, else_block, is_comptime);
ResultLocPeerParent *peer_parent = ir_build_result_peers(ag, cond_br_inst, end_block, result_loc, is_comptime);
@ -6377,8 +6366,8 @@ static IrInstSrc *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode
}
if (!instr_is_unreachable(body_result)) {
ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, node->data.for_expr.body, body_result));
ir_mark_gen(ir_build_br(ag, child_scope, node, continue_block, is_comptime));
ir_build_check_statement_is_void(ag, child_scope, node->data.for_expr.body, body_result);
ir_build_br(ag, child_scope, node, continue_block, is_comptime);
}
ir_set_cursor_at_end_and_append_block(ag, continue_block);
@ -6399,7 +6388,7 @@ static IrInstSrc *astgen_for_expr(Stage1AstGen *ag, Scope *parent_scope, AstNode
if (else_result == ag->codegen->invalid_inst_src)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(ag, parent_scope, node, end_block, is_comptime));
ir_build_br(ag, parent_scope, node, end_block, is_comptime);
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
ir_set_cursor_at_end_and_append_block(ag, end_block);
@ -6719,7 +6708,7 @@ static IrInstSrc *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, AstNod
return then_expr_result;
Stage1ZirBasicBlock *after_then_block = ag->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, else_block);
IrInstSrc *else_expr_result;
@ -6733,7 +6722,7 @@ static IrInstSrc *astgen_if_optional_expr(Stage1AstGen *ag, Scope *scope, AstNod
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, endif_block);
IrInstSrc **incoming_values = heap::c_allocator.allocate<IrInstSrc *>(2);
@ -6802,7 +6791,7 @@ static IrInstSrc *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
return then_expr_result;
Stage1ZirBasicBlock *after_then_block = ag->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, else_block);
@ -6831,7 +6820,7 @@ static IrInstSrc *astgen_if_err_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
}
Stage1ZirBasicBlock *after_else_block = ag->current_basic_block;
if (!instr_is_unreachable(else_expr_result))
ir_mark_gen(ir_build_br(ag, scope, node, endif_block, is_comptime));
ir_build_br(ag, scope, node, endif_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, endif_block);
IrInstSrc **incoming_values = heap::c_allocator.allocate<IrInstSrc *>(2);
@ -6893,7 +6882,7 @@ static bool astgen_switch_prong_expr(Stage1AstGen *ag, Scope *scope, AstNode *sw
if (expr_result == ag->codegen->invalid_inst_src)
return false;
if (!instr_is_unreachable(expr_result))
ir_mark_gen(ir_build_br(ag, scope, switch_node, end_block, is_comptime));
ir_build_br(ag, scope, switch_node, end_block, is_comptime);
incoming_blocks->append(ag->current_basic_block);
incoming_values->append(expr_result);
return true;
@ -7008,8 +6997,8 @@ static IrInstSrc *astgen_switch_expr(Stage1AstGen *ag, Scope *scope, AstNode *no
assert(ok_bit);
assert(last_item_node);
IrInstSrc *br_inst = ir_mark_gen(ir_build_cond_br(ag, scope, last_item_node, ok_bit,
range_block_yes, range_block_no, is_comptime));
IrInstSrc *br_inst = ir_build_cond_br(ag, scope, last_item_node, ok_bit,
range_block_yes, range_block_no, is_comptime);
if (peer_parent->base.source_instruction == nullptr) {
peer_parent->base.source_instruction = br_inst;
}
@ -7349,14 +7338,14 @@ static IrInstSrc *astgen_continue(Stage1AstGen *ag, Scope *continue_scope, AstNo
for (size_t i = 0; i < runtime_scopes.length; i += 1) {
ScopeRuntime *scope_runtime = runtime_scopes.at(i);
ir_mark_gen(ir_build_check_runtime_scope(ag, continue_scope, node, scope_runtime->is_comptime, is_comptime));
ir_build_check_runtime_scope(ag, continue_scope, node, scope_runtime->is_comptime, is_comptime);
}
runtime_scopes.deinit();
Stage1ZirBasicBlock *dest_block = loop_scope->continue_block;
if (!astgen_defers_for_block(ag, continue_scope, dest_block->scope, nullptr, nullptr))
return ag->codegen->invalid_inst_src;
return ir_mark_gen(ir_build_br(ag, continue_scope, node, dest_block, is_comptime));
return ir_build_br(ag, continue_scope, node, dest_block, is_comptime);
}
static IrInstSrc *astgen_error_type(Stage1AstGen *ag, Scope *scope, AstNode *node) {
@ -7482,7 +7471,7 @@ static IrInstSrc *astgen_catch(Stage1AstGen *ag, Scope *parent_scope, AstNode *n
return ag->codegen->invalid_inst_src;
Stage1ZirBasicBlock *after_err_block = ag->current_basic_block;
if (!instr_is_unreachable(err_result))
ir_mark_gen(ir_build_br(ag, parent_scope, node, end_block, is_comptime));
ir_build_br(ag, parent_scope, node, end_block, is_comptime);
ir_set_cursor_at_end_and_append_block(ag, ok_block);
IrInstSrc *unwrapped_ptr = ir_build_unwrap_err_payload_src(ag, parent_scope, node, err_union_ptr, false, false);
@ -7757,9 +7746,9 @@ static IrInstSrc *astgen_suspend(Stage1AstGen *ag, Scope *parent_scope, AstNode
IrInstSrc *susp_res = astgen_node(ag, node->data.suspend.block, child_scope);
if (susp_res == ag->codegen->invalid_inst_src)
return ag->codegen->invalid_inst_src;
ir_mark_gen(ir_build_check_statement_is_void(ag, child_scope, node->data.suspend.block, susp_res));
ir_build_check_statement_is_void(ag, child_scope, node->data.suspend.block, susp_res);
return ir_mark_gen(ir_build_suspend_finish_src(ag, parent_scope, node, begin));
return ir_build_suspend_finish_src(ag, parent_scope, node, begin);
}
static IrInstSrc *astgen_node_raw(Stage1AstGen *ag, AstNode *node, Scope *scope,
@ -8073,13 +8062,13 @@ bool stage1_astgen(CodeGen *codegen, AstNode *node, Scope *scope, Stage1Zir *sta
}
if (!instr_is_unreachable(result)) {
ir_mark_gen(ir_build_add_implicit_return_type(ag, scope, result->base.source_node, result, nullptr));
ir_build_add_implicit_return_type(ag, scope, result->base.source_node, result, nullptr);
// no need for save_err_ret_addr because this cannot return error
ResultLocReturn *result_loc_ret = heap::c_allocator.create<ResultLocReturn>();
result_loc_ret->base.id = ResultLocIdReturn;
ir_build_reset_result(ag, scope, node, &result_loc_ret->base);
ir_mark_gen(ir_build_end_expr(ag, scope, node, result, &result_loc_ret->base));
ir_mark_gen(ir_build_return_src(ag, scope, result->base.source_node, result));
ir_build_end_expr(ag, scope, node, result, &result_loc_ret->base);
ir_build_return_src(ag, scope, result->base.source_node, result);
}
return true;

View File

@ -5407,16 +5407,6 @@ static void ir_finish_bb(IrAnalyze *ira) {
ira->new_irb.current_basic_block->debug_id);
}
}
ira->instruction_index += 1;
while (ira->instruction_index < ira->zir_current_basic_block->instruction_list.length) {
IrInstSrc *next_instruction = ira->zir_current_basic_block->instruction_list.at(ira->instruction_index);
if (!next_instruction->is_gen) {
ir_add_error(ira, &next_instruction->base, buf_sprintf("unreachable code"));
break;
}
ira->instruction_index += 1;
}
ir_start_next_bb(ira);
}
@ -15934,7 +15924,7 @@ static IrInstGen *ir_analyze_instruction_pop_count(IrAnalyze *ira, IrInstSrcPopC
return ir_build_pop_count_gen(ira, &instruction->base.base, return_type, op);
}
static IrInstGen *ir_analyze_union_tag(IrAnalyze *ira, IrInst* source_instr, IrInstGen *value, bool is_gen) {
static IrInstGen *ir_analyze_union_tag(IrAnalyze *ira, IrInst* source_instr, IrInstGen *value) {
if (type_is_invalid(value->value->type))
return ira->codegen->invalid_inst_gen;
@ -15943,7 +15933,7 @@ static IrInstGen *ir_analyze_union_tag(IrAnalyze *ira, IrInst* source_instr, IrI
buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value->type->name)));
return ira->codegen->invalid_inst_gen;
}
if (!value->value->type->data.unionation.have_explicit_tag_type && !is_gen) {
if (!value->value->type->data.unionation.have_explicit_tag_type) {
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union has no associated enum"));
if (value->value->type->data.unionation.decl_node != nullptr) {
add_error_note(ira->codegen, msg, value->value->type->data.unionation.decl_node,
@ -16906,7 +16896,7 @@ static IrInstGen *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstSrc
}
if (target_type->id == ZigTypeIdUnion) {
target = ir_analyze_union_tag(ira, &instruction->base.base, target, instruction->base.is_gen);
target = ir_analyze_union_tag(ira, &instruction->base.base, target);
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_inst_gen;
target_type = target->value->type;

View File

@ -4762,7 +4762,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\
\\fn b() void {}
, &[_][]const u8{
"tmp.zig:3:5: error: unreachable code",
"tmp.zig:3:6: error: unreachable code",
"tmp.zig:2:5: note: control flow is diverted here",
});
cases.add("bad import",