| author | |
| committer | |
| log | 9a9a7daef0aff340e029fb9bb6d29361a3d7e767 |
| tree | ee3b87c09113bb012f9fd0b530ca77f5bcc2664e |
| parent | 0435026474cc3489337f3d6a7ac9d2e5cb1b7044 |
| parent | 741c74e427a9502d7e074b2737016cc61bc29b44 |
| signature |
5 files changed, 40 insertions(+), 13 deletions(-)
std/special/start.zig+21-11| ... | @@ -125,10 +125,13 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { | ... | @@ -125,10 +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 | switch (@typeId(@typeOf(root.main).ReturnType)) { | 134 | switch (@typeInfo(@typeOf(root.main).ReturnType)) { |
| 132 | .NoReturn => { | 135 | .NoReturn => { |
| 133 | root.main(); | 136 | root.main(); |
| 134 | }, | 137 | }, |
| ... | @@ -136,25 +139,32 @@ inline fn callMain() u8 { | ... | @@ -136,25 +139,32 @@ inline fn callMain() u8 { |
| 136 | root.main(); | 139 | root.main(); |
| 137 | return 0; | 140 | return 0; |
| 138 | }, | 141 | }, |
| 139 | .Int => { | 142 | .Int => |info| { |
| 140 | if (@typeOf(root.main).ReturnType.bit_count != 8) { | 143 | if (info.bits != 8) { |
| 141 | @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); | 144 | @compileError(bad_main_ret); |
| 142 | } | 145 | } |
| 143 | return root.main(); | 146 | return root.main(); |
| 144 | }, | 147 | }, |
| 145 | .ErrorUnion => { | 148 | .ErrorUnion => { |
| 146 | root.main() catch |err| { | 149 | const result = root.main() catch |err| { |
| 147 | std.debug.warn("error: {}\n", @errorName(err)); | 150 | std.debug.warn("error: {}\n", @errorName(err)); |
| 148 | if (builtin.os != builtin.Os.zen) { | 151 | if (@errorReturnTrace()) |trace| { |
| 149 | if (@errorReturnTrace()) |trace| { | 152 | std.debug.dumpStackTrace(trace.*); |
| 150 | std.debug.dumpStackTrace(trace.*); | ||
| 151 | } | ||
| 152 | } | 153 | } |
| 153 | return 1; | 154 | return 1; |
| 154 | }; | 155 | }; |
| 155 | return 0; | 156 | switch (@typeInfo(@typeOf(result))) { |
| 157 | .Void => return 0, | ||
| 158 | .Int => |info| { | ||
| 159 | if (info.bits != 8) { | ||
| 160 | @compileError(bad_main_ret); | ||
| 161 | } | ||
| 162 | return result; | ||
| 163 | }, | ||
| 164 | else => @compileError(bad_main_ret), | ||
| 165 | } | ||
| 156 | }, | 166 | }, |
| 157 | else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), | 167 | else => @compileError(bad_main_ret), |
| 158 | } | 168 | } |
| 159 | } | 169 | } |
| 160 | 170 |
test/build_examples.zig+2| ... | @@ -7,6 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void { | ... | @@ -7,6 +7,8 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void { |
| 7 | cases.addC("example/hello_world/hello_libc.zig"); | 7 | cases.addC("example/hello_world/hello_libc.zig"); |
| 8 | cases.add("example/cat/main.zig"); | 8 | cases.add("example/cat/main.zig"); |
| 9 | cases.add("example/guess_number/main.zig"); | 9 | cases.add("example/guess_number/main.zig"); |
| 10 | cases.add("test/standalone/main_return_error/error_u8.zig"); | ||
| 11 | cases.add("test/standalone/main_return_error/error_u8_non_zero.zig"); | ||
| 10 | cases.addBuildFile("test/standalone/main_pkg_path/build.zig"); | 12 | cases.addBuildFile("test/standalone/main_pkg_path/build.zig"); |
| 11 | cases.addBuildFile("example/shared_library/build.zig"); | 13 | cases.addBuildFile("example/shared_library/build.zig"); |
| 12 | cases.addBuildFile("example/mix_o_files/build.zig"); | 14 | cases.addBuildFile("example/mix_o_files/build.zig"); |
test/compile_errors.zig+2-2| ... | @@ -2247,7 +2247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -2247,7 +2247,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2247 | "wrong return type for main", | 2247 | "wrong return type for main", |
| 2248 | \\pub fn main() f32 { } | 2248 | \\pub fn main() f32 { } |
| 2249 | , | 2249 | , |
| 2250 | "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'", | 2250 | "error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'", |
| 2251 | ); | 2251 | ); |
| 2252 | 2252 | ||
| 2253 | cases.add( | 2253 | cases.add( |
| ... | @@ -2255,7 +2255,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -2255,7 +2255,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2255 | \\pub fn main() ??void { | 2255 | \\pub fn main() ??void { |
| 2256 | \\} | 2256 | \\} |
| 2257 | , | 2257 | , |
| 2258 | "error: expected return type of main to be 'u8', 'noreturn', 'void', or '!void'", | 2258 | "error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'", |
| 2259 | ); | 2259 | ); |
| 2260 | 2260 | ||
| 2261 | cases.add( | 2261 | cases.add( |
test/standalone/main_return_error/error_u8.zig created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | const Err = error { | ||
| 2 | Foo | ||
| 3 | }; | ||
| 4 | |||
| 5 | pub fn main() !u8 { | ||
| 6 | return Err.Foo; | ||
| 7 | } | ||
test/standalone/main_return_error/error_u8_non_zero.zig created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | const Err = error { Foo }; | ||
| 2 | |||
| 3 | fn foo() u8 { var x = @intCast(u8, 9); return x; } | ||
| 4 | |||
| 5 | pub fn main() !u8 { | ||
| 6 | if (foo() == 7) return Err.Foo; | ||
| 7 | return 123; | ||
| 8 | } | ||