From f24b8f2a4a8ffc014231e6f294153ff05be16f38 Mon Sep 17 00:00:00 2001 From: SamTebbs33 Date: Fri, 21 Jun 2019 00:29:47 +0100 Subject: [PATCH 1/2] Support returning !u8 from main --- std/special/start.zig | 34 ++++++++++++------- test/build_examples.zig | 2 ++ test/compile_errors.zig | 4 +-- .../standalone/main_return_error/error_u8.zig | 7 ++++ .../main_return_error/error_u8_non_zero.zig | 8 +++++ 5 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 test/standalone/main_return_error/error_u8.zig create mode 100644 test/standalone/main_return_error/error_u8_non_zero.zig diff --git a/std/special/start.zig b/std/special/start.zig index f2572def05..02fa271d2c 100644 --- a/std/special/start.zig +++ b/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), } } diff --git a/test/build_examples.zig b/test/build_examples.zig index d38336939d..4733a25b64 100644 --- a/test/build_examples.zig +++ b/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"); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e0ac76bbf0..6631200210 100644 --- a/test/compile_errors.zig +++ b/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( diff --git a/test/standalone/main_return_error/error_u8.zig b/test/standalone/main_return_error/error_u8.zig new file mode 100644 index 0000000000..4edac26afd --- /dev/null +++ b/test/standalone/main_return_error/error_u8.zig @@ -0,0 +1,7 @@ +const Err = error { + Foo +}; + +pub fn main() !u8 { + return Err.Foo; +} diff --git a/test/standalone/main_return_error/error_u8_non_zero.zig b/test/standalone/main_return_error/error_u8_non_zero.zig new file mode 100644 index 0000000000..703a19b314 --- /dev/null +++ b/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; +} From 741c74e427a9502d7e074b2737016cc61bc29b44 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 16 Jul 2019 11:50:00 -0400 Subject: [PATCH 2/2] cleanups --- std/special/start.zig | 50 ++++++++++++++++++++--------------------- test/compile_errors.zig | 4 ++-- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/std/special/start.zig b/std/special/start.zig index f2fe27e26c..30298669e3 100644 --- a/std/special/start.zig +++ b/std/special/start.zig @@ -125,13 +125,13 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); } +// General error message for a malformed return type +const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'"; + // 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)) { + switch (@typeInfo(@typeOf(root.main).ReturnType)) { .NoReturn => { root.main(); }, @@ -139,32 +139,32 @@ inline fn callMain() u8 { root.main(); return 0; }, - .Int => { - if (@typeOf(root.main).ReturnType.bit_count != 8) { - @compileError(compile_err); + .Int => |info| { + if (info.bits != 8) { + @compileError(bad_main_ret); } return root.main(); }, - 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.*); - } + .ErrorUnion => { + const result = root.main() catch |err| { + std.debug.warn("error: {}\n", @errorName(err)); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + return 1; + }; + switch (@typeInfo(@typeOf(result))) { + .Void => return 0, + .Int => |info| { + if (info.bits != 8) { + @compileError(bad_main_ret); } - return 1; - }; - // If main didn't error, return 0 or the exit code - return if (PayloadType == void) 0 else tmp; - } else @compileError(payload_err); + return result; + }, + else => @compileError(bad_main_ret), + } }, - else => @compileError(compile_err), + else => @compileError(bad_main_ret), } } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 86c7b7f1f1..fd365235d8 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2247,7 +2247,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', '!void', or '!u8'", + "error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'", ); cases.add( @@ -2255,7 +2255,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\pub fn main() ??void { \\} , - "error: expected return type of main to be 'u8', 'noreturn', 'void', '!void', or '!u8'", + "error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'", ); cases.add(