Zig 0.15.x
Language / type system
- usingnamespace keyword removed entirely; refactor to explicit imports / conditional expressions (the mixin pattern now uses zero-bit fields plus @fieldParentPtr("name", m)).
- async and await keywords removed; @frameSize builtin removed. To be replaced by stdlib I/O-based implementations.
- Packed union fields no longer accept align attributes (matches packed structs).
- New rules for undefined: only operators that cannot trigger illegal behavior accept undefined operands; arithmetic on undefined is now a compile error / illegal behavior.
- Integer-to-float coercion is a compile error at comptime when precision would be lost; integer literals must be written as float literals (e.g. 123_456_789 → 123_456_789.0).
- Inline assembly clobber lists changed from string syntax to typed struct syntax (zig fmt auto-upgrades).
- @ptrCast extended to allow single-item-pointer → slice (slice byte count matches operand).
- Boolean vector operators (!, &, |, ^, and/or semantics) now defined on bool vectors.
Standard library
- "Writergate" — std.io reader/writer interfaces overhauled into std.Io:
- std.io.GenericReader / std.io.AnyReader → std.Io.Reader
- std.io.GenericWriter / std.io.AnyWriter → std.Io.Writer
- std.io.SeekableStream removed; use concrete std.fs.File.Reader / std.fs.File.Writer.
- std.io.BitReader, std.io.BitWriter removed.
- std.Io.LimitedReader, std.Io.BufferedReader removed.
- std.io.CountingWriter removed; use std.Io.Writer.Discarding or std.Io.Writer.Allocating.
- std.io.BufferedWriter removed; pass an explicit buffer to a file writer.
- std.fifo module removed entirely (std.fifo.LinearFifo gone).
- std.RingBuffer removed (replaced by I/O stream ring buffers).
- std.fs.File.reader() / .writer() → .deprecatedReader() / .deprecatedWriter(); new .reader(buffer) / .writer(buffer) require a caller-provided buffer and explicit flush().
- std.fs.File.WriteFileOptions, std.fs.File.writeFileAll, std.fs.File.writeFileAllUnseekable removed.
- std.fs.Dir.atomicFile now requires write_buffer in options; fs.AtomicFile.File field replaced with File.Writer.
- std.posix.sendfile removed in favor of std.fs.File.Reader.sendFile.
- std.fs.Dir.copyFile no longer returns error.OutOfMemory.
- Formatting overhaul:
- format method signature changed from fn format(self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void to fn format(self, writer: *std.Io.Writer) std.Io.Writer.Error!void.
- {} no longer calls a type's format method; you must use {f}.
- std.fmt.FormatOptions removed; alignment over Unicode codepoints removed (ASCII/bytes only).
- std.fmt.format → std.Io.Writer.print.
- std.fmt.Formatter → std.fmt.Alt (requires explicit context type).
- std.fmt.fmtSliceHexLower / fmtSliceHexUpper removed → use {x} / {X}.
- std.fmt.fmtSliceEscapeLower / fmtSliceEscapeUpper → std.ascii.hexEscape.
- std.fmt.fmtIntSizeDec / fmtIntSizeBin removed → use {B} / {Bi}.
- std.fmt.fmtDuration / fmtDurationSigned removed → use {D}.
- std.zig.fmtEscapes → std.zig.fmtString.
- New specifiers: {t} (tag name), {b64} (base64).
- Collections — ArrayList and friends migrated to unmanaged-by-default:
- std.ArrayList(T) (managed) → std.array_list.Managed(T); the unmanaged variant is now the default std.ArrayList.
- std.ArrayListAligned → std.array_list.AlignedManaged.
- std.BoundedArray removed; use ArrayListUnmanaged with a fixed buffer.
- std.DoublyLinkedList(T) de-genericified: nodes are now std.DoublyLinkedList.Node embedded in user structs and traversed with @fieldParentPtr.
- std.compress.flate.CircularBuffer removed.
- Compression: std.compress.flate.Decompress now takes a container parameter; higher-level compression and checksum helpers removed (do checksums out-of-band, use third-party packages for compression).
Build system / toolchain
- Deprecated implicit root-module fields on std.Build.ExecutableOptions (and siblings) removed, including root_source_file; must use the root_module field introduced in 0.14.0.
- std.Build.Step.Compile.sanitize_c changed type from ?bool to ?std.zig.SanitizeC; replace true/false with .full/.off.
- -fsanitize-c split into -fsanitize-c=full and -fsanitize-c=trap.
- x86_64 self-hosted backend is now the default for Debug mode (except NetBSD, OpenBSD, Windows, which still default to LLVM).
- New CLI: zig test-obj (compile tests to an object file instead of an executable).
- LLVM bumped to 20.1.8.
- zig cc: -static and -dynamic now respected.
- zig objcopy regressed; some subcommands now return "unimplemented".
Sources:
- 0.15.1 Release Notes
@Typebuiltin removed. Replaced by@Int,@Tuple,@Pointer,@Fn,@Struct,@Union,@Enum,@EnumLiteral.@cImportdeprecated. Use the build system:b.addTranslateC(...).@intFromFloatdeprecated.@floor,@ceil,@round,@truncnow convert directly to integer types.- Unary float builtins (
@sqrt,@sin,@floor, …) forward result types into earlier operations. - Integer → float coercion is implicit when all values fit losslessly.
- Runtime indexing of vectors with non-comptime values is forbidden — coerce to array first.
- Array ↔ vector in-memory coercion removed.
- Returning the address of a local variable is now a compile error (
returning address of expired local variable). *u8and*align(1) u8are now distinct types (they coerce, but are not identical).- Pointers to
comptime-only types (e.g.*comptime_int) are no longer themselves comptime-only. - Packed structs/unions:
- Switch on packed types compares solely on the backing integer.
- All packed-union fields must have identical
@bitSizeOfmatching a backing integer. - Pointers are forbidden as fields of packed structs/unions.
- Packed unions accept explicit backing-integer syntax:
packed union(u16) { … }. - Packed structs/unions with inferred backing integer, and enums with inferred tag types, are no longer valid
externtypes.
- Lazy field analysis: structs/unions/enums/opaques only resolve when size or field types are required — affects code that probed types via
@typeInfo. - Zero-bit tuple fields no longer auto-promote to
comptimefields. - New dependency-loop cases; error messages explain the loop.
Anything that "potentially blocks control flow or introduces nondeterminism" now lives behind a std.Io instance.
- File system fully migrated
std.fs→std.Io.Dir/std.Io.File:fs.Dir→std.Io.Dirfs.File→std.Io.Filefs.File.Mode→std.Io.File.Permissionsfs.cwd→std.Io.Dir.cwdfs.realpath→std.Io.Dir.realPathFileAbsolutefs.Dir.makeDir→std.Io.Dir.createDirfs.Dir.makePath→std.Io.Dir.createDirPathfs.Dir.makeOpenDir→std.Io.Dir.createDirPathOpenfs.Dir.renamenow takes twoDirparameters; returnserror.DirNotEmptyinstead oferror.PathAlreadyExists.fs.Dir.chmod→std.Io.Dir.setPermissionsfs.Dir.chown→std.Io.Dir.setOwnerfs.File.setEndPos→std.Io.File.setLengthfs.File.getEndPos→std.Io.File.lengthfs.File.read→std.Io.File.readStreamingfs.File.write→std.Io.File.writeStreamingfs.File.updateTimes→std.Io.File.setTimestamps- All
*Zand*Wpath variants removed (realpathZ,realpathW,makeDirAbsoluteZ,deleteDirAbsoluteZ,deleteTreeAbsolute, etc. — ~300 functions deleted).
- Time:
std.time.Instant→std.Io.Timestampstd.time.Timer→std.Io.Timestampstd.time.timestamp()→std.Io.Timestamp.now(io)
- Randomness:
std.crypto.random.bytes→io.randomstd.crypto.random→std.Random.IoSourceviaio.interface()posix.getrandom→io.random
- Synchronisation primitives all relocated under
std.Io:std.Thread.Mutex→std.Io.Mutexstd.Thread.Condition→std.Io.Conditionstd.Thread.RwLock→std.Io.RwLockstd.Thread.Semaphore→std.Io.Semaphorestd.Thread.WaitGroup→std.Io.Groupstd.Thread.ResetEvent→std.Io.Eventstd.Thread.Futex→std.Io.Futexstd.Thread.Poolremoved.std.Thread.Mutex.Recursiveremoved.std.onceremoved.heap.ThreadSafeAllocatorremoved.
- Process:
std.process.Child.init→std.process.spawn(...)with options struct.std.process.execv→std.process.replace.
fmt.Formatter→fmt.Alt.fmt.format→std.Io.Writer.print.fmt.bufPrintZ→fmt.bufPrintSentinel.- Removed:
SegmentedList,meta.declList,Io.GenericWriter,Io.AnyWriter,Io.null_writer,Io.CountingReader. - Error renames:
error.RenameAcrossMountPoints→error.CrossDeviceerror.NotSameFileSystem→error.CrossDeviceerror.SharingViolation→error.FileBusyerror.EnvironmentVariableNotFound→error.EnvironmentVariableMissing
- Debug:
captureStackTrace→captureCurrentStackTracedumpStackTraceFromBase→dumpCurrentStackTracewriteStackTraceWindows→writeCurrentStackTracestd.debug.StackIteratorno longerpub.
BitSet/EnumSetinitEmpty/initFullreplaced with declaration literals.- Container migration to "unmanaged" forms continues across the std lib.
DynLib: Windows support removed (LoadLibraryExW+GetProcAddressdirectly).std.posixalmost entirely removed; OS-specific APIs gone.
- Local package overrides in the build system.
- Project-local package fetching (instead of global cache).
- Unit-test timeouts.
- New
--error-styleand--multiline-errorsflags. - LLVM 21; loop vectorisation disabled to dodge a regression.
- Solaris / AIX / z/OS removed; illumos still supported.