diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 2d17765ccb..a172a4b679 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1345,8 +1345,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { _ = try astgen.blockExpr(self, params_scope, .none, body_block); - if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or - !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())) + if (gen_scope.instructions.items.len == 0 or + !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()) { const src = tree.token_locs[body_block.rbrace].start; _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid); diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 97c47db9b6..862df4ec9a 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -112,8 +112,17 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! } pub fn analyzeBody(mod: *Module, scope: *Scope, body: zir.Module.Body) !void { - for (body.instructions) |src_inst| { - src_inst.analyzed_inst = try analyzeInst(mod, scope, src_inst); + for (body.instructions) |src_inst, i| { + const analyzed_inst = try analyzeInst(mod, scope, src_inst); + src_inst.analyzed_inst = analyzed_inst; + if (analyzed_inst.ty.zigTypeTag() == .NoReturn) { + for (body.instructions[i..]) |unreachable_inst| { + if (unreachable_inst.castTag(.dbg_stmt)) |dbg_stmt| { + return mod.fail(scope, dbg_stmt.base.src, "unreachable code", .{}); + } + } + break; + } } } @@ -1216,6 +1225,15 @@ fn analyzeInstRet(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError! fn analyzeInstRetVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst { const b = try mod.requireRuntimeBlock(scope, inst.base.src); + if (b.func) |func| { + // Need to emit a compile error if returning void is not allowed. + const void_inst = try mod.constVoid(scope, inst.base.src); + const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty; + const casted_void = try mod.coerce(scope, fn_ty.fnReturnType(), void_inst); + if (casted_void.ty.zigTypeTag() != .Void) { + return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, casted_void); + } + } return mod.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .retvoid); } diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig index 5e2d56b5ed..0608221866 100644 --- a/test/stage2/cbe.zig +++ b/test/stage2/cbe.zig @@ -10,13 +10,19 @@ const linux_x64 = std.zig.CrossTarget{ pub fn addCases(ctx: *TestContext) !void { ctx.c("empty start function", linux_x64, - \\export fn _start() noreturn {} + \\export fn _start() noreturn { + \\ unreachable; + \\} , - \\zig_noreturn void _start(void) {} + \\zig_noreturn void _start(void) { + \\ zig_unreachable(); + \\} \\ ); ctx.c("less empty start function", linux_x64, - \\fn main() noreturn {} + \\fn main() noreturn { + \\ unreachable; + \\} \\ \\export fn _start() noreturn { \\ main(); @@ -28,7 +34,9 @@ pub fn addCases(ctx: *TestContext) !void { \\ main(); \\} \\ - \\zig_noreturn void main(void) {} + \\zig_noreturn void main(void) { + \\ zig_unreachable(); + \\} \\ ); // TODO: implement return values @@ -40,6 +48,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ : [number] "{rax}" (231), \\ [arg1] "{rdi}" (0) \\ ); + \\ unreachable; \\} \\ \\export fn _start() noreturn { @@ -62,6 +71,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ register size_t rax_constant __asm__("rax") = 231; \\ register size_t rdi_constant __asm__("rdi") = 0; \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant)); + \\ zig_unreachable(); \\} \\ ); diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index f151880225..4664d001fd 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -26,6 +26,11 @@ pub fn addCases(ctx: *TestContext) !void { case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); + case.addError( + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + // Regular old hello world case.addCompareOutput( \\export fn _start() noreturn {