https://ziglang.org/download/0.10.0/release-notes.html 0.10.0 Release Notes Zero the Ziguana Download & Documentation Zig is a general-purpose programming language and toolchain for maintaining robust, optimal, and reusable software. Backed by the Zig Software Foundation, the project is financially sustainable. These core team members work on Zig full-time: * Andrew Kelley * Loris Cro * Jakub Konka * Veikka Tuominen Please consider a recurring donation to the ZSF to help us pay more contributors! This release features 10 months of work: changes from 272 different contributors, spread among 4737 commits. It is the debut of the Self-Hosted Compiler. Table of Contents SS * Table of Contents * Cody Tapscott Joins the Core Zig Team * Veikka Tuominen Goes Full-Time * Support Table + Tier System o Tier 1 Support o Tier 2 Support o Tier 3 Support o Tier 4 Support + WebAssembly + Windows + Linux + macOS o Default C ABI changed from gnu to none + OpenBSD + SPARC + PowerPC + WASI + UEFI + GPU Programming * Documentation + Language Reference + Autodoc * Language Changes + Function Pointers + Packed Structs + Inline Switch Cases + Equality Testing of Error Unions + Pointers to Zero-Bit Types + @minimum and @maximum renamed to @min and @max + Removed Type Parameter from Bit Builtins + Runtime Array Concatenation & Multiplication + Address-of Temporaries Now Produces Const Pointers + std.builtin.CompilerBackend + f80 + TypeInfo.Declaration no longer has a data field + Removed anytype fields + Address Spaces + Compile Error for Misleading Whitespace + Compile Error for Pointless Discards + Disallow Leading Zeroes in Literals + More Calling Conventions + Inline Assembly + Boolean Logic with comptime RHS * Bootstrap Compiler * Self-Hosted Compiler + Is it time to upgrade? o Improvements over stage1 o Falling short of stage1 + How to Upgrade o Void Literal Syntax o Escaped Pointer to Parameter + C ABI Compatibility + C Translation + Cache System + Safety for Switching on Corrupted Enums + Referenced-By Traces + Error Return Traces o Unwrapping Errors in Switch o Removal of Useless Stack Frames + Code Generation o WebAssembly Backend o C Backend o x86 Backend o arm Backend o aarch64 Backend * Self-Hosted Linker + MachO + COFF + ELF + Wasm Modules + DWARF Linking + Linker Performance + Linker Test Harness * Standard Library + Math + File System o Optimized Tree Deletion + Data Structures + Crypto o ECDSA Signatures o Ed25519 API changes o Add Xoodoo, Deprecate Gimli o Exploit CPU Features for SHA-256 + Concurrency + Networking + Testing o Check All Allocation Failures + Debugging o std.debug.Trace + New Deflate Compressor + Formatted Printing * Bug Fixes + This Release Contains Bugs * Build System * Toolchain + LLVM 15 + musl 1.2.3 + glibc 2.34 + mingw-w64 10.0.0 + zig cc + zig c++ + zig fmt + compiler-rt * Roadmap + Package Manager + Accepted Proposals * Thank You Contributors! * Thank You Sponsors! Cody Tapscott Joins the Core Zig Team SS Ziggy the Ziguana I am pleased to announce our newest Zig team member, Cody Tapscott (screenname: topolarity). Cody excels at troubleshooting and debugging. He fearlessly deep dives into unfamiliar areas of code, relentlessly attacking the problem until a solution presents itself. In addition, Cody has proven to be a steadfast community leader, setting an example for how to treat others with kindness and respect. Please give him a warm welcome to the core Zig team. Veikka Tuominen Goes Full-Time SS If you have been following along with Zig's development process lately, you might have noticed a distinct uptick in pull requests being merged, Bug Fixes to the Self-Hosted Compiler, and implementation of Language Changes. Vexu has been doing brilliant work, and we are all fortunate that, one, he has decided to take on full-time hours lately, and two, donations have been steadily rising so that there are enough funds to offer the hours. Support Table SS Tier System SS A green check mark () indicates the target meets all the requirements for the support tier. The other icons indicate what is preventing the target from reaching the support tier. In other words, the icons are to-do items. If you find any wrong data here please submit a pull request! Tier 1 Support SS * Not only can Zig generate machine code for these targets, but the Standard Library cross-platform abstractions have implementations for these targets. * The CI server automatically tests these targets on every commit to master branch. The icon means this target does not yet have CI test coverage. * The CI server automatically produces pre-built binaries for these targets, on every commit to master, and updates the download page with links. The icon means the download page is missing this target. * These targets have debug info capabilities and therefore produce stack traces on failed assertions. * libc is available for this target even when cross compiling. * All the behavior tests and applicable standard library tests pass for this target. All language features are known to work correctly. Experimental features do not count towards disqualifying an operating system or architecture from Tier 1. The icon means there are known bugs preventing this target from reaching Tier 1. * zig cc, zig c++, and related toolchain commands support this target. * If the Operating System is proprietary then the target is not marked deprecated by the vendor. The icon means the OS is officially deprecated, such as macos/x86. freestanding Linux 3.16+ macOS 11+ Windows 8.1+ WASI x86_64 N/A x86 #1929 #537 N/A aarch64 #2443 N/A arm #3174 N/A mips #3345 N/A N/A N/A riscv64 #4456 N/A N/A N/A sparc64 #4931 N/A N/A N/A powerpc64 N/A N/A N/A wasm32 N/A N/A N/A Tier 2 Support SS * The Standard Library supports this target, but it is possible that some APIs will give an "Unsupported OS" compile error. One can link with libc or other libraries to fill in the gaps in the standard library. The icon means the standard library is too incomplete to be considered Tier 2 worthy. * These targets are known to work, but may not be automatically tested, so there are occasional regressions. means that nobody has really looked into this target so whether or not it works is unknown. * Some tests may be disabled for these targets as we work toward Tier 1 Support. free Linux macOS Windows FreeBSD NetBSD DragonFlyBSD UEFI standing 3.16+ 11+ 8.1+ 12.0+ 8.0+ 5.8+ x86_64 Tier 1 Tier Tier Tier 1 1 1 x86 Tier 1 N/A aarch64 Tier 1 Tier N/A 1 arm Tier 1 N/A mips64 N/A N/A N/A N/A mips Tier 1 N/A N/A N/A N/A powerpc64 N/A N/A N/A powerpc N/A N/A N/A riscv64 Tier 1 N/A N/A N/A sparc64 Tier 1 N/A N/A N/A N/A Tier 3 Support SS * The standard library has little to no knowledge of the existence of this target. * If this target is provided by LLVM, LLVM has the target enabled by default. * These targets are not frequently tested; one will likely need to contribute to Zig in order to build for these targets. * The Zig compiler might need to be updated with a few things such as + what sizes are the C integer types + C ABI calling convention for this target + start code and default panic handler * zig targets is guaranteed to include this target. freestanding Linux Windows FreeBSD NetBSD UEFI 3.16+ 8.1+ 12.0+ 8.0+ x86_64 Tier 1 Tier 1 Tier 1 Tier 2 Tier 2 Tier 2 x86 Tier 1 Tier 2 Tier 2 Tier 2 aarch64 Tier 1 Tier 2 arm Tier 1 Tier 2 mips64 Tier 2 Tier 2 N/A N/A mips Tier 1 Tier 2 N/A N/A riscv64 Tier 1 Tier 2 N/A powerpc32 Tier 2 Tier 2 N/A N/A powerpc64 Tier 2 Tier 2 N/A N/A bpf N/A N/A hexagon N/A N/A amdgcn N/A N/A sparc N/A N/A s390x N/A N/A lanai N/A N/A csky N/A N/A freestanding emscripten wasm32 Tier 1 Tier 4 Support SS * Support for these targets is entirely experimental. * If this target is provided by LLVM, LLVM may have the target as an experimental target, which means that you need to use Zig-provided binaries for the target to be available, or build LLVM from source with special configure flags. zig targets will display the target if it is available. * This target may be considered deprecated by an official party, in which case this target will remain forever stuck in Tier 4. * This target may only support -femit-asm and cannot emit object files, in which case -fno-emit-bin is enabled by default and cannot be overridden. Tier 4 targets: * avr * riscv32 * xcore * nvptx * msp430 * r600 * arc * tce * le * amdil * hsail * spir * kalimba * shave * renderscript * 32-bit x86 macOS, 32-bit ARM macOS, powerpc32 and powerpc64 macOS, because Apple has officially dropped support for them. WebAssembly SS During this release cycle, a lot of time was spent on both visible and invisible improvements. Refactors were done to increase readability, maintainability, and also the performance of the backend and its generated code. With this release, we're one step closer to being able to make the WebAssembly Backend the default for debug mode . Resolved issues: * Wasm has a max stack size of ~66K (#3735) * zig cc doesn't support clang Wasm linker arg --export (#12126) * Missing "name" section from binary (#11420) * No Debugging symbols for Wasm target (#11330) * Compile Zig (compiler) to Wasm/WASI (#10716) * Saturating shift-left error on wasm32 with > 64 bits (#9668) * crypto.25519.field.Fe.isSquare causes too many locals to be emitted (#11947) Windows SS Improvements to the Standard Library: * libc++ now includes the fs/filesystem module. * Removed __muloti4 from libc++ (#10719) compiler-rt already provides this symbol but libc++ was also providing it and when linking libc++ it caused a crash on Windows. * zig test has proper detection for Windows console. * Add CANNOT_DELETE as a possible error in os.windows.DeleteFile. * Use explicit integer bit widths for windows GUID. * Improved comptime windows GUID.parse performance. * child_process: collectOutputWindows handle broken_pipe from ReadFile (#10813) * std.os: throw compile error for argv on Windows * std.Thread.getName/setName: rework windows implementation (#10003 ) * Added GetProcessTimes binding to the kernel32.zig (#11488) * std.coff: parse out codebase and entrypoint from optionalheader * Introduce std.process.EnvMap which handles case insensitivity on Windows (#10796) * Added missing error to WriteFile * Fixed HANDLER_ROUTINE callconv * Changed HKEY to *opaque {} * Added os check for std.fs.setAsCwd() to work with Windows The 32-bit Windows tarball is missing for this release due to (#12886 ). It will be available again in the 0.10.1 bugfix release. Linux SS Previously, updating the SYS enum for each architecture required manually looking at the syscall tables and inserting any new additions. Now there is a tool, generate_linux_syscalls.zig, that automates this process using the syscall tables in the Linux source tree. On architectures without a table, it runs zig cc as a pre-processor to extract the system-call numbers from the Linux headers. Improvements to the Standard Library: * In the path names of Linux headers that Zig distributes, rename arm64 to aarch64 for consistency (#10699) * io_uring: fix version check in tests (#10466) * io_uring: improve IO_Uring.copy_cqe * io_uring: add recvmsg and sendmsg (#10212) * io_uring: implemented automatic buffer selection (#10197) * io_uring: added new flags and opcodes * io_uring: allow for optional arguments * Fixed os.rusage when linking with c library on Linux (#10543) * std.c: add shm_open and shm_unlink * fchown: use the 32-bit uid/gid variant of the syscall on 32-bit linux targets. * Fixed preadv/pwritev bug on 64bit platform * Added Linux support for POSIX file locking with fcntl * Fixed ucontext_t * std.fs: Handle EINVAL from getdents64 (#11178) * Added Seccomp bits for linux (#10717) * Fixed signature of setgroups * Ported signal handling in abort() from musl (#11565) * Added IN_MASK_CREATE and corresponding error handling in inotify_add_watch * Fixed os.linux.S function signatures to use mode_t * Added linux support for packet sockaddr * Fixes to BPF module * copy_file_range: save a syscall for most operations macOS SS Added support for macOS 13 (Ventura); dropped support for macOS 10 (Catalina). This matches Apple's security policy. * libc headers are updated and more complete (copyfile.h). * Use libc if_nametoindex for macOS when parsing IPs (#10576) * Implement segfault handler for macOS (both x86_64 and aarch64). * std.debug: fix edge cases in macOS debug symbol lookup * std: add mach_* syscalls for process mgmt * Added more darwin primitives to the Standard Library * Updated Mach routines for accessing page info * Fixed incorrect return types on some libc functions (#12964) * Extend CodeSignature to accept entitlements. * Fixed child process spawn on macos hanging with stdin, stdout behavior set to pipe (#11480) Default C ABI changed from gnu to none SS Prior to this change Zig would assume the ABI for Apple targets to be GNU which could result in subtle errors of emitting calls to non-existent system libc provided functions such as _sincosf which is a GNU extension and therefore not provided by macOS. This would result in linker errors due to not finding the symbol in libSystem.tbd. With this change, Zig now correctly identifies macOS (and other Apple platforms such as iPhoneOS, tvOS, and watchOS) as having ABI none (# 11684). In LLVM, this translates to unknown: // main.ll target triple = "aarch64-unknown-macos-unknown" OpenBSD SS * Added OpenBSD Authentication constants and functions (#10376) * Fixed i386-openbsd failing to build from source (#9705) * Fixed sigcontext struct and avoid defining fxsave64 SPARC SS * sparcv9 has been renamed to sparc64. * More compiler-rt routines were added. * libunwind is updated to be compatible with sparc64. * Fixed stat struct definition for sparc64. * The Self-Hosted Compiler now has an experimental sparc64 backend (not based on LLVM). PowerPC SS powerpc64 moved from Tier 3 Support to Tier 2 Support. powerpc64le now has CI test coverage for the behavior tests, the Standard Library, targeting musl, and targeting glibc. Softfloat support was added in compiler-rt. WASI SS Zig can now build itself for the WASI target. Shell $ uname -m x86_64 $ zig build -Dtarget=wasm32-wasi -Drelease $ file zig-out/bin/zig.wasm zig-out/bin/zig.wasm: WebAssembly (wasm) binary module version 0x1 (MVP) $ ls -hl zig-out/bin/zig.wasm -rwxr-xr-x 1 andy users 37M Oct 19 12:24 zig-out/bin/zig.wasm $ cat hello.zig const std = @import("std"); pub fn main() void { std.io.getStdOut().writeAll("Hello, World!\n") catch {}; } $ wasmtime --dir=. --mapdir=/cwd::. --mapdir=/cache::"$HOME/.cache/zig" --mapdir=/zig::zig-out zig-out/bin/zig.wasm build-exe /cwd/hello.zig -target x86_64-linux-musl $ chmod +x hello $ file hello hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, with debug_info, not stripped $ ./hello Hello, World! The chmod is because of WebAssembly/wasi-filesystem#33. This snippet demonstrates creating a WASI build of Zig, then executing it with wasmtime 1.0.1, cross compiling an executable for x86_64-linux, and then executing the cross-compiled executable. Computers are fun! Additionally: * Zig's WASI libc has been synchronized with upstream (#11864) * The Standard Library is modified to integrate with libc when linking against it. * Added emulated CWD to std.os for WASI targets (#11021) * The Standard Library has been synchronized with the latest WASI snapshot, which includes sock_accept (#13011) This makes it possible to run web servers in WASI. UEFI SS * Standard Library improvements/fixes (#10566) (#10604) (#12897) * Fixed GUID formatting (#11452) * Added BlockIoProtocol * Querying memory map size with no allocation This makes possible to query the memory map size from EFI firmware without making any allocation beforehand. This makes possible to be precise about the size of the allocation which will own a copy of the memory map from the UEFI application. GPU Programming SS * Added experimental support for AMDGPU. * Added support for debug info on NVPTX. * Added std.os.panic implementation for NVPTX. * Made Address Spaces easier to use when targeting GPUs. Documentation SS There were minimal changes to the Language Reference in 0.10.0, however, the big news is that Autodoc has been completely rewritten! Language Reference SS Ziggy the Ziguana * Replace mentions of c_void with anyopaque. * Added documentation for implicit struct pointer dereferencing. * Reorganize @truncate and @intCast for clarity. * Added documentation for common mistakes in errdefer scoping. * Clarify behavior of slicing with constant indexes (#11219) * Add pointer arithmetic example. * Updated to keep in sync with Language Changes. * Miscellaneous minor improvements and corrections. Autodoc SS This feature is still experimental. Zig gained a first (experimental) implementation of automated doc generation in version 0.6.0. That version integrated with the Bootstrap Compiler and, more specifically, it observed the data resulting from semantic analysis. With the new Self-Hosted Compiler we needed to re-implement the main part of the system (now internally named Autodoc) to make it consume the new data format, but we took the opportunity of also re-designing its entire approach to data collection. The first Autodoc proof-of-concept (from Zig 0.6.0) relied entirely on semantic analysis data, which had the main downside of only showing the information that had been typechecked. The most annoying result of this fact was that the docs would leave holes in the documentation, making them feel unreliable. The new Autodoc is instead based on a two pass approach. The main source of information consumed by Autodoc is ZIR, an untyped intermediate representation close to an AST, which gets generated unconditionally for the entire codebase everytime a Zig project is built. This makes sure that Autodoc doesn't have blind spots. The problem with ZIR is that it is untyped, which means that it describes the program before any comptime logic is run. This means that ZIR alone won't be enough to find out all the concrete instantiations of a generic type, for example. To solve this problem, we plan to use ZIR information as the main skeleton for Autodoc, and to overlay semantic analysis information on top of that, in order to obtain both full coverage and also full resolution of comptime metaprogramming. Autodoc is still a work in progress and in fact it is still relying on ZIR information only. There is a tremendous amount of work ahead of us and, while we encourage you to check out Zig's stdlib docs, there are plenty of basic things that still need to be implemented. If you see something missing or broken in Autodoc, please file an issue or, even better, consider becoming a contributor. Language Changes SS Function Pointers SS In Zig 0.9.x and the Bootstrap Compiler, the type fn () void is a function pointer and acts like a pointer. However, the language spec, which is not written yet, will have this type be a function body type. It must be compile-time-known, and in order to get a function pointer, *const fn () void must be used. The Self-Hosted Compiler implements this correctly, which means your project will likely break everywhere that you use a function pointer. Here is the problem most people will run into: test.zig test "function pointer" { const s = foo(); s.fnPtr(); } const S = struct { fnPtr: fn () void, }; fn bar() void {} fn baz() void {} var runtime: bool = true; fn foo() S { if (runtime) { return .{ .fnPtr = bar, }; } else { return .{ .fnPtr = baz, }; } } Shell $ zig test test.zig docgen_tmp/test.zig:16:9: error: unable to resolve comptime value if (runtime) { ^~~~~~~ docgen_tmp/test.zig:16:9: note: condition in comptime branch must be comptime-known docgen_tmp/test.zig:15:10: note: expression is evaluated at comptime because the function returns a comptime-only type 'test.S' fn foo() S { ^ docgen_tmp/test.zig:7:12: note: struct requires comptime because of this field fnPtr: fn () void, ^~~~~~~~~~ docgen_tmp/test.zig:7:12: note: use '*const fn() void' for a function pointer type fnPtr: fn () void, ^~~~~~~~~~ docgen_tmp/test.zig:2:18: note: called from here const s = foo(); ~~~^~ The solution becomes obvious upon reading the compile error notes: - fnPtr: fn () void,+ fnPtr: *const fn () void, Packed Structs SS In previous releases of Zig there have been some nasty bugs that unfortunately did not get fixed for a long time, resulting in packed structs having a deservedly poor reputation. Finally, the situation is resolved. Packed structs have been reworked, both in terms of the Zig language specification, as well as the implementation. Now, one can reason about packed structs in a similar way as one reasons about enums - that is - they are merely integers wearing fancy hats. Each packed struct has a backing integer which defines the ABI of the type as well as the memory layout. The backing integer can be specified explicitly, or it can be inferred from the total bits of all the fields. If the backing integer is explicitly specified, then a compile error enforces that all the fields add up to that number of bits: test.zig const S = packed struct(u32) { a: u29, b: u2, }; test "packed struct" { var s: S = .{ .a = 1234, .b = 3, }; _ = s; } Shell $ zig test test.zig docgen_tmp/test.zig:1:25: error: backing integer type 'u32' has bit size 32 but the struct fields have a total bit size of 31 const S = packed struct(u32) { ^~~ referenced by: S: docgen_tmp/test.zig:1:18 test.packed struct: docgen_tmp/test.zig:7:12 remaining reference traces hidden; use '-freference-trace' to see all reference traces The fields are specified in order starting from logically least-significant and ending with logically most-significant within the backing integer. The backing integer is stored in memory with the same endianness as the equivalent integer type for that target. This makes Zig's packed structs have a well-defined memory layout, unlike in C where the memory layout is implementation-defined and therefore usually cannot be relied upon. In the near future, the syntax will change to avoid confusion with C's packed structs, which is a different concept that relates to padding. In Zig, such a struct is done by using extern and setting each field's alignment to 1 byte: align-1.zig const std = @import("std"); const assert = std.debug.assert; // Equivalent of C's __attribute__((__packed__)) const S = extern struct { a: u64 align(1), b: u8 align(1), }; comptime { assert(@sizeOf([2]S) == 18); } Shell $ zig test align-1.zig All 0 tests passed. Inline Switch Cases SS The inline keyword can now be placed in front of switch cases. This effectively turns a runtime-known value into a compile-time-known value: inline-switch.zig const std = @import("std"); pub fn main() !void { var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); const arena = arena_instance.allocator(); const args = try std.process.argsAlloc(arena); const arg = if (args.len >= 2) args[1] else "50"; const some_number = try std.fmt.parseInt(i32, arg, 10); switch (some_number) { inline 1...100 => |x| { foo(x); }, else => @panic("not in range"), } } fn foo(comptime x: i32) void { // Doing something that requires a comptime number, such as // using it as the length of an array: var array: [x]u8 = undefined; for (array) |*elem, i| { elem.* = @intCast(u8, i); } } Shell $ zig build-exe inline-switch.zig $ ./inline-switch In this example, we take a number that was passed in as a command line parameter at runtime, and pass it to a function that requires a comptime parameter. This works because the switch gets inlined - 100 prongs are generated, similar to unrolling an inline for loop that looped from 1 to 100. Let's look at a less contrived example. Here is the use case where this pattern is the most useful: dynamic dispatch for enums and tagged unions. Before: pub fn iterate(base: *Node, index: usize) ?*Node { inline for (@typeInfo(Tag).Enum.fields) |field| { const tag = @intToEnum(Tag, field.value); if (base.tag == tag) { return @fieldParentPtr(tag.Type(), "base", base).iterate(index); } } unreachable; } After: pub fn iterate(base: *Node, index: usize) ?*Node { return switch (base.tag) { inline else => |tag| @fieldParentPtr(tag.Type(), "base", base).iterate(index), }; } Unfortunately, we cannot use this feature in the Standard Library or the Self-Hosted Compiler yet, because this feature is not implemented in the Bootstrap Compiler. The next steps to accomplish this will be enhancing the C Backend until we can replace the bootstrap compiler. See the full inline switch documentation in the Language Reference. Equality Testing of Error Unions SS Similar to how the == operator can be used to check if an optional is null, it can now also be used to check if an error union is a specific error code: error-equality.zig const std = @import("std"); const expect = std.testing.expect; test "equality testing of error unions" { try expect(foo() == error.Bad); try expect(bar() == error.RealBad); } fn foo() anyerror { return error.Bad; } fn bar() anyerror!void { return error.RealBad; } Shell $ zig test error-equality.zig 1/1 test.equality testing of error unions... OK All 1 tests passed. Pointers to Zero-Bit Types SS Before, a pointer to a zero-bit type was itself a zero bit type. Now, pointers to zero-bit types store addresses the same as regular pointers. This change is unlikely to affect many codebases. A use case where it might be relevant is representing a struct that has a variable-sized last field, as demonstrated by the name field here: vla.zig const std = @import("std"); const testing = std.testing; test "struct with variable length last field" { const foo = try make(testing.allocator, "Blah blah"); defer foo.free(testing.allocator); try testing.expect(foo.a == 1234); try testing.expectEqualStrings(foo.getName(), "Blah blah"); // The pointer address of the 'name' field is still well-defined and meaningful: try testing.expect(@ptrCast(*u8, &foo.name).* == 'B'); } const S = extern struct { a: i32, name: [0]u8 = .{}, fn getName(s: *const S) []const u8 { return std.mem.sliceTo(@ptrCast([*:0]const u8, &s.name), 0); } fn free(s: *S, gpa: std.mem.Allocator) void { const buf = @ptrCast([*]u8, s)[0 .. @sizeOf(S) + s.getName().len + 1]; gpa.free(buf); } }; fn make(gpa: std.mem.Allocator, name: []const u8) !*S { const s = try make_vla(gpa, S, name.len + 1); s.* = .{ .a = 1234 }; const name_ptr = @ptrCast([*]u8, &s.name); std.mem.copy(u8, name_ptr[0..name.len], name); name_ptr[name.len] = 0; return s; } fn make_vla(gpa: std.mem.Allocator, comptime T: type, extra_bytes: usize) !*T { const buf = try gpa.alignedAlloc(u8, @alignOf(T), @sizeOf(T) + extra_bytes); const ptr = @ptrCast(*T, buf); return ptr; } Shell $ zig test vla.zig 1/1 test.struct with variable length last field... OK All 1 tests passed. This assertion does not pass with the Bootstrap Compiler but it does with the Self-Hosted Compiler: ptrs.zig const std = @import("std"); const assert = std.debug.assert; comptime { assert(@sizeOf(*u0) == @sizeOf(*u8)); } Shell $ zig test ptrs.zig All 0 tests passed. However, pointers to comptime-only types are still zero bit types, such as *comptime_int. @minimum and @maximum renamed to @min and @max SS See the Language Reference: @min @max zig fmt will automatically perform the rename. Removed Type Parameter from Bit Builtins SS The following builtins no longer have types as the first parameter: * @byteSwap * @bitReverse * @clz * @ctz * @popCount Instead, the type is inferred from the operand. This makes the builtins more ergonomic for SIMD. Runtime Array Concatenation & Multiplication SS The ++ and ** operators now support runtime-known operands, as long as the length is compile-time-known: array_cat.zig const std = @import("std"); pub fn main() !void { var array1 = "hellp".*; var array2 = "!world ".*; array1[array1.len - 1] -= 1; std.mem.swap(u8, &array2[0], &array2[array2.len - 1]); const final = array1 ++ array2 ++ "\n"; try std.io.getStdOut().writeAll(final); } Shell $ zig build-exe array_cat.zig $ ./array_cat hello world! This may be a breaking change for some people who were relying on Zig to automatically evaluate the operands in a comptime scope, like this: test.zig const std = @import("std"); test { const a = foo() ++ "bb"; try std.testing.expect(a.len == 5); } fn foo() []const u8 { return "aaa"; } Shell $ zig test test.zig docgen_tmp/test.zig:4:18: error: unable to resolve comptime value const a = foo() ++ "bb"; ~~~^~ docgen_tmp/test.zig:4:18: note: slice value being concatenated must be comptime-known The previous behavior can be obtained with explicit use of the comptime keyword: - const a = foo() ++ "bb";+ const a = comptime foo() ++ "bb"; This language change is implemented in Self-Hosted Compiler only. Address-of Temporaries Now Produces Const Pointers SS Zig 0.9.x and the Bootstrap Compiler allow this code: test.zig const std = @import("std"); test { const arena = std.heap.ArenaAllocator.init(std.heap.page_allocator).allocator(); const ptr = try arena.create(i32); ptr.* = 1234; } Shell $ zig test test.zig docgen_tmp/test.zig:4:72: error: expected type '*heap.arena_allocator.ArenaAllocator', found '*const heap.arena_allocator.ArenaAllocator' const arena = std.heap.ArenaAllocator.init(std.heap.page_allocator).allocator(); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~ docgen_tmp/test.zig:4:72: note: cast discards const qualifier Zig 0.10.0 does not allow this. Address of temporaries produces constant pointers for safety reasons. To fix this code, extract the temporary into an explicit var. This makes the mutable temporary more obvious, which is safer. - const arena = std.heap.ArenaAllocator.init(std.heap.page_allocator).allocator();+ var arena_state = std.heap.ArenaAllocator.init(std.heap.page_allocator); + const arena = arena_state.allocator(); std.builtin.CompilerBackend SS Now that there are multiple competing Code Generation backends, it may be necessary to work around bugs in one of them. Similarly, as Zig gains popularity, there may be third party compiler implementations which have quirks. Zig now provides a comptime enum value so that one can use conditional compilation to work around such issues. Documentation comments are reproduced here: test.zig /// This enum is set by the compiler and communicates which compiler backend is /// used to produce machine code. /// Think carefully before deciding to observe this value. Nearly all code should /// be agnostic to the backend that implements the language. The use case /// to use this value is to **work around problems with compiler implementations.** /// /// Avoid failing the compilation if the compiler backend does not match a /// whitelist of backends; rather one should detect that a known problem would /// occur in a blacklist of backends. /// /// The enum is nonexhaustive so that alternate Zig language implementations may /// choose a number as their tag (please use a random number generator rather /// than a "cute" number) and codebases can interact with these values even if /// this upstream enum does not have a name for the number. Of course, upstream /// is happy to accept pull requests to add Zig implementations to this enum. /// /// This data structure is part of the Zig language specification, however, the /// specific tag names and values are implementation defined. pub const CompilerBackend = enum(u64) { /// It is allowed for a compiler implementation to not reveal its identity, /// in which case this value is appropriate. Be cool and make sure your /// code supports `other` Zig compilers! other = 0, /// The original Zig compiler created in 2015 by Andrew Kelley. /// Implemented in C++. Uses LLVM. stage1 = 1, /// The reference implementation self-hosted compiler of Zig, using the /// LLVM backend. stage2_llvm = 2, /// The reference implementation self-hosted compiler of Zig, using the /// backend that generates C source code. /// Note that one can observe whether the compilation will output C code /// directly with `object_format` value rather than the `compiler_backend` value. stage2_c = 3, /// The reference implementation self-hosted compiler of Zig, using the /// WebAssembly backend. stage2_wasm = 4, /// The reference implementation self-hosted compiler of Zig, using the /// arm backend. stage2_arm = 5, /// The reference implementation self-hosted compiler of Zig, using the /// x86_64 backend. stage2_x86_64 = 6, /// The reference implementation self-hosted compiler of Zig, using the /// aarch64 backend. stage2_aarch64 = 7, /// The reference implementation self-hosted compiler of Zig, using the /// x86 backend. stage2_x86 = 8, /// The reference implementation self-hosted compiler of Zig, using the /// riscv64 backend. stage2_riscv64 = 9, /// The reference implementation self-hosted compiler of Zig, using the /// sparc64 backend. stage2_sparc64 = 10, _, }; Please read the documentation comments carefully before using this value. In summary, you can work around compiler issues by doing something like this: const FnPtr = switch (builtin.zig_backend) { .stage1 => fn()void, else => *const fn()void, }; f80 SS Zig now has f80, a primitive type that provides x86 extended precision format. This type is fully supported on all systems. On those which lack hardware support for this type, softfloat implementations are provided by compiler-rt. When would you use this? Well if you were implementing a C compiler for instance. It is also required for C ABI Compatibility - for some C targets long double is an alias for f80. This is implemented in both the Bootstrap Compiler and Self-Hosted Compiler. TypeInfo.Declaration no longer has a data field SS Zig 0.9.x allows inspecting certain kinds of extra information about declarations via @typeInfo, but 0.10.0 does not (#10753): test.zig const std = @import("std"); test "type info on declarations" { _ = @typeInfo(@This()).Struct.decls[0].data; } Shell $ zig test test.zig docgen_tmp/test.zig:3:44: error: no field named 'data' in struct 'builtin.Type.Declaration' _ = @typeInfo(@This()).Struct.decls[0].data; ^~~~ /home/andy/Downloads/zig/lib/std/builtin.zig:410:29: note: struct declared here pub const Declaration = struct { ^~~~~~ The data field looked like this: pub const Data = union(enum) { Type: type, Var: type, Fn: FnDecl, }; This was removed because it was an unnecessary complication. There are already alternatives for each of these fields: * Var - @typeOf(@field(a, b)) * Type - @field(a, b) (after checking the @typeOf) * Fn - @field(a, b) (after checking the @typeOf) This is implemented in both the Bootstrap Compiler and Self-Hosted Compiler. Removed anytype fields SS Zig 0.9.x allows declaring a struct field anytype which made the struct be a compile-time-only type and made the field's type allowed to be changed during comptime code execution. test.zig const S = struct { x: anytype }; Shell $ zig test test.zig docgen_tmp/test.zig:1:23: error: expected type expression, found 'anytype' const S = struct { x: anytype }; ^~~~~~~ This was removed in order to simplify the language (#10766). This is implemented in both the Bootstrap Compiler and Self-Hosted Compiler. Address Spaces SS New builtin: @addrSpaceCast Compile Error for Misleading Whitespace SS Have a look at this code: const directions = [_]isize{ -pitch-1, -pitch, -pitch+1 -1, 1, pitch-1, pitch, pitch+1, }; See the bug? It took me a minute. Answer: the , is missing from the third item in the list. This makes the list 7 items long instead of 8, and the third item -pitch+1-1. This code is now a compile error due to a new rule in the language: misleading whitespace is a compile error. In this case the misleading whitespace is being inconsistent on either side of a binary operator. test.zig const directions = [_]isize{ -pitch-1, -pitch, -pitch+1 -1, 1, pitch-1, pitch, pitch+1, }; Shell $ zig test test.zig docgen_tmp/test.zig:5:5: error: binary operator `-` has whitespace on one side, but not the other. -1, ^ More compile errors for misleading whitespace are planned. Compile Error for Pointless Discards SS It is no longer possible to discard a local variable or parameter that is referenced: test.zig test "example" { var x: i32 = 1234; _ = x; var y = x; _ = y; } Shell $ zig test test.zig docgen_tmp/test.zig:3:9: error: pointless discard of local variable _ = x; ^ docgen_tmp/test.zig:4:13: note: used here var y = x; ^ Zero the Ziguana The fix is simple - delete the pointless discard. This compile error dovetails with the compile error for unused locals introduced in Zig 0.9.0. Together, these compile errors ensure that when you are reading Zig code, whether it is yours or some random codebase on the Internet, you can be assured that all locals are used somewhere, and that any discarded locals are otherwise unused. This is a divisive feature of Zig. Generally, those with large codebases favor the errors since they help prevent bugs and aid refactoring, while those with small codebases find these errors annoying and unproductive. There is an upcoming autofix feature that unfortunately did not make it in time for 0.10.0 which can be used by those who find this pair of compile errors problematic for their workflow. Disallow Leading Zeroes in Literals SS This new compile error helps catch bugs (#11963) (#12417): test.zig var x: i032 = 1234; var y: i32 = 01234; Shell $ zig test test.zig docgen_tmp/test.zig:1:8: error: primitive integer type 'i032' has leading zero var x: i032 = 1234; ^~~~ docgen_tmp/test.zig:2:14: error: number '01234' has leading zero var y: i32 = 01234; ^~~~~ docgen_tmp/test.zig:2:14: note: use '0o' prefix for octal literals This caught two C header translation mistakes in haiku.zig. More Calling Conventions SS The Win64 calling convention is the same as Cdecl on Windows x64, however using the C calling convention as a stand-in for the Win64 calling convention only works when the compiler targets Windows. This means, before Zig 0.10.0, one was not able to create a function with the Win64 calling convention when targeting an OS other than Windows. Now the Win64 calling convention can be used from Zig code on any target, using std.builtin.CallingConvention.Win64 (#11585). Also added in this release: * PtxKernel * AmdgpuKernel This is implemented in both the Bootstrap Compiler and Self-Hosted Compiler. Inline Assembly SS The sub-project of parsing inline assembly in the Self-Hosted Compiler has been delayed in the past due to the large tables of instructions that would be declared in source files, likely running into the unwieldly memory consumption properties of the Bootstrap Compiler. But now that we are shipping a stage3 build, this obstacle has been overcome. Zig 0.9.x allowed comptime expressions to produce the assembly template for inline assembly. For most of the 0.10.0 release cycle, Zig emitted a compile error when inline assembly source code was not a string literal, however, that restriction was lifted just before this 0.10.0 release. Zig is at a crossroads right now with regards to inline assembly. On one hand, there is this proposal: parse inline assembly syntax according to a set of dialects; integrate inline assembly more closely with the zig language Meanwhile, other stakeholders have rightfully pointed out that inline assembly abstractions based on string concatenation are easy to reason about and do not require any more language features added. Either way, Zig needs to gain the ability to parse inline assembly for all targets, so that it can get lowered to the LLVM backend as well as the other Code Generation backends, so that error handling, semantic analysis, and language features of inline assembly can be uniform across backends, something that would not be the case if LLVM is sometimes responsible for assembly code parsing and sometimes not. Whichever path Zig ends up going down, we will make sure to involve the users who will ultimately be affected, such as the Zig Embedded Group, and the various folks who have started operating system projects written in Zig. Boolean Logic with comptime RHS SS foo() and false as well as bar() or true are now compile-time-known expressions. The left-hand side is allowed to contain runtime side effects, which are preserved as expected. Allows code like this to compile: test.zig const std = @import("std"); var i: usize = 0; fn foo() bool { const stdout = std.io.getStdOut().writer(); stdout.print("i = {}\n", .{i}) catch unreachable; return true; } pub fn main() void { if (false and foo()) { // This works already today @compileError("Condition should be comptime-false"); } i += 1; if (foo() and false) { // PR allows this condition to be comptime-known @compileError("Condition should be comptime-false"); } } Shell $ zig build-exe test.zig $ ./test i = 1 Note that side effects are still respected, but the result can be compile-time-known despite them. This is the same way Zig handles, e.g. x * 0 and 0 * x (#6768). Bootstrap Compiler SS In the previous release, the main Zig compiler everybody used was the bootstrap compiler, written in C++, also known as stage1. This release changes the default to become the Self-Hosted Compiler, however, the legacy compiler can be selected with -fstage1. Despite the main focus being the Self-Hosted Compiler, this release brings some improvements to the legacy compiler codebase as well: * Fixed access of slice sentinel at comptime. * Fixed @errorName null termination. * Improved compilation speed of comptime format string parsing. * C ABI fixes related to packed struct (#10499) * Fixed packed struct (#11279) * Fixed exporting of symbols on WebAssembly. * Fixed bigint_init_bigfloat for single-limb negative floats (# 10592) * Fixed big-endian handling in stage1 bigint_write_twos_complement (#10858) * Removed the noisy "referenced here" error note. The Self-Hosted Compiler has this implemented in a better way. * Fixed saturating arithmetic on type comptime_int (#10393) * Fixed x86 i128 C ABI for extern structs (#10834) * Improve error message if error union is cast to payload (#10770) * Implemented f128 @rem * Fixed comptime saturation subtraction (#10870) * Improved error message when casting tuples (#10913) * Made type names more unique (#11226) * Implemented casting from u0 * Fixed crash when generating a particular error note * Fixed crash when slicing string literal with sentinel * Fixed referencing type info alignment causes error in unrelated function (#6944) * Fixed building with Clang 16 * CMake: detect use of CMAKE_PREFIX_PATH env var (#13242) Self-Hosted Compiler SS Zero the Ziguana The main feature of this release cycle is the debut of the self-hosted compiler. It is now enabled by default, however the Bootstrap Compiler is available behind the -fstage1 flag for those not ready to upgrade. This compiler implementation beats the older one in terms of performance and memory usage. Here are two data points for the compiler building itself (measured on an Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz): * Wall Clock Time: 43 seconds to 40 seconds (7% faster) * Peak RSS: 9.6 GiB to 2.8 GiB (3.5x less memory used) The new compiler implementation is slightly faster despite that, unlike the Bootstrap Compiler, it is capable of incremental compilation due to being tightly coupled with the linker. The bigger compilation speed wins will come with the Code Generation backends that do not use LLVM. The vast majority of the development effort of this release cycle was spent on this new compiler implementation, and therefore the Language Changes are minimal. Instead, this new codebase lays the groundwork for major enhancements, mainly concerned with speeding up the edit/ test/debug cycle. Now that the self-hosted compiler is no longer sucking up so much effort, you should expect to see significant, visible progress on these Roadmap milestones. Miscellaneous improvements: * Introduce --entry [name] to set entrypoint symbol name (#10475) * --strip is renamed to -fstrip and -fno-strip is introduced. Stripping is enabled by default for ReleaseSmall and the flag is properly forwarded to LLD. * Linking libc++ now implies also linking libc. * CLI: ignore -lgcc_s when it is redundant with compiler-rt. For some projects, they can't help themselves, -lgcc_s ends up on the compiler command line even though it does not belong there. In Zig we know what -lgcc_s does. It is an alternative to compiler-rt. With this commit we emit a warning telling that it is unnecessary to put such thing on the command line, and happily ignore it, since we will fulfill the dependency with compiler-rt. Since libgcc also provides exception handling functions, this flag on the linker line additionally links libunwind, which is also provided by Zig. Furthermore, linking libunwind implies linking libc. * Added support for -fbuild-id, -fno-build-id (#3047) * Enable full RELRO by default (#11825) * Remove -z noexecstack option (#11826) * Fixed crash when building static library in the same directory where Zig source is located (#11833) * Improve error reporting when libc is missing. * Added ZIG_GLOBAL_CACHE_DIR environment variable. * Improved glibc version and dynamic linker detection (#12788) * zig env now includes a field for the native target. * Improved header searchlist handling (#12888) * Better error message for --name operand containing folder separator. * Better template for zig init-exe * Native target detection now supports the case when /usr/bin/env happens to be a shell script. It will follow the shebang line until it finds an ELF file from which to learn the native dynamic linker path. Additionally, glibc version detection is improved. * Fixed header searchlist priorities (#12888) * Native include dir and lib dir are now aware of GUIX environment variables (#13145) Is it time to upgrade? SS One option you have is to simply wait for 0.10.1, or even 0.11.0, before attempting an upgrade. This gives you the smoothest experience, letting other, more brave souls, help with quality assurance before you get your hands dirty. There is no shame in this; do what works for you. If anything goes wrong in the upgrade, you can always start using -fstage1 to get the old compiler, or put the equivalent in your build.zig file, so that your users can continue using zig build as usual. exe.use_stage1 = true; The new compiler, sometimes called "stage2" or "stage3", is in many ways better than the old compiler (also called "stage1"), however it is not yet strictly better. All 0.10.x releases will have the -fstage1 option; the upgrade only will become mandatory starting with 0.11.0. For some users, sticking with stage1 for the duration of the 0.10.x release will be the best move; for others, upgrading to self-hosted earlier will be right for them. This guide should help you decide which category you fall into. Improvements over stage1 SS * Many bugs are fixed, which could never be fixed in stage1 due to fundamental design flaws. * Performance is minorly improved. For Zig, we observe 7% speed improvement in building itself. * Memory usage is improved by a factor of about 3.5x. For Zig, building itself went from using 9.6 GiB to 2.8 GiB. * The LLVM code generated is better. LLVM has an easier time optimizing. You likely will have small improvements in perf of your project. * Many compile errors are more helpful. * The core design is fundamentally different so that game-changing performance enhancements become possible Falling short of stage1 SS Although we fully intend to make the self-hosted compiler a strict improvement, that is not the case yet. * There are some fresh bugs. * async/await is not done yet (#6025). Users of async/await cannot upgrade until a few more months when this feature is complete. * Some compile errors are still missing. * Some compile errors are less helpful. * There are some patterns that generate worse runtime performance. How to Upgrade SS Assuming that you have decided the time is nigh, here are some tips. Although most of the language is the same between stage1 and self-hosted, there are some incompatibilities. Here are two strategies to deal with this: 1. Have a different branch for when using Zig self-hosted. Once you decide to commit to the upgrade, merge that branch into your main branch. 2. Make the codebase support both stage1 and self-hosted at the same time using conditional compilation based on std.builtin.CompilerBackend. In addition to the sub-sections below, see also these Language Changes which should be considered part of the upgrade guide: * Function Pointers * Runtime Array Concatenation & Multiplication * Address-of Temporaries Now Produces Const Pointers * Pointers to Zero-Bit Types * std.builtin.CompilerBackend Void Literal Syntax SS {} vs .{} This one is pretty simple: test.zig test { var x: void = .{}; _ = x; } Shell $ zig test test.zig docgen_tmp/test.zig:2:20: error: expected type 'void', found '@TypeOf(.{})' var x: void = .{}; ~^~ .{} is a struct literal; {} is a void value. It has always been a bug for the Bootstrap Compiler to accept this code. Just change .{} to {} . - var x: void = .{};+ var x: void = {}; Escaped Pointer to Parameter SS test.zig const std = @import("std"); const expect = std.testing.expect; test "escaped pointer to parameter" { var s: S = .{ .field = 1234 }; const value = s.foo(); try expect(value == &s.field); } const S = struct { field: i32, fn foo(s: S) *const i32 { return &s.field; // XXX: escaped pointer to parameter } }; Shell $ zig test test.zig 1/1 test.escaped pointer to parameter... FAIL (TestUnexpectedResult) /home/andy/Downloads/zig/lib/std/testing.zig:347:14: 0x21156f in expect (test) if (!ok) return error.TestUnexpectedResult; ^ docgen_tmp/test.zig:7:5: 0x2116a7 in test.escaped pointer to parameter (test) try expect(value == &s.field); ^ 0 passed; 0 skipped; 1 failed. error: the following test command failed with exit code 1: /home/andy/.cache/zig/o/92074f0ff860192f15f1d46f1cf33c8d/test This test passes with the Bootstrap Compiler despite having a critical bug: a temporary is created by taking the address of the the pass-by-value parameter which is then returned from the function. The legacy compiler is naive, always passing structs by pointer in code such as this. Meanwhile, the self-hosted compiler efficiently takes advantage of smaller arguments such as this, passing them truly by value, revealing the bug. Hopefully in the future Zig will have runtime safety for this, however, currently this will manifest as a use-after-free. So if you find a pointer to bogus data, double check that the pointer was not created this way. Once the problem has been identified, the fix is simple: - fn foo(s: S) *const i32 {+ fn foo(s: *const S) *const i32 { C ABI Compatibility SS C ABI compatibility is notoriously difficult when using LLVM. In Zig 0.9.x, there were several major miscompilations for functions with C calling convention, especially when using an architecture other than x86_64. Thanks to a nicer abstraction for dealing with the C ABI, plus some good old-fashioned hard work, in 0.10.0, Zig has near full C ABI compliance on several targets: * x86_64 - close to 100% * aarch64 - close to 100% * wasm32 - close to 100% * arm, x86 - complex numbers are not handled correctly yet You can have a look at the new test harness to see what exactly is covered. Each of these targets are now tested with every CI run with QEMU. C Translation SS * Handle typedef'ed void return type for functions (#10356) * Fixed macro define of float constant using scientific notation. Fixes compiler attempting to use null value when translating macro define of float constant using scientific notation with no decimal point. * Fixed issues translating macro define of hex float constant + Fixed incorrect result when the first digit after the decimal point is not 0-9 - eg 0x0.ap0 + Fixed compiler panic when the number starts with 0X with a capital X - eg 0X0p0 + Fixed compiler panic when the number has a decimal point immediately after 0x - eg 0x.0p0 * Improve error messages when expecting specific tokens. * Add support for cast-to-union (#10955) * Use nested scope for comma operator in macros (#11040) * Check child records for opaque types (#10461) * Fixed cast or call macro with parenthesis (#11962) * Do not try to get rid of do while loop because it might contain breaks and continues (#11994) * Take address of functions before passing them to @ptrToInt (# 12194) * Use correct number of initializers for vectors (#12264) * Fixed alignment in pointer casts * Don't add self-defined macros to global name table (#12471) * Convert tabs to \t in object-like macro string literals (#12549) * Escape non-ASCII characters that appear in macros (#12784) * Translate clang packed struct C into Zig extern struct with align (1) (#12745) * Fixed function pointers, add cast to subscripts in macros (#13126 ) * Added missing builtins used by CRuby * Better support for division in macros by performing C-style arithmetic conversions on operands to division operator (#13162) Cache System SS Zig now places the zig-cache directory next to build.zig. If no build.zig file is found, it falls back to using the global cache directory (#11672). Internally, there are now two cache modes: incremental and whole. Whole cache mode is what everyone is used to from previous Zig releases. It relies on hashing the full set of inputs, including every source file that is directly or indirectly imported. Incremental cache mode is new and is based on re-opening existing build artifacts and rebuilding only the modified symbols. Although Zig's incremental compilation system is still experimental, it can be enabled with the --watch flag. Incremental cache mode is the default for the self-hosted code generation backends, and for the LLVM backend when not using the Build System. Because the compiler does not yet serialize and restore its state, without the --watch flag, this will result in recompiling with every invocation of the compiler. On the other hand, it results in less garbage accumulating into the zig-cache directory. Safety for Switching on Corrupted Enums SS The following code, when run with Zig 0.9.1, will invoke undefined behavior: test.zig const std = @import("std"); const E = enum(u32) { one = 1, two = 2, }; test "example" { var a: E = .two; @ptrCast(*u32, &a).* = 255; switch (a) { .one => @panic("one"), else => return, } } Shell $ zig test test.zig 1/1 test.example... thread 1642916 panic: switch on corrupt value docgen_tmp/test.zig:12:17: 0x2115b6 in test.example (test) .one => @panic("one"), ^ /home/andy/Downloads/zig/lib/test_runner.zig:63:28: 0x212be8 in main (test) } else test_fn.func(); ^ /home/andy/Downloads/zig/lib/std/start.zig:596:22: 0x211ebd in posixCallMainAndExit (test) root.main(); ^ /home/andy/Downloads/zig/lib/std/start.zig:368:5: 0x211981 in _start (test) @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); ^ error: the following test command crashed: /home/andy/.cache/zig/o/92074f0ff860192f15f1d46f1cf33c8d/test As you can see, with Zig 0.10.0, this problem is caught with a safety check. A future enhancement will further refine this to make the stack trace point at the switch expression rather than the prong. Referenced-By Traces SS You can find referenced-by traces in a few other example snippets throughout this document, but here is illustrated a real world example that was particularly helpful: Shell $ stage3/bin/zig build -p wasi -Dskip-install-lib-files -Dtarget=wasm32-wasi /home/andy/Downloads/zig/lib/std/os.zig:110:28: error: root struct of file 'os.wasi' has no member named 'PATH_MAX' pub const PATH_MAX = system.PATH_MAX; ~~~~~~^~~~~~~~~ referenced by: calcInstallNameLen: /home/andy/Downloads/zig/src/link/MachO.zig:3540:53 calcLCsSize: /home/andy/Downloads/zig/src/link/MachO.zig:3577:24 remaining reference traces hidden; use '-freference-trace' to see all reference traces Here I tried to build the Self-Hosted Compiler for WASI but ran into some code that incorrectly tried to reference std.os.PATH_MAX even though no such definition exists for the WASI target. You can see that without the referenced-by trace, this bug would have been annoying to fix, but with it, the fix was trivial. Error Return Traces SS Zig's error return traces are a resource-efficient alternative to the tracebacks provided by exceptions in other languages. With the default limit of 32 stack frames, only 256 bytes per-thread are needed to maintain the error trace. Unwrapping Errors in Switch SS A small quality-of-life improvement Vexu thought of while trying to figure out where an error.GenericPoison was coming from (#12889). Example situation: test.zig fn foo() !void { return error.Foo; } fn bar() !void { try foo(); } fn baz() void { // bar() catch unreachable; // bar() catch @panic("foo"); // const S = struct { // const S = struct { // const fooo = "foo"; // }; // }; bar() catch |err| switch (err) { // error.Foo => @panic(S.S.fooo), error.Foo => unreachable, }; } test { baz(); } Shell $ zig test test.zig 1/1 test_0... thread 1642961 panic: attempt to unwrap error: Foo docgen_tmp/test.zig:2:5: 0x211ef8 in foo (test) return error.Foo; ^ docgen_tmp/test.zig:5:5: 0x211ff3 in bar (test) try foo(); ^ docgen_tmp/test.zig:17:22: 0x2115d1 in baz (test) error.Foo => unreachable, ^ docgen_tmp/test.zig:21:8: 0x211548 in test_0 (test) baz(); ^ /home/andy/Downloads/zig/lib/test_runner.zig:63:28: 0x212d58 in main (test) } else test_fn.func(); ^ /home/andy/Downloads/zig/lib/std/start.zig:596:22: 0x211ebd in posixCallMainAndExit (test) root.main(); ^ /home/andy/Downloads/zig/lib/std/start.zig:368:5: 0x211981 in _start (test) @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); ^ error: the following test command crashed: /home/andy/.cache/zig/o/92074f0ff860192f15f1d46f1cf33c8d/test Before, it did this instead: Shell Test [1/1] test_0... thread 18432 panic: reached unreachable code ./a.zig:17:22: 0x20f0fc in baz (test) error.Foo => unreachable, ^ ./a.zig:21:8: 0x20f078 in test_0 (test) baz(); ^ /home/vexu/Documents/zig/zig/lib/test_runner.zig:79:28: 0x2105b5 in main (test) } else test_fn.func(); ^ /home/vexu/Documents/zig/zig/lib/std/start.zig:568:22: 0x20f9bd in posixCallMainAndExit (test) root.main(); ^ /home/vexu/Documents/zig/zig/lib/std/start.zig:340:5: 0x20f3c2 in _start (test) @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); ^ error: the following test command crashed: This also makes @panic show error return trace in these same situations which you can test by uncommenting lines in the example. Removal of Useless Stack Frames SS Prior to this release, error return traces suffered from a major drawback: handled errors were never cleaned up and would pollute the error trace. Zig now intelligently removes any error traces corresponding to errors handled in a catch { ... } or if ... else | err| { ... } block. pub fn main() !void { makeEggs() catch { if (money < 10) return error.OutOfMoney; // If executed: trace shows makeEggs()'s error, followed by this line try buyIngredients(); // On error: trace shows makeEggs()'s error, then buyIngredients()'s error }; // makeEggs() removed from the trace here try serveBreakfast(); // On error: trace shows serveBreakfast()'s error only } Very long error return traces are also trimmed correctly and print a helpful note to let you know about the missing entries: ... ./test_err.zig:5:5: 0x10224b39e in recursive__anon_1055 (test_err) return recursive(N - 1); ^ ./test_err.zig:5:5: 0x10224b35e in recursive__anon_1054 (test_err) return recursive(N - 1); ^ (98 additional stack frames skipped...) There is one restriction to be aware of: error traces do not follow errors into local variables (var) by default. This restriction is what allows all functions in the thread to share the same 256-byte error trace storage. The new std.debug.Trace API allows users to copy and store error return traces for mutable variables where needed. Here is a real world example. Before, one might get debug output that looks like this: Shell $ ~/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/zig run tools/copy-from-glibc.zig -- ~/glibc/multi-2.32/install/glibcs headers 2.32 error: FileNotFound tools/copy-from-glibc.zig:21:23: 0x218e39 in main (copy-from-glibc) var sub_dir = try glibcs_dir.openIterableDir(sub_path, .{}); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2755:19: 0x21f936 in mkdiratZ (copy-from-glibc) .EXIST => return error.PathAlreadyExists, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:2715:9: 0x218537 in mkdirat (copy-from-glibc) return mkdiratZ(dir_fd, &sub_dir_path_c, mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1402:9: 0x21842b in makeDir (copy-from-glibc) try os.mkdirat(self.fd, sub_path, default_new_dir_mode); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/os.zig:1689:23: 0x24b498 in openatZ (copy-from-glibc) .NOENT => return error.FileNotFound, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1747:25: 0x23dbf1 in openDirFlagsZ (copy-from-glibc) else => |e| return e, ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1717:13: 0x21e0a6 in openDirZ (copy-from-glibc) return self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | symlink_flags); ^ /home/andy/tmp/zig-linux-x86_64-0.10.0-dev.4474+b41b35f57/lib/std/fs.zig:1654:40: 0x2180e5 in openIterableDir (copy-from-glibc) return IterableDir{ .dir = try self.openDirZ(&sub_path_c, args, true) }; ^ After this improvement, we see this instead: Shell $ ~/zig-bootstrap/out/host/bin/zig run tools/copy-from-glibc.zig -- ~/glibc/multi-2.32/install/glibcs headers 2.32 error: FileNotFound /home/andy/zig-bootstrap/out/host/lib/zig/std/os.zig:1689:23: 0x24c038 in openatZ (copy-from-glibc) .NOENT => return error.FileNotFound, ^ /home/andy/zig-bootstrap/out/host/lib/zig/std/fs.zig:1747:25: 0x23e4e8 in openDirFlagsZ (copy-from-glibc) else => |e| return e, ^ /home/andy/zig-bootstrap/out/host/lib/zig/std/fs.zig:1717:13: 0x21e406 in openDirZ (copy-from-glibc) return self.openDirFlagsZ(sub_path_c, os.O.DIRECTORY | os.O.RDONLY | os.O.CLOEXEC | symlink_flags); ^ /home/andy/zig-bootstrap/out/host/lib/zig/std/fs.zig:1654:40: 0x2182d5 in openIterableDir (copy-from-glibc) return IterableDir{ .dir = try self.openDirZ(&sub_path_c, args, true) }; ^ tools/copy-from-glibc.zig:21:23: 0x219059 in main (copy-from-glibc) var sub_dir = try glibcs_dir.openIterableDir(sub_path, .{}); ^ This was an old issue that plagued Zig developers for a long time. We have Cody Tapscott to thank for solving it. Code Generation SS While the default backend is still LLVM, Zig is starting to invest in providing its own code generation. The primary motivation for this is compilation speed. However, there is also a benefit to providing a bootstrapping process that does not depend on C++, CMake, Python, libxml, zlib, and zstd, all of which LLVM require in order to build. Furthermore, there is value in providing healthy competition so that compiler backends do not become a monoculture. As a point of comparison, a stripped release build of Zig with LLVM is 169 MiB, while without LLVM (but with all the code generation backends you see here) it is 4.4 MiB. WebAssembly Backend SS One of the visible improvements to the self-hosted Wasm backend is its capabilities to generate code. The backend is now capable of passing 75% of the behavior tests, compared to 13% in Zig 0.9.x. At this point, most Zig features are supported. For features of which the WebAsssembly architecture has no support, the backend is already capable of generating calls into compiler-rt, and correctly link with it. This is thanks to the C ABI Compatibility work that was done during this release. This also benefitted the LLVM backend with regards to its WebAssembly target, as the logic for the C ABI implemtation is fully shared between the backends. This will ensure that regardless of the chosen backend, the function signatures they generate are equal. One notable feature that was previously missing was support for DWARF Linking when targetting WebAssembly. This is now fully supported in the LLVM backend, and partly in the native backend. This allows for a great developer experience when targetting WebAssembly. The goal is to add full support to the native backend by its next release. Some invisible improvements were done also. The backend was refactored to be aware of the Wasm stack and leave locals there when possible, avoiding unnecessary stores. This means we not only generate fewer instructions, but also create fewer locals. Besides this, the backend now integrates with Liveness Analysis, reusing locals that are no longer being referenced. All of those changes are with the goal of making the native backends not only compile fast, but also generate code which runs faster than when using the LLVM backend. Some notable changes that were partly responsible for the above include: * Move responsibilities lowerUnnamedConst (#10983) * Unify Code Generation with other backends (#11070) * Add support for Debugging information (LLVM backend)(#11461) * Initial C ABI implementation (native backend) (#11521) * DWARF support (native backend) (#11610) * Prerequisites compiler-rt integration (#11904) * Implement C ABI when targetting wasm32 (LLVM backend) (#12188) * Reuse (temporary) locals (#12394) * Integrate liveness analysis for locals reusal (#13193) C Backend SS A new contributor jacobly0 came out of nowhere and did a massive amount of work to Zig's C backend, reaching these notable milestones: * The C backend is now passing 1259/1374 (92%) of the behavior tests. * The official hello world now works on at least x86_64-linux (with and without libc). * The test runner now prints output to the console. Additionally, in this release zig.h moved to become an installation file. Instead of zig.h being baked into the compiler binary, it is a header file distributed along with all the other header files distributed with Zig (#11643). Soon, this backend will be used to replace the Bootstrap Compiler with a C implementation that outputs C code (#5246). x86 Backend SS Although this backend remains experimental, it has seen considerable progress during this release cycle. Notable milestones reached: * Partially implemented SystemV calling convention. * Implemented Windows x64 calling convention. * Enhanced the x86_64 encoder to handle most of general purpose register encodings such as I, OI, MI, RM, MR, and RMI. * Added basic support for the VEX prefix and SSE/AVX encodings such as MV, RVM and RVMI. * Implemented lowerings for many fundamental AIR instructions. All of the above culminates in the x86_64 self-hosted backend passing 875/1365 (64%) of the behavior tests compared to the LLVM backend. It will need to get very close to 100% before being enabled by default for debug mode. arm Backend SS This backend remains experimental, however it now supports error unions, structs, and switch statements and is thereby passing 790/ 1365 (58%) of the behavior tests. It will need to get very close to 100% before being enabled by default for debug mode. aarch64 Backend SS This backend remains experimental, however it now supports error unions, structs, and switch statements and is thereby passing 560/ 1365 (41%) of the behavior tests. It will need to get very close to 100% before being enabled by default for debug mode. Self-Hosted Linker SS The self-hosted linker is tightly coupled with the Self-Hosted Compiler. There has been progress on ELF and COFF however they are not generally usable yet. By default, LLD will be used for these object formats, however, one can opt in to the self-hosted linker with -fno-LLD. MachO SS Ziggy the Ziguana The incremental MachO linker, like its traditional linking counterpart, has seen a major rewrite where Zig now lays out the incrementally linked binary such that there is one section per segment. This might sound wasteful but it allows Zig to use the quick file space allocation algorithm used already in the ELF and COFF linkers. How does it work? By enclosing a single section within a single segment Zig is able to disassociate the file offsets from the allocated virtual memory addresses. This provides the uncanny ability to reorder and move the sections within the underlying binary file without affecting the ordering in the virtual memory space. This implies that if the section grows beyond what was originally allocated, Zig only needs to copy its contents in the file to a new location without any virtual address space recalculations unless the section has also exceeded its allocated virtual address space. But even then only some atoms are affected in subsequent sections in the virtual address space. Thanks to this trick, Zig is on the path of achieving truly incremental linking for MachO which should also make implementing hot-code swapping for MachO much simpler and more efficient. For a more in-depth look into the changes involved have a look at this pull request: macho: rewrite incremental linker, and init splitting of linking contexts In addition, the following improvements have been made: * The linker no longer artificially limits the maximum jump size to ISA's b/bl's 28bits signed displacement which roughly equates to 128MB of compiled machine code section. The linker now extends the jump range via thunks which load the target address into the scratch register followed by a branch via register blr (#13260) ( #13274) * do not write out ZEROFILL physically to file * extend CodeSignature to accept entitlements * set CS_LINKER_SIGNED flag in code signature generated by Zig * round down pagezero size to page size. If page aligned requested pagezero size is 0, skip generating __PAGEZERO segment. Add misc improvements to the pipeline, and correctly transfer the requested __PAGEZERO size to the linker. * -pagezero_size is always in hex. This matches the behavior of other linkers out there including ld64 and lld. * fix aligning linkedit sections * implement -search_dylibs_first linker option * verbose print all input linker args verbatim * implement -headerpad_size option * prefill any space between __DATA and __LINKEDIT with 0s if required. If there are zerofill sections, the loader may copy the contents of the physical space in file directly into memory and attach that to the zerofill section. This is a performance optimisation in the loader but requires us, the linker, to properly zero-out any space between __DATA and __LINKEDIT segments in file. This is of course completely skipped if there are no zerofill sections present. * implement -headerpad_size and -headerpad_max_install_names options * implement -dead_strip_dylibs linker flag * implement and handle -needed-* and -needed_* family of flags * implement -weak-lx and -weak_framework x flags * implement -dead_strip flag. Dead-code stripping is on by default for release build modes, and off for debug builds, but can be opted in/out via --gc-sections and --no-gc-sections flags. * mark __mh_execute_header as referenced dynamically * build.zig: handle weakly imported libs and frameworks * support -force_load=archive_path flag COFF SS The COFF linker has been reimplemented from scratch giving our Windows users a chance to finally be able to play with the incremental linking (using the --watch flag and x86 Backend via -fno-LLVM). In addition, the linker now matches the implementation progress of both ELF and MachO, and hence, it is now possible to run the behavior tests on x86_64-windows successfully: Shell > C:\Users\kubkon\dev\zig\stage3\bin\zig.exe test test\behavior.zig -Itest -fno-LLVM -fno-unwind-tables -fno-emit-implib 817 passed; 571 skipped; 0 failed. For more detailed description of the implementation, have a look at this pull request: coff: implement enough of the incremental linker to pass behavior and incremental tests on Windows ELF SS The self-hosted ELF linker remains experimental, capable of incremental compilation of simple Zig programs but not capable of acting as a traditional linker. Wasm Modules SS Major progress has been made on the in-house WebAssembly linker. Zig is nearing feature-parity with wasm-ld, which is the linker the compiler uses today when targeting WebAssembly. The linker is now capable of linking with most object files, while also being able to link with archive files such as compiler-rt. During linking, it now correctly relocates Debugging information. The next milestone would be to make the in-house linker the default linker. To accomplish this, the following features must be implemented: * Garbage collection - Remove unused code and sections to ensure binaries remain small which is crucial for Wasm. * TLS support (including shared memory) - While being a non-MVP feature, it is a feature that we see being used more and more in the open. By implementing these features, we ensure existing projects will remain to link correctly. * Execution model - To fully support WASI, it is important to generate the correct symbols for both the reactor and command models. Those features will bring the linker to near feature parity. By making the switch before being fully feature complete, we can begin the debugging process sooner, as well as focusing on optimizing the memory usage and runtime performance of the linker. The following changes highlight some of the features mentioned above: * Object parsing and linking (#10911) * Implement relocatable object files (#10962) * Place decls in the correct segment and order segments (#11933) * Implement linker tests (#12006) * Improve symbol resolution (#12467) * Improve archive linking (#12557) * Implement linking debug-information (#12770) * Implement non-function extern variables (#12687) * Generate the "producers" section (#13054) * Feature compatibility validation (#13287) DWARF Linking SS The incremental DWARF emitter/linker is now capable of emitting correctly relocated debug info for x86_64, arm and aarch64 architectures on Linux and macOS. The state of implementation varies slightly between architectures with x86_64 being the furthest ahead. Example progress includes correctly generating DWARF debug info for slices including []const u8 for passing as formal parameters. Breaking on a function accepting a slice in gdb will now yield the same behavior as the Bootstrap Compiler and LLVM backend: test.zig fn sumArrayLens(a: []const u32, b: []const u8) usize { return a.len + b.len; } Both a and b can now be inspected in the debugger: Breakpoint 1, sumArrayLens (a=..., b=...) at arr.zig:59 (gdb) p a $1 = {ptr = 0x7fffffff685c, len = 5} (gdb) p b $2 = {ptr = 0x7fffffff683d "\252\252\252\\h\377\377\377\177", len = 3} (gdb) Linker Performance SS This release saw a general rewrite of the majority of the linker in the spirit of data-oriented design which led to: * significantly reduced link times to the point where, dare I say, we start to become competitive with lld and ld64 * reduced memory usage by avoiding unnecessary allocs, and instead re-parsing data when actually needed. In the benchmarks below, zld refers to our linker as a standalone binary (which you can find at kubkon/zld), lld to LLVM's linker, and ld64 to Apple's linker. I should also point out that we are still missing a number of optimisations in the linker such as cstring deduplication, compression of dynamic linker's relocations, and synthesising of the unwind info section, so this difference between zld and other linkers will most likely shrink a little. I've run the benchmarks on a MacBook Pro 16" with M1 Pro SoC and 32GB RAM. The generated code for the linker was not using hardware sha256 extensions. Linking redis-server binary: Shell hyperfine ./zld ./lld ./ld64 --warmup 60 Benchmark 1: ./zld Time (mean +- s): 35.6 ms +- 0.4 ms [User: 35.9 ms, System: 10.4 ms] Range (min ... max): 34.8 ms ... 36.4 ms 79 runs Benchmark 2: ./lld Time (mean +- s): 49.2 ms +- 0.8 ms [User: 42.6 ms, System: 17.6 ms] Range (min ... max): 48.0 ms ... 51.2 ms 59 runs Benchmark 3: ./ld64 Time (mean +- s): 47.2 ms +- 0.5 ms [User: 60.1 ms, System: 14.4 ms] Range (min ... max): 46.2 ms ... 48.1 ms 61 runs Summary './zld' ran 1.32 +- 0.02 times faster than './ld64' 1.38 +- 0.03 times faster than './lld' Linking Self-Hosted Compiler binary: Shell hyperfine ./zld ./lld ./ld64 --warmup 5 Benchmark 1: ./zld Time (mean +- s): 1.934 s +- 0.012 s [User: 2.870 s, System: 0.468 s] Range (min ... max): 1.923 s ... 1.962 s 10 runs Benchmark 2: ./lld Time (mean +- s): 1.153 s +- 0.014 s [User: 1.289 s, System: 0.230 s] Range (min ... max): 1.141 s ... 1.179 s 10 runs Benchmark 3: ./ld64 Time (mean +- s): 2.349 s +- 0.006 s [User: 3.875 s, System: 0.218 s] Range (min ... max): 2.341 s ... 2.357 s 10 runs Summary './lld' ran 1.68 +- 0.02 times faster than './zld' 2.04 +- 0.02 times faster than './ld64' Linker Test Harness SS The incremental compilation that utilises Zig's self-hosted native backends has seen the addition of a vastly improved and easily extensible test harness. In order to add a new incremental test (emulating the --watch flag), it is now only required to drop a Zig source file in the test harness directory with a specially crafted comment instructing the harness of several test parameters such as test target, and that's it. Thanks to this dynamic approach there is no longer any need in recompiling the harness (#11530) (#11572). Linkers also have received a new test harness, which is based on the StandaloneTestContext and CheckFileStep, and as such assumes each test case specifies a build.zig script where we instruct the harness what the link flags/conditions are the expected results such as a runtime result or a greppable contents of the generated binary file ( #11910). Notable features: * CheckObjectStep specialises CheckFileStep into directed (surgical) MachO file fuzzy searches. This will be the building block for comprehensive linker tests. * dump metadata to string and grep results. This approach is more inline with what LLVM/LLD does for testing of their output, and seems to be more generic and easier to extend than implementing a lot of repetitive and nontrivial comparison logic when working directly on structures. * extract values from parsed binaries into variables. We can then collect multiple variables (currently assumed always in global scope) and run a comparison with some very basic arithmetic on the values. Standard Library SS The Zig standard library is still unstable and mainly serves as a testbed for the language. After the Self-Hosted Compiler is completed, the language stabilized, and Package Manager completed, then it will be time to start working on stabilizing the standard library. Until then, experimentation and breakage without warning is allowed. * process.ArgIterator.next return type is changed. * Fixed process.argsAlloc buffer size * process: add option to support single quotes to ArgIteratorGeneral * Make it easier to avoid depending on child process execution when not supported by the target OS. * Implement child processes with posix_spawn as an alternative to fork-exec where possible * ChildProcess.init no longer heap allocates * Fixed ChildProcess crash when PATH is empty * std.os.execvpe: fix buffer overflow * Break up some long lines. This makes packaging Zig for Debian slightly easier since it will no longer trigger a Lintian warning for long lines. * Skip comptime struct fields in mem.zeroes() (#10406) * Rename mem.bswapAllFields to byteSwapAllFields * mem: add indexOfMin and indexOfMax (#9915) * Allow mem.zeroes to work at comptime with extern union (#10797) * mem.zeroes: Zero sized structs with uninitialized members (#12246 ) * mem.zeroInit: Fixed behavior with empty initialiser * mem: added concatWithSentinel * mem: add peek() to TokenIterator(T) * mem: add splitBackwards (#11908) * mem: add first and reset method to SplitIterator and SplitBackwardsIterator * Enhanced ascii.indexOfIgnoreCase with Boyer-Moore-Horspool algorithm. * Support parsing tz timezone data (#10456) * Added json.stringifyAlloc * json: fix compile error for comptime fields (#10849) * json: correctly handle sentinel terminated slices * JSON stringify string setting affects keys (#11618) * json: Support disabling indent (#11823) * json: Fixed parsing of large numbers * json: expose encodeJsonString and encodeJsonStringChars * Added meta.DeclEnum * Makes std.meta.Tuple and std.meta.ArgsTuple generate a unique type instead of generating one per invocation. * meta: made FieldEnum(T) == Tag(T) for tagged unions when values match field indices * Added isTag function to std.meta (#11895) * Added some missing termios types to c/linux.zig and os.zig * readUntilDelimiter: read only if buffer not full (#9594) * Avoid duplicate TLS startup symbols * Correct rounding in parse_hex_float.zig (#10743) * Progress: make the API infallible by handling error.TimerUnsupported. In this case, only explicit calls to refresh() will cause the progress line to be printed. * Progress: fix suffix printing * Fixed data race in std.Progress.maybeRefresh() * Added elf.EM, coff.MachineType to Target.CPU.Arch conversions * Fixed sigaction double panic (#8357) * Added sem_open and sem_close * Added SIMD utility functions * Added unicode.replacement_character * unicode: add utf16 byte length and codepoints counting routines ( #11663) * os.getenvW: Fixed case-insensitivity for Unicode env var names (# 10595) * Added memfd_create for FreeBSD. This is minorly breaking as e.g. std.os.linux.MFD_CLOEXEC is now std.os.linux.MFD.CLOEXEC. * Added FreeBSD support to std.os.getFdPath * Audit FreeBSD structs to match header files/ABI * Added functions from dirent.h to std.c (#11598) * std.c: Fixed incorrect dirent structure (#11602) * Added const to msghdr_const iov and control pointers * Mark fstype argument to mount as optional. * Renamed systemz to s390x * Fixed definition of SIG_IGN, SIG_DFL, etc. (#12410) * Added bounded array functions to io.Reader * ascii: rename functions and other improvements (#12448) Math SS * Fixed overflow in isNormal when applied to -Inf or a negative NaN * Optimize division with divisors less than a half-limb * Simplify implementation of floorPowerOfTwo * Fixed big.int div, gcd and bitAnd edge-cases (#10932) * lossyCast: Fixed integer overflow caused by cast from maxInt(u32) as an f32 to u32. * Fixed for big int divmod (#11271) * Complex: add 'negation' and 'mulitply by i' * Added new float-parser based on eisel-lemire algorithm (#11566) * Added math.sign * powi: use standard definition of underflow/overflow, implement u0 , i0, i1 edge case (#11499) * Made cast return optional instead of an error. * Added O(log N) implementation of log2(x) for comptime_int * big int: update Managed.toString() to use provided allocator (# 11839) * big int: breaking API changes to prevent UAF (#11897) * Added degreesToRadians and radiansToDegrees * Fixed big.Rational order/orderAbs (#12440) * Added "Greatest common divisor" (gcd) * Fixed memory leak on OutOfMemory error in math.big.int and math.big.rational * Fixed cast behavior relating to comptime_int arguments (#12918) File System SS * fs.getAppDataDir: recognize XDG_DATA_HOME * fs: Use OpenMode enum instead of read/write flags. * Define static error set for fs.Dir.copyFile * Fixed using fs.Dir.Iterator twice (#10404) * Implemented cross-platform metadata API (#10486) * Added File.sync (#11410) * Prevent possible integer overflow in Dir.makePath (#11397) * Split Dir into IterableDir (#12060) * End iteration on Linux/WASI during Iterator.next when hitting ENOENT (#12211) * Split Iterator.next on Linux and WASI to allow for handling platform-specific errors * Fixed WalkerEntry.dir not always being the containing dir Optimized Tree Deletion SS Ryan Liptak improved the performance of std.fs.Dir.deleteTree (#13073 ). The new implementation has the same constraints: * No heap-allocating any memory or requiring an Allocator parameter. * No possibility of stack overflow due to a deeply nested file system tree. The new implementation has better performance than rm -rf (at least on Linux - see benchmark details): $ hyperfine "./rm-fast my-app-copy" "./rm-master my-app-copy" "rm -rf my-app-copy" --prepare="cp -r my-app my-app-copy" --warmup 1 --runs 20 Benchmark #1: ./rm-fast my-app-copy Time (mean +- s): 382.7 ms +- 7.8 ms [User: 13.6 ms, System: 358.9 ms] Range (min ... max): 372.2 ms ... 395.9 ms 20 runs Benchmark #2: ./rm-master my-app-copy Time (mean +- s): 701.2 ms +- 28.3 ms [User: 36.8 ms, System: 646.2 ms] Range (min ... max): 673.4 ms ... 799.4 ms 20 runs Benchmark #3: rm -rf my-app-copy Time (mean +- s): 423.9 ms +- 35.4 ms [User: 17.5 ms, System: 379.4 ms] Range (min ... max): 391.6 ms ... 518.9 ms 20 runs Summary './rm-fast my-app-copy' ran 1.11 +- 0.10 times faster than 'rm -rf my-app-copy' 1.83 +- 0.08 times faster than './rm-master my-app-copy' The new implementation accomplishes this by having a fixed-size buffer on the stack, temporarily falling back to a slower algorithm when it encounters deeply nested file system trees. The fallback implementation is also optimized to reduce the number of syscalls emitted. Data Structures SS * hash_map: optimize isFree/isTombstone (#10562) * HashMap: add removeByPtr * Made ArrayHashMap eql function accept an additional param (#10742 ) * Fixed memory leak in ArrayHashMap (#13001) * Fixed getOrPutAdapted on Managed array hash map * HashMap: return explicit errors (#11000) * Fixed auto_hash not hashing arrays of slices uniquely (#12423) * Allow BoundedArray to be default initialized * Slice function of BoundedArray now returns slice based on self pointer. If self pointer is const, the slice is const. Otherwise the slice is mutable. * BoundedArray: return explicit errors (#11044) * BoundedArray: Add Writer interface * MultiArrayList: fixed insert compile error. * Added sort method to ArrayHashMap and MultiArrayList * MultiArrayList: add functions addOne, pop, and popOrNull (#11553) * enums: make directEnumArrayLen public * bit_set: add setRangeValue(Range, bool) * Added ArrayList.clone * Use explicit error sets for ArrayList return types. * ArrayList.ensureTotalCapacity: optimize and fix integer overflow (#12099) * BufSet: add clone and cloneWithAllocator * Fixed bug in PriorityQueue::removeIndex() * PriorityQueue: fix missing siftUp in remove * PriorityQueue: use compareFn in update() (#9918) * PriorityDequeue: use compareFn in update() method * Added Treap data structure (#11444) * SegmentedList: add constIterator * Made IntegerBitSet and ArrayBitSet have defined memory layout Crypto SS We have Frank Denis to thank for Zig's state-of-the-art cryptography capabilities. In this release: * Added bcrypt pbkdf (#10331) * edwards25519: faster point decompression. Make recovery of the x-coordinate slightly faster. * 25519.scalar: implement edwards25519 scalar field inversion. This operation is extremely useful for multiplicative blinding. * x25519: implement clearCofactor() (#11355) This is the x25519 counterpart to edwards25519.clearCofactor(). It is useful to check for low-order points in protocols where it matters and where clamping cannot work, such as PAKEs. * edwards25519 fixes (#11568) * Generate AES constants at compile time (#11612) * 25519: add scalar.random(), use CompressedScalar type. Add the ability to generate a random, canonical curve25519 scalar, like we do for p256. Also leverage the existing CompressedScalar type to represent these scalars. * Added support for the NIST P-384 curve (#11735) After P-256, here comes P-384, also known as secp384r1. Like P-256, it is required for TLS, and is the current NIST recommendation for key exchange and signatures, for better or for worse. Like P-256, all the finite field arithmetic has been computed and verified to be correct by fiat-crypto. * pcurves: compute constants for inversion at comptime (#11780) * p256, p384: process the top nibble in mulDoubleBasePublic (#11956 ) Unlike curve25519 where the scalar size is not large enough to fill the top nibble, this can definitely be the case for p256 and p384. * 25519, pcurves: make the scalar field order public (#11955) * ecc: add support for the secp256k1 curve (#11880) Usage of the secp256k1 elliptic curve recently grew exponentially, since this is the curve used by Bitcoin and other popular blockchains such as Ethereum. With this, Zig has support for all the widely deployed elliptic curves today. * hash: allow creating hash functions from compositions (#11965) * sign.ed25519: add support for blind key signatures (#11868) Key blinding allows public keys to be augmented with a secret scalar, making multiple signatures from the same signer unlinkable. This is required by privacy-preserving applications such as Tor onion services and the PrivacyPass protocol. * sign.ed25519: include a context string in blind key signatures (# 12316) * Improved stdlib's random float generation (#10428) (#11641) * Added std.rand.RomuTrio * Random interface is no longer passed by reference. * random: add weightedIndex function ECDSA Signatures SS Zig 0.10.0 adds support for ECDSA signatures (#11855). ECDSA is the most commonly used signature scheme today, mainly for historical and conformance reasons. It is a necessary evil for many standard protocols such as TLS and JWT. It is tricky to implement securely and has been the root cause of multiple security disasters, from the Playstation 3 hack to multiple critical issues in OpenSSL and Java. This implementation combines lessons learned from the past with recent recommendations. In Zig, the NIST curves that ECDSA is almost always instantied with use formally verified field arithmetic, giving us peace of mind even on edge cases. And the API rejects neutral elements where it matters, and unconditionally checks for non-canonical encoding for scalars and group elements. This automatically eliminates common vulnerabilities. ECDSA's security heavily relies on the security of the random number generator, which is a concern in some environments. This implementation mitigates this by computing deterministic nonces using the conservative scheme from Pornin et al. with the optional addition of randomness as proposed in Ericsson's "Deterministic ECDSA and EdDSA Signatures with Additional Randomness" document. This approach mitigates both the implications of a weak RNG and the practical implications of fault attacks. Project Wycheproof is a Google project to test crypto libraries against known attacks by triggering edge cases. It discovered vulnerabilities in virtually all major ECDSA implementations. The entire set of ECDSA-P256-SHA256 test vectors from Project Wycheproof is included here. Zero defects were found in this implementation. Instead of raw byte strings for keys and signatures, we introduce the Signature, PublicKey and SecretKey structures. The reason is that a raw byte representation would not be optimal. There are multiple standard representations for keys and signatures, and decoding/encoding them may not be cheap (field elements have to be converted from/to the montgomery domain). Ed25519 API changes SS The std.crypto.sign.ed25519 API has been changed to adopt the same structure as the ECDSA API. This is a breaking change. Instead of raw bytes, Ed25519 keys are now represented with the newly introduced Ed25519.PublicKey and Ed25519.SecretKey types. Similarly, the Ed25519.Signature type is now used to store signatures. In Zig 0.9.x, key pair creation, signature computation and verification were typically done this way: const Ed25519 = std.crypto.sign.Ed25519; // Key pair creation const key_pair = try Ed25519.KeyPair.create(null); // Signature computation const sig = try Ed25519.sign("message", key_pair, null); // Signature verification try Ed25519.verify(sig, "message", key_pair.public_key); In Zig 0.10.0, the code above becomes: const Ed25519 = std.crypto.sign.Ed25519; // Key pair creation const key_pair = try Ed25519.KeyPair.create(null); // Signature computation const sig = try key_pair.sign("message", null); // Signature verification try sig.verify("message", key_pair.public_key); In Zig 0.9.x, the entire message to be signed had to be loaded in memory before signing. In Zig 0.10, the message can be streamed, which is especially useful for large messages. For example, the following code signs a message that is too large to fit in memory: var signer = try key_pair.signer(null); signer.update("message_part_1"); signer.update("message_part_2"); signer.update("message_part_3"); const sig = signer.finalize(); Similarly, the following code verifies a multi-part message: var verifier = try sig.verifier(key_pair.public_key); verifier.update("message_part_1"); verifier.update("message_part_2"); verifier.update("message_part_3"); try verifier.verify(); Add Xoodoo, Deprecate Gimli SS Zig 0.10.0 adds the Xoodoo permutation, preparing for Gimli deprecation (#11866). Gimli was a game changer. A permutation that is large enough to be used in sponge-like constructions, yet small enough to be compact to implement and fast on a wide range of platforms. And Gimli being part of the Zig standard library was awesome. But since then, Gimli entered the NIST Lightweight Cryptography Competition, competing againt other candidates sharing a similar set of properties. Unfortunately, Gimli didn't pass the 3rd round. There are no practical attacks against Gimli when used correctly, but NIST's decision means that Gimli is unlikely to ever get any traction. So, maybe the time has come to move Gimli from the standard library to another repository. We shouldn't do it without providing an alternative, though. And the best candidate for this is probably Xoodoo. Xoodoo is the core function of Xoodyak, one of the finalists of the NIST LWC competition, and the most direct competitor to Gimli. It is also a 384-bit permutation, so it can easily be used everywhere Gimli was used with no parameter changes. It is the building block of Xoodyak (for actual encryption and hashing) as well as Charm, that some Zig applications are already using. Like Gimli that it was heavily inspired from, it is compact and suitable for constrained environments. This change adds the Xoodoo permutation to std.crypto.core. The set of public functions includes everything required to later implement existing Xoodoo-based constructions. In order to prepare for the Gimli deprecation, the default CSPRNG was changed to a Xoodoo-based that works exactly the same way. Exploit CPU Features for SHA-256 SS On x86_64 and AArch64, SHA-256 now takes advantage of specialized CPU features when available. This can affect MachO linking performance due to Apple's signature requirement. On my Intel(R) Core(TM) i9-9980HK, for example, this CPU feature is not available, and I therefore do not observe any improved performance. However, Apple's M1 laptops do have this feature, and I observed SHA-256 increase from 199 MiB/s to 2.1 GiB/s in the crypto benchmark. Concurrency SS * Fixed a bug in Thread.Condition and add a basic Condition test (# 10538) * Renamed sched_yield to yield and move it to std.Thread * Thread: Mutex and Condition improvements (#11497) * Added Thread.Condition.timedWait (#11352) * Thread.Futex improvements (#11464) * Thread: ResetEvent improvements (#11523) * Single-threaded panicImpl sleep is unreachable (#11569) * std.event: use .{} to initiate Lock to unlocked state * Thread: fix freeAndExit on x86_64 Linux (#12693) * Update RwLock to use static initialization (#10838) * time: introduce Instant (#10972) * std.os: add timerfd_create, timerfd_settime and timerfd_gettime * Fixed Android definition of pthread_rwlock_t (#12830) * Fixed DefaultRwLock accumulating write-waiters, eventually failing to write lock (#13180) Networking SS * Added http definitions for Method and Status (#10661) * Handle HOSTUNREACH for blocking and non-blocking connects * net.getAddressList: fix segfault on bad hostname (#12065) * Added AFNOSUPPORT error to bind (#12560) * Added tcdrain on Linux * std.os now handles error.UnreachableAddress in send() * Fixed setsockopt returning ENODEV Networking has mostly been quiet until now, but it is about to get lit as we dive into the Package Manager in the next release cycle. Testing SS * Removed std.testing.zig_exe_path in favor of ZIG_EXE environment variable (#11633) * Fixed expectStringEndsWith error output. Before it started outputting the actual starting, not ending characters. * Fixed progress indicator for zig test (#10859) * Added refAllDeclsRecursive function * Made the caret indicator line more helpful Check All Allocation Failures SS There is a new API that checks for memory leaks (and other problems) caused by allocation failures by taking advantage of the FailingAllocator and inducing failure at every allocation point within the provided function (#10586). Below is the function's giant doc comment in a more readable form: Exhaustively check that allocation failures within test_fn are handled without introducing memory leaks. If used with the testing.allocator as the backing_allocator, it will also perform memory sanitization when runtime safety is enabled. The provided test_fn must have a std.mem.Allocator as its first argument, and must have a return type of !void. Any extra arguments of test_fn can be provided via the extra_args tuple. Any relevant state shared between runs of test_fn must be reset within test_fn. Expects that the test_fn has a deterministic number of memory allocations. An error will be returned if non-deterministic allocations are detected. The strategy employed is to: * Run the test function once to get the total number of allocations. * Then, iterate and run the function X more times, incrementing the failing index each iteration (where X is the total number of allocations determined previously) Here is an example of using a simple test case that will cause a leak when the allocation of bar fails (but will pass normally): cleanup_leak.zig const std = @import("std"); test { const length: usize = 10; const allocator = std.testing.allocator; var foo = try allocator.alloc(u8, length); var bar = try allocator.alloc(u8, length); allocator.free(foo); allocator.free(bar); } Shell $ zig test cleanup_leak.zig 1/1 test_0... OK All 1 tests passed. When the test case is converted to use the new checkAllAllocationFailures API, the test fails: test.zig const std = @import("std"); fn testImpl(allocator: std.mem.Allocator, length: usize) !void { var foo = try allocator.alloc(u8, length); var bar = try allocator.alloc(u8, length); allocator.free(foo); allocator.free(bar); } test { const length: usize = 10; const allocator = std.testing.allocator; try std.testing.checkAllAllocationFailures(allocator, testImpl, .{length}); } Shell $ zig test test.zig 1/1 test_0... fail_index: 1/2 allocated bytes: 10 freed bytes: 0 allocations: 1 deallocations: 0 allocation that was made to fail: docgen_tmp/test.zig:5:34: 0x213b19 in testImpl (test) var bar = try allocator.alloc(u8, length); ^ /home/andy/Downloads/zig/lib/std/testing.zig:693:13: 0x214081 in checkAllAllocationFailures__anon_1936 (test) if (@call(.{}, test_fn, args)) |_| { ^ docgen_tmp/test.zig:14:47: 0x2145fa in test_0 (test) try std.testing.checkAllAllocationFailures(allocator, testImpl, .{length}); ^ /home/andy/Downloads/zig/lib/test_runner.zig:63:28: 0x21c568 in main (test) } else test_fn.func(); ^ /home/andy/Downloads/zig/lib/std/start.zig:596:22: 0x214e9d in posixCallMainAndExit (test) root.main(); ^ /home/andy/Downloads/zig/lib/std/start.zig:368:5: 0x214961 in _start (test) @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); ^ FAIL (MemoryLeakDetected) /home/andy/Downloads/zig/lib/std/mem/Allocator.zig:72:13: 0x229226 in allocImpl (test) return @call(.{ .modifier = .always_inline }, allocFn, .{ self, len, ptr_align, len_align, ret_addr }); ^ /home/andy/Downloads/zig/lib/std/mem/Allocator.zig:302:24: 0x21b552 in allocAdvancedWithRetAddr__anon_3779 (test) const byte_slice = try self.rawAlloc(byte_count, a, len_align, return_address); ^ /home/andy/Downloads/zig/lib/std/mem/Allocator.zig:194:5: 0x213c1b in alloc__anon_2377 (test) return self.allocAdvancedWithRetAddr(T, null, n, .exact, @returnAddress()); ^ docgen_tmp/test.zig:5:15: 0x213b37 in testImpl (test) var bar = try allocator.alloc(u8, length); ^ /home/andy/Downloads/zig/lib/std/testing.zig:714:21: 0x2141d6 in checkAllAllocationFailures__anon_1936 (test) return error.MemoryLeakDetected; ^ docgen_tmp/test.zig:14:5: 0x21460d in test_0 (test) try std.testing.checkAllAllocationFailures(allocator, testImpl, .{length}); ^ [gpa] (err): memory address 0x7fb46478c000 leaked: docgen_tmp/test.zig:4:34: 0x213aa4 in testImpl (test) var foo = try allocator.alloc(u8, length); ^ /home/andy/Downloads/zig/lib/std/testing.zig:693:13: 0x214081 in checkAllAllocationFailures__anon_1936 (test) if (@call(.{}, test_fn, args)) |_| { ^ docgen_tmp/test.zig:14:47: 0x2145fa in test_0 (test) try std.testing.checkAllAllocationFailures(allocator, testImpl, .{length}); ^ /home/andy/Downloads/zig/lib/test_runner.zig:63:28: 0x21c568 in main (test) } else test_fn.func(); ^ /home/andy/Downloads/zig/lib/std/start.zig:596:22: 0x214e9d in posixCallMainAndExit (test) root.main(); ^ /home/andy/Downloads/zig/lib/std/start.zig:368:5: 0x214961 in _start (test) @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); ^ 0 passed; 0 skipped; 1 failed. 1 errors were logged. 1 tests leaked memory. error: the following test command failed with exit code 1: /home/andy/.cache/zig/o/92074f0ff860192f15f1d46f1cf33c8d/test Running this test will show that foo is leaked when the allocation of bar fails. The simplest fix, in this case, would be to use defer: leak_fixed.zig const std = @import("std"); fn testImpl(allocator: std.mem.Allocator, length: usize) !void { var foo = try allocator.alloc(u8, length); defer allocator.free(foo); var bar = try allocator.alloc(u8, length); defer allocator.free(bar); } test { const length: usize = 10; const allocator = std.testing.allocator; try std.testing.checkAllAllocationFailures(allocator, testImpl, .{length}); } Shell $ zig test leak_fixed.zig 1/1 test_0... OK All 1 tests passed. Debugging SS * Added DWARFv5 support (#12120) * Make stack traces more reliable by checking if pages are mapped before loading from them. * std.debug now has better resource management (#11485) This code used to assume that it would only be used for dumping stack traces right before an application crashed, however, it is now sometimes used in non-catastrophic cases, so now it behaves properly with regards to allocations and file descriptors. * Fixed ConfigurableTrace.dump OOB * Fixed stack traces with non-null first_address on Windows (#6687) * Added stack trace capturing to FailingAllocator and use it to improve checkAllAllocationFailures (#11919) * Dwarf: Added stroffsetsptr support (#12270) * Fixed incorrect output on Windows when .pdb file is not found during stack trace * Only check the file's length once in pdb.Msf.init * Validate frame-pointer address in stack walking (#10863) * Fixed off-by-one error in def of ProcSym in pdb * Check for overflow in dumpStackTraceFromBase std.debug.Trace SS This is a new API that you can use to efficiently save small stack traces for later, along with relevant data, so that when a problematic behavior is observed, you can dump the corresponding stack trace (#11819): test.zig const std = @import("std"); pub fn main() !void { var s1 = make(); var s2 = make(); if (std.crypto.random.uintLessThanBiased(u8, 100) < 100) { s1.trace.add("got lucky"); } if (std.crypto.random.uintLessThanBiased(u8, 100) < 100) { s2.trace.add("got very lucky"); } if (std.crypto.random.uintLessThanBiased(u8, 100) < 50) { s1.trace.dump(); } else { s2.trace.dump(); } } const S = struct { blah: i32, trace: std.debug.Trace = .{}, }; fn make() S { var result: S = .{ .blah = 1234, }; result.trace.add("initial creation"); return result; } Shell $ zig build-exe test.zig $ ./test initial creation: docgen_tmp/test.zig:30:21: 0x210f86 in make (test) result.trace.add("initial creation"); ^ docgen_tmp/test.zig:5:18: 0x210e67 in main (test) var s2 = make(); ^ /home/andy/Downloads/zig/lib/std/start.zig:578:37: 0x2109f9 in posixCallMainAndExit (test) const result = root.main() catch |err| { ^ /home/andy/Downloads/zig/lib/std/start.zig:340:5: 0x210482 in _start (test) @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); ^ got very lucky: docgen_tmp/test.zig:11:21: 0x210eee in main (test) s2.trace.add("got very lucky"); ^ /home/andy/Downloads/zig/lib/std/start.zig:578:37: 0x2109f9 in posixCallMainAndExit (test) const result = root.main() catch |err| { ^ /home/andy/Downloads/zig/lib/std/start.zig:340:5: 0x210482 in _start (test) @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); ^ This provides insight about the state of the program at a cross-section according to specific objects, which can lead directly to identifying bugs that otherwise would be completely opaque. By default the Trace objects are empty in release modes, so the cost is only paid when debugging. Even when debugging, however, the size of the Trace objects are small - only one usize per stack frame. It defaults to 2 events, 4 stack frames, but can be configured with std.debug.ConfigurableTrace. New Deflate Compressor SS Hadrien Dorio provided a new deflate implementation (#10552). Old API: inflateStream(reader: anytype, window_slice: []u8) New API: decompressor(allocator: mem.Allocator, reader: anytype, dictionary: ?[]const u8) compressor(allocator: mem.Allocator, writer: anytype, options: CompressorOptions) The implementation is a port of the compress/flate package from Go, and appears to be about 2-3x faster. Shell $ zig run bench.zig -O ReleaseFast size: 100B deflate_old: 20.459ms deflate_new: 38.101us new is 536.98x faster size: 1KiB deflate_old: 30.71us deflate_new: 15.159us new is 2.03x faster size: 1MiB deflate_old: 2.824ms deflate_new: 916.366us new is 3.08x faster size: 10MiB deflate_old: 28.298ms deflate_new: 8.246ms new is 3.43x faster size: 22MiB deflate_old: 62.643ms deflate_new: 24.133ms new is 2.60x faster size: 100MiB deflate_old: 288.08ms deflate_new: 107.465ms new is 2.68x faster size: 220MiB deflate_old: 628.471ms deflate_new: 232.427ms new is 2.70x faster Benchmark details Big thanks to Ryan Liptak for fuzz testing. There is still a lot of room for performance improvement beyond this. Formatted Printing SS * Refactor parsing of placeholders into its own function. Makes compilation faster. * Handle FormatOptions in fmtDuration/fmtDurationSigned * Fixed out-of-bounds array write in float printing * Allow uppercase prefix to be parsed in std.fmt.parseInt() * Fixed false positive for zig.isValidId with empty string (#11104) * Fixed incorrect behavior with large floating point integers (# 11283) * fmtIntSizeDec/fmtIntSizeBin support FormatOptions (#9184) * Require specifier for unwrapping ?T and E!T * Added more invalid format string errors * Made fmt.formatAsciiChar respect options parameter Bug Fixes SS Full list of the 452 bug reports closed during this release cycle. Many bugs were both introduced and resolved within this release cycle. This Release Contains Bugs SS Zero the Ziguana Zig has known bugs and even some miscompilations. Zig is immature. Even with Zig 0.10.0, working on a non-trivial project using Zig will likely require participating in the development process. When Zig reaches 1.0.0, Tier 1 Support will gain a bug policy as an additional requirement. A 0.10.1 release is planned. Waiting until 0.10.1 to upgrade is recommended for users who desire a more stable experience. Build System SS * zig build now respects the ZIG_LIB_DIR environment variable. * RunStep: allow expected_exit_code to be null * Normalize build function names such as "addIncludeDir" and "addIncludePath". Also use "Library" instead of the "Lib" abbreviation. * TranslateCStep: add C macro support * Allow tests to use cache and setOutputDir * Use response files for long command lines (#10950) * OptionsStep: Always use fmtId for type names. * Renamed std.build.Pkg.path to std.build.Pkg.source (#11557) * Added EmulatableRunStep (#12059) * Allow comptime_int in OptionsStep.addOption * Fixed transitive linkSystemLibraryName() dependencies * Made no_dll_export_fns accessible in build step * Added flag for -fstack-protector * Made runPkgConfig pub * Fixed Step.cast for OptionsStep and CheckObjectStep * Added unwind_tables integration. Toolchain SS LLVM 15 SS This release of Zig upgrades to LLVM 15.0.3. Note that the Zig 0.9.x series used LLVM 13 - there is no Zig release that depends on LLVM 14. * CMake: Improve usage of llvm-config, especially for consistent static/shared linking (#12136) * CMake: Print all LLVM config errors instead of just the last one. Helps when there are multiple llvm-config executables in PATH. musl 1.2.3 SS Zig ships with the source code to musl. When the musl C ABI is selected, Zig builds static musl from source for the selected target. Zig also supports targeting dynamically linked musl which is useful for Linux distributions that use it as their system libc, such as Alpine Linux. This release upgrades from v1.2.2 to v1.2.3. glibc 2.34 SS Zero the Ziguana The bad news is that although glibc 2.35 and 2.36 have already been released, Zig is behind in adding cross-compilation support for them due to exploring the Universal Headers project. The good news, however, is that Zig can now integrate with system glibc that is newer than what Zig can provide (#12797). Additionally: * Restored compatibility with glibc<=2.33 for global initializers ( #10587) * Added libresolv stubs (#12629) * Added support for targeting glibc for the native system target even when no system C compiler is installed (#12814) * Version-gate _DYNAMIC_STACK_SIZE_SOURCE (#10713) mingw-w64 10.0.0 SS Zig ships with the source code to mingw-w64. When targeting *-windows-gnu and linking against libc, Zig builds mingw-w64 from source for the selected target. This release updates the bundled mingw-w64 source code to v10.0.0. Zig now passes -D__USE_MINGW_ANSI_STDIO=0 for crt files. This was supposed to be happening all along, and it was a bug that Zig did not do this before (#7356). Thanks to Martin Storsjo for helping us discover this on IRC. This fix means that Zig no longer carries any patches on top of upstream mingw-w64 sources! Speaking of Martin, he has just a couple days ago signed up for GitHub Sponsors. He does brilliant work on mingw-w64, and he has patiently helped us when we go into the IRC channel asking for troubleshooting tips from Zig's unusual way of building mingw-w64 from source. Most people would (understandably) say, "sorry, that's unsupported." We are proud to be Martin's first sponsor and hope you will join us in showing support! zig cc SS zig cc is Zig's drop-in C compiler tool. Enhancements in this release: * Integration with --sysroot arg (#10568). * Integration with more linker args: + --whole-archive, -whole-archive + --no-whole-archive, -no-whole-archive + -s, --strip-all + -S, --strip-debug * Add --hash-style linker parameter (applies to ELF). * Fixed a bug where passing a zig source file to zig cc would incorrectly punt to clang because it thought there were no positional arguments. * Emit to a.out if outpath is unspecified (#12858) * Disable the cache for link operations (#12317) This makes zig cc match the equivalent behavior of zig build-exe with regards to caching. That is - it will cache individual .c to .o compilations (with the usual exceptions), but will always repeat the linking process so that incremental linking has a chance to happen. Perhaps a future enhancement will provide a way to get the old behavior, but I suspect this new behavior will be preferred by everyone, because it is closer to what C compilers do. Note that the old behavior can be obtained by switching to zig build-exe instead of zig cc and using the --enable-cache parameter, matching what the Build System does. * Support for -Wl,--export= * Support --subsystem linker flag (#11396) * Integrate with -fstack-check, -fno-stack-check * Introduce special handling of /dev/null Now Zig handles -o /dev/null equivalent to -fno-emit-bin because otherwise the atomic rename into place will fail. This also makes Zig do less work, avoiding pointless file system operations. * Handle -l :FILE syntax (#10851) * Full response file (*.rsp) support (#4833) * Recognize CUDA source files (#10634) * Recognize .stub as yet another C++ source file extension. * Support -Wl,--soname * No longer strip by default, even when -g is not present. * Detect MinGW-flavored static libraries. Ideally on Windows, static libraries look like "foo.lib". However, CMake and other build systems will unfortunately produce static libraries that instead look like "libfoo.a". This patch makes Zig's CLI resolve "-lfoo" arguments into static libraries that match this other pattern. * Support -z nocopyreloc. * Support -no-pie. * Pass -O0 rather than -Og to Clang for Debug builds (#11949) * Recognize --verbose as an alias for -v * Support --compress-debug-sections (#11863) * Add support for -M (#12369) * Avoid pointless caching (#12317) When the entire purpose of this compilation is to perform a single zig cc operation we could "tail call" clang by doing an execve, and any use of the caching system would actually be problematic since the user is presumably doing their own caching by using dep file flags. * Add --print-gc-sections, --print-icf-sections, and --print-map * Ensure that assembly source file command lines get the -g flag when appropriate. * When passing arguments to zig clang internally, Zig will now use a response file (.rsp) if the CLI length would exceed what the system supports. This fixes a CI test failure on Windows (#12540) Please be aware that there are still open zig cc issues. However, these are use cases that never worked in the first place, making them bugs and enhancements rather than regressions. zig c++ SS zig c++ is equivalent to zig cc with an added -lc++ parameter, but I made a separate heading here because I realized that some people are not aware that Zig supports compiling C++ code and providing libc++ too! hello.cpp #include int main() { std::cout << "Hello World!" >> std::endl; return 0; } Shell $ zig c++ -o hello hello.cpp $ ./hello Hello World! Cross-compiling too, of course: Shell $ zig c++ -o hello hello.cpp -target riscv64-linux $ qemu-riscv64 ./hello Hello World! One thing that trips people up when they use this feature is that the C++ ABI is not stable across compilers, so always remember the rule: You must use the same C++ compiler to compile all your objects and static libraries. This is an unfortunate limitation of C++ which Zig can never fix. Improvements to libc++ in this release: * Normalized C++ compilation options for single-threaded targets (# 10143) * Improved Windows compatibility. * Only pass -DHAVE___CXA_THREAD_ATEXIT_IMPL for glibc (#13314) zig fmt SS * Remove trailing whitespace on doc comments (#11353) * Respect trailing commas in inline assembly, however, remove trailing comma at the end of clobbers. * Keep callconv(.Inline) on function pointer types. * Fixed formatting for single-line containers with comments (#8810) * Fixed performance issue with nested arrays (#10224) * Handle doc comments on struct members (#10443) * Fixed switch cases dropping comments in certain situations (# 11131) * Fixed idempotency with newlines surrounding doc comment (#11802) * Stop deleting container doc comments (#12617) * --exclude now ignores missing directories. compiler-rt SS compiler-rt is the library that provides, for example, 64-bit integer multiplication for 32-bit architectures which do not have a machine code instruction for it. In the GNU world, it is called libgcc. Unlike most compilers, which depend on a binary build of compiler-rt being installed alongside the compiler, Zig builds compiler-rt on-the-fly, from source, as needed for the target platform. This release saw some improvements to Zig's compiler-rt implementation (# 1290). * Added __absvsi2, __absvdi2, __absvti2 * Added __negvsi2, __negvdi2, __negvti2 * Added complex multiply/division (#13117) * Added addo and subo routines (#10824) * Added TAS lock support for SPARC (#11437) * Fixed softfloat support for PowerPC (#13100) * Optimized mulo * Added routines for f80 * Avoid symbol collisions with Windows libc (#11609) * Started consolidating libc functions that codegen depends on into compiler-rt (#7265) Compiler backends want to emit calls to e.g. memcpy or sqrt. These are typically provided by libc, but they might not be in the case of freestanding, or depending on which third party libc is linked against. Therefore Zig has started to provide all possible symbols with weak linkage, meaning that these symbols will be overridden by libc if provided. This means the only necessary runtime library that Zig objects need to be linked against is compiler-rt, no matter the target. * The source code has been re-organized to support the use case of building compiler-rt with a different compilation unit per file ( #11847) It was hypothesized that this could improve Self-Hosted Linker performance, however -ffunction-sections plus garbage collection ended up being faster. * Support compiling for the Android NDK (#13245) Roadmap SS Ziggy the Ziguana Now that the Self-Hosted Compiler is launched, we can move on with the roadmap! The major themes of the 0.11.0 release cycle will be language changes , compilation speed, and package management. Some upcoming milestones we will be working towards in the 0.11.0 release cycle: * Finishing the tail end of test coverage - getting the Self-Hosted Compiler to pass a strict superset of tests passed by the Bootstrap Compiler. This is down to a few dozen compile error tests. * Self-Hosted Compiler can build itself with the C Backend. Unlocks ability to replace the Bootstrap Compiler with generated C code ( #5246). * Many Accepted Proposals implemented. Expect breakage! * Behavior tests passing for the x86 Backend, aarch64 Backend, or WebAssembly Backend. Unleashes our full compilation speed when targeting the respective architecture. * Experimental first implementation of the official package manager . * Fuzz test incremental compilation so that we can enable it and gain compilation speed for all backends, including the LLVM backend. * Self-Hosted Linker support for ELF and COFF. Eliminate dependency on LLD. * Hot code swapping for Windows, macOS, and Linux. * Introduce Concurrency to semantic analysis to further increase compilation speed. Here are the steps for Zig to reach 1.0: 1. Stabilize the language. No more Language Changes after this. 2. Complete the language specification first draft. 3. Implement the official package manager. 4. Stabilize the Standard Library. That means to add any missing functionality, audit the existing functionality, curate it, re-organize everything, and fix all the bugs. 5. Go one full release cycle without any breaking changes. 6. Finally we can tag 1.0. Package Manager SS Having a package manager built into the Zig compiler is a long-anticipated feature. Zig 0.10.0 does not have this feature. However, all the prerequisites are finally done, and work begins now! We will do our best to keep in mind the needs of system package maintainers while working on this language package manager. Accepted Proposals SS If you want more of a sense of the direction Zig is heading, you can look at the set of accepted proposals. Thank You Contributors! SS Here are all the people who landed at least one contribution into this release: * Andrew Kelley * Jakub Konka * Veikka Tuominen * Luuk de Gram * joachimschmidt557 * Koakuma * Loris Cro * Cody Tapscott * Mitchell Hashimoto * r00ster91 * Vallahor * Robin Voetter * John Schmidt * Ryan Liptak * William Sengir * Jacob Young * Jonathan Marler * Daniele Cocca * fifty-six * Motiejus Jakstys * ominitay * Jimmi Holst Christensen * Isaac Freund * Evan Haas * viri * Frank Denis * Meghan * Joachim Schmidt * Der Teufel * Guillaume Wenzek * Stephen Gutekanst * Vincent Rischmann * mparadinha * Jacob G-W * Jan Philipp Hafer * Lee Cannon * Marc Tiehuis * riverbl * zooster * Ali Chraghi * Stephen Gregoratto * Jens Goldberg * LordMZTE * Yujiri * Hadrien Dorio * kkHAIKE * r00ster * Erik Arvstedt * Evin Yulo * Hiroaki Nakamura * InKryption * Rabin Gaire * Tau * iddev5 * jagt * matu3ba * protty * r00ster * Andreas Reischuck * Bill Nagel * Eric Joldasov * Felix "xq" Queissner * InKryption * John Schmidt * Kirk Scheibelhut * LeRoyce Pearson * Sage Hane * VOROSKOI Andras * Yusuf Bham * aiotter * alice * antlilja * frmdstryr * kcbanner * kprotty * riChar * vi * xReveres * Al Hoang * Austin Rude * Ben Fiedler * BratishkaErik * Dan Ellis Echavarria * Daniel Saier * Daniele Cocca * Dante Catalfamo * David Gonzalez Martin * David John * David Martschenko * Erik Hugne * Flandre Scarlet * Francesco Alemanno * GethDW * Helio Machado * Igor Stojkovic * Ikko Ashimine * Jarred Sumner * Jonathan S * Locria Cyber * Mateusz Radomski * Mikhail Popov * Philipp Luhmann * Reece Van Atta * Sebsatian Keller * Shane Kennedy * Silver * Sebastien Marie * Techatrix * Techcable * Tom Read Cutting * TwoClocks * Vincenzo Palazzo * Wojtek Mach * Xavier Bouchoux * alichraghi * bfredl * billzez * cod1r * fn ^ [?] * gwenzek * leesongun * m * martinhath * naeu * paulsnar * praschke * r00ster91 * sin-ack * xavier * zseri * ABuffSeagull * Alexander Slesarev * Allan Regush * Andrew Lee * Annika L * Anthony Carrico * Anton Lilja * Arnavion * Benjamin San Souci * BlueAlmost * Brian Gold * C-BJ * Carlos Zuniga * Chris Boesch * Curtis Tate Wilkinson * Curtis Wilkinson * Damien Firmenich * Daniel Hooper * David John * Dominic Tarr * Duncan Holm * Endel Dreyer * Eric Milliken * Eric Shrewsberry * Ersikan * Exonorid * Felix "xq" Queissner * FlandreScarlet * Gaetan * GethDW * GithubPrankster * Gregory Anders * Hanna * Hannes Bredberg * Hashi364 * Henrique Dante de Almeida * Igor Anic * Isaac Yonemoto * J87 * James Mintram * Jan200101 * Jason Ho * Jay Petacat * Jean Dao * Johannes Lothberg * John Simon * Jonas Gollenz * Josh Hannaford * Julian * Justas Zabulionis * Justin Whear * Kazuki Sakamoto * Keith Chambers * Ken Micklas * Kenta Iwasaki * Kim SHrier * Kirk Scheibelhut * Lewis Gaul * Maciej 'vesim' Kulinski * Mahdi Rakhshandehroo * Manlio Perillo * Marian Beermann * Marijn Stollenga * Martin Hafskjold Thoresen * Martin Stuurwold * Martin Wickham * Mateusz Radomski * Matthew Hall * May B * Meredith Oleander * Michael Dusan * Mikael Berthe * Mikko Kaihlavirta * Morritz * N00byEdge * Naoki MATSUMOTO * Natalia Cholewa * OfekShochat * Omar Alhammadi * Pablo Santiago Blum de Aguiar * PhaseMage * Philipp Luhmann * Pierre Curto * Rekai Musuka * Rekai Nyangadzayi Musuka * Riccardo Binetti * Robin * Ryotaro "Justin" Kimura * Sebastian Keller * Shupei Fan * Sizhe Zhao * Stephen Lumenta * Steven Fackler * Takeshi Yoneda * Techcable * The Depressed Milkman * Thiago Teodoro Pereira Silva * Thomas Cheng * Tom Maenan Read Cutting * Tom Manner * Travis Staloch * Tw * Wei Fu * Will Hawkins * YeonJiKun * Yorhel * Yusuf Bham * Yusuke Tanaka * Yuto Oguchi * Zhora Trush * afranchuk * alex * biexelar * boofexxx * bryfry * chip2n * cryptocode * dan * daurnimator * devins2518 * djg * drew * dxps * emma * erikarvstedt * jcalabro * johnLate * jumpnbrownweasel * max * mllken * noiryuh * rohlem * sharpobject * sin-ack * tecanec * vnc5 * xEgoist * yujiri8 * yyny * zc * Ziga Zeljko * noYuh Thank You Sponsors! SS Ziggy the Ziguana Special thanks to those who sponsor Zig. Because of you, Zig is driven by the open source community, rather than the goal of making profit. In particular, these fine folks sponsor Zig for $50/month or more: * Pex * Kirk Scheibelhut * drfuchs * tarasbob * CoilHQ * Stephen Gutekanst * Stevie Hryciw * Mitchell Hashimoto * Paul Harrington * Derek Collison * Karrick McDermott * Joran Dirk Greef * bfredl * Dustin Taylor * Tom Manner * Jose M Rico * Wasmer * Simon A. Nielsen Knights * Mikoverse * Josh Wolfe * ryanworl * Rui Ueyama * Alun Bestor * Terin Stock * Aras Pranckevicius * Daniele Cocca * The Lycus Foundation * Dan Banta * Jethro Nederhof * Brian Gold * David Vanderson * Matt Knight * Loic Tosser * GoofyFoot Labs * Martin Schwaighofer * Santiago Andaluz * Luke Champine * Yurii Rashkovskii * Rand Fitzpatrick * Jesus Alvarez * Benjamin Ebby * Charlie Cheever * Ralph Brorsen * Brett Slatkin * Wojtek Mach * Max De Marzi * Josh Ashby * Christopher Dolan * Alex Bubnov * Anton Kochkov * Damien Firmenich * Jamie Brandon * Jordan Orelli * Max Bernstein * Timothy Ham * Jay Petacat * Garett Bass * Marco Munizaga * Christian Wesselhoeft * Tyler Gibbons * Keith Devens * Agam Dua * Aaron Olson * Ian Applegate * Daniel Hensley * Charles * Erik Mallberg * Luca Bolognese * Sean Carey * Andre Rodrigues * Wesley Hill * Peter Dinges * Emily A. Bellows * Lee Cannon * sparrisable * Chris Baldwin * Martin Hochenwarter * Wang Ai Guo * Ross Rheingans-Yoo * Felix Queissner * Baptiste Canton * Mario Arias * Luuk de Gram * Mateusz Czarnecki * James McGill * Rafael Batiati * Yaroslav Zhavoronkov * Tom Read Cutting * Mykhailo Tsiuptsiun (miktwon) [Flag of Ukraine] * Curtis Tate Wilkinson * Alex Sergeev * Auguste Rame * Mamadou S Diallo * Dirk de Visser * Joe Gordon * OM PropTech GmbH