mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
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:
parent
d84b386f60
commit
125b85d737
@ -247,7 +247,6 @@ pub const Utf8View = struct {
|
||||
} else |err| switch (err) {
|
||||
error.InvalidUtf8 => {
|
||||
@compileError("invalid utf8");
|
||||
unreachable;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user