| ... | @@ -125,13 +125,13 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { | ... | @@ -125,13 +125,13 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { |
| 125 | return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); | 125 | return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); |
| 126 | } | 126 | } |
| 127 | | 127 | |
| | 128 | // General error message for a malformed return type |
| | 129 | const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'"; |
| | 130 | |
| 128 | // This is marked inline because for some reason LLVM in release mode fails to inline it, | 131 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 129 | // and we want fewer call frames in stack traces. | 132 | // and we want fewer call frames in stack traces. |
| 130 | inline fn callMain() u8 { | 133 | inline fn callMain() u8 { |
| 131 | // General error message for a malformed return type | 134 | switch (@typeInfo(@typeOf(root.main).ReturnType)) { |
| 132 | const compile_err_prefix = "expected return type of main to be 'u8', 'noreturn', 'void', '!void', or '!u8', found '"; | | |
| 133 | const compile_err = compile_err_prefix ++ @typeName(@typeOf(root.main).ReturnType) ++ "'"; | | |
| 134 | switch (@typeId(@typeOf(root.main).ReturnType)) { | | |
| 135 | .NoReturn => { | 135 | .NoReturn => { |
| 136 | root.main(); | 136 | root.main(); |
| 137 | }, | 137 | }, |
| ... | @@ -139,32 +139,32 @@ inline fn callMain() u8 { | ... | @@ -139,32 +139,32 @@ inline fn callMain() u8 { |
| 139 | root.main(); | 139 | root.main(); |
| 140 | return 0; | 140 | return 0; |
| 141 | }, | 141 | }, |
| 142 | .Int => { | 142 | .Int => |info| { |
| 143 | if (@typeOf(root.main).ReturnType.bit_count != 8) { | 143 | if (info.bits != 8) { |
| 144 | @compileError(compile_err); | 144 | @compileError(bad_main_ret); |
| 145 | } | 145 | } |
| 146 | return root.main(); | 146 | return root.main(); |
| 147 | }, | 147 | }, |
| 148 | builtin.TypeId.ErrorUnion => { | 148 | .ErrorUnion => { |
| 149 | const PayloadType = @typeOf(root.main).ReturnType.Payload; | 149 | const result = root.main() catch |err| { |
| 150 | // In this case the error should include the payload type | 150 | std.debug.warn("error: {}\n", @errorName(err)); |
| 151 | const payload_err = compile_err_prefix ++ "!" ++ @typeName(PayloadType) ++ "'"; | 151 | if (@errorReturnTrace()) |trace| { |
| 152 | // If the payload is void or a u8 | 152 | std.debug.dumpStackTrace(trace.*); |
| 153 | if (@typeId(PayloadType) == builtin.TypeId.Void or (@typeId(PayloadType) == builtin.TypeId.Int and PayloadType.bit_count == 8)) { | 153 | } |
| 154 | const tmp = root.main() catch |err| { | 154 | return 1; |
| 155 | std.debug.warn("error: {}\n", @errorName(err)); | 155 | }; |
| 156 | if (builtin.os != builtin.Os.zen) { | 156 | switch (@typeInfo(@typeOf(result))) { |
| 157 | if (@errorReturnTrace()) |trace| { | 157 | .Void => return 0, |
| 158 | std.debug.dumpStackTrace(trace.*); | 158 | .Int => |info| { |
| 159 | } | 159 | if (info.bits != 8) { |
| | 160 | @compileError(bad_main_ret); |
| 160 | } | 161 | } |
| 161 | return 1; | 162 | return result; |
| 162 | }; | 163 | }, |
| 163 | // If main didn't error, return 0 or the exit code | 164 | else => @compileError(bad_main_ret), |
| 164 | return if (PayloadType == void) 0 else tmp; | 165 | } |
| 165 | } else @compileError(payload_err); | | |
| 166 | }, | 166 | }, |
| 167 | else => @compileError(compile_err), | 167 | else => @compileError(bad_main_ret), |
| 168 | } | 168 | } |
| 169 | } | 169 | } |
| 170 | | 170 | |