diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ded1c29fb..b1306d732b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,6 +204,10 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST}) install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}") +install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c") +install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c") +install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") +install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c") install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/darwin.zig" DESTINATION "${ZIG_STD_DEST}") @@ -231,6 +235,7 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}") +install(FILES "${CMAKE_SOURCE_DIR}/std/windows.zig" DESTINATION "${ZIG_STD_DEST}") add_executable(run_tests ${TEST_SOURCES}) target_link_libraries(run_tests) diff --git a/src/all_types.hpp b/src/all_types.hpp index 35ed95fbdb..e1ebf50e69 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -246,6 +246,7 @@ enum TldId { enum TldResolution { TldResolutionUnresolved, + TldResolutionResolving, TldResolutionInvalid, TldResolutionOk, }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 1a0f0b8fe8..631707c978 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2423,8 +2423,8 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { AstNode *use_decl_node = import->use_decls.at(i); if (use_decl_node->data.use.resolution == TldResolutionUnresolved) { preview_use_decl(g, use_decl_node); + resolve_use_decl(g, use_decl_node); } - resolve_use_decl(g, use_decl_node); } while (scope) { @@ -2795,14 +2795,18 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * void resolve_use_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeUse); - if (node->data.use.resolution != TldResolutionUnresolved) + if (node->data.use.resolution == TldResolutionOk || + node->data.use.resolution == TldResolutionInvalid) + { return; + } add_symbols_from_import(g, node, node); } void preview_use_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeUse); + node->data.use.resolution = TldResolutionResolving; IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, node->data.use.expr, g->builtin_types.entry_namespace, nullptr); diff --git a/src/codegen.cpp b/src/codegen.cpp index 3babaac0e4..03629b2da1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -272,7 +272,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { } TypeTableEntry *fn_type = fn_table_entry->type_entry; - fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); + LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; + if (!fn_table_entry->internal_linkage && fn_table_entry->body_node == nullptr) { + LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); + if (existing_llvm_fn) { + fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); + } else { + fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); + } + } else { + fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); + } switch (fn_table_entry->fn_inline) { case FnInlineAlways: diff --git a/std/bootstrap.zig b/std/bootstrap.zig index 074f06557e..b490989a4d 100644 --- a/std/bootstrap.zig +++ b/std/bootstrap.zig @@ -4,7 +4,7 @@ const root = @import("@root"); const std = @import("std"); -const want_main_symbol = std.build.linkingLibrary("c"); +const want_main_symbol = std.build.linking_libc; const want_start_symbol = !want_main_symbol; const exit = switch(@compileVar("os")) { @@ -18,6 +18,9 @@ var argv: &&u8 = undefined; export nakedcc fn _start() -> unreachable { @setFnVisible(this, want_start_symbol); + if (!want_start_symbol) { + @unreachable(); + } switch (@compileVar("arch")) { Arch.x86_64 => { @@ -49,6 +52,9 @@ fn callMainAndExit() -> unreachable { export fn main(c_argc: i32, c_argv: &&u8) -> i32 { @setFnVisible(this, want_main_symbol); + if (!want_main_symbol) { + @unreachable(); + } argc = usize(c_argc); argv = c_argv; diff --git a/std/build.zig b/std/build.zig index a21baa387d..f6b6f7177d 100644 --- a/std/build.zig +++ b/std/build.zig @@ -1,5 +1,7 @@ const mem = @import("mem.zig"); +pub const linking_libc = linkingLibrary("c"); + pub fn linkingLibrary(lib_name: []const u8) -> bool { // TODO shouldn't need this if if (@compileVar("link_libs").len != 0) { diff --git a/std/c/darwin.zig b/std/c/darwin.zig new file mode 100644 index 0000000000..2095139b91 --- /dev/null +++ b/std/c/darwin.zig @@ -0,0 +1,4 @@ +pub extern fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int; + +extern fn __error() -> &c_int; +pub const _errno = __error; diff --git a/std/c/index.zig b/std/c/index.zig new file mode 100644 index 0000000000..84b54cfc8e --- /dev/null +++ b/std/c/index.zig @@ -0,0 +1,13 @@ +pub use @import("errno.zig"); + +pub use switch(@compileVar("os")) { + Os.linux => @import("c/linux.zig"), + Os.windows => @import("c/windows.zig"), + Os.darwin, Os.macosx, Os.ios => @import("c/darwin.zig"), + else => empty_import, +}; + +pub extern fn abort() -> unreachable; + + +const empty_import = @import("empty.zig"); diff --git a/std/c/linux.zig b/std/c/linux.zig new file mode 100644 index 0000000000..fe5476a20f --- /dev/null +++ b/std/c/linux.zig @@ -0,0 +1,4 @@ +pub extern fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int; + +extern fn __errno_location() -> &c_int; +pub const _errno = __errno_location; diff --git a/std/c/windows.zig b/std/c/windows.zig new file mode 100644 index 0000000000..de77f67f6c --- /dev/null +++ b/std/c/windows.zig @@ -0,0 +1 @@ +pub extern fn _errno() -> &c_int; diff --git a/std/debug.zig b/std/debug.zig index d03f22b4c9..7fe1ef4d4b 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -78,13 +78,13 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void { } }, ObjectFormat.coff => { - out_stream.write("(stack trace unavailable for COFF object format)\n"); + %return out_stream.write("(stack trace unavailable for COFF object format)\n"); }, ObjectFormat.macho => { %return out_stream.write("(stack trace unavailable for Mach-O object format)\n"); }, ObjectFormat.unknown => { - out_stream.write("(stack trace unavailable for unknown object format)\n"); + %return out_stream.write("(stack trace unavailable for unknown object format)\n"); }, } } diff --git a/std/os.zig b/std/os.zig index bfb8daecb3..b50aa021f9 100644 --- a/std/os.zig +++ b/std/os.zig @@ -1,20 +1,49 @@ -const system = switch(@compileVar("os")) { +const posix = switch(@compileVar("os")) { Os.linux => @import("linux.zig"), - Os.darwin => @import("darwin.zig"), + Os.darwin, Os.macosx, Os.ios => @import("darwin.zig"), else => @compileError("Unsupported OS"), }; +const windows = @import("windows.zig"); const errno = @import("errno.zig"); +const linking_libc = @import("build.zig").linking_libc; +const c = @import("c/index.zig"); error Unexpected; +/// Fills `buf` with random bytes. If linking against libc, this calls the +/// appropriate OS-specific library call. Otherwise it uses the zig standard +/// library implementation. pub fn getRandomBytes(buf: []u8) -> %void { while (true) { - const ret = switch (@compileVar("os")) { - Os.linux => system.getrandom(buf.ptr, buf.len, 0), - Os.darwin => system.getrandom(buf.ptr, buf.len), - else => @compileError("unsupported os"), + const err = switch (@compileVar("os")) { + Os.linux => { + if (linking_libc) { + if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 0 + } else { + posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0)) + } + }, + Os.darwin, Os.macosx, Os.ios => { + if (linking_libc) { + if (posix.getrandom(buf.ptr, buf.len) == -1) *c._errno() else 0 + } else { + posix.getErrno(posix.getrandom(buf.ptr, buf.len)) + } + }, + Os.windows => { + var hCryptProv: windows.HCRYPTPROV = undefined; + if (!windows.CryptAcquireContext(&hCryptProv, null, null, windows.PROV_RSA_FULL, 0)) { + return error.Unexpected; + } + defer _ = windows.CryptReleaseContext(hCryptProv, 0); + + if (!windows.CryptGenRandom(hCryptProv, windows.DWORD(buf.len), buf.ptr)) { + return error.Unexpected; + } + return; + }, + else => @compileError("Unsupported OS"), }; - const err = system.getErrno(ret); if (err > 0) { return switch (err) { errno.EINVAL => @unreachable(), @@ -27,13 +56,19 @@ pub fn getRandomBytes(buf: []u8) -> %void { } } +/// Raises a signal in the current kernel thread, ending its execution. +/// If linking against libc, this calls the abort() libc function. Otherwise +/// it uses the zig standard library implementation. pub coldcc fn abort() -> unreachable { + if (linking_libc) { + c.abort(); + } switch (@compileVar("os")) { - Os.linux, Os.darwin => { - _ = system.raise(system.SIGABRT); - _ = system.raise(system.SIGKILL); + Os.linux => { + _ = posix.raise(posix.SIGABRT); + _ = posix.raise(posix.SIGKILL); while (true) {} }, - else => @compileError("unsupported os"), + else => @compileError("Unsupported OS"), } } diff --git a/std/windows.zig b/std/windows.zig new file mode 100644 index 0000000000..f713f61abe --- /dev/null +++ b/std/windows.zig @@ -0,0 +1,17 @@ +pub extern fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR, + pszProvider: LPCTSTR, dwProvType: DWORD, dwFlags: DWORD) -> bool; + +pub extern fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool; + +pub extern fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool; + +pub const PROV_RSA_FULL = 1; + + +pub const BYTE = u8; +pub const DWORD = u32; +// TODO something about unicode WCHAR vs char +pub const TCHAR = u8; +pub const LPCTSTR = ?&const TCHAR; +pub const ULONG_PTR = usize; +pub const HCRYPTPROV = ULONG_PTR;