| author | |
| committer | |
| log | d6856859d3082d9b66aac7c25ceb2abcd13e2f7c |
| tree | dacade36cf18d88b1c21414130b33da91d7f7784 |
| parent | 01b2bf4a44c586f2fa51e8824be608b92d82fed4 |
* standard library knows if it is linking against libc and will
sometimes call libc functions in that case instead of providing
redundant definitions
* fix infinite loop bug when resolving use declarations
* allow calling the same C function from different C imports.
closes #277
* push more logic from compiler to std/bootstrap.zig
* standard library provides way to access errno
closes #274
* fix compile error in standard library for windows
* add implementation of getRandomBytes for windows13 files changed, 119 insertions(+), 17 deletions(-)
CMakeLists.txt+5| ... | ... | @@ -204,6 +204,10 @@ install(FILES ${C_HEADERS} DESTINATION ${C_HEADERS_DEST}) |
| 204 | 204 | install(FILES "${CMAKE_SOURCE_DIR}/std/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}") |
| 205 | 205 | install(FILES "${CMAKE_SOURCE_DIR}/std/build.zig" DESTINATION "${ZIG_STD_DEST}") |
| 206 | 206 | install(FILES "${CMAKE_SOURCE_DIR}/std/builtin.zig" DESTINATION "${ZIG_STD_DEST}") |
| 207 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/darwin.zig" DESTINATION "${ZIG_STD_DEST}/c") | |
| 208 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}/c") | |
| 209 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") | |
| 210 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c") | |
| 207 | 211 | install(FILES "${CMAKE_SOURCE_DIR}/std/compiler_rt.zig" DESTINATION "${ZIG_STD_DEST}") |
| 208 | 212 | install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") |
| 209 | 213 | 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}") |
| 231 | 235 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}") |
| 232 | 236 | install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") |
| 233 | 237 | install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}") |
| 238 | install(FILES "${CMAKE_SOURCE_DIR}/std/windows.zig" DESTINATION "${ZIG_STD_DEST}") | |
| 234 | 239 | |
| 235 | 240 | add_executable(run_tests ${TEST_SOURCES}) |
| 236 | 241 | target_link_libraries(run_tests) |
src/all_types.hpp+1| ... | ... | @@ -246,6 +246,7 @@ enum TldId { |
| 246 | 246 | |
| 247 | 247 | enum TldResolution { |
| 248 | 248 | TldResolutionUnresolved, |
| 249 | TldResolutionResolving, | |
| 249 | 250 | TldResolutionInvalid, |
| 250 | 251 | TldResolutionOk, |
| 251 | 252 | }; |
src/analyze.cpp+6-2| ... | ... | @@ -2423,8 +2423,8 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { |
| 2423 | 2423 | AstNode *use_decl_node = import->use_decls.at(i); |
| 2424 | 2424 | if (use_decl_node->data.use.resolution == TldResolutionUnresolved) { |
| 2425 | 2425 | preview_use_decl(g, use_decl_node); |
| 2426 | resolve_use_decl(g, use_decl_node); | |
| 2426 | 2427 | } |
| 2427 | resolve_use_decl(g, use_decl_node); | |
| 2428 | 2428 | } |
| 2429 | 2429 | |
| 2430 | 2430 | while (scope) { |
| ... | ... | @@ -2795,14 +2795,18 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * |
| 2795 | 2795 | void resolve_use_decl(CodeGen *g, AstNode *node) { |
| 2796 | 2796 | assert(node->type == NodeTypeUse); |
| 2797 | 2797 | |
| 2798 | if (node->data.use.resolution != TldResolutionUnresolved) | |
| 2798 | if (node->data.use.resolution == TldResolutionOk || | |
| 2799 | node->data.use.resolution == TldResolutionInvalid) | |
| 2800 | { | |
| 2799 | 2801 | return; |
| 2802 | } | |
| 2800 | 2803 | add_symbols_from_import(g, node, node); |
| 2801 | 2804 | } |
| 2802 | 2805 | |
| 2803 | 2806 | void preview_use_decl(CodeGen *g, AstNode *node) { |
| 2804 | 2807 | assert(node->type == NodeTypeUse); |
| 2805 | 2808 | |
| 2809 | node->data.use.resolution = TldResolutionResolving; | |
| 2806 | 2810 | IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, |
| 2807 | 2811 | node->data.use.expr, g->builtin_types.entry_namespace, nullptr); |
| 2808 | 2812 |
src/codegen.cpp+11-1| ... | ... | @@ -272,7 +272,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 272 | 272 | } |
| 273 | 273 | |
| 274 | 274 | TypeTableEntry *fn_type = fn_table_entry->type_entry; |
| 275 | fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref); | |
| 275 | LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref; | |
| 276 | if (!fn_table_entry->internal_linkage && fn_table_entry->body_node == nullptr) { | |
| 277 | LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name)); | |
| 278 | if (existing_llvm_fn) { | |
| 279 | fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); | |
| 280 | } else { | |
| 281 | fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); | |
| 282 | } | |
| 283 | } else { | |
| 284 | fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type); | |
| 285 | } | |
| 276 | 286 | |
| 277 | 287 | switch (fn_table_entry->fn_inline) { |
| 278 | 288 | case FnInlineAlways: |
std/bootstrap.zig+7-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | const root = @import("@root"); |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | |
| 7 | const want_main_symbol = std.build.linkingLibrary("c"); | |
| 7 | const want_main_symbol = std.build.linking_libc; | |
| 8 | 8 | const want_start_symbol = !want_main_symbol; |
| 9 | 9 | |
| 10 | 10 | const exit = switch(@compileVar("os")) { |
| ... | ... | @@ -18,6 +18,9 @@ var argv: &&u8 = undefined; |
| 18 | 18 | |
| 19 | 19 | export nakedcc fn _start() -> unreachable { |
| 20 | 20 | @setFnVisible(this, want_start_symbol); |
| 21 | if (!want_start_symbol) { | |
| 22 | @unreachable(); | |
| 23 | } | |
| 21 | 24 | |
| 22 | 25 | switch (@compileVar("arch")) { |
| 23 | 26 | Arch.x86_64 => { |
| ... | ... | @@ -49,6 +52,9 @@ fn callMainAndExit() -> unreachable { |
| 49 | 52 | |
| 50 | 53 | export fn main(c_argc: i32, c_argv: &&u8) -> i32 { |
| 51 | 54 | @setFnVisible(this, want_main_symbol); |
| 55 | if (!want_main_symbol) { | |
| 56 | @unreachable(); | |
| 57 | } | |
| 52 | 58 | |
| 53 | 59 | argc = usize(c_argc); |
| 54 | 60 | argv = c_argv; |
std/build.zig+2| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | const mem = @import("mem.zig"); |
| 2 | 2 | |
| 3 | pub const linking_libc = linkingLibrary("c"); | |
| 4 | ||
| 3 | 5 | pub fn linkingLibrary(lib_name: []const u8) -> bool { |
| 4 | 6 | // TODO shouldn't need this if |
| 5 | 7 | if (@compileVar("link_libs").len != 0) { |
std/c/darwin.zig created+4| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | pub extern fn getrandom(buf_ptr: &u8, buf_len: usize) -> c_int; | |
| 2 | ||
| 3 | extern fn __error() -> &c_int; | |
| 4 | pub const _errno = __error; |
std/c/index.zig created+13| ... | ... | @@ -0,0 +1,13 @@ |
| 1 | pub use @import("errno.zig"); | |
| 2 | ||
| 3 | pub use switch(@compileVar("os")) { | |
| 4 | Os.linux => @import("c/linux.zig"), | |
| 5 | Os.windows => @import("c/windows.zig"), | |
| 6 | Os.darwin, Os.macosx, Os.ios => @import("c/darwin.zig"), | |
| 7 | else => empty_import, | |
| 8 | }; | |
| 9 | ||
| 10 | pub extern fn abort() -> unreachable; | |
| 11 | ||
| 12 | ||
| 13 | const empty_import = @import("empty.zig"); |
std/c/linux.zig created+4| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | pub extern fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) -> c_int; | |
| 2 | ||
| 3 | extern fn __errno_location() -> &c_int; | |
| 4 | pub const _errno = __errno_location; |
std/c/windows.zig created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | pub extern fn _errno() -> &c_int; |
std/debug.zig+2-2| ... | ... | @@ -78,13 +78,13 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void { |
| 78 | 78 | } |
| 79 | 79 | }, |
| 80 | 80 | ObjectFormat.coff => { |
| 81 | out_stream.write("(stack trace unavailable for COFF object format)\n"); | |
| 81 | %return out_stream.write("(stack trace unavailable for COFF object format)\n"); | |
| 82 | 82 | }, |
| 83 | 83 | ObjectFormat.macho => { |
| 84 | 84 | %return out_stream.write("(stack trace unavailable for Mach-O object format)\n"); |
| 85 | 85 | }, |
| 86 | 86 | ObjectFormat.unknown => { |
| 87 | out_stream.write("(stack trace unavailable for unknown object format)\n"); | |
| 87 | %return out_stream.write("(stack trace unavailable for unknown object format)\n"); | |
| 88 | 88 | }, |
| 89 | 89 | } |
| 90 | 90 | } |
std/os.zig+46-11| ... | ... | @@ -1,20 +1,49 @@ |
| 1 | const system = switch(@compileVar("os")) { | |
| 1 | const posix = switch(@compileVar("os")) { | |
| 2 | 2 | Os.linux => @import("linux.zig"), |
| 3 | Os.darwin => @import("darwin.zig"), | |
| 3 | Os.darwin, Os.macosx, Os.ios => @import("darwin.zig"), | |
| 4 | 4 | else => @compileError("Unsupported OS"), |
| 5 | 5 | }; |
| 6 | const windows = @import("windows.zig"); | |
| 6 | 7 | const errno = @import("errno.zig"); |
| 8 | const linking_libc = @import("build.zig").linking_libc; | |
| 9 | const c = @import("c/index.zig"); | |
| 7 | 10 | |
| 8 | 11 | error Unexpected; |
| 9 | 12 | |
| 13 | /// Fills `buf` with random bytes. If linking against libc, this calls the | |
| 14 | /// appropriate OS-specific library call. Otherwise it uses the zig standard | |
| 15 | /// library implementation. | |
| 10 | 16 | pub fn getRandomBytes(buf: []u8) -> %void { |
| 11 | 17 | while (true) { |
| 12 | const ret = switch (@compileVar("os")) { | |
| 13 | Os.linux => system.getrandom(buf.ptr, buf.len, 0), | |
| 14 | Os.darwin => system.getrandom(buf.ptr, buf.len), | |
| 15 | else => @compileError("unsupported os"), | |
| 18 | const err = switch (@compileVar("os")) { | |
| 19 | Os.linux => { | |
| 20 | if (linking_libc) { | |
| 21 | if (c.getrandom(buf.ptr, buf.len, 0) == -1) *c._errno() else 0 | |
| 22 | } else { | |
| 23 | posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0)) | |
| 24 | } | |
| 25 | }, | |
| 26 | Os.darwin, Os.macosx, Os.ios => { | |
| 27 | if (linking_libc) { | |
| 28 | if (posix.getrandom(buf.ptr, buf.len) == -1) *c._errno() else 0 | |
| 29 | } else { | |
| 30 | posix.getErrno(posix.getrandom(buf.ptr, buf.len)) | |
| 31 | } | |
| 32 | }, | |
| 33 | Os.windows => { | |
| 34 | var hCryptProv: windows.HCRYPTPROV = undefined; | |
| 35 | if (!windows.CryptAcquireContext(&hCryptProv, null, null, windows.PROV_RSA_FULL, 0)) { | |
| 36 | return error.Unexpected; | |
| 37 | } | |
| 38 | defer _ = windows.CryptReleaseContext(hCryptProv, 0); | |
| 39 | ||
| 40 | if (!windows.CryptGenRandom(hCryptProv, windows.DWORD(buf.len), buf.ptr)) { | |
| 41 | return error.Unexpected; | |
| 42 | } | |
| 43 | return; | |
| 44 | }, | |
| 45 | else => @compileError("Unsupported OS"), | |
| 16 | 46 | }; |
| 17 | const err = system.getErrno(ret); | |
| 18 | 47 | if (err > 0) { |
| 19 | 48 | return switch (err) { |
| 20 | 49 | errno.EINVAL => @unreachable(), |
| ... | ... | @@ -27,13 +56,19 @@ pub fn getRandomBytes(buf: []u8) -> %void { |
| 27 | 56 | } |
| 28 | 57 | } |
| 29 | 58 | |
| 59 | /// Raises a signal in the current kernel thread, ending its execution. | |
| 60 | /// If linking against libc, this calls the abort() libc function. Otherwise | |
| 61 | /// it uses the zig standard library implementation. | |
| 30 | 62 | pub coldcc fn abort() -> unreachable { |
| 63 | if (linking_libc) { | |
| 64 | c.abort(); | |
| 65 | } | |
| 31 | 66 | switch (@compileVar("os")) { |
| 32 | Os.linux, Os.darwin => { | |
| 33 | _ = system.raise(system.SIGABRT); | |
| 34 | _ = system.raise(system.SIGKILL); | |
| 67 | Os.linux => { | |
| 68 | _ = posix.raise(posix.SIGABRT); | |
| 69 | _ = posix.raise(posix.SIGKILL); | |
| 35 | 70 | while (true) {} |
| 36 | 71 | }, |
| 37 | else => @compileError("unsupported os"), | |
| 72 | else => @compileError("Unsupported OS"), | |
| 38 | 73 | } |
| 39 | 74 | } |
std/windows.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | pub extern fn CryptAcquireContext(phProv: &HCRYPTPROV, pszContainer: LPCTSTR, | |
| 2 | pszProvider: LPCTSTR, dwProvType: DWORD, dwFlags: DWORD) -> bool; | |
| 3 | ||
| 4 | pub extern fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> bool; | |
| 5 | ||
| 6 | pub extern fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: &BYTE) -> bool; | |
| 7 | ||
| 8 | pub const PROV_RSA_FULL = 1; | |
| 9 | ||
| 10 | ||
| 11 | pub const BYTE = u8; | |
| 12 | pub const DWORD = u32; | |
| 13 | // TODO something about unicode WCHAR vs char | |
| 14 | pub const TCHAR = u8; | |
| 15 | pub const LPCTSTR = ?&const TCHAR; | |
| 16 | pub const ULONG_PTR = usize; | |
| 17 | pub const HCRYPTPROV = ULONG_PTR; |