Commit f24b8f2a4a

SamTebbs33 <samuel.tebbs@gmail.com>
2019-06-21 01:29:47
Support returning !u8 from main
1 parent 57d6724
Changed files (5)
std/special/start.zig
@@ -121,6 +121,9 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 {
 // This is marked inline because for some reason LLVM in release mode fails to inline it,
 // and we want fewer call frames in stack traces.
 inline fn callMain() u8 {
+    // General error message for a malformed return type
+    const compile_err_prefix = "expected return type of main to be 'u8', 'noreturn', 'void', '!void', or '!u8', found '";
+    const compile_err = compile_err_prefix ++ @typeName(@typeOf(root.main).ReturnType) ++ "'";
     switch (@typeId(@typeOf(root.main).ReturnType)) {
         .NoReturn => {
             root.main();
@@ -131,23 +134,30 @@ inline fn callMain() u8 {
         },
         .Int => {
             if (@typeOf(root.main).ReturnType.bit_count != 8) {
-                @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
+                @compileError(compile_err);
             }
             return root.main();
         },
-        .ErrorUnion => {
-            root.main() catch |err| {
-                std.debug.warn("error: {}\n", @errorName(err));
-                if (builtin.os != builtin.Os.zen) {
-                    if (@errorReturnTrace()) |trace| {
-                        std.debug.dumpStackTrace(trace.*);
+        builtin.TypeId.ErrorUnion => {
+            const PayloadType = @typeOf(root.main).ReturnType.Payload;
+            // In this case the error should include the payload type
+            const payload_err = compile_err_prefix ++ "!" ++ @typeName(PayloadType) ++ "'";
+            // If the payload is void or a u8
+            if (@typeId(PayloadType) == builtin.TypeId.Void or (@typeId(PayloadType) == builtin.TypeId.Int and PayloadType.bit_count == 8)) {
+                const tmp = root.main() catch |err| {
+                    std.debug.warn("error: {}\n", @errorName(err));
+                    if (builtin.os != builtin.Os.zen) {
+                        if (@errorReturnTrace()) |trace| {
+                            std.debug.dumpStackTrace(trace.*);
+                        }
                     }
-                }
-                return 1;
-            };
-            return 0;
+                    return 1;
+                };
+                // If main didn't error, return 0 or the exit code
+                return if (PayloadType == void) 0 else tmp;
+            } else @compileError(payload_err);
         },
-        else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"),
+        else => @compileError(compile_err),
     }
 }
 
test/standalone/main_return_error/error_u8.zig
@@ -0,0 +1,7 @@
+const Err = error {
+    Foo
+};
+
+pub fn main() !u8 {
+    return Err.Foo;
+}
test/standalone/main_return_error/error_u8_non_zero.zig
@@ -0,0 +1,8 @@
+const Err = error { Foo };
+
+fn foo() u8 { var x = @intCast(u8, 9); return x; }
+
+pub fn main() !u8 {
+    if (foo() == 7) return Err.Foo;
+    return 123;
+}
test/build_examples.zig
@@ -7,6 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
     cases.addC("example/hello_world/hello_libc.zig");
     cases.add("example/cat/main.zig");
     cases.add("example/guess_number/main.zig");
+    cases.add("test/standalone/main_return_error/error_u8.zig");
+    cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
     cases.addBuildFile("test/standalone/main_pkg_path/build.zig");
     cases.addBuildFile("example/shared_library/build.zig");
     cases.addBuildFile("example/mix_o_files/build.zig");
test/compile_errors.zig
@@ -2213,7 +2213,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         "wrong return type for main",
         \\pub fn main() f32 { }
     ,
-        "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'",
+        "error: expected return type of main to be 'u8', 'noreturn', 'void', '!void', or '!u8'",
     );
 
     cases.add(
@@ -2221,7 +2221,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\pub fn main() ??void {
         \\}
     ,
-        "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'",
+        "error: expected return type of main to be 'u8', 'noreturn', 'void', '!void', or '!u8'",
     );
 
     cases.add(