From b37acc4d6870a090c3501d81d3f647bc30220e4b Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Thu, 12 Dec 2019 01:31:32 +0000 Subject: allow custom OS entrypoint Also: * Expose `std.start.callMain`. * Other fixes added to fix issues found in development. --- lib/std/builtin.zig | 4 ++++ lib/std/os.zig | 20 ++++++++++++-------- lib/std/special.zig | 1 + lib/std/special/c.zig | 2 +- lib/std/special/start.zig | 15 ++++++--------- lib/std/std.zig | 1 + 6 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 lib/std/special.zig (limited to 'lib/std') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 36fa46e953..5b7051eafb 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -424,6 +424,10 @@ pub const panic: PanicFn = if (@hasDecl(root, "panic")) root.panic else default_ /// therefore must be kept in sync with the compiler implementation. pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace) noreturn { @setCold(true); + if (@hasDecl(root, "os") and @hasDecl(root.os, "panic")) { + root.os.panic(msg, error_return_trace); + unreachable; + } switch (os) { .freestanding => { while (true) { diff --git a/lib/std/os.zig b/lib/std/os.zig index 04de59d6e1..6d49bcd38e 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -187,19 +187,23 @@ pub fn abort() noreturn { } windows.kernel32.ExitProcess(3); } - if (builtin.link_libc) { - system.abort(); + if (!builtin.link_libc and builtin.os == .linux) { + raise(SIGABRT) catch {}; + + // TODO the rest of the implementation of abort() from musl libc here + + raise(SIGKILL) catch {}; + exit(127); } if (builtin.os == .uefi) { exit(0); // TODO choose appropriate exit code } + if (builtin.os == .wasi) { + @breakpoint(); + exit(1); + } - raise(SIGABRT) catch {}; - - // TODO the rest of the implementation of abort() from musl libc here - - raise(SIGKILL) catch {}; - exit(127); + system.abort(); } pub const RaiseError = UnexpectedError; diff --git a/lib/std/special.zig b/lib/std/special.zig new file mode 100644 index 0000000000..03012d5a1c --- /dev/null +++ b/lib/std/special.zig @@ -0,0 +1 @@ +pub const start = @import("special/start.zig"); diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 4c2eb2a958..0895b1e6f9 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -83,7 +83,7 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn @setCold(true); std.debug.panic("{}", msg); } - if (builtin.os != .freestanding) { + if (builtin.os != .freestanding and builtin.os != .other) { std.os.abort(); } while (true) {} diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index 60745dab7f..ee53254098 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -17,6 +17,7 @@ const is_mips = switch (builtin.arch) { .mips, .mipsel, .mips64, .mips64el => true, else => false, }; +const start_sym_name = if (is_mips) "__start" else "_start"; comptime { if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { @@ -34,14 +35,10 @@ comptime { } } else if (builtin.os == .uefi) { if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong); - } else if (builtin.os != .freestanding) { - if (is_mips) { - if (!@hasDecl(root, "__start")) @export("__start", _start, .Strong); - } else { - if (!@hasDecl(root, "_start")) @export("_start", _start, .Strong); - } - } else if (is_wasm) { - if (!@hasDecl(root, "_start")) @export("_start", wasm_freestanding_start, .Strong); + } else if (is_wasm and builtin.os == .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(start_sym_name, wasm_freestanding_start, .Strong); + } else if (builtin.os != .other and builtin.os != .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(start_sym_name, _start, .Strong); } } } @@ -247,7 +244,7 @@ async fn callMainAsync(loop: *std.event.Loop) u8 { // This is not marked inline because it is called with @asyncCall when // there is an event loop. -fn callMain() u8 { +pub fn callMain() u8 { switch (@typeInfo(@TypeOf(root.main).ReturnType)) { .NoReturn => { root.main(); diff --git a/lib/std/std.zig b/lib/std/std.zig index 09db489604..48b3c27987 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -65,6 +65,7 @@ pub const time = @import("time.zig"); pub const unicode = @import("unicode.zig"); pub const valgrind = @import("valgrind.zig"); pub const zig = @import("zig.zig"); +pub const special = @import("special.zig"); test "" { meta.refAllDecls(@This()); -- cgit v1.2.3 From fff3c1fff4c3ebfcb2bd4f08a43ae7815b5c446b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 12 Dec 2019 18:27:17 -0500 Subject: un-special-case startup code in the std lib Previously, the compiler had special logic to determine whether to include the startup code, which was in `std/special/start.zig`. Now, the file is moved to `std/start.zig`, and there is no special logic in the compiler. Instead, the standard library unconditionally imports the `start.zig` file, which then has a `comptime` block that does the logic of determining what, if any, start symbols to export. Instead of `start.zig` being in its own special package, it is just another normal file that is part of the standard library. `std.builtin.TestFn` is now part of the standard library rather than specially generated by the compiler. --- lib/std/builtin.zig | 7 + lib/std/special.zig | 1 - lib/std/special/start.zig | 283 ---------------------------------- lib/std/special/start_windows_tls.zig | 48 ------ lib/std/special/test_runner.zig | 6 +- lib/std/start.zig | 283 ++++++++++++++++++++++++++++++++++ lib/std/start_windows_tls.zig | 48 ++++++ lib/std/std.zig | 8 +- src/all_types.hpp | 4 +- src/analyze.cpp | 43 +++++- src/analyze.hpp | 3 + src/codegen.cpp | 83 +++------- src/dump_analysis.cpp | 2 +- src/ir.cpp | 40 ----- src/main.cpp | 4 +- 15 files changed, 420 insertions(+), 443 deletions(-) delete mode 100644 lib/std/special.zig delete mode 100644 lib/std/special/start.zig delete mode 100644 lib/std/special/start_windows_tls.zig create mode 100644 lib/std/start.zig create mode 100644 lib/std/start_windows_tls.zig (limited to 'lib/std') diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 5b7051eafb..687e169bbe 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -412,6 +412,13 @@ pub const CallOptions = struct { }; }; +/// This function type is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const TestFn = struct { + name: []const u8, + func: fn()anyerror!void, +}; + /// This function type is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn; diff --git a/lib/std/special.zig b/lib/std/special.zig deleted file mode 100644 index 03012d5a1c..0000000000 --- a/lib/std/special.zig +++ /dev/null @@ -1 +0,0 @@ -pub const start = @import("special/start.zig"); diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig deleted file mode 100644 index ee53254098..0000000000 --- a/lib/std/special/start.zig +++ /dev/null @@ -1,283 +0,0 @@ -// This file is included in the compilation unit when exporting an executable. - -const root = @import("root"); -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; -const uefi = std.os.uefi; - -var starting_stack_ptr: [*]usize = undefined; - -const is_wasm = switch (builtin.arch) { - .wasm32, .wasm64 => true, - else => false, -}; - -const is_mips = switch (builtin.arch) { - .mips, .mipsel, .mips64, .mips64el => true, - else => false, -}; -const start_sym_name = if (is_mips) "__start" else "_start"; - -comptime { - 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")) { - 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); - } - } else if (builtin.os == .uefi) { - if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong); - } else if (is_wasm and builtin.os == .freestanding) { - if (!@hasDecl(root, start_sym_name)) @export(start_sym_name, wasm_freestanding_start, .Strong); - } else if (builtin.os != .other and builtin.os != .freestanding) { - if (!@hasDecl(root, start_sym_name)) @export(start_sym_name, _start, .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; -} - -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. - _ = @call(.{ .modifier = .always_inline }, callMain, .{}); -} - -extern fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) usize { - const bad_efi_main_ret = "expected return type of main to be 'void', 'noreturn', or 'usize'"; - uefi.handle = handle; - uefi.system_table = system_table; - - switch (@typeInfo(@TypeOf(root.main).ReturnType)) { - .NoReturn => { - root.main(); - }, - .Void => { - root.main(); - return 0; - }, - .Int => |info| { - if (info.bits != @typeInfo(usize).Int.bits) { - @compileError(bad_efi_main_ret); - } - return root.main(); - }, - else => @compileError(bad_efi_main_ret), - } -} - -nakedcc fn _start() noreturn { - if (builtin.os == builtin.Os.wasi) { - // 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. - std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); - } - - switch (builtin.arch) { - .x86_64 => { - starting_stack_ptr = asm ("" - : [argc] "={rsp}" (-> [*]usize) - ); - }, - .i386 => { - starting_stack_ptr = asm ("" - : [argc] "={esp}" (-> [*]usize) - ); - }, - .aarch64, .aarch64_be, .arm => { - starting_stack_ptr = asm ("mov %[argc], sp" - : [argc] "=r" (-> [*]usize) - ); - }, - .riscv64 => { - starting_stack_ptr = asm ("mv %[argc], sp" - : [argc] "=r" (-> [*]usize) - ); - }, - .mipsel => { - // Need noat here because LLVM is free to pick any register - starting_stack_ptr = asm ( - \\ .set noat - \\ move %[argc], $sp - : [argc] "=r" (-> [*]usize) - ); - }, - else => @compileError("unsupported arch"), - } - // If LLVM inlines stack variables into _start, they will overwrite - // the command line argument data. - @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); -} - -stdcallcc fn WinMainCRTStartup() noreturn { - @setAlignStack(16); - if (!builtin.single_threaded) { - _ = @import("start_windows_tls.zig"); - } - - std.debug.maybeEnableSegfaultHandler(); - - std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain()); -} - -// TODO https://github.com/ziglang/zig/issues/265 -fn posixCallMainAndExit() noreturn { - if (builtin.os == builtin.Os.freebsd) { - @setAlignStack(16); - } - const argc = starting_stack_ptr[0]; - const argv = @ptrCast([*][*:0]u8, starting_stack_ptr + 1); - - const envp_optional = @ptrCast([*:null]?[*:0]u8, argv + argc + 1); - var envp_count: usize = 0; - while (envp_optional[envp_count]) |_| : (envp_count += 1) {} - const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count]; - - if (builtin.os == .linux) { - // Find the beginning of the auxiliary vector - const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); - std.os.linux.elf_aux_maybe = auxv; - // Initialize the TLS area - const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size"); - - if (std.os.linux.tls.tls_image) |tls_img| { - const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); - const tp = std.os.linux.tls.copyTLS(tls_addr); - std.os.linux.tls.setThreadPointer(tp); - } - - // TODO This is disabled because what should we do when linking libc and this code - // does not execute? And also it's causing a test failure in stack traces in release modes. - - //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further - //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down - //// the stack and requires "probing". So here we allocate our own stack. - //const wanted_stack_size = gnu_stack_phdr.p_memsz; - //assert(wanted_stack_size % std.mem.page_size == 0); - //// Allocate an extra page as the guard page. - //const total_size = wanted_stack_size + std.mem.page_size; - //const new_stack = std.os.mmap( - // null, - // total_size, - // std.os.PROT_READ | std.os.PROT_WRITE, - // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS, - // -1, - // 0, - //) catch @panic("out of memory"); - //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; - //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp})); - } - - std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); -} - -fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { - std.os.argv = argv[0..argc]; - std.os.environ = envp; - - std.debug.maybeEnableSegfaultHandler(); - - return initEventLoopAndCallMain(); -} - -extern fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) i32 { - var env_count: usize = 0; - while (c_envp[env_count] != null) : (env_count += 1) {} - const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; - return @call(.{ .modifier = .always_inline }, 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 initEventLoopAndCallMain() u8 { - if (std.event.Loop.instance) |loop| { - if (!@hasDecl(root, "event_loop")) { - loop.init() catch |err| { - std.debug.warn("error: {}\n", .{@errorName(err)}); - if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace.*); - } - return 1; - }; - defer loop.deinit(); - - var result: u8 = undefined; - var frame: @Frame(callMainAsync) = undefined; - _ = @asyncCall(&frame, &result, callMainAsync, loop); - loop.run(); - return result; - } - } - - // 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. - return @call(.{ .modifier = .always_inline }, callMain, .{}); -} - -async fn callMainAsync(loop: *std.event.Loop) u8 { - // This prevents the event loop from terminating at least until main() has returned. - loop.beginOneEvent(); - defer loop.finishOneEvent(); - return callMain(); -} - -// This is not marked inline because it is called with @asyncCall when -// there is an event loop. -pub fn callMain() u8 { - switch (@typeInfo(@TypeOf(root.main).ReturnType)) { - .NoReturn => { - root.main(); - }, - .Void => { - root.main(); - return 0; - }, - .Int => |info| { - if (info.bits != 8) { - @compileError(bad_main_ret); - } - return root.main(); - }, - .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 result; - }, - else => @compileError(bad_main_ret), - } - }, - else => @compileError(bad_main_ret), - } -} diff --git a/lib/std/special/start_windows_tls.zig b/lib/std/special/start_windows_tls.zig deleted file mode 100644 index bfd0e44122..0000000000 --- a/lib/std/special/start_windows_tls.zig +++ /dev/null @@ -1,48 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); - -export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; -export var _tls_start: u8 linksection(".tls") = 0; -export var _tls_end: u8 linksection(".tls$ZZZ") = 0; -export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; -export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; - -comptime { - if (builtin.arch == .i386) { - // The __tls_array is the offset of the ThreadLocalStoragePointer field - // in the TEB block whose base address held in the %fs segment. - asm ( - \\ .global __tls_array - \\ __tls_array = 0x2C - ); - } -} - -// TODO this is how I would like it to be expressed -// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate -// why they do that. -//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { -// .StartAddressOfRawData = @ptrToInt(&_tls_start), -// .EndAddressOfRawData = @ptrToInt(&_tls_end), -// .AddressOfIndex = @ptrToInt(&_tls_index), -// .AddressOfCallBacks = @ptrToInt(__xl_a), -// .SizeOfZeroFill = 0, -// .Characteristics = 0, -//}; -// This is the workaround because we can't do @ptrToInt at comptime like that. -pub const IMAGE_TLS_DIRECTORY = extern struct { - StartAddressOfRawData: *c_void, - EndAddressOfRawData: *c_void, - AddressOfIndex: *c_void, - AddressOfCallBacks: *c_void, - SizeOfZeroFill: u32, - Characteristics: u32, -}; -export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ - .StartAddressOfRawData = &_tls_start, - .EndAddressOfRawData = &_tls_end, - .AddressOfIndex = &_tls_index, - .AddressOfCallBacks = &__xl_a, - .SizeOfZeroFill = 0, - .Characteristics = 0, -}; diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 7bb53774d3..0335c8562d 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -1,9 +1,9 @@ const std = @import("std"); const io = std.io; const builtin = @import("builtin"); -const test_fn_list = builtin.test_functions; pub fn main() anyerror!void { + const test_fn_list = builtin.test_functions; var ok_count: usize = 0; var skip_count: usize = 0; var progress = std.Progress{}; @@ -16,7 +16,9 @@ pub fn main() anyerror!void { var test_node = root_node.start(test_fn.name, null); test_node.activate(); progress.refresh(); - if (progress.terminal == null) std.debug.warn("{}/{} {}...", .{ i + 1, test_fn_list.len, test_fn.name }); + if (progress.terminal == null) { + std.debug.warn("{}/{} {}...", .{ i + 1, test_fn_list.len, test_fn.name }); + } if (test_fn.func()) |_| { ok_count += 1; test_node.end(); diff --git a/lib/std/start.zig b/lib/std/start.zig new file mode 100644 index 0000000000..3c46449949 --- /dev/null +++ b/lib/std/start.zig @@ -0,0 +1,283 @@ +// This file is included in the compilation unit when exporting an executable. + +const root = @import("root"); +const std = @import("std.zig"); +const builtin = std.builtin; +const assert = std.debug.assert; +const uefi = std.os.uefi; + +var starting_stack_ptr: [*]usize = undefined; + +const is_wasm = switch (builtin.arch) { + .wasm32, .wasm64 => true, + else => false, +}; + +const is_mips = switch (builtin.arch) { + .mips, .mipsel, .mips64, .mips64el => true, + else => false, +}; +const start_sym_name = if (is_mips) "__start" else "_start"; + +comptime { + 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")) { + 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); + } + } else if (builtin.os == .uefi) { + if (!@hasDecl(root, "EfiMain")) @export("EfiMain", EfiMain, .Strong); + } else if (is_wasm and builtin.os == .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(start_sym_name, wasm_freestanding_start, .Strong); + } else if (builtin.os != .other and builtin.os != .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(start_sym_name, _start, .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; +} + +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. + _ = @call(.{ .modifier = .always_inline }, callMain, .{}); +} + +extern fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) usize { + const bad_efi_main_ret = "expected return type of main to be 'void', 'noreturn', or 'usize'"; + uefi.handle = handle; + uefi.system_table = system_table; + + switch (@typeInfo(@TypeOf(root.main).ReturnType)) { + .NoReturn => { + root.main(); + }, + .Void => { + root.main(); + return 0; + }, + .Int => |info| { + if (info.bits != @typeInfo(usize).Int.bits) { + @compileError(bad_efi_main_ret); + } + return root.main(); + }, + else => @compileError(bad_efi_main_ret), + } +} + +nakedcc fn _start() noreturn { + if (builtin.os == builtin.Os.wasi) { + // 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. + std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); + } + + switch (builtin.arch) { + .x86_64 => { + starting_stack_ptr = asm ("" + : [argc] "={rsp}" (-> [*]usize) + ); + }, + .i386 => { + starting_stack_ptr = asm ("" + : [argc] "={esp}" (-> [*]usize) + ); + }, + .aarch64, .aarch64_be, .arm => { + starting_stack_ptr = asm ("mov %[argc], sp" + : [argc] "=r" (-> [*]usize) + ); + }, + .riscv64 => { + starting_stack_ptr = asm ("mv %[argc], sp" + : [argc] "=r" (-> [*]usize) + ); + }, + .mipsel => { + // Need noat here because LLVM is free to pick any register + starting_stack_ptr = asm ( + \\ .set noat + \\ move %[argc], $sp + : [argc] "=r" (-> [*]usize) + ); + }, + else => @compileError("unsupported arch"), + } + // If LLVM inlines stack variables into _start, they will overwrite + // the command line argument data. + @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); +} + +stdcallcc fn WinMainCRTStartup() noreturn { + @setAlignStack(16); + if (!builtin.single_threaded) { + _ = @import("start_windows_tls.zig"); + } + + std.debug.maybeEnableSegfaultHandler(); + + std.os.windows.kernel32.ExitProcess(initEventLoopAndCallMain()); +} + +// TODO https://github.com/ziglang/zig/issues/265 +fn posixCallMainAndExit() noreturn { + if (builtin.os == builtin.Os.freebsd) { + @setAlignStack(16); + } + const argc = starting_stack_ptr[0]; + const argv = @ptrCast([*][*:0]u8, starting_stack_ptr + 1); + + const envp_optional = @ptrCast([*:null]?[*:0]u8, argv + argc + 1); + var envp_count: usize = 0; + while (envp_optional[envp_count]) |_| : (envp_count += 1) {} + const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count]; + + if (builtin.os == .linux) { + // Find the beginning of the auxiliary vector + const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); + std.os.linux.elf_aux_maybe = auxv; + // Initialize the TLS area + const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size"); + + if (std.os.linux.tls.tls_image) |tls_img| { + const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); + const tp = std.os.linux.tls.copyTLS(tls_addr); + std.os.linux.tls.setThreadPointer(tp); + } + + // TODO This is disabled because what should we do when linking libc and this code + // does not execute? And also it's causing a test failure in stack traces in release modes. + + //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further + //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down + //// the stack and requires "probing". So here we allocate our own stack. + //const wanted_stack_size = gnu_stack_phdr.p_memsz; + //assert(wanted_stack_size % std.mem.page_size == 0); + //// Allocate an extra page as the guard page. + //const total_size = wanted_stack_size + std.mem.page_size; + //const new_stack = std.os.mmap( + // null, + // total_size, + // std.os.PROT_READ | std.os.PROT_WRITE, + // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS, + // -1, + // 0, + //) catch @panic("out of memory"); + //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; + //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp})); + } + + std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); +} + +fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { + std.os.argv = argv[0..argc]; + std.os.environ = envp; + + std.debug.maybeEnableSegfaultHandler(); + + return initEventLoopAndCallMain(); +} + +extern fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) i32 { + var env_count: usize = 0; + while (c_envp[env_count] != null) : (env_count += 1) {} + const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; + return @call(.{ .modifier = .always_inline }, 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 initEventLoopAndCallMain() u8 { + if (std.event.Loop.instance) |loop| { + if (!@hasDecl(root, "event_loop")) { + loop.init() catch |err| { + std.debug.warn("error: {}\n", .{@errorName(err)}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + return 1; + }; + defer loop.deinit(); + + var result: u8 = undefined; + var frame: @Frame(callMainAsync) = undefined; + _ = @asyncCall(&frame, &result, callMainAsync, loop); + loop.run(); + return result; + } + } + + // 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. + return @call(.{ .modifier = .always_inline }, callMain, .{}); +} + +async fn callMainAsync(loop: *std.event.Loop) u8 { + // This prevents the event loop from terminating at least until main() has returned. + loop.beginOneEvent(); + defer loop.finishOneEvent(); + return callMain(); +} + +// This is not marked inline because it is called with @asyncCall when +// there is an event loop. +pub fn callMain() u8 { + switch (@typeInfo(@TypeOf(root.main).ReturnType)) { + .NoReturn => { + root.main(); + }, + .Void => { + root.main(); + return 0; + }, + .Int => |info| { + if (info.bits != 8) { + @compileError(bad_main_ret); + } + return root.main(); + }, + .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 result; + }, + else => @compileError(bad_main_ret), + } + }, + else => @compileError(bad_main_ret), + } +} diff --git a/lib/std/start_windows_tls.zig b/lib/std/start_windows_tls.zig new file mode 100644 index 0000000000..f6dd2bc132 --- /dev/null +++ b/lib/std/start_windows_tls.zig @@ -0,0 +1,48 @@ +const std = @import("std"); +const builtin = std.builtin; + +export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; +export var _tls_start: u8 linksection(".tls") = 0; +export var _tls_end: u8 linksection(".tls$ZZZ") = 0; +export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; +export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; + +comptime { + if (builtin.arch == .i386) { + // The __tls_array is the offset of the ThreadLocalStoragePointer field + // in the TEB block whose base address held in the %fs segment. + asm ( + \\ .global __tls_array + \\ __tls_array = 0x2C + ); + } +} + +// TODO this is how I would like it to be expressed +// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate +// why they do that. +//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { +// .StartAddressOfRawData = @ptrToInt(&_tls_start), +// .EndAddressOfRawData = @ptrToInt(&_tls_end), +// .AddressOfIndex = @ptrToInt(&_tls_index), +// .AddressOfCallBacks = @ptrToInt(__xl_a), +// .SizeOfZeroFill = 0, +// .Characteristics = 0, +//}; +// This is the workaround because we can't do @ptrToInt at comptime like that. +pub const IMAGE_TLS_DIRECTORY = extern struct { + StartAddressOfRawData: *c_void, + EndAddressOfRawData: *c_void, + AddressOfIndex: *c_void, + AddressOfCallBacks: *c_void, + SizeOfZeroFill: u32, + Characteristics: u32, +}; +export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ + .StartAddressOfRawData = &_tls_start, + .EndAddressOfRawData = &_tls_end, + .AddressOfIndex = &_tls_index, + .AddressOfCallBacks = &__xl_a, + .SizeOfZeroFill = 0, + .Characteristics = 0, +}; diff --git a/lib/std/std.zig b/lib/std/std.zig index 48b3c27987..dd4d968efb 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -65,7 +65,13 @@ pub const time = @import("time.zig"); pub const unicode = @import("unicode.zig"); pub const valgrind = @import("valgrind.zig"); pub const zig = @import("zig.zig"); -pub const special = @import("special.zig"); +pub const start = @import("start.zig"); + +// This forces the start.zig file to be imported, and the comptime logic inside that +// file decides whether to export any appropriate start symbols. +comptime { + _ = start; +} test "" { meta.refAllDecls(@This()); diff --git a/src/all_types.hpp b/src/all_types.hpp index 747655987c..5f0211df74 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2003,10 +2003,11 @@ struct CodeGen { ZigPackage *std_package; ZigPackage *test_runner_package; ZigPackage *compile_var_package; + ZigPackage *root_pkg; // @import("root") + ZigPackage *main_pkg; // usually same as root_pkg, except for `zig test` ZigType *compile_var_import; ZigType *root_import; ZigType *start_import; - ZigType *test_runner_import; struct { ZigType *entry_bool; @@ -2179,7 +2180,6 @@ struct CodeGen { Buf *root_out_name; Buf *test_filter; Buf *test_name_prefix; - ZigPackage *root_package; Buf *zig_lib_dir; Buf *zig_std_dir; Buf *dynamic_linker_path; diff --git a/src/analyze.cpp b/src/analyze.cpp index f46c4fc07c..35a4bd7d4a 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3536,7 +3536,7 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope return; ZigType *import = get_scope_import(&decls_scope->base); - if (import->data.structure.root_struct->package != g->root_package) + if (import->data.structure.root_struct->package != g->main_pkg) return; Buf *decl_name_buf = node->data.test_decl.name; @@ -3577,7 +3577,7 @@ void update_compile_var(CodeGen *g, Buf *name, ZigValue *value) { resolve_top_level_decl(g, tld, tld->source_node, false); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; - tld_var->var->const_value = value; + copy_const_val(tld_var->var->const_value, value); tld_var->var->var_type = value->type; tld_var->var->align_bytes = get_abi_alignment(g, value->type); } @@ -9178,3 +9178,42 @@ bool is_anon_container(ZigType *ty) { ty->data.structure.special == StructSpecialInferredTuple || ty->data.structure.special == StructSpecialInferredStruct); } + +bool is_opt_err_set(ZigType *ty) { + return ty->id == ZigTypeIdErrorSet || + (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); +} + +// Returns whether the x_optional field of ZigValue is active. +bool type_has_optional_repr(ZigType *ty) { + if (ty->id != ZigTypeIdOptional) { + return false; + } else if (get_codegen_ptr_type(ty) != nullptr) { + return false; + } else if (is_opt_err_set(ty)) { + return false; + } else { + return true; + } +} + +void copy_const_val(ZigValue *dest, ZigValue *src) { + memcpy(dest, src, sizeof(ZigValue)); + if (src->special != ConstValSpecialStatic) + return; + dest->parent.id = ConstParentIdNone; + if (dest->type->id == ZigTypeIdStruct) { + dest->data.x_struct.fields = alloc_const_vals_ptrs(dest->type->data.structure.src_field_count); + for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { + copy_const_val(dest->data.x_struct.fields[i], src->data.x_struct.fields[i]); + dest->data.x_struct.fields[i]->parent.id = ConstParentIdStruct; + dest->data.x_struct.fields[i]->parent.data.p_struct.struct_val = dest; + dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i; + } + } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { + dest->data.x_optional = create_const_vals(1); + copy_const_val(dest->data.x_optional, src->data.x_optional); + dest->data.x_optional->parent.id = ConstParentIdOptionalPayload; + dest->data.x_optional->parent.data.p_optional_payload.optional_val = dest; + } +} diff --git a/src/analyze.hpp b/src/analyze.hpp index 8f07434203..0accff8e5b 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -276,4 +276,7 @@ Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_targe ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path); ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry); bool is_anon_container(ZigType *ty); +void copy_const_val(ZigValue *dest, ZigValue *src); +bool type_has_optional_repr(ZigType *ty); +bool is_opt_err_set(ZigType *ty); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 5b0899544d..a3f3eb622f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8440,11 +8440,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { if (g->is_test_build) { buf_appendf(contents, - "const TestFn = struct {\n" - "name: []const u8,\n" - "func: fn()anyerror!void,\n" - "};\n" - "pub const test_functions = {}; // overwritten later\n" + "pub var test_functions: []TestFn = undefined; // overwritten later\n" ); } @@ -8535,23 +8531,23 @@ static Error define_builtin_compile_vars(CodeGen *g) { } } - assert(g->root_package); + assert(g->main_pkg); assert(g->std_package); g->compile_var_package = new_package(buf_ptr(this_dir), builtin_zig_basename, "builtin"); - g->compile_var_package->package_table.put(buf_create_from_str("std"), g->std_package); - g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); - g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); - ZigPackage *root_pkg; if (g->is_test_build) { if (g->test_runner_package == nullptr) { g->test_runner_package = create_test_runner_pkg(g); } - root_pkg = g->test_runner_package; + g->root_pkg = g->test_runner_package; } else { - root_pkg = g->root_package; + g->root_pkg = g->main_pkg; } - g->std_package->package_table.put(buf_create_from_str("root"), root_pkg); + g->compile_var_package->package_table.put(buf_create_from_str("std"), g->std_package); + g->main_pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); + g->main_pkg->package_table.put(buf_create_from_str("root"), g->root_pkg); + g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); + g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); + g->std_package->package_table.put(buf_create_from_str("root"), g->root_pkg); g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents, SourceKindPkgMain); @@ -8670,7 +8666,7 @@ static void init(CodeGen *g) { // no longer reference DW_AT_comp_dir, for the purpose of being able to support the // common practice of stripping all but the line number sections from an executable. const char *compile_unit_dir = target_os_is_darwin(g->zig_target->os) ? "." : - buf_ptr(&g->root_package->root_src_dir); + buf_ptr(&g->main_pkg->root_src_dir); ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name), compile_unit_dir); @@ -9083,30 +9079,7 @@ void codegen_translate_c(CodeGen *g, Buf *full_path, FILE *out_file, bool use_us } } -static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *basename) { - Buf *code_basename = buf_create_from_str(basename); - Buf path_to_code_src = BUF_INIT; - os_path_join(g->zig_std_special_dir, code_basename, &path_to_code_src); - - Buf *resolve_paths[] = {&path_to_code_src}; - Buf *resolved_path = buf_alloc(); - *resolved_path = os_path_resolve(resolve_paths, 1); - Buf *import_code = buf_alloc(); - Error err; - if ((err = file_fetch(g, resolved_path, import_code))) { - zig_panic("unable to open '%s': %s\n", buf_ptr(&path_to_code_src), err_str(err)); - } - - return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain); -} - -static ZigPackage *create_start_pkg(CodeGen *g, ZigPackage *pkg_with_main) { - ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "start.zig", "std.special"); - package->package_table.put(buf_create_from_str("root"), pkg_with_main); - return package; -} - -static void create_test_compile_var_and_add_test_runner(CodeGen *g) { +static void update_test_functions_builtin_decl(CodeGen *g) { Error err; assert(g->is_test_build); @@ -9166,16 +9139,15 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { update_compile_var(g, buf_create_from_str("test_functions"), test_fn_slice); assert(g->test_runner_package != nullptr); - g->test_runner_import = add_special_code(g, g->test_runner_package, "test_runner.zig"); } static Buf *get_resolved_root_src_path(CodeGen *g) { // TODO memoize - if (buf_len(&g->root_package->root_src_path) == 0) + if (buf_len(&g->main_pkg->root_src_path) == 0) return nullptr; Buf rel_full_path = BUF_INIT; - os_path_join(&g->root_package->root_src_dir, &g->root_package->root_src_path, &rel_full_path); + os_path_join(&g->main_pkg->root_src_dir, &g->main_pkg->root_src_path, &rel_full_path); Buf *resolved_path = buf_alloc(); Buf *resolve_paths[] = {&rel_full_path}; @@ -9198,7 +9170,7 @@ static void gen_root_source(CodeGen *g) { exit(1); } - ZigType *root_import_alias = add_source_file(g, g->root_package, resolved_path, source_code, SourceKindRoot); + ZigType *root_import_alias = add_source_file(g, g->main_pkg, resolved_path, source_code, SourceKindRoot); assert(root_import_alias == g->root_import); assert(g->root_out_name); @@ -9250,16 +9222,8 @@ static void gen_root_source(CodeGen *g) { } report_errors_and_maybe_exit(g); - if (!g->is_test_build) { - g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start.zig"); - } - if (!g->error_during_imports) { - semantic_analyze(g); - } if (g->is_test_build) { - create_test_compile_var_and_add_test_runner(g); - g->start_import = add_special_code(g, create_start_pkg(g, g->test_runner_package), "start.zig"); - + update_test_functions_builtin_decl(g); if (!g->error_during_imports) { semantic_analyze(g); } @@ -10058,7 +10022,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { CacheHash *ch = &g->cache_hash; cache_init(ch, manifest_dir); - add_cache_pkg(g, ch, g->root_package); + add_cache_pkg(g, ch, g->main_pkg); if (g->linker_script != nullptr) { cache_file(ch, buf_create_from_str(g->linker_script)); } @@ -10141,7 +10105,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { } static bool need_llvm_module(CodeGen *g) { - return buf_len(&g->root_package->root_src_path) != 0; + return buf_len(&g->main_pkg->root_src_path) != 0; } static void resolve_out_paths(CodeGen *g) { @@ -10388,8 +10352,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c assert(g->compile_var_package != nullptr); pkg->package_table.put(buf_create_from_str("std"), g->std_package); - ZigPackage *main_pkg = g->is_test_build ? g->test_runner_package : g->root_package; - pkg->package_table.put(buf_create_from_str("root"), main_pkg); + pkg->package_table.put(buf_create_from_str("root"), g->root_pkg); pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); } @@ -10516,15 +10479,13 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget buf_len(&resolved_root_src_path) - buf_len(&resolved_main_pkg_path) - 1); } - g->root_package = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), ""); + g->main_pkg = new_package(buf_ptr(root_pkg_path), buf_ptr(rel_root_src_path), ""); g->std_package = new_package(buf_ptr(g->zig_std_dir), "std.zig", "std"); - g->root_package->package_table.put(buf_create_from_str("std"), g->std_package); + g->main_pkg->package_table.put(buf_create_from_str("std"), g->std_package); } else { - g->root_package = new_package(".", "", ""); + g->main_pkg = new_package(".", "", ""); } - g->root_package->package_table.put(buf_create_from_str("root"), g->root_package); - g->zig_std_special_dir = buf_alloc(); os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir); diff --git a/src/dump_analysis.cpp b/src/dump_analysis.cpp index 2b7d7a8bd9..c31438b658 100644 --- a/src/dump_analysis.cpp +++ b/src/dump_analysis.cpp @@ -1216,7 +1216,7 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const jw_end_object(jw); jw_object_field(jw, "rootPkg"); - anal_dump_pkg_ref(&ctx, g->root_package); + anal_dump_pkg_ref(&ctx, g->main_pkg); // Poke the functions for (size_t i = 0; i < g->fn_defs.length; i += 1) { diff --git a/src/ir.cpp b/src/ir.cpp index 8b588b5dee..bdf8c33bc2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -232,7 +232,6 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, ZigType *dest_type, IrInstruction *dest_type_src, bool safety_check_on); static ZigValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); -static void copy_const_val(ZigValue *dest, ZigValue *src); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *ptr_type); @@ -718,11 +717,6 @@ static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { return result; } -static bool is_opt_err_set(ZigType *ty) { - return ty->id == ZigTypeIdErrorSet || - (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); -} - static bool is_tuple(ZigType *type) { return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialInferredTuple; } @@ -11451,40 +11445,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT } } -// Returns whether the x_optional field of ZigValue is active. -static bool type_has_optional_repr(ZigType *ty) { - if (ty->id != ZigTypeIdOptional) { - return false; - } else if (get_codegen_ptr_type(ty) != nullptr) { - return false; - } else if (is_opt_err_set(ty)) { - return false; - } else { - return true; - } -} - -static void copy_const_val(ZigValue *dest, ZigValue *src) { - memcpy(dest, src, sizeof(ZigValue)); - if (src->special != ConstValSpecialStatic) - return; - dest->parent.id = ConstParentIdNone; - if (dest->type->id == ZigTypeIdStruct) { - dest->data.x_struct.fields = alloc_const_vals_ptrs(dest->type->data.structure.src_field_count); - for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { - copy_const_val(dest->data.x_struct.fields[i], src->data.x_struct.fields[i]); - dest->data.x_struct.fields[i]->parent.id = ConstParentIdStruct; - dest->data.x_struct.fields[i]->parent.data.p_struct.struct_val = dest; - dest->data.x_struct.fields[i]->parent.data.p_struct.field_index = i; - } - } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { - dest->data.x_optional = create_const_vals(1); - copy_const_val(dest->data.x_optional, src->data.x_optional); - dest->data.x_optional->parent.id = ConstParentIdOptionalPayload; - dest->data.x_optional->parent.data.p_optional_payload.optional_val = dest; - } -} - static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_instr, CastOp cast_op, ZigValue *other_val, ZigType *other_type, diff --git a/src/main.cpp b/src/main.cpp index 5739f68df4..a6b26893b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -623,7 +623,7 @@ int main(int argc, char **argv) { ZigPackage *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname), buf_ptr(&build_file_basename), "std.special"); - g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg); + g->main_pkg->package_table.put(buf_create_from_str("@build"), build_pkg); g->enable_cache = get_cache_opt(enable_cache, true); codegen_build_and_link(g); if (root_progress_node != nullptr) { @@ -1269,7 +1269,7 @@ int main(int argc, char **argv) { codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix)); } - add_package(g, cur_pkg, g->root_package); + add_package(g, cur_pkg, g->main_pkg); if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) { g->c_source_files = c_source_files; -- cgit v1.2.3