aboutsummaryrefslogtreecommitdiff
path: root/src/AstGen.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-06-28 14:16:15 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-07-02 13:26:50 -0700
commit7f5560689aeb0e2ab84c5e3dc48f84247bd5bdc3 (patch)
treeeafe7ba69a4ebffc6c54067f6bf615daf6d89bdb /src/AstGen.zig
parentcffa22a658d23bdedbdd7e23853b80d856e43627 (diff)
downloadzig-7f5560689aeb0e2ab84c5e3dc48f84247bd5bdc3.tar.gz
zig-7f5560689aeb0e2ab84c5e3dc48f84247bd5bdc3.zip
AstGen: introduce 'reachableExpr' function
This function can be swapped out for calls to expr() to report a compile error when the expression results in control flow that does not return.
Diffstat (limited to 'src/AstGen.zig')
-rw-r--r--src/AstGen.zig59
1 files changed, 25 insertions, 34 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index c74106ef44..15b5b88d9a 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -261,6 +261,23 @@ fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zi
return expr(gz, scope, .{ .ty = .type_type }, type_node);
}
+/// Same as `expr` but fails with a compile error if the result type is `noreturn`.
+fn reachableExpr(
+ gz: *GenZir,
+ scope: *Scope,
+ rl: ResultLoc,
+ node: ast.Node.Index,
+ src_node: ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+ const result_inst = try expr(gz, scope, rl, node);
+ if (gz.refIsNoReturn(result_inst)) {
+ return gz.astgen.failNodeNotes(src_node, "unreachable code", .{}, &[_]u32{
+ try gz.astgen.errNoteNode(node, "control flow is diverted here", .{}),
+ });
+ }
+ return result_inst;
+}
+
fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
@@ -2331,8 +2348,7 @@ fn varDecl(
const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{
.ty = try typeExpr(gz, scope, var_decl.ast.type_node),
} else .none;
- const init_inst = try expr(gz, scope, result_loc, var_decl.ast.init_node);
- try astgen.checkVarInitExpr(gz.*, node, var_decl.ast.init_node, init_inst, "local constant");
+ const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node);
const sub_scope = try block_arena.create(Scope.LocalVal);
sub_scope.* = .{
@@ -2383,8 +2399,7 @@ fn varDecl(
init_scope.rl_ptr = alloc;
}
const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
- const init_inst = try expr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node);
- try astgen.checkVarInitExpr(init_scope, node, var_decl.ast.init_node, init_inst, "local constant");
+ const init_inst = try reachableExpr(&init_scope, &init_scope.base, init_result_loc, var_decl.ast.init_node, node);
const zir_tags = astgen.instructions.items(.tag);
const zir_datas = astgen.instructions.items(.data);
@@ -2486,8 +2501,7 @@ fn varDecl(
resolve_inferred_alloc = alloc;
break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
};
- const init_inst = try expr(gz, scope, var_data.result_loc, var_decl.ast.init_node);
- try astgen.checkVarInitExpr(gz.*, node, var_decl.ast.init_node, init_inst, "local variable");
+ _ = try reachableExpr(gz, scope, var_data.result_loc, var_decl.ast.init_node, node);
if (resolve_inferred_alloc != .none) {
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
}
@@ -6618,14 +6632,14 @@ fn as(
const dest_type = try typeExpr(gz, scope, lhs);
switch (rl) {
.none, .none_or_ref, .discard, .ref, .ty => {
- const result = try expr(gz, scope, .{ .ty = dest_type }, rhs);
+ const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
return rvalue(gz, rl, result, node);
},
.ptr, .inferred_ptr => |result_ptr| {
- return asRlPtr(gz, scope, rl, result_ptr, rhs, dest_type);
+ return asRlPtr(gz, scope, rl, node, result_ptr, rhs, dest_type);
},
.block_ptr => |block_scope| {
- return asRlPtr(gz, scope, rl, block_scope.rl_ptr, rhs, dest_type);
+ return asRlPtr(gz, scope, rl, node, block_scope.rl_ptr, rhs, dest_type);
},
}
}
@@ -6679,6 +6693,7 @@ fn asRlPtr(
parent_gz: *GenZir,
scope: *Scope,
rl: ResultLoc,
+ src_node: ast.Node.Index,
result_ptr: Zir.Inst.Ref,
operand_node: ast.Node.Index,
dest_type: Zir.Inst.Ref,
@@ -6692,7 +6707,7 @@ fn asRlPtr(
defer as_scope.instructions.deinit(astgen.gpa);
as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
- const result = try expr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node);
+ const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);
const parent_zir = &parent_gz.instructions;
if (as_scope.rvalue_rl_count == 1) {
// Busted! This expression didn't actually need a pointer.
@@ -9607,27 +9622,3 @@ fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void {
astgen.source_line = line;
astgen.source_column = column;
}
-
-fn checkVarInitExpr(
- astgen: *AstGen,
- gz: GenZir,
- var_node: ast.Node.Index,
- init_node: ast.Node.Index,
- init_inst: Zir.Inst.Ref,
- var_name_text: []const u8,
-) !void {
- if (gz.refIsNoReturn(init_inst)) {
- return astgen.failNodeNotes(
- var_node,
- "useless {s}",
- .{var_name_text},
- &[_]u32{
- try astgen.errNoteNode(
- init_node,
- "control flow is diverted here",
- .{},
- ),
- },
- );
- }
-}