From a0ca30ce014f4abd9d31ea335e8860fd1b110495 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 30 Nov 2019 15:39:11 +0200 Subject: [PATCH 1/9] move more startup code to std lib --- lib/std/builtin.zig | 16 +++++++++ lib/std/special/start.zig | 55 ++++++++++++++++++++++++------- lib/std/special/start_lib.zig | 21 ------------ src/all_types.hpp | 2 -- src/analyze.cpp | 38 ---------------------- src/codegen.cpp | 61 ++++++++++++----------------------- 6 files changed, 79 insertions(+), 114 deletions(-) delete mode 100644 lib/std/special/start_lib.zig diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 689c5cd898..789880dd88 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -348,6 +348,22 @@ pub const Endian = enum { Little, }; +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const OutType = enum { + Unknown, + Exe, + Lib, + Obj, +}; + +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const LinkType = enum { + Static, + Dynamic, +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Version = struct { diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index 6d99618d2e..478876c689 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -19,21 +19,52 @@ const is_mips = switch (builtin.arch) { }; comptime { - if (builtin.link_libc) { - @export("main", main, .Strong); - } else if (builtin.os == .windows) { - @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); - } else if (is_wasm and builtin.os == .freestanding) { - @export("_start", wasm_freestanding_start, .Strong); - } else if (builtin.os == .uefi) { - @export("EfiMain", EfiMain, .Strong); - } else if (is_mips) { - if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong); - } else { - if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong); + switch (builtin.output_type) { + .Unknown => unreachable, + .Exe => { + if (builtin.link_libc) { + if (!@hasDecl(root, "main") or + @typeInfo(@typeOf(root.main)).Fn.calling_convention != .C) + { + @export("main", main, .Weak); + } + } else if (builtin.os == .windows) { + if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) { + @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); + } + } else if (is_wasm and builtin.os == .freestanding) { + if (!@hasDecl(root, "_start")) @export("_start", wasm_freestanding_start, .Strong); + } else if (builtin.os == .uefi) { + if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong); + } else if (is_mips) { + if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong); + } else { + if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong); + } + }, + .Lib => { + if (builtin.os == .windows and builtin.link_type == .Dynamic and + !@hasDecl(root, "_DllMainCRTStartup")) + { + @export("_DllMainCRTStartup", _DllMainCRTStartup, .Strong); + } + }, + .Obj => {}, } } +stdcallcc fn _DllMainCRTStartup( + hinstDLL: std.os.windows.HINSTANCE, + fdwReason: std.os.windows.DWORD, + lpReserved: std.os.windows.LPVOID, +) std.os.windows.BOOL { + if (@hasDecl(root, "DllMain")) { + return root.DllMain(hinstDLL, fdwReason, lpReserved); + } + + return std.os.windows.TRUE; +} + extern fn wasm_freestanding_start() void { // 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. diff --git a/lib/std/special/start_lib.zig b/lib/std/special/start_lib.zig deleted file mode 100644 index 994bc14fd5..0000000000 --- a/lib/std/special/start_lib.zig +++ /dev/null @@ -1,21 +0,0 @@ -// This file is included in the compilation unit when exporting a DLL on windows. - -const root = @import("root"); -const std = @import("std"); -const builtin = @import("builtin"); - -comptime { - @export("_DllMainCRTStartup", _DllMainCRTStartup, builtin.GlobalLinkage.Strong); -} - -stdcallcc fn _DllMainCRTStartup( - hinstDLL: std.os.windows.HINSTANCE, - fdwReason: std.os.windows.DWORD, - lpReserved: std.os.windows.LPVOID, -) std.os.windows.BOOL { - if (@hasDecl(root, "DllMain")) { - return root.DllMain(hinstDLL, fdwReason, lpReserved); - } - - return std.os.windows.TRUE; -} diff --git a/src/all_types.hpp b/src/all_types.hpp index 5a248f9cd2..b6310b02fb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2061,7 +2061,6 @@ struct CodeGen { ZigList global_vars; ZigFn *cur_fn; - ZigFn *main_fn; ZigFn *panic_fn; ZigFn *largest_frame_fn; @@ -2081,7 +2080,6 @@ struct CodeGen { uint32_t target_abi_index; uint32_t target_oformat_index; bool is_big_endian; - bool have_pub_main; bool have_c_main; bool have_winmain; bool have_winmain_crt_startup; diff --git a/src/analyze.cpp b/src/analyze.cpp index 7d75bef7d9..d616148596 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3304,17 +3304,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { return fn_entry; } -static bool scope_is_root_decls(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdDecls) { - ScopeDecls *scope_decls = (ScopeDecls *)scope; - return is_top_level_struct(scope_decls->container_type); - } - scope = scope->parent; - } - zig_unreachable(); -} - ZigType *get_test_fn_type(CodeGen *g) { if (g->test_fn_type) return g->test_fn_type; @@ -3353,7 +3342,6 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, G } static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { - ZigType *import = tld_fn->base.import; AstNode *source_node = tld_fn->base.source_node; if (source_node->type == NodeTypeFnProto) { AstNodeFnProto *fn_proto = &source_node->data.fn_proto; @@ -3433,12 +3421,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) { fn_table_entry->inferred_async_node = fn_table_entry->proto_node; } - - if (scope_is_root_decls(tld_fn->base.parent_scope) && import == g->root_import) { - if (g->have_pub_main && buf_eql_str(tld_fn->base.name, "main")) { - g->main_fn = fn_table_entry; - } - } } else if (source_node->type == NodeTypeTestDecl) { ZigFn *fn_table_entry = create_fn_raw(g, FnInlineAuto); @@ -4813,26 +4795,6 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu ast_print(stderr, root_node, 0); } - if (source_kind == SourceKindRoot) { - // Look for main - for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) { - AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i); - - if (top_level_decl->type == NodeTypeFnDef) { - AstNode *proto_node = top_level_decl->data.fn_def.fn_proto; - assert(proto_node->type == NodeTypeFnProto); - Buf *proto_name = proto_node->data.fn_proto.name; - - bool is_pub = (proto_node->data.fn_proto.visib_mod == VisibModPub); - if (is_pub) { - if (buf_eql_str(proto_name, "main")) { - g->have_pub_main = true; - } - } - } - } - } - for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) { AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i); scan_decls(g, import_entry->data.structure.decls_scope, top_level_decl); diff --git a/src/codegen.cpp b/src/codegen.cpp index dc29e8f4b1..e3aa8c3609 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8229,7 +8229,7 @@ TargetSubsystem detect_subsystem(CodeGen *g) { if (g->zig_target->os == OsWindows) { if (g->have_dllmain_crt_startup || (g->out_type == OutTypeLib && g->is_dynamic)) return TargetSubsystemAuto; - if (g->have_c_main || g->have_pub_main || g->is_test_build) + if (g->have_c_main || g->is_test_build) return TargetSubsystemConsole; if (g->have_winmain || g->have_winmain_crt_startup) return TargetSubsystemWindows; @@ -8375,6 +8375,24 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little"; buf_appendf(contents, "pub const endian = %s;\n", endian_str); } + const char *out_type = nullptr; + switch (g->out_type) { + case OutTypeUnknown: + out_type = "Unknown"; + break; + case OutTypeExe: + out_type = "Exe"; + break; + case OutTypeLib: + out_type = "Lib"; + break; + case OutTypeObj: + out_type = "Obj"; + break; + } + buf_appendf(contents, "pub const output_type = OutType.%s;\n", out_type); + const char *link_type = g->is_dynamic ? "Dynamic" : "Static"; + buf_appendf(contents, "pub const link_type = LinkType.%s;\n", link_type); buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); @@ -9148,38 +9166,6 @@ static Buf *get_resolved_root_src_path(CodeGen *g) { return resolved_path; } -static bool want_startup_code(CodeGen *g) { - // Test builds get handled separately. - if (g->is_test_build) - return false; - - // WASM freestanding can still have an entry point but other freestanding targets do not. - if (g->zig_target->os == OsFreestanding && !target_is_wasm(g->zig_target)) - return false; - - // Declaring certain export functions means skipping the start code - if (g->have_c_main || g->have_winmain || g->have_winmain_crt_startup) - return false; - - // If there is a pub main in the root source file, that means we need start code. - if (g->have_pub_main) { - return true; - } else { - if (g->zig_target->os == OsUefi) - return false; - } - - if (g->out_type == OutTypeExe) { - // For build-exe, we might add start code even though there is no pub main, so that the - // programmer gets the "no pub main" compile error. However if linking libc and there is - // a C source file, that might have main(). - return g->c_source_files.length == 0 || g->libc_link_lib == nullptr; - } - - // For objects and libraries, and we don't have pub main, no start code. - return false; -} - static void gen_root_source(CodeGen *g) { Buf *resolved_path = get_resolved_root_src_path(g); if (resolved_path == nullptr) @@ -9241,21 +9227,14 @@ static void gen_root_source(CodeGen *g) { assert(g->panic_fn != nullptr); } - if (!g->error_during_imports) { semantic_analyze(g); } report_errors_and_maybe_exit(g); - if (want_startup_code(g)) { + if (!g->is_test_build) { g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start.zig"); } - if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && - g->out_type == OutTypeLib && g->is_dynamic) - { - g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start_lib.zig"); - } - if (!g->error_during_imports) { semantic_analyze(g); } From 20bcdab462dc21dc912da3ce4deb432a81cbc3c5 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 30 Nov 2019 19:14:45 +0200 Subject: [PATCH 2/9] correct caching and add test for missing fn name --- src/codegen.cpp | 2 ++ test/compile_errors.zig | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/codegen.cpp b/src/codegen.cpp index e3aa8c3609..f41ea7abab 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8459,6 +8459,8 @@ static Error define_builtin_compile_vars(CodeGen *g) { cache_buf(&cache_hash, compiler_id); cache_int(&cache_hash, g->build_mode); cache_bool(&cache_hash, g->strip_debug_symbols); + cache_int(&cache_hash, g->out_type); + cache_bool(&cache_hash, g->is_dynamic); cache_bool(&cache_hash, g->is_test_build); cache_bool(&cache_hash, g->is_single_threaded); cache_int(&cache_hash, g->zig_target->is_native); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 65ff8e4540..d3d439aeaf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -6,6 +6,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\export async fn foo() void {} , "tmp.zig:1:1: error: exported function cannot be async"); + cases.addExe( + "main missing name", + \\pub fn (main) void {} + , + "tmp.zig:1:5: error: missing function name", + ); + cases.addCase(x: { var tc = cases.create("@newStackCall on unsupported target", \\export fn entry() void { From 621c08e692256af9b0cc5ef6438b0ecf547e2b38 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 1 Dec 2019 11:31:18 +0200 Subject: [PATCH 3/9] exported main must be pub --- lib/std/special/start.zig | 2 +- test/compare_output.zig | 8 ++++---- test/stage2/compare_output.zig | 4 ++-- test/standalone/hello_world/hello_libc.zig | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index 478876c689..33ecc6f1f0 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -23,7 +23,7 @@ comptime { .Unknown => unreachable, .Exe => { if (builtin.link_libc) { - if (!@hasDecl(root, "main") or + if (@hasDecl(root, "main") and @typeInfo(@typeOf(root.main)).Fn.calling_convention != .C) { @export("main", main, .Weak); diff --git a/test/compare_output.zig b/test/compare_output.zig index 03f71d380e..35687b6a6c 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -6,7 +6,7 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompareOutputContext) void { cases.addC("hello world with libc", \\const c = @cImport(@cInclude("stdio.h")); - \\export fn main(argc: c_int, argv: [*][*]u8) c_int { + \\pub export fn main(argc: c_int, argv: [*][*]u8) c_int { \\ _ = c.puts("Hello, world!"); \\ return 0; \\} @@ -139,7 +139,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ @cInclude("stdio.h"); \\}); \\ - \\export fn main(argc: c_int, argv: [*][*]u8) c_int { + \\pub export fn main(argc: c_int, argv: [*][*]u8) c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); @@ -286,7 +286,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ } \\} \\ - \\export fn main() c_int { + \\pub export fn main() c_int { \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; \\ \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn); @@ -314,7 +314,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ @cInclude("stdio.h"); \\}); \\ - \\export fn main(argc: c_int, argv: [*][*]u8) c_int { + \\pub export fn main(argc: c_int, argv: [*][*]u8) c_int { \\ if (is_windows) { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index a86811b27b..443ed7a0ee 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -5,7 +5,7 @@ pub fn addCases(ctx: *TestContext) !void { // hello world try ctx.testCompareOutputLibC( \\extern fn puts([*]const u8) void; - \\export fn main() c_int { + \\pub export fn main() c_int { \\ puts("Hello, world!"); \\ return 0; \\} @@ -14,7 +14,7 @@ pub fn addCases(ctx: *TestContext) !void { // function calling another function try ctx.testCompareOutputLibC( \\extern fn puts(s: [*]const u8) void; - \\export fn main() c_int { + \\pub export fn main() c_int { \\ return foo("OK"); \\} \\fn foo(s: [*]const u8) c_int { diff --git a/test/standalone/hello_world/hello_libc.zig b/test/standalone/hello_world/hello_libc.zig index c6f290f70e..5c0a233f1c 100644 --- a/test/standalone/hello_world/hello_libc.zig +++ b/test/standalone/hello_world/hello_libc.zig @@ -7,7 +7,7 @@ const c = @cImport({ const msg = "Hello, world!\n"; -export fn main(argc: c_int, argv: **u8) c_int { +pub export fn main(argc: c_int, argv: **u8) c_int { if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1; return 0; } From ffd21c586dbed40b991c5578b2b2ba7d12c72a8e Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 1 Dec 2019 14:27:28 +0200 Subject: [PATCH 4/9] fix tests --- test/compile_errors.zig | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d3d439aeaf..7e16f858ef 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -156,7 +156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:9:27: error: @atomicRmw on enum only works with .Xchg", ); - cases.add( + cases.addExe( "disallow coercion from non-null-terminated pointer to null-terminated pointer", \\extern fn puts(s: [*:0]const u8) c_int; \\pub fn main() void { @@ -876,7 +876,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:32: note: cast discards const qualifier", ); - cases.add( + cases.addExe( "overflow in enum value allocation", \\const Moo = enum(u8) { \\ Last = 255, @@ -3000,14 +3000,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:9: error: encountered @panic at compile-time", ); - cases.add( + cases.addExe( "wrong return type for main", \\pub fn main() f32 { } , "error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'", ); - cases.add( + cases.addExe( "double ?? on main return value", \\pub fn main() ??void { \\} @@ -4900,7 +4900,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:13: error: cannot assign to constant", ); - cases.add( + cases.addExe( "main function with bogus args type", \\pub fn main(args: [][]bogus) !void {} , @@ -5718,7 +5718,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:4:13: error: cannot continue out of defer expression", ); - cases.add( + cases.addExe( "calling a var args function only known at runtime", \\var foos = [_]fn(...) void { foo1, foo2 }; \\ @@ -5732,7 +5732,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:9: error: calling a generic function requires compile-time known function value", ); - cases.add( + cases.addExe( "calling a generic function only known at runtime", \\var foos = [_]fn(var) void { foo1, foo2 }; \\ @@ -6850,7 +6850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:23: error: vector element type must be integer, float, bool, or pointer; 'comptime_int' is invalid", ); - cases.add("compileLog of tagged enum doesn't crash the compiler", + cases.addExe("compileLog of tagged enum doesn't crash the compiler", \\const Bar = union(enum(u32)) { \\ X: i32 = 1 \\}; From 6a046c1bcda1d02d4f9a05ea125ef56b50cf6e7c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Dec 2019 12:29:55 -0500 Subject: [PATCH 5/9] activate start code when pub main exists and rename LinkType->LinkMode, OutType->OutputMode --- lib/std/builtin.zig | 5 ++-- lib/std/special/start.zig | 51 ++++++++++++++++----------------------- src/codegen.cpp | 7 +++--- test/compile_errors.zig | 16 ++++++------ 4 files changed, 34 insertions(+), 45 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 789880dd88..b073d7300b 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -350,8 +350,7 @@ pub const Endian = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const OutType = enum { - Unknown, +pub const OutputMode = enum { Exe, Lib, Obj, @@ -359,7 +358,7 @@ pub const OutType = enum { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const LinkType = enum { +pub const LinkMode = enum { Static, Dynamic, }; diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index 33ecc6f1f0..5d168490fc 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -19,37 +19,28 @@ const is_mips = switch (builtin.arch) { }; comptime { - switch (builtin.output_type) { - .Unknown => unreachable, - .Exe => { - if (builtin.link_libc) { - if (@hasDecl(root, "main") and - @typeInfo(@typeOf(root.main)).Fn.calling_convention != .C) - { - @export("main", main, .Weak); - } - } else if (builtin.os == .windows) { - if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) { - @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); - } - } else if (is_wasm and builtin.os == .freestanding) { - if (!@hasDecl(root, "_start")) @export("_start", wasm_freestanding_start, .Strong); - } else if (builtin.os == .uefi) { - if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong); - } else if (is_mips) { - if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong); - } else { - if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong); + if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { + if (builtin.os == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { + @export("_DllMainCRTStartup", _DllMainCRTStartup, .Strong); + } + } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { + if (builtin.link_libc and @hasDecl(root, "main") and + @typeInfo(@typeOf(root.main)).Fn.calling_convention != .C) + { + @export("main", main, .Weak); + } else if (builtin.os == .windows) { + if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) { + @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); } - }, - .Lib => { - if (builtin.os == .windows and builtin.link_type == .Dynamic and - !@hasDecl(root, "_DllMainCRTStartup")) - { - @export("_DllMainCRTStartup", _DllMainCRTStartup, .Strong); - } - }, - .Obj => {}, + } else if (is_wasm and builtin.os == .freestanding) { + if (!@hasDecl(root, "_start")) @export("_start", wasm_freestanding_start, .Strong); + } else if (builtin.os == .uefi) { + if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong); + } else if (is_mips) { + if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong); + } else { + if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong); + } } } diff --git a/src/codegen.cpp b/src/codegen.cpp index f41ea7abab..8ba0613334 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8378,8 +8378,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { const char *out_type = nullptr; switch (g->out_type) { case OutTypeUnknown: - out_type = "Unknown"; - break; + zig_unreachable(); case OutTypeExe: out_type = "Exe"; break; @@ -8390,9 +8389,9 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { out_type = "Obj"; break; } - buf_appendf(contents, "pub const output_type = OutType.%s;\n", out_type); + buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type); const char *link_type = g->is_dynamic ? "Dynamic" : "Static"; - buf_appendf(contents, "pub const link_type = LinkType.%s;\n", link_type); + buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type); buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 7e16f858ef..d3d439aeaf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -156,7 +156,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:9:27: error: @atomicRmw on enum only works with .Xchg", ); - cases.addExe( + cases.add( "disallow coercion from non-null-terminated pointer to null-terminated pointer", \\extern fn puts(s: [*:0]const u8) c_int; \\pub fn main() void { @@ -876,7 +876,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:32: note: cast discards const qualifier", ); - cases.addExe( + cases.add( "overflow in enum value allocation", \\const Moo = enum(u8) { \\ Last = 255, @@ -3000,14 +3000,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:9: error: encountered @panic at compile-time", ); - cases.addExe( + cases.add( "wrong return type for main", \\pub fn main() f32 { } , "error: expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'", ); - cases.addExe( + cases.add( "double ?? on main return value", \\pub fn main() ??void { \\} @@ -4900,7 +4900,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:13: error: cannot assign to constant", ); - cases.addExe( + cases.add( "main function with bogus args type", \\pub fn main(args: [][]bogus) !void {} , @@ -5718,7 +5718,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:4:13: error: cannot continue out of defer expression", ); - cases.addExe( + cases.add( "calling a var args function only known at runtime", \\var foos = [_]fn(...) void { foo1, foo2 }; \\ @@ -5732,7 +5732,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:9: error: calling a generic function requires compile-time known function value", ); - cases.addExe( + cases.add( "calling a generic function only known at runtime", \\var foos = [_]fn(var) void { foo1, foo2 }; \\ @@ -6850,7 +6850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:23: error: vector element type must be integer, float, bool, or pointer; 'comptime_int' is invalid", ); - cases.addExe("compileLog of tagged enum doesn't crash the compiler", + cases.add("compileLog of tagged enum doesn't crash the compiler", \\const Bar = union(enum(u32)) { \\ X: i32 = 1 \\}; From a91f55239369b4401aaa50a74ed939f5eb98395d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Dec 2019 12:52:28 -0500 Subject: [PATCH 6/9] WinMainCRTStartup implies defaulting to console subsystem --- lib/std/builtin.zig | 3 ++- src/codegen.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index b073d7300b..89acb0df60 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -26,7 +26,8 @@ pub const subsystem: ?SubSystem = blk: { if (is_test) { break :blk SubSystem.Console; } - if (@hasDecl(root, "WinMain") or + if (@hasDecl(root, "main") or + @hasDecl(root, "WinMain") or @hasDecl(root, "wWinMain") or @hasDecl(root, "WinMainCRTStartup") or @hasDecl(root, "wWinMainCRTStartup")) diff --git a/src/codegen.cpp b/src/codegen.cpp index 8ba0613334..bc66d08167 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8229,9 +8229,9 @@ TargetSubsystem detect_subsystem(CodeGen *g) { if (g->zig_target->os == OsWindows) { if (g->have_dllmain_crt_startup || (g->out_type == OutTypeLib && g->is_dynamic)) return TargetSubsystemAuto; - if (g->have_c_main || g->is_test_build) + if (g->have_c_main || g->is_test_build || g->have_winmain_crt_startup) return TargetSubsystemConsole; - if (g->have_winmain || g->have_winmain_crt_startup) + if (g->have_winmain) return TargetSubsystemWindows; } else if (g->zig_target->os == OsUefi) { return TargetSubsystemEfiApplication; From 8db4d2332e62ba31412b28e725f4c4ae3b7dd801 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Dec 2019 13:10:26 -0500 Subject: [PATCH 7/9] correct startup logic for exporting libc main --- lib/std/special/start.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index 5d168490fc..c483fda756 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -24,10 +24,10 @@ comptime { @export("_DllMainCRTStartup", _DllMainCRTStartup, .Strong); } } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { - if (builtin.link_libc and @hasDecl(root, "main") and - @typeInfo(@typeOf(root.main)).Fn.calling_convention != .C) - { - @export("main", main, .Weak); + if (builtin.link_libc and @hasDecl(root, "main")) { + if (@typeInfo(@typeOf(root.main)).Fn.calling_convention != .C) { + @export("main", main, .Weak); + } } else if (builtin.os == .windows) { if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) { @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); From e3ebaab3c71a9af833e30dc4fe3a7b49d5cd9149 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Dec 2019 13:57:13 -0500 Subject: [PATCH 8/9] fix `zig builtin` --- src/codegen.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index bc66d08167..324a32485e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8377,8 +8377,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { } const char *out_type = nullptr; switch (g->out_type) { - case OutTypeUnknown: - zig_unreachable(); case OutTypeExe: out_type = "Exe"; break; @@ -8386,6 +8384,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { out_type = "Lib"; break; case OutTypeObj: + case OutTypeUnknown: // This happens when running the `zig builtin` command. out_type = "Obj"; break; } From 521744bb91b486bfab7d9a6bd74dd658da95ea18 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 3 Dec 2019 16:55:27 -0500 Subject: [PATCH 9/9] correct the calling convention of WinMainCRTStartup --- lib/std/special/start.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index c483fda756..a93b01c290 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -128,7 +128,7 @@ nakedcc fn _start() noreturn { @noInlineCall(posixCallMainAndExit); } -extern fn WinMainCRTStartup() noreturn { +stdcallcc fn WinMainCRTStartup() noreturn { @setAlignStack(16); if (!builtin.single_threaded) { _ = @import("start_windows_tls.zig");