Commit 25b1c00c72

Andrew Kelley <andrew@ziglang.org>
2020-07-13 08:50:25
stage2: add implicit return void where applicable
1 parent c306392
Changed files (4)
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 {
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) },
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()) {
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 {