diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index bb8eca5ccf..03307ab96d 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1210,6 +1210,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { try self.astGenBlock(&gen_scope.base, body_block); + const last_inst = gen_scope.instructions.items[gen_scope.instructions.items.len - 1]; + if (!last_inst.tag.isNoReturn()) { + const src = tree.token_locs[body_block.rbrace].start; + _ = try self.addZIRInst(&gen_scope.base, src, zir.Inst.ReturnVoid, .{}, .{}); + } + const fn_zir = try gen_scope_arena.allocator.create(Fn.ZIR); fn_zir.* = .{ .body = .{ @@ -2686,7 +2692,7 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr // Blocks must terminate with noreturn instruction. assert(child_block.instructions.items.len != 0); - assert(child_block.instructions.items[child_block.instructions.items.len - 1].tag.isNoReturn()); + assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn()); // Need to set the type and emit the Block instruction. This allows machine code generation // to emit a jump instruction to after the block when it encounters the break. @@ -3271,7 +3277,7 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner defer false_block.instructions.deinit(self.gpa); try self.analyzeBody(&false_block.base, inst.positionals.false_body); - return self.addNewInstArgs(parent_block, inst.base.src, Type.initTag(.void), Inst.CondBr, Inst.Args(Inst.CondBr){ + return self.addNewInstArgs(parent_block, inst.base.src, Type.initTag(.noreturn), Inst.CondBr, Inst.Args(Inst.CondBr){ .condition = cond, .true_body = .{ .instructions = try scope.arena().dupe(*Inst, true_block.instructions.items) }, .false_body = .{ .instructions = try scope.arena().dupe(*Inst, false_block.instructions.items) }, diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 094b877b53..74da3430a7 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -60,36 +60,6 @@ pub const Inst = struct { retvoid, sub, unreach, - - /// Returns whether the instruction is one of the control flow "noreturn" types. - /// Function calls do not count. When ZIR is generated, the compiler automatically - /// emits an `Unreach` after a function call with the `noreturn` return type. - pub fn isNoReturn(tag: Tag) bool { - return switch (tag) { - .add, - .arg, - .assembly, - .bitcast, - .block, - .breakpoint, - .call, - .cmp, - .constant, - .isnonnull, - .isnull, - .ptrtoint, - .sub, - => false, - - .br, - .brvoid, - .condbr, - .ret, - .retvoid, - .unreach, - => true, - }; - } }; pub fn cast(base: *Inst, comptime T: type) ?*T { diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index c0d88b1414..512dd631a7 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -468,6 +468,10 @@ pub const Type = extern union { }; } + pub fn isNoReturn(self: Type) bool { + return self.zigTypeTag() == .NoReturn; + } + /// Asserts that hasCodeGenBits() is true. pub fn abiAlignment(self: Type, target: Target) u32 { return switch (self.tag()) { diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 8faf248636..0dfbdd20a0 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -81,6 +81,52 @@ pub const Inst = struct { condbr, isnull, isnonnull, + + /// Returns whether the instruction is one of the control flow "noreturn" types. + /// Function calls do not count. + pub fn isNoReturn(tag: Tag) bool { + return switch (tag) { + .arg, + .block, + .breakpoint, + .call, + .@"const", + .declref, + .declref_str, + .declval, + .declval_in_module, + .str, + .int, + .inttype, + .ptrtoint, + .fieldptr, + .deref, + .as, + .@"asm", + .@"fn", + .fntype, + .@"export", + .primitive, + .intcast, + .bitcast, + .elemptr, + .add, + .sub, + .cmp, + .isnull, + .isnonnull, + => false, + + .condbr, + .@"unreachable", + .@"return", + .returnvoid, + .@"break", + .breakvoid, + .compileerror, + => true, + }; + } }; pub fn TagToType(tag: Tag) type {