Commit f20e449fd6
Changed files (11)
test
cases
aarch64-macos
x86_64-linux
x86_64-macos
x86_64-windows
src/AstGen.zig
@@ -2632,7 +2632,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.compile_error,
.ret_node,
.ret_load,
- .ret_tok,
+ .ret_implicit,
.ret_err_value,
.@"unreachable",
.repeat,
@@ -3914,9 +3914,8 @@ fn fnDecl(
// As our last action before the return, "pop" the error trace if needed
_ = try gz.addRestoreErrRetIndex(.ret, .always);
- // Since we are adding the return instruction here, we must handle the coercion.
- // We do this by using the `ret_tok` instruction.
- _ = try fn_gz.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node));
+ // Add implicit return at end of function.
+ _ = try fn_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
}
break :func try decl_gz.addFunc(.{
@@ -4334,9 +4333,8 @@ fn testDecl(
// As our last action before the return, "pop" the error trace if needed
_ = try gz.addRestoreErrRetIndex(.ret, .always);
- // Since we are adding the return instruction here, we must handle the coercion.
- // We do this by using the `ret_tok` instruction.
- _ = try fn_block.addUnTok(.ret_tok, .void_value, tree.lastToken(body_node));
+ // Add implicit return at end of function.
+ _ = try fn_block.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
}
const func_inst = try decl_block.addFunc(.{
src/print_zir.zig
@@ -235,7 +235,7 @@ const Writer = struct {
=> try self.writeUnNode(stream, inst),
.ref,
- .ret_tok,
+ .ret_implicit,
.closure_capture,
.switch_capture_tag,
=> try self.writeUnTok(stream, inst),
src/Sema.zig
@@ -1098,7 +1098,7 @@ fn analyzeBodyInner(
// These functions match the return type of analyzeBody so that we can
// tail call them here.
.compile_error => break sema.zirCompileError(block, inst),
- .ret_tok => break sema.zirRetTok(block, inst),
+ .ret_implicit => break sema.zirRetImplicit(block, inst),
.ret_node => break sema.zirRetNode(block, inst),
.ret_load => break sema.zirRetLoad(block, inst),
.ret_err_value => break sema.zirRetErrValue(block, inst),
@@ -16546,7 +16546,7 @@ fn zirRetErrValue(
return sema.analyzeRet(block, result_inst, src);
}
-fn zirRetTok(
+fn zirRetImplicit(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
@@ -16556,9 +16556,33 @@ fn zirRetTok(
const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
const operand = try sema.resolveInst(inst_data.operand);
- const src = inst_data.src();
- return sema.analyzeRet(block, operand, src);
+ const r_brace_src = inst_data.src();
+ const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
+ const base_tag = sema.fn_ret_ty.baseZigTypeTag();
+ if (base_tag == .NoReturn) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{
+ sema.fn_ret_ty.fmt(sema.mod),
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ } else if (base_tag != .Void) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{
+ sema.fn_ret_ty.fmt(sema.mod),
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+
+ return sema.analyzeRet(block, operand, .unneeded);
}
fn zirRetNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
src/type.zig
@@ -160,6 +160,17 @@ pub const Type = extern union {
}
}
+ pub fn baseZigTypeTag(self: Type) std.builtin.TypeId {
+ return switch (self.zigTypeTag()) {
+ .ErrorUnion => self.errorUnionPayload().baseZigTypeTag(),
+ .Optional => {
+ var buf: Payload.ElemType = undefined;
+ return self.optionalChild(&buf).baseZigTypeTag();
+ },
+ else => |t| t,
+ };
+ }
+
pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool {
return switch (ty.zigTypeTag()) {
.Int,
src/Zir.zig
@@ -519,7 +519,7 @@ pub const Inst = struct {
/// Includes an operand as the return value.
/// Includes a token source location.
/// Uses the `un_tok` union field.
- ret_tok,
+ ret_implicit,
/// Sends control flow back to the function's callee.
/// The return operand is `error.foo` where `foo` is given by the string.
/// If the current function has an inferred error set, the error given by the
@@ -1256,7 +1256,7 @@ pub const Inst = struct {
.compile_error,
.ret_node,
.ret_load,
- .ret_tok,
+ .ret_implicit,
.ret_err_value,
.@"unreachable",
.repeat,
@@ -1530,7 +1530,7 @@ pub const Inst = struct {
.compile_error,
.ret_node,
.ret_load,
- .ret_tok,
+ .ret_implicit,
.ret_err_value,
.ret_ptr,
.ret_type,
@@ -1659,7 +1659,7 @@ pub const Inst = struct {
.ref = .un_tok,
.ret_node = .un_node,
.ret_load = .un_node,
- .ret_tok = .un_tok,
+ .ret_implicit = .un_tok,
.ret_err_value = .str_tok,
.ret_err_value_code = .str_tok,
.ret_ptr = .node,
test/cases/aarch64-macos/hello_world_with_updates.1.zig
@@ -2,5 +2,5 @@ pub export fn main() noreturn {}
// error
//
-// :1:32: error: function declared 'noreturn' returns
-// :1:22: note: 'noreturn' declared here
+// :1:22: error: function declared 'noreturn' implicitly returns
+// :1:32: note: control flow reaches end of body here
test/cases/compile_errors/control_reaches_end_of_non-void_function.zig
@@ -1,9 +0,0 @@
-fn a() i32 {}
-export fn entry() void { _ = a(); }
-
-// error
-// backend=stage2
-// target=native
-//
-// :1:13: error: expected type 'i32', found 'void'
-// :1:8: note: function return type declared here
test/cases/compile_errors/type_error_in_implicit_return.zig
@@ -0,0 +1,17 @@
+fn f1(x: bool) u32 {
+ if (x) return 1;
+}
+fn f2() noreturn {}
+pub export fn entry() void {
+ _ = f1(true);
+ _ = f2();
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :1:16: error: function with non-void return type 'u32' implicitly returns
+// :3:1: note: control flow reaches end of body here
+// :4:9: error: function declared 'noreturn' implicitly returns
+// :4:19: note: control flow reaches end of body here
test/cases/x86_64-linux/hello_world_with_updates.1.zig
@@ -1,6 +1,6 @@
-pub export fn _start() noreturn {}
+pub export fn main() noreturn {}
// error
//
-// :1:34: error: function declared 'noreturn' returns
-// :1:24: note: 'noreturn' declared here
+// :1:22: error: function declared 'noreturn' implicitly returns
+// :1:32: note: control flow reaches end of body here
test/cases/x86_64-macos/hello_world_with_updates.1.zig
@@ -2,5 +2,5 @@ pub export fn main() noreturn {}
// error
//
-// :1:32: error: function declared 'noreturn' returns
-// :1:22: note: 'noreturn' declared here
+// :1:22: error: function declared 'noreturn' implicitly returns
+// :1:32: note: control flow reaches end of body here
test/cases/x86_64-windows/hello_world_with_updates.1.zig
@@ -2,5 +2,5 @@ pub export fn main() noreturn {}
// error
//
-// :1:32: error: function declared 'noreturn' returns
-// :1:22: note: 'noreturn' declared here
+// :1:22: error: function declared 'noreturn' implicitly returns
+// :1:32: note: control flow reaches end of body here