From 0e37ff0d591dd75ceec9208196bec29efaec607a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 27 Jun 2025 20:05:22 -0700 Subject: [PATCH] std.fmt: breaking API changes added adapter to AnyWriter and GenericWriter to help bridge the gap between old and new API make std.testing.expectFmt work at compile-time std.fmt no longer has a dependency on std.unicode. Formatted printing was never properly unicode-aware. Now it no longer pretends to be. Breakage/deprecations: * std.fs.File.reader -> std.fs.File.deprecatedReader * std.fs.File.writer -> std.fs.File.deprecatedWriter * std.io.GenericReader -> std.io.Reader * std.io.GenericWriter -> std.io.Writer * std.io.AnyReader -> std.io.Reader * std.io.AnyWriter -> std.io.Writer * std.fmt.format -> std.fmt.deprecatedFormat * std.fmt.fmtSliceEscapeLower -> std.ascii.hexEscape * std.fmt.fmtSliceEscapeUpper -> std.ascii.hexEscape * std.fmt.fmtSliceHexLower -> {x} * std.fmt.fmtSliceHexUpper -> {X} * std.fmt.fmtIntSizeDec -> {B} * std.fmt.fmtIntSizeBin -> {Bi} * std.fmt.fmtDuration -> {D} * std.fmt.fmtDurationSigned -> {D} * {} -> {f} when there is a format method * format method signature - anytype -> *std.io.Writer - inferred error set -> error{WriteFailed} - options -> (deleted) * std.fmt.Formatted - now takes context type explicitly - no fmt string --- CMakeLists.txt | 1 - build.zig | 6 +- lib/compiler/aro/aro/Compilation.zig | 2 +- lib/compiler/aro/aro/Diagnostics.zig | 26 +- lib/compiler/aro/aro/Driver.zig | 12 +- lib/compiler/aro/aro/Parser.zig | 10 +- lib/compiler/aro/aro/Preprocessor.zig | 5 +- lib/compiler/aro/aro/Value.zig | 2 +- lib/compiler/aro/backend/Object/Elf.zig | 2 +- lib/compiler/aro_translate_c/ast.zig | 12 +- lib/compiler/build_runner.zig | 58 +- lib/compiler/libc.zig | 6 +- lib/compiler/objcopy.zig | 6 +- lib/compiler/reduce.zig | 2 +- lib/compiler/resinator/cli.zig | 2 +- lib/compiler/resinator/compile.zig | 18 +- lib/compiler/resinator/errors.zig | 25 +- lib/compiler/resinator/lex.zig | 4 +- lib/compiler/resinator/main.zig | 12 +- lib/compiler/resinator/res.zig | 44 +- lib/compiler/test_runner.zig | 2 +- lib/docs/wasm/markdown.zig | 2 +- lib/docs/wasm/markdown/renderer.zig | 12 +- lib/init/src/root.zig | 2 +- lib/std/Build.zig | 12 +- lib/std/Build/Cache.zig | 68 +- lib/std/Build/Cache/DepTokenizer.zig | 201 +- lib/std/Build/Cache/Directory.zig | 11 +- lib/std/Build/Cache/Path.zig | 45 +- lib/std/Build/Fuzz/WebServer.zig | 18 +- lib/std/Build/Module.zig | 2 +- lib/std/Build/Step.zig | 9 +- lib/std/Build/Step/CheckObject.zig | 1242 ++++++------- lib/std/Build/Step/Compile.zig | 19 +- lib/std/Build/Step/ConfigHeader.zig | 230 +-- lib/std/Build/Step/InstallArtifact.zig | 2 +- lib/std/Build/Step/InstallDir.zig | 2 +- lib/std/Build/Step/Options.zig | 258 +-- lib/std/Build/Step/Run.zig | 45 +- lib/std/Build/Step/UpdateSourceFiles.zig | 6 +- lib/std/Build/Step/WriteFile.zig | 14 +- lib/std/Build/Watch.zig | 6 +- lib/std/Progress.zig | 31 + lib/std/Random/benchmark.zig | 2 +- lib/std/SemanticVersion.zig | 20 +- lib/std/Target.zig | 27 +- lib/std/Target/Query.zig | 41 +- lib/std/Thread.zig | 6 +- lib/std/Uri.zig | 98 +- lib/std/ascii.zig | 41 + lib/std/builtin.zig | 10 +- lib/std/crypto/25519/curve25519.zig | 4 +- lib/std/crypto/25519/ed25519.zig | 6 +- lib/std/crypto/25519/edwards25519.zig | 2 +- lib/std/crypto/25519/ristretto255.zig | 8 +- lib/std/crypto/25519/scalar.zig | 6 +- lib/std/crypto/benchmark.zig | 2 +- lib/std/crypto/chacha20.zig | 4 +- lib/std/crypto/ml_kem.zig | 16 +- lib/std/crypto/tls/Client.zig | 8 +- lib/std/debug.zig | 350 ++-- lib/std/debug/Dwarf.zig | 14 +- lib/std/debug/Pdb.zig | 4 +- lib/std/fmt.zig | 1649 ++--------------- lib/std/fmt/{format_float.zig => float.zig} | 24 +- lib/std/fs/File.zig | 1235 +++++++----- lib/std/fs/path.zig | 7 +- lib/std/fs/test.zig | 111 +- lib/std/hash/benchmark.zig | 2 +- lib/std/heap/debug_allocator.zig | 20 +- lib/std/http.zig | 21 +- lib/std/http/Client.zig | 27 +- lib/std/http/test.zig | 6 +- lib/std/io.zig | 28 +- lib/std/io/DeprecatedWriter.zig | 28 +- lib/std/io/Reader.zig | 46 +- lib/std/io/Writer.zig | 257 ++- lib/std/io/buffered_atomic_file.zig | 2 +- lib/std/io/test.zig | 8 +- lib/std/json/dynamic.zig | 2 +- lib/std/json/fmt.zig | 13 +- lib/std/json/stringify.zig | 9 +- lib/std/log.zig | 4 +- lib/std/math/big/int.zig | 21 +- lib/std/math/big/int_test.zig | 8 +- lib/std/multi_array_list.zig | 1 + lib/std/net.zig | 70 +- lib/std/net/test.zig | 27 +- lib/std/os.zig | 1 + lib/std/os/freebsd.zig | 49 + lib/std/os/linux.zig | 130 +- lib/std/os/uefi.zig | 37 +- lib/std/os/uefi/protocol/file.zig | 24 - lib/std/os/windows.zig | 34 - lib/std/os/windows/ws2_32.zig | 10 +- lib/std/posix.zig | 2 +- lib/std/posix/test.zig | 2 +- lib/std/process.zig | 14 +- lib/std/process/Child.zig | 4 +- lib/std/testing.zig | 21 +- lib/std/unicode.zig | 59 +- lib/std/unicode/throughput_test.zig | 2 +- lib/std/zig.zig | 223 ++- lib/std/zig/Ast.zig | 4 +- lib/std/zig/ErrorBundle.zig | 2 +- lib/std/zig/ZonGen.zig | 8 +- lib/std/zig/llvm/Builder.zig | 1032 +++++------ lib/std/zig/parser_test.zig | 2 +- lib/std/zig/perf_test.zig | 2 +- lib/std/zig/render.zig | 6 +- lib/std/zig/string_literal.zig | 11 +- lib/std/zip.zig | 2 +- lib/std/zip/test.zig | 2 +- lib/std/zon/parse.zig | 242 ++- lib/std/zon/stringify.zig | 15 +- lib/ubsan_rt.zig | 95 +- src/Air/print.zig | 8 +- src/Builtin.zig | 80 +- src/Compilation.zig | 12 +- src/InternPool.zig | 6 +- src/Package.zig | 2 +- src/Package/Fetch.zig | 30 +- src/Package/Fetch/git.zig | 18 +- src/Package/Manifest.zig | 4 +- src/Sema.zig | 906 ++++----- src/Sema/LowerZon.zig | 2 +- src/Type.zig | 4 +- src/Zcu.zig | 2 +- src/Zcu/PerThread.zig | 10 +- src/arch/x86_64/Encoding.zig | 2 +- src/arch/x86_64/encoder.zig | 4 +- src/codegen/llvm.zig | 2 +- src/crash_report.zig | 14 +- src/fmt.zig | 6 +- src/libs/libtsan.zig | 2 +- src/libs/mingw.zig | 4 +- src/link/Coff.zig | 4 +- src/link/Elf/Archive.zig | 6 +- src/link/Elf/LinkerDefined.zig | 4 +- src/link/Elf/ZigObject.zig | 8 +- src/link/Elf/gc.zig | 2 +- src/link/LdScript.zig | 4 +- src/link/Lld.zig | 10 +- src/link/MachO/Archive.zig | 4 +- src/link/MachO/Object.zig | 14 +- src/link/MachO/ZigObject.zig | 2 +- src/link/MachO/dyld_info/Trie.zig | 4 +- src/link/Wasm/Flush.zig | 12 +- src/link/tapi/parse.zig | 49 +- src/main.zig | 45 +- src/print_value.zig | 4 +- src/print_zir.zig | 62 +- src/print_zoir.zig | 6 +- src/translate_c.zig | 22 +- test/behavior/union_with_members.zig | 4 +- test/link/elf.zig | 4 +- .../run_output_paths/create_file.zig | 2 +- test/standalone/simple/brace_expansion.zig | 2 +- test/standalone/windows_argv/fuzz.zig | 2 +- test/standalone/windows_argv/lib.zig | 12 +- test/tests.zig | 2 +- 161 files changed, 4385 insertions(+), 5847 deletions(-) rename lib/std/fmt/{format_float.zig => float.zig} (99%) create mode 100644 lib/std/os/freebsd.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 22419aa9fa..57e7cba085 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -436,7 +436,6 @@ set(ZIG_STAGE2_SOURCES lib/std/elf.zig lib/std/fifo.zig lib/std/fmt.zig - lib/std/fmt/format_float.zig lib/std/fmt/parse_float.zig lib/std/fs.zig lib/std/fs/AtomicFile.zig diff --git a/build.zig b/build.zig index 4cff998384..60c4e8f0e4 100644 --- a/build.zig +++ b/build.zig @@ -279,7 +279,7 @@ pub fn build(b: *std.Build) !void { const ancestor_ver = try std.SemanticVersion.parse(tagged_ancestor); if (zig_version.order(ancestor_ver) != .gt) { - std.debug.print("Zig version '{}' must be greater than tagged ancestor '{}'\n", .{ zig_version, ancestor_ver }); + std.debug.print("Zig version '{f}' must be greater than tagged ancestor '{f}'\n", .{ zig_version, ancestor_ver }); std.process.exit(1); } @@ -1449,7 +1449,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath { } var dir = b.build_root.handle.openDir("doc/langref", .{ .iterate = true }) catch |err| { - std.debug.panic("unable to open '{}doc/langref' directory: {s}", .{ + std.debug.panic("unable to open '{f}doc/langref' directory: {s}", .{ b.build_root, @errorName(err), }); }; @@ -1470,7 +1470,7 @@ fn generateLangRef(b: *std.Build) std.Build.LazyPath { // in a temporary directory "--cache-root", b.cache_root.path orelse ".", }); - cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) }); + cmd.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) }); cmd.addArgs(&.{"-i"}); cmd.addFileArg(b.path(b.fmt("doc/langref/{s}", .{entry.name}))); diff --git a/lib/compiler/aro/aro/Compilation.zig b/lib/compiler/aro/aro/Compilation.zig index 798c192516..d723fdc3c5 100644 --- a/lib/compiler/aro/aro/Compilation.zig +++ b/lib/compiler/aro/aro/Compilation.zig @@ -1432,7 +1432,7 @@ fn getFileContents(comp: *Compilation, path: []const u8, limit: ?u32) ![]const u defer buf.deinit(); const max = limit orelse std.math.maxInt(u32); - file.reader().readAllArrayList(&buf, max) catch |e| switch (e) { + file.deprecatedReader().readAllArrayList(&buf, max) catch |e| switch (e) { error.StreamTooLong => if (limit == null) return e, else => return e, }; diff --git a/lib/compiler/aro/aro/Diagnostics.zig b/lib/compiler/aro/aro/Diagnostics.zig index f3ae4be38a..04c92d58a8 100644 --- a/lib/compiler/aro/aro/Diagnostics.zig +++ b/lib/compiler/aro/aro/Diagnostics.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const assert = std.debug.assert; const Allocator = mem.Allocator; const mem = std.mem; const Source = @import("Source.zig"); @@ -443,18 +444,13 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void { printRt(m, prop.msg, .{"{s}"}, .{&str}); } else { var buf: [3]u8 = undefined; - const str = std.fmt.bufPrint(&buf, "x{x}", .{std.fmt.fmtSliceHexLower(&.{msg.extra.invalid_escape.char})}) catch unreachable; + const str = std.fmt.bufPrint(&buf, "x{x}", .{&.{msg.extra.invalid_escape.char}}) catch unreachable; printRt(m, prop.msg, .{"{s}"}, .{str}); } }, .normalized => { const f = struct { - pub fn f( - bytes: []const u8, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn f(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void { var it: std.unicode.Utf8Iterator = .{ .bytes = bytes, .i = 0, @@ -464,22 +460,16 @@ pub fn renderMessage(comp: *Compilation, m: anytype, msg: Message) void { try writer.writeByte(@intCast(codepoint)); } else if (codepoint < 0xFFFF) { try writer.writeAll("\\u"); - try std.fmt.formatInt(codepoint, 16, .upper, .{ - .fill = '0', - .width = 4, - }, writer); + try writer.printIntOptions(codepoint, 16, .upper, .{ .fill = '0', .width = 4 }); } else { try writer.writeAll("\\U"); - try std.fmt.formatInt(codepoint, 16, .upper, .{ - .fill = '0', - .width = 8, - }, writer); + try writer.printIntOptions(codepoint, 16, .upper, .{ .fill = '0', .width = 8 }); } } } }.f; - printRt(m, prop.msg, .{"{s}"}, .{ - std.fmt.Formatter(f){ .data = msg.extra.normalized }, + printRt(m, prop.msg, .{"{f}"}, .{ + std.fmt.Formatter([]const u8, f){ .data = msg.extra.normalized }, }); }, .none, .offset => m.write(prop.msg), @@ -541,7 +531,7 @@ const MsgWriter = struct { fn init(config: std.io.tty.Config) MsgWriter { std.debug.lockStdErr(); return .{ - .w = std.io.bufferedWriter(std.fs.File.stderr().writer()), + .w = std.io.bufferedWriter(std.fs.File.stderr().deprecatedWriter()), .config = config, }; } diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index 91bf06573a..2fb1f0fe2f 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -591,7 +591,7 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_ var macro_buf = std.ArrayList(u8).init(d.comp.gpa); defer macro_buf.deinit(); - const std_out = std.fs.File.stdout().writer(); + const std_out = std.fs.File.stdout().deprecatedWriter(); if (try parseArgs(d, std_out, macro_buf.writer(), args)) return; const linking = !(d.only_preprocess or d.only_syntax or d.only_compile or d.only_preprocess_and_compile); @@ -689,7 +689,7 @@ fn processSource( std.fs.File.stdout(); defer if (d.output_name != null) file.close(); - var buf_w = std.io.bufferedWriter(file.writer()); + var buf_w = std.io.bufferedWriter(file.deprecatedWriter()); pp.prettyPrintTokens(buf_w.writer(), dump_mode) catch |er| return d.fatal("unable to write result: {s}", .{errorDescription(er)}); @@ -705,7 +705,7 @@ fn processSource( if (d.verbose_ast) { const stdout = std.fs.File.stdout(); - var buf_writer = std.io.bufferedWriter(stdout.writer()); + var buf_writer = std.io.bufferedWriter(stdout.deprecatedWriter()); tree.dump(d.detectConfig(stdout), buf_writer.writer()) catch {}; buf_writer.flush() catch {}; } @@ -735,7 +735,7 @@ fn processSource( if (d.verbose_ir) { const stdout = std.fs.File.stdout(); - var buf_writer = std.io.bufferedWriter(stdout.writer()); + var buf_writer = std.io.bufferedWriter(stdout.deprecatedWriter()); ir.dump(d.comp.gpa, d.detectConfig(stdout), buf_writer.writer()) catch {}; buf_writer.flush() catch {}; } @@ -806,10 +806,10 @@ fn processSource( } fn dumpLinkerArgs(items: []const []const u8) !void { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); for (items, 0..) |item, i| { if (i > 0) try stdout.writeByte(' '); - try stdout.print("\"{}\"", .{std.zig.fmtEscapes(item)}); + try stdout.print("\"{f}\"", .{std.zig.fmtString(item)}); } try stdout.writeByte('\n'); } diff --git a/lib/compiler/aro/aro/Parser.zig b/lib/compiler/aro/aro/Parser.zig index 5ebd89ec3d..ada6298a87 100644 --- a/lib/compiler/aro/aro/Parser.zig +++ b/lib/compiler/aro/aro/Parser.zig @@ -500,8 +500,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_ const w = p.strings.writer(); const msg_str = p.comp.interner.get(@"error".msg.ref()).bytes; - try w.print("call to '{s}' declared with attribute error: {}", .{ - p.tokSlice(@"error".__name_tok), std.zig.fmtEscapes(msg_str), + try w.print("call to '{s}' declared with attribute error: {f}", .{ + p.tokSlice(@"error".__name_tok), std.zig.fmtString(msg_str), }); const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]); try p.errStr(.error_attribute, usage_tok, str); @@ -512,8 +512,8 @@ fn checkDeprecatedUnavailable(p: *Parser, ty: Type, usage_tok: TokenIndex, decl_ const w = p.strings.writer(); const msg_str = p.comp.interner.get(warning.msg.ref()).bytes; - try w.print("call to '{s}' declared with attribute warning: {}", .{ - p.tokSlice(warning.__name_tok), std.zig.fmtEscapes(msg_str), + try w.print("call to '{s}' declared with attribute warning: {f}", .{ + p.tokSlice(warning.__name_tok), std.zig.fmtString(msg_str), }); const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]); try p.errStr(.warning_attribute, usage_tok, str); @@ -542,7 +542,7 @@ fn errDeprecated(p: *Parser, tag: Diagnostics.Tag, tok_i: TokenIndex, msg: ?Valu try w.writeAll(reason); if (msg) |m| { const str = p.comp.interner.get(m.ref()).bytes; - try w.print(": {}", .{std.zig.fmtEscapes(str)}); + try w.print(": {f}", .{std.zig.fmtString(str)}); } const str = try p.comp.diagnostics.arena.allocator().dupe(u8, p.strings.items[strings_top..]); return p.errStr(tag, tok_i, str); diff --git a/lib/compiler/aro/aro/Preprocessor.zig b/lib/compiler/aro/aro/Preprocessor.zig index 220ca4f7dd..d71bf4f857 100644 --- a/lib/compiler/aro/aro/Preprocessor.zig +++ b/lib/compiler/aro/aro/Preprocessor.zig @@ -811,7 +811,7 @@ fn verboseLog(pp: *Preprocessor, raw: RawToken, comptime fmt: []const u8, args: const source = pp.comp.getSource(raw.source); const line_col = source.lineCol(.{ .id = raw.source, .line = raw.line, .byte_offset = raw.start }); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); var buf_writer = std.io.bufferedWriter(stderr); const writer = buf_writer.writer(); defer buf_writer.flush() catch {}; @@ -3262,7 +3262,8 @@ fn printLinemarker( // containing the same bytes as the input regardless of encoding. else => { try w.writeAll("\\x"); - try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, w); + // TODO try w.printIntOptions(byte, 16, .lower, .{ .width = 2, .fill = '0' }); + try w.print("{x:0>2}", .{byte}); }, }; try w.writeByte('"'); diff --git a/lib/compiler/aro/aro/Value.zig b/lib/compiler/aro/aro/Value.zig index 02c9cfc830..f9f9ac590b 100644 --- a/lib/compiler/aro/aro/Value.zig +++ b/lib/compiler/aro/aro/Value.zig @@ -982,7 +982,7 @@ pub fn printString(bytes: []const u8, ty: Type, comp: *const Compilation, w: any const without_null = bytes[0 .. bytes.len - @intFromEnum(size)]; try w.writeByte('"'); switch (size) { - .@"1" => try w.print("{}", .{std.zig.fmtEscapes(without_null)}), + .@"1" => try w.print("{f}", .{std.zig.fmtString(without_null)}), .@"2" => { var items: [2]u16 = undefined; var i: usize = 0; diff --git a/lib/compiler/aro/backend/Object/Elf.zig b/lib/compiler/aro/backend/Object/Elf.zig index 9b4f347de5..ddd66a3c9d 100644 --- a/lib/compiler/aro/backend/Object/Elf.zig +++ b/lib/compiler/aro/backend/Object/Elf.zig @@ -171,7 +171,7 @@ pub fn addRelocation(elf: *Elf, name: []const u8, section_kind: Object.Section, /// strtab /// section headers pub fn finish(elf: *Elf, file: std.fs.File) !void { - var buf_writer = std.io.bufferedWriter(file.writer()); + var buf_writer = std.io.bufferedWriter(file.deprecatedWriter()); const w = buf_writer.writer(); var num_sections: std.elf.Elf64_Half = additional_sections; diff --git a/lib/compiler/aro_translate_c/ast.zig b/lib/compiler/aro_translate_c/ast.zig index 77e7bf1609..132a07c6c8 100644 --- a/lib/compiler/aro_translate_c/ast.zig +++ b/lib/compiler/aro_translate_c/ast.zig @@ -849,7 +849,7 @@ const Context = struct { fn addIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex { if (std.zig.primitives.isPrimitive(bytes)) return c.addTokenFmt(.identifier, "@\"{s}\"", .{bytes}); - return c.addTokenFmt(.identifier, "{p}", .{std.zig.fmtId(bytes)}); + return c.addTokenFmt(.identifier, "{f}", .{std.zig.fmtIdFlags(bytes, .{ .allow_primitive = true })}); } fn listToSpan(c: *Context, list: []const NodeIndex) Allocator.Error!NodeSubRange { @@ -1201,7 +1201,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { const compile_error_tok = try c.addToken(.builtin, "@compileError"); _ = try c.addToken(.l_paren, "("); - const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(payload.mangled)}); + const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{f}\"", .{std.zig.fmtString(payload.mangled)}); const err_msg = try c.addNode(.{ .tag = .string_literal, .main_token = err_msg_tok, @@ -2116,7 +2116,7 @@ fn renderRecord(c: *Context, node: Node) !NodeIndex { defer c.gpa.free(members); for (payload.fields, 0..) |field, i| { - const name_tok = try c.addTokenFmt(.identifier, "{p}", .{std.zig.fmtId(field.name)}); + const name_tok = try c.addTokenFmt(.identifier, "{f}", .{std.zig.fmtIdFlags(field.name, .{ .allow_primitive = true })}); _ = try c.addToken(.colon, ":"); const type_expr = try renderNode(c, field.type); @@ -2205,7 +2205,7 @@ fn renderFieldAccess(c: *Context, lhs: NodeIndex, field_name: []const u8) !NodeI .main_token = try c.addToken(.period, "."), .data = .{ .node_and_token = .{ lhs, - try c.addTokenFmt(.identifier, "{p}", .{std.zig.fmtId(field_name)}), + try c.addTokenFmt(.identifier, "{f}", .{std.zig.fmtIdFlags(field_name, .{ .allow_primitive = true })}), } }, }); } @@ -2681,7 +2681,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex { _ = try c.addToken(.l_paren, "("); const res = try c.addNode(.{ .tag = .string_literal, - .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}), + .main_token = try c.addTokenFmt(.string_literal, "\"{f}\"", .{std.zig.fmtString(some)}), .data = undefined, }); _ = try c.addToken(.r_paren, ")"); @@ -2765,7 +2765,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { _ = try c.addToken(.l_paren, "("); const res = try c.addNode(.{ .tag = .string_literal, - .main_token = try c.addTokenFmt(.string_literal, "\"{}\"", .{std.zig.fmtEscapes(some)}), + .main_token = try c.addTokenFmt(.string_literal, "\"{f}\"", .{std.zig.fmtString(some)}), .data = undefined, }); _ = try c.addToken(.r_paren, ")"); diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index c2ecea1cf4..c3ecfa14b6 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -365,7 +365,7 @@ pub fn main() !void { .data = buffer.items, .flags = .{ .exclusive = true }, }) catch |err| { - fatal("unable to write configuration results to '{}{s}': {s}", .{ + fatal("unable to write configuration results to '{f}{s}': {s}", .{ local_cache_directory, tmp_sub_path, @errorName(err), }); }; @@ -378,7 +378,7 @@ pub fn main() !void { validateSystemLibraryOptions(builder); - const stdout_writer = std.fs.File.stdout().writer(); + const stdout_writer = std.fs.File.stdout().deprecatedWriter(); if (help_menu) return usage(builder, stdout_writer); @@ -704,14 +704,14 @@ fn runStepNames( ttyconf.setColor(stderr, .cyan) catch {}; stderr.writeAll("Build Summary:") catch {}; ttyconf.setColor(stderr, .reset) catch {}; - stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; - if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {}; - if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {}; + stderr.deprecatedWriter().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; + if (skipped_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{skipped_count}) catch {}; + if (failure_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{failure_count}) catch {}; - if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; - if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {}; - if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {}; - if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {}; + if (test_count > 0) stderr.deprecatedWriter().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; + if (test_skip_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{test_skip_count}) catch {}; + if (test_fail_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{test_fail_count}) catch {}; + if (test_leak_count > 0) stderr.deprecatedWriter().print("; {d} leaked", .{test_leak_count}) catch {}; stderr.writeAll("\n") catch {}; @@ -820,10 +820,10 @@ fn printStepStatus( try stderr.writeAll(" cached"); } else if (s.test_results.test_count > 0) { const pass_count = s.test_results.passCount(); - try stderr.writer().print(" {d} passed", .{pass_count}); + try stderr.deprecatedWriter().print(" {d} passed", .{pass_count}); if (s.test_results.skip_count > 0) { try ttyconf.setColor(stderr, .yellow); - try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count}); + try stderr.deprecatedWriter().print(" {d} skipped", .{s.test_results.skip_count}); } } else { try stderr.writeAll(" success"); @@ -832,15 +832,15 @@ fn printStepStatus( if (s.result_duration_ns) |ns| { try ttyconf.setColor(stderr, .dim); if (ns >= std.time.ns_per_min) { - try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min}); + try stderr.deprecatedWriter().print(" {d}m", .{ns / std.time.ns_per_min}); } else if (ns >= std.time.ns_per_s) { - try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s}); + try stderr.deprecatedWriter().print(" {d}s", .{ns / std.time.ns_per_s}); } else if (ns >= std.time.ns_per_ms) { - try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms}); + try stderr.deprecatedWriter().print(" {d}ms", .{ns / std.time.ns_per_ms}); } else if (ns >= std.time.ns_per_us) { - try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us}); + try stderr.deprecatedWriter().print(" {d}us", .{ns / std.time.ns_per_us}); } else { - try stderr.writer().print(" {d}ns", .{ns}); + try stderr.deprecatedWriter().print(" {d}ns", .{ns}); } try ttyconf.setColor(stderr, .reset); } @@ -848,13 +848,13 @@ fn printStepStatus( const rss = s.result_peak_rss; try ttyconf.setColor(stderr, .dim); if (rss >= 1000_000_000) { - try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000}); + try stderr.deprecatedWriter().print(" MaxRSS:{d}G", .{rss / 1000_000_000}); } else if (rss >= 1000_000) { - try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000}); + try stderr.deprecatedWriter().print(" MaxRSS:{d}M", .{rss / 1000_000}); } else if (rss >= 1000) { - try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000}); + try stderr.deprecatedWriter().print(" MaxRSS:{d}K", .{rss / 1000}); } else { - try stderr.writer().print(" MaxRSS:{d}B", .{rss}); + try stderr.deprecatedWriter().print(" MaxRSS:{d}B", .{rss}); } try ttyconf.setColor(stderr, .reset); } @@ -866,7 +866,7 @@ fn printStepStatus( if (skip == .skipped_oom) { try stderr.writeAll(" (not enough memory)"); try ttyconf.setColor(stderr, .dim); - try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); + try stderr.deprecatedWriter().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); try ttyconf.setColor(stderr, .yellow); } try stderr.writeAll("\n"); @@ -883,18 +883,18 @@ fn printStepFailure( ) !void { if (s.result_error_bundle.errorMessageCount() > 0) { try ttyconf.setColor(stderr, .red); - try stderr.writer().print(" {d} errors\n", .{ + try stderr.deprecatedWriter().print(" {d} errors\n", .{ s.result_error_bundle.errorMessageCount(), }); try ttyconf.setColor(stderr, .reset); } else if (!s.test_results.isSuccess()) { - try stderr.writer().print(" {d}/{d} passed", .{ + try stderr.deprecatedWriter().print(" {d}/{d} passed", .{ s.test_results.passCount(), s.test_results.test_count, }); if (s.test_results.fail_count > 0) { try stderr.writeAll(", "); try ttyconf.setColor(stderr, .red); - try stderr.writer().print("{d} failed", .{ + try stderr.deprecatedWriter().print("{d} failed", .{ s.test_results.fail_count, }); try ttyconf.setColor(stderr, .reset); @@ -902,7 +902,7 @@ fn printStepFailure( if (s.test_results.skip_count > 0) { try stderr.writeAll(", "); try ttyconf.setColor(stderr, .yellow); - try stderr.writer().print("{d} skipped", .{ + try stderr.deprecatedWriter().print("{d} skipped", .{ s.test_results.skip_count, }); try ttyconf.setColor(stderr, .reset); @@ -910,7 +910,7 @@ fn printStepFailure( if (s.test_results.leak_count > 0) { try stderr.writeAll(", "); try ttyconf.setColor(stderr, .red); - try stderr.writer().print("{d} leaked", .{ + try stderr.deprecatedWriter().print("{d} leaked", .{ s.test_results.leak_count, }); try ttyconf.setColor(stderr, .reset); @@ -992,7 +992,7 @@ fn printTreeStep( if (s.dependencies.items.len == 0) { try stderr.writeAll(" (reused)\n"); } else { - try stderr.writer().print(" (+{d} more reused dependencies)\n", .{ + try stderr.deprecatedWriter().print(" (+{d} more reused dependencies)\n", .{ s.dependencies.items.len, }); } @@ -1209,7 +1209,7 @@ pub fn printErrorMessages( var indent: usize = 0; while (step_stack.pop()) |s| : (indent += 1) { if (indent > 0) { - try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3); + try stderr.deprecatedWriter().writeByteNTimes(' ', (indent - 1) * 3); try printChildNodePrefix(stderr, ttyconf); } @@ -1231,7 +1231,7 @@ pub fn printErrorMessages( } if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) { - try failing_step.result_error_bundle.renderToWriter(options, stderr.writer()); + try failing_step.result_error_bundle.renderToWriter(options, stderr.deprecatedWriter()); } for (failing_step.result_error_msgs.items) |msg| { diff --git a/lib/compiler/libc.zig b/lib/compiler/libc.zig index 6bd47d15ea..0d26b59d24 100644 --- a/lib/compiler/libc.zig +++ b/lib/compiler/libc.zig @@ -40,7 +40,7 @@ pub fn main() !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.writeAll(usage_libc); return std.process.cleanExit(); } else if (mem.eql(u8, arg, "-target")) { @@ -97,7 +97,7 @@ pub fn main() !void { fatal("no include dirs detected for target {s}", .{zig_target}); } - var bw = std.io.bufferedWriter(std.fs.File.stdout().writer()); + var bw = std.io.bufferedWriter(std.fs.File.stdout().deprecatedWriter()); var writer = bw.writer(); for (libc_dirs.libc_include_dir_list) |include_dir| { try writer.writeAll(include_dir); @@ -125,7 +125,7 @@ pub fn main() !void { }; defer libc.deinit(gpa); - var bw = std.io.bufferedWriter(std.fs.File.stdout().writer()); + var bw = std.io.bufferedWriter(std.fs.File.stdout().deprecatedWriter()); try libc.render(bw.writer()); try bw.flush(); } diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig index 0c256c9796..3e383e6ad4 100644 --- a/lib/compiler/objcopy.zig +++ b/lib/compiler/objcopy.zig @@ -635,11 +635,11 @@ const HexWriter = struct { const payload_bytes = self.getPayloadBytes(); assert(payload_bytes.len <= MAX_PAYLOAD_LEN); - const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3s}{4X:0>2}" ++ linesep, .{ + const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3X}{4X:0>2}" ++ linesep, .{ @as(u8, @intCast(payload_bytes.len)), self.address, @intFromEnum(self.payload), - std.fmt.fmtSliceHexUpper(payload_bytes), + payload_bytes, self.checksum(), }); try file.writeAll(line); @@ -1495,7 +1495,7 @@ const ElfFileHelper = struct { if (size < prefix.len) return null; try in_file.seekTo(offset); - var section_reader = std.io.limitedReader(in_file.reader(), size); + var section_reader = std.io.limitedReader(in_file.deprecatedReader(), size); // allocate as large as decompressed data. if the compression doesn't fit, keep the data uncompressed. const compressed_data = try allocator.alignedAlloc(u8, .@"8", @intCast(size)); diff --git a/lib/compiler/reduce.zig b/lib/compiler/reduce.zig index 746e0d363d..a25ef5304b 100644 --- a/lib/compiler/reduce.zig +++ b/lib/compiler/reduce.zig @@ -68,7 +68,7 @@ pub fn main() !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.writeAll(usage); return std.process.cleanExit(); } else if (mem.eql(u8, arg, "--")) { diff --git a/lib/compiler/resinator/cli.zig b/lib/compiler/resinator/cli.zig index 61c88b2ec0..0f0bbdd281 100644 --- a/lib/compiler/resinator/cli.zig +++ b/lib/compiler/resinator/cli.zig @@ -127,7 +127,7 @@ pub const Diagnostics = struct { pub fn renderToStdErr(self: *Diagnostics, args: []const []const u8, config: std.io.tty.Config) void { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); self.renderToWriter(args, stderr, config) catch return; } diff --git a/lib/compiler/resinator/compile.zig b/lib/compiler/resinator/compile.zig index 4407635bf4..3515421ff0 100644 --- a/lib/compiler/resinator/compile.zig +++ b/lib/compiler/resinator/compile.zig @@ -570,7 +570,7 @@ pub const Compiler = struct { switch (predefined_type) { .GROUP_ICON, .GROUP_CURSOR => { // Check for animated icon first - if (ani.isAnimatedIcon(file.reader())) { + if (ani.isAnimatedIcon(file.deprecatedReader())) { // Animated icons are just put into the resource unmodified, // and the resource type changes to ANIICON/ANICURSOR @@ -586,14 +586,14 @@ pub const Compiler = struct { try header.write(writer, self.errContext(node.id)); try file.seekTo(0); - try writeResourceData(writer, file.reader(), header.data_size); + try writeResourceData(writer, file.deprecatedReader(), header.data_size); return; } // isAnimatedIcon moved the file cursor so reset to the start try file.seekTo(0); - const icon_dir = ico.read(self.allocator, file.reader(), try file.getEndPos()) catch |err| switch (err) { + const icon_dir = ico.read(self.allocator, file.deprecatedReader(), try file.getEndPos()) catch |err| switch (err) { error.OutOfMemory => |e| return e, else => |e| { return self.iconReadError( @@ -672,7 +672,7 @@ pub const Compiler = struct { } try file.seekTo(entry.data_offset_from_start_of_file); - var header_bytes = file.reader().readBytesNoEof(16) catch { + var header_bytes = file.deprecatedReader().readBytesNoEof(16) catch { return self.iconReadError( error.UnexpectedEOF, filename_utf8, @@ -803,7 +803,7 @@ pub const Compiler = struct { } try file.seekTo(entry.data_offset_from_start_of_file); - try writeResourceDataNoPadding(writer, file.reader(), entry.data_size_in_bytes); + try writeResourceDataNoPadding(writer, file.deprecatedReader(), entry.data_size_in_bytes); try writeDataPadding(writer, full_data_size); if (self.state.icon_id == std.math.maxInt(u16)) { @@ -859,7 +859,7 @@ pub const Compiler = struct { header.applyMemoryFlags(node.common_resource_attributes, self.source); const file_size = try file.getEndPos(); - const bitmap_info = bmp.read(file.reader(), file_size) catch |err| { + const bitmap_info = bmp.read(file.deprecatedReader(), file_size) catch |err| { const filename_string_index = try self.diagnostics.putString(filename_utf8); return self.addErrorDetailsAndFail(.{ .err = .bmp_read_error, @@ -922,7 +922,7 @@ pub const Compiler = struct { header.data_size = bmp_bytes_to_write; try header.write(writer, self.errContext(node.id)); try file.seekTo(bmp.file_header_len); - const file_reader = file.reader(); + const file_reader = file.deprecatedReader(); try writeResourceDataNoPadding(writer, file_reader, bitmap_info.dib_header_size); if (bitmap_info.getBitmasksByteLen() > 0) { try writeResourceDataNoPadding(writer, file_reader, bitmap_info.getBitmasksByteLen()); @@ -968,7 +968,7 @@ pub const Compiler = struct { header.data_size = @intCast(file_size); try header.write(writer, self.errContext(node.id)); - var header_slurping_reader = headerSlurpingReader(148, file.reader()); + var header_slurping_reader = headerSlurpingReader(148, file.deprecatedReader()); try writeResourceData(writer, header_slurping_reader.reader(), header.data_size); try self.state.font_dir.add(self.arena, FontDir.Font{ @@ -1002,7 +1002,7 @@ pub const Compiler = struct { // We now know that the data size will fit in a u32 header.data_size = @intCast(data_size); try header.write(writer, self.errContext(node.id)); - try writeResourceData(writer, file.reader(), header.data_size); + try writeResourceData(writer, file.deprecatedReader(), header.data_size); } fn iconReadError( diff --git a/lib/compiler/resinator/errors.zig b/lib/compiler/resinator/errors.zig index 72156beff2..97dfac9d86 100644 --- a/lib/compiler/resinator/errors.zig +++ b/lib/compiler/resinator/errors.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const assert = std.debug.assert; const Token = @import("lex.zig").Token; const SourceMappings = @import("source_mapping.zig").SourceMappings; const utils = @import("utils.zig"); @@ -63,7 +64,7 @@ pub const Diagnostics = struct { pub fn renderToStdErr(self: *Diagnostics, cwd: std.fs.Dir, source: []const u8, tty_config: std.io.tty.Config, source_mappings: ?SourceMappings) void { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); for (self.errors.items) |err_details| { renderErrorMessage(stderr, tty_config, cwd, err_details, source, self.strings.items, source_mappings) catch return; } @@ -409,15 +410,7 @@ pub const ErrorDetails = struct { failed_to_open_cwd, }; - fn formatToken( - ctx: TokenFormatContext, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = fmt; - _ = options; - + fn formatToken(ctx: TokenFormatContext, writer: *std.io.Writer) std.io.Writer.Error!void { switch (ctx.token.id) { .eof => return writer.writeAll(ctx.token.id.nameForErrorDisplay()), else => {}, @@ -441,7 +434,7 @@ pub const ErrorDetails = struct { code_page: SupportedCodePage, }; - fn fmtToken(self: ErrorDetails, source: []const u8) std.fmt.Formatter(formatToken) { + fn fmtToken(self: ErrorDetails, source: []const u8) std.fmt.Formatter(TokenFormatContext, formatToken) { return .{ .data = .{ .token = self.token, .code_page = self.code_page, @@ -466,10 +459,14 @@ pub const ErrorDetails = struct { .hint => return, }, .illegal_byte => { - return writer.print("character '{s}' is not allowed", .{std.fmt.fmtSliceEscapeUpper(self.token.slice(source))}); + return writer.print("character '{f}' is not allowed", .{ + std.ascii.hexEscape(self.token.slice(source), .upper), + }); }, .illegal_byte_outside_string_literals => { - return writer.print("character '{s}' is not allowed outside of string literals", .{std.fmt.fmtSliceEscapeUpper(self.token.slice(source))}); + return writer.print("character '{f}' is not allowed outside of string literals", .{ + std.ascii.hexEscape(self.token.slice(source), .upper), + }); }, .illegal_codepoint_outside_string_literals => { // This is somewhat hacky, but we know that: @@ -1106,7 +1103,7 @@ const CorrespondingLines = struct { .code_page = err_details.code_page, }; corresponding_lines.buffered_reader = BufferedReaderType{ - .unbuffered_reader = corresponding_lines.file.reader(), + .unbuffered_reader = corresponding_lines.file.deprecatedReader(), }; errdefer corresponding_lines.deinit(); diff --git a/lib/compiler/resinator/lex.zig b/lib/compiler/resinator/lex.zig index cfb75e4c5b..0b276b92f5 100644 --- a/lib/compiler/resinator/lex.zig +++ b/lib/compiler/resinator/lex.zig @@ -237,7 +237,9 @@ pub const Lexer = struct { } pub fn dump(self: *Self, token: *const Token) void { - std.debug.print("{s}:{d}: {s}\n", .{ @tagName(token.id), token.line_number, std.fmt.fmtSliceEscapeLower(token.slice(self.buffer)) }); + std.debug.print("{s}:{d}: {f}\n", .{ + @tagName(token.id), token.line_number, std.ascii.hexEscape(token.slice(self.buffer), .lower), + }); } pub const LexMethod = enum { diff --git a/lib/compiler/resinator/main.zig b/lib/compiler/resinator/main.zig index e1f229a88e..75e902982a 100644 --- a/lib/compiler/resinator/main.zig +++ b/lib/compiler/resinator/main.zig @@ -29,7 +29,7 @@ pub fn main() !void { defer std.process.argsFree(allocator, args); if (args.len < 2) { - try renderErrorMessage(stderr.writer(), stderr_config, .err, "expected zig lib dir as first argument", .{}); + try renderErrorMessage(stderr.deprecatedWriter(), stderr_config, .err, "expected zig lib dir as first argument", .{}); std.process.exit(1); } const zig_lib_dir = args[1]; @@ -82,14 +82,14 @@ pub fn main() !void { if (options.print_help_and_exit) { const stdout = std.fs.File.stdout(); - try cli.writeUsage(stdout.writer(), "zig rc"); + try cli.writeUsage(stdout.deprecatedWriter(), "zig rc"); return; } // Don't allow verbose when integrating with Zig via stdout options.verbose = false; - const stdout_writer = std.fs.File.stdout().writer(); + const stdout_writer = std.fs.File.stdout().deprecatedWriter(); if (options.verbose) { try options.dumpVerbose(stdout_writer); try stdout_writer.writeByte('\n'); @@ -290,7 +290,7 @@ pub fn main() !void { }; defer depfile.close(); - const depfile_writer = depfile.writer(); + const depfile_writer = depfile.deprecatedWriter(); var depfile_buffered_writer = std.io.bufferedWriter(depfile_writer); switch (options.depfile_fmt) { .json => { @@ -645,7 +645,7 @@ const ErrorHandler = union(enum) { }, .tty => { // extra newline to separate this line from the aro errors - try renderErrorMessage(std.fs.File.stderr().writer(), self.tty, .err, "{s}\n", .{fail_msg}); + try renderErrorMessage(std.fs.File.stderr().deprecatedWriter(), self.tty, .err, "{s}\n", .{fail_msg}); aro.Diagnostics.render(comp, self.tty); }, } @@ -690,7 +690,7 @@ const ErrorHandler = union(enum) { try server.serveErrorBundle(error_bundle); }, .tty => { - try renderErrorMessage(std.fs.File.stderr().writer(), self.tty, msg_type, format, args); + try renderErrorMessage(std.fs.File.stderr().deprecatedWriter(), self.tty, msg_type, format, args); }, } } diff --git a/lib/compiler/resinator/res.zig b/lib/compiler/resinator/res.zig index b4fcd53f9d..266efbaa69 100644 --- a/lib/compiler/resinator/res.zig +++ b/lib/compiler/resinator/res.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const assert = std.debug.assert; const rc = @import("rc.zig"); const ResourceType = rc.ResourceType; const CommonResourceAttributes = rc.CommonResourceAttributes; @@ -163,14 +164,8 @@ pub const Language = packed struct(u16) { return @bitCast(self); } - pub fn format( - language: Language, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - _ = fmt; - _ = options; + pub fn format(language: Language, w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); const language_id = language.asInt(); const language_name = language_name: { if (std.enums.fromInt(lang.LanguageId, language_id)) |lang_enum_val| { @@ -181,7 +176,7 @@ pub const Language = packed struct(u16) { } break :language_name ""; }; - try out_stream.print("{s} (0x{X})", .{ language_name, language_id }); + try w.print("{s} (0x{X})", .{ language_name, language_id }); } }; @@ -445,47 +440,34 @@ pub const NameOrOrdinal = union(enum) { } } - pub fn format( - self: NameOrOrdinal, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - _ = fmt; - _ = options; + pub fn format(self: NameOrOrdinal, w: *std.io.Writer, comptime fmt: []const u8) !void { + comptime assert(fmt.len == 0); switch (self) { .name => |name| { - try out_stream.print("{s}", .{std.unicode.fmtUtf16Le(name)}); + try w.print("{s}", .{std.unicode.fmtUtf16Le(name)}); }, .ordinal => |ordinal| { - try out_stream.print("{d}", .{ordinal}); + try w.print("{d}", .{ordinal}); }, } } - fn formatResourceType( - self: NameOrOrdinal, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - _ = fmt; - _ = options; + fn formatResourceType(self: NameOrOrdinal, w: *std.io.Writer) std.io.Writer.Error!void { switch (self) { .name => |name| { - try out_stream.print("{s}", .{std.unicode.fmtUtf16Le(name)}); + try w.print("{s}", .{std.unicode.fmtUtf16Le(name)}); }, .ordinal => |ordinal| { if (std.enums.tagName(RT, @enumFromInt(ordinal))) |predefined_type_name| { - try out_stream.print("{s}", .{predefined_type_name}); + try w.print("{s}", .{predefined_type_name}); } else { - try out_stream.print("{d}", .{ordinal}); + try w.print("{d}", .{ordinal}); } }, } } - pub fn fmtResourceType(type_value: NameOrOrdinal) std.fmt.Formatter(formatResourceType) { + pub fn fmtResourceType(type_value: NameOrOrdinal) std.fmt.Formatter(NameOrOrdinal, formatResourceType) { return .{ .data = type_value }; } }; diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index d21d86b40a..929bd1c417 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -328,7 +328,7 @@ pub fn mainSimple() anyerror!void { passed += 1; } if (enable_print and print_summary) { - stderr.writer().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {}; + stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {}; } if (failed != 0) std.process.exit(1); } diff --git a/lib/docs/wasm/markdown.zig b/lib/docs/wasm/markdown.zig index d21dd419e6..7283e29b6a 100644 --- a/lib/docs/wasm/markdown.zig +++ b/lib/docs/wasm/markdown.zig @@ -160,7 +160,7 @@ fn mainImpl() !void { var doc = try parser.endInput(); defer doc.deinit(gpa); - var stdout_buf = std.io.bufferedWriter(std.fs.File.stdout().writer()); + var stdout_buf = std.io.bufferedWriter(std.fs.File.stdout().deprecatedWriter()); try doc.render(stdout_buf.writer()); try stdout_buf.flush(); } diff --git a/lib/docs/wasm/markdown/renderer.zig b/lib/docs/wasm/markdown/renderer.zig index 1e6041399a..b01bab7863 100644 --- a/lib/docs/wasm/markdown/renderer.zig +++ b/lib/docs/wasm/markdown/renderer.zig @@ -1,6 +1,7 @@ const std = @import("std"); const Document = @import("Document.zig"); const Node = Document.Node; +const assert = std.debug.assert; /// A Markdown document renderer. /// @@ -229,18 +230,11 @@ pub fn renderInlineNodeText( } } -pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter(formatHtml) { +pub fn fmtHtml(bytes: []const u8) std.fmt.Formatter([]const u8, formatHtml) { return .{ .data = bytes }; } -fn formatHtml( - bytes: []const u8, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = fmt; - _ = options; +fn formatHtml(bytes: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void { for (bytes) |b| { switch (b) { '<' => try writer.writeAll("<"), diff --git a/lib/init/src/root.zig b/lib/init/src/root.zig index 8cb5867153..9afb8debf2 100644 --- a/lib/init/src/root.zig +++ b/lib/init/src/root.zig @@ -5,7 +5,7 @@ pub fn bufferedPrint() !void { // Stdout is for the actual output of your application, for example if you // are implementing gzip, then only the compressed bytes should be sent to // stdout, not any debugging messages. - const stdout_file = std.fs.File.stdout().writer(); + const stdout_file = std.fs.File.stdout().deprecatedWriter(); // Buffering can improve performance significantly in print-heavy programs. var bw = std.io.bufferedWriter(stdout_file); const stdout = bw.writer(); diff --git a/lib/std/Build.zig b/lib/std/Build.zig index df5a323572..12097bf404 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -1745,7 +1745,7 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8 return true; }, .lazy_path, .lazy_path_list => { - log.warn("the lazy path value type isn't added from the CLI, but somehow '{s}' is a .{}", .{ name, std.zig.fmtId(@tagName(gop.value_ptr.value)) }); + log.warn("the lazy path value type isn't added from the CLI, but somehow '{s}' is a .{f}", .{ name, std.zig.fmtId(@tagName(gop.value_ptr.value)) }); return true; }, } @@ -2059,7 +2059,7 @@ pub fn runAllowFail( try Step.handleVerbose2(b, null, child.env_map, argv); try child.spawn(); - const stdout = child.stdout.?.reader().readAllAlloc(b.allocator, max_output_size) catch { + const stdout = child.stdout.?.deprecatedReader().readAllAlloc(b.allocator, max_output_size) catch { return error.ReadFailure; }; errdefer b.allocator.free(stdout); @@ -2770,7 +2770,7 @@ fn dumpBadDirnameHelp( defer debug.unlockStdErr(); const stderr: fs.File = .stderr(); - const w = stderr.writer(); + const w = stderr.deprecatedWriter(); try w.print(msg, args); const tty_config = std.io.tty.detectConfig(stderr); @@ -2785,7 +2785,7 @@ fn dumpBadDirnameHelp( if (asking_step) |as| { tty_config.setColor(w, .red) catch {}; - try stderr.writer().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); + try stderr.deprecatedWriter().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); tty_config.setColor(w, .reset) catch {}; as.dump(stderr); @@ -2803,7 +2803,7 @@ pub fn dumpBadGetPathHelp( src_builder: *Build, asking_step: ?*Step, ) anyerror!void { - const w = stderr.writer(); + const w = stderr.deprecatedWriter(); try w.print( \\getPath() was called on a GeneratedFile that wasn't built yet. \\ source package path: {s} @@ -2822,7 +2822,7 @@ pub fn dumpBadGetPathHelp( s.dump(stderr); if (asking_step) |as| { tty_config.setColor(w, .red) catch {}; - try stderr.writer().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); + try stderr.deprecatedWriter().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); tty_config.setColor(w, .reset) catch {}; as.dump(stderr); diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index bf63acdead..81a72a11c6 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -68,7 +68,7 @@ const PrefixedPath = struct { fn findPrefix(cache: *const Cache, file_path: []const u8) !PrefixedPath { const gpa = cache.gpa; - const resolved_path = try fs.path.resolve(gpa, &[_][]const u8{file_path}); + const resolved_path = try fs.path.resolve(gpa, &.{file_path}); errdefer gpa.free(resolved_path); return findPrefixResolved(cache, resolved_path); } @@ -132,7 +132,7 @@ pub const Hasher = crypto.auth.siphash.SipHash128(1, 3); /// Initial state with random bytes, that can be copied. /// Refresh this with new random bytes when the manifest /// format is modified in a non-backwards-compatible way. -pub const hasher_init: Hasher = Hasher.init(&[_]u8{ +pub const hasher_init: Hasher = Hasher.init(&.{ 0x33, 0x52, 0xa2, 0x84, 0xcf, 0x17, 0x56, 0x57, 0x01, 0xbb, 0xcd, 0xe4, @@ -286,11 +286,8 @@ pub const HashHelper = struct { pub fn binToHex(bin_digest: BinDigest) HexDigest { var out_digest: HexDigest = undefined; - _ = fmt.bufPrint( - &out_digest, - "{s}", - .{fmt.fmtSliceHexLower(&bin_digest)}, - ) catch unreachable; + var w: std.io.Writer = .fixed(&out_digest); + w.printHex(&bin_digest, .lower) catch unreachable; return out_digest; } @@ -337,7 +334,6 @@ pub const Manifest = struct { manifest_create: fs.File.OpenError, manifest_read: fs.File.ReadError, manifest_lock: fs.File.LockError, - manifest_seek: fs.File.SeekError, file_open: FileOp, file_stat: FileOp, file_read: FileOp, @@ -611,12 +607,6 @@ pub const Manifest = struct { var file = self.files.pop().?; file.key.deinit(self.cache.gpa); } - // Also, seek the file back to the start. - self.manifest_file.?.seekTo(0) catch |err| { - self.diagnostic = .{ .manifest_seek = err }; - return error.CacheCheckFailed; - }; - switch (try self.hitWithCurrentLock()) { .hit => break :hit, .miss => |m| break :digests m.file_digests_populated, @@ -661,9 +651,8 @@ pub const Manifest = struct { return true; } - /// Assumes that `self.hash.hasher` has been updated only with the original digest, that - /// `self.files` contains only the original input files, and that `self.manifest_file.?` is - /// seeked to the start of the file. + /// Assumes that `self.hash.hasher` has been updated only with the original digest and that + /// `self.files` contains only the original input files. fn hitWithCurrentLock(self: *Manifest) HitError!union(enum) { hit, miss: struct { @@ -672,12 +661,13 @@ pub const Manifest = struct { } { const gpa = self.cache.gpa; const input_file_count = self.files.entries.len; - - const file_contents = self.manifest_file.?.reader().readAllAlloc(gpa, manifest_file_size_max) catch |err| switch (err) { + var manifest_reader = self.manifest_file.?.reader(&.{}); // Reads positionally from zero. + const limit: std.io.Limit = .limited(manifest_file_size_max); + const file_contents = manifest_reader.interface.allocRemaining(gpa, limit) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.StreamTooLong => return error.OutOfMemory, - else => |e| { - self.diagnostic = .{ .manifest_read = e }; + error.ReadFailed => { + self.diagnostic = .{ .manifest_read = manifest_reader.err.? }; return error.CacheCheckFailed; }, }; @@ -1063,14 +1053,17 @@ pub const Manifest = struct { } fn addDepFileMaybePost(self: *Manifest, dir: fs.Dir, dep_file_basename: []const u8) !void { - const dep_file_contents = try dir.readFileAlloc(self.cache.gpa, dep_file_basename, manifest_file_size_max); - defer self.cache.gpa.free(dep_file_contents); + const gpa = self.cache.gpa; + const dep_file_contents = try dir.readFileAlloc(gpa, dep_file_basename, manifest_file_size_max); + defer gpa.free(dep_file_contents); - var error_buf = std.ArrayList(u8).init(self.cache.gpa); - defer error_buf.deinit(); + var error_buf: std.ArrayListUnmanaged(u8) = .empty; + defer error_buf.deinit(gpa); + + var resolve_buf: std.ArrayListUnmanaged(u8) = .empty; + defer resolve_buf.deinit(gpa); var it: DepTokenizer = .{ .bytes = dep_file_contents }; - while (it.next()) |token| { switch (token) { // We don't care about targets, we only want the prereqs @@ -1080,16 +1073,14 @@ pub const Manifest = struct { _ = try self.addFile(file_path, null); } else try self.addFilePost(file_path), .prereq_must_resolve => { - var resolve_buf = std.ArrayList(u8).init(self.cache.gpa); - defer resolve_buf.deinit(); - - try token.resolve(resolve_buf.writer()); + resolve_buf.clearRetainingCapacity(); + try token.resolve(gpa, &resolve_buf); if (self.manifest_file == null) { _ = try self.addFile(resolve_buf.items, null); } else try self.addFilePost(resolve_buf.items); }, else => |err| { - try err.printError(error_buf.writer()); + try err.printError(gpa, &error_buf); log.err("failed parsing {s}: {s}", .{ dep_file_basename, error_buf.items }); return error.InvalidDepFile; }, @@ -1127,24 +1118,25 @@ pub const Manifest = struct { if (self.manifest_dirty) { self.manifest_dirty = false; - var contents = std.ArrayList(u8).init(self.cache.gpa); - defer contents.deinit(); + const gpa = self.cache.gpa; + var contents: std.ArrayListUnmanaged(u8) = .empty; + defer contents.deinit(gpa); - const writer = contents.writer(); - try writer.writeAll(manifest_header ++ "\n"); + try contents.appendSlice(gpa, manifest_header ++ "\n"); for (self.files.keys()) |file| { - try writer.print("{d} {d} {d} {} {d} {s}\n", .{ + try contents.print(gpa, "{d} {d} {d} {x} {d} {s}\n", .{ file.stat.size, file.stat.inode, file.stat.mtime, - fmt.fmtSliceHexLower(&file.bin_digest), + &file.bin_digest, file.prefixed_path.prefix, file.prefixed_path.sub_path, }); } try manifest_file.setEndPos(contents.items.len); - try manifest_file.pwriteAll(contents.items, 0); + var pos: usize = 0; + while (pos < contents.items.len) pos += try manifest_file.pwrite(contents.items[pos..], pos); } if (self.want_shared_lock) { diff --git a/lib/std/Build/Cache/DepTokenizer.zig b/lib/std/Build/Cache/DepTokenizer.zig index a515d8a1f7..8221f92dba 100644 --- a/lib/std/Build/Cache/DepTokenizer.zig +++ b/lib/std/Build/Cache/DepTokenizer.zig @@ -7,6 +7,7 @@ state: State = .lhs, const std = @import("std"); const testing = std.testing; const assert = std.debug.assert; +const Allocator = std.mem.Allocator; pub fn next(self: *Tokenizer) ?Token { var start = self.index; @@ -362,7 +363,7 @@ pub const Token = union(enum) { }; /// Resolve escapes in target or prereq. Only valid with .target_must_resolve or .prereq_must_resolve. - pub fn resolve(self: Token, writer: anytype) @TypeOf(writer).Error!void { + pub fn resolve(self: Token, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!void { switch (self) { .target_must_resolve => |bytes| { var state: enum { start, escape, dollar } = .start; @@ -372,27 +373,27 @@ pub const Token = union(enum) { switch (c) { '\\' => state = .escape, '$' => state = .dollar, - else => try writer.writeByte(c), + else => try list.append(gpa, c), } }, .escape => { switch (c) { ' ', '#', '\\' => {}, '$' => { - try writer.writeByte('\\'); + try list.append(gpa, '\\'); state = .dollar; continue; }, - else => try writer.writeByte('\\'), + else => try list.append(gpa, '\\'), } - try writer.writeByte(c); + try list.append(gpa, c); state = .start; }, .dollar => { - try writer.writeByte('$'); + try list.append(gpa, '$'); switch (c) { '$' => {}, - else => try writer.writeByte(c), + else => try list.append(gpa, c), } state = .start; }, @@ -406,19 +407,19 @@ pub const Token = union(enum) { .start => { switch (c) { '\\' => state = .escape, - else => try writer.writeByte(c), + else => try list.append(gpa, c), } }, .escape => { switch (c) { ' ' => {}, '\\' => { - try writer.writeByte(c); + try list.append(gpa, c); continue; }, - else => try writer.writeByte('\\'), + else => try list.append(gpa, '\\'), } - try writer.writeByte(c); + try list.append(gpa, c); state = .start; }, } @@ -428,20 +429,20 @@ pub const Token = union(enum) { } } - pub fn printError(self: Token, writer: anytype) @TypeOf(writer).Error!void { + pub fn printError(self: Token, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) error{OutOfMemory}!void { switch (self) { .target, .target_must_resolve, .prereq, .prereq_must_resolve => unreachable, // not an error .incomplete_quoted_prerequisite, .incomplete_target, => |index_and_bytes| { - try writer.print("{s} '", .{self.errStr()}); + try list.print(gpa, "{s} '", .{self.errStr()}); if (self == .incomplete_target) { const tmp = Token{ .target_must_resolve = index_and_bytes.bytes }; - try tmp.resolve(writer); + try tmp.resolve(gpa, list); } else { - try printCharValues(writer, index_and_bytes.bytes); + try printCharValues(gpa, list, index_and_bytes.bytes); } - try writer.print("' at position {d}", .{index_and_bytes.index}); + try list.print(gpa, "' at position {d}", .{index_and_bytes.index}); }, .invalid_target, .bad_target_escape, @@ -450,9 +451,9 @@ pub const Token = union(enum) { .incomplete_escape, .expected_colon, => |index_and_char| { - try writer.writeAll("illegal char "); - try printUnderstandableChar(writer, index_and_char.char); - try writer.print(" at position {d}: {s}", .{ index_and_char.index, self.errStr() }); + try list.appendSlice(gpa, "illegal char "); + try printUnderstandableChar(gpa, list, index_and_char.char); + try list.print(gpa, " at position {d}: {s}", .{ index_and_char.index, self.errStr() }); }, } } @@ -1026,41 +1027,41 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void { defer arena_allocator.deinit(); var it: Tokenizer = .{ .bytes = input }; - var buffer = std.ArrayList(u8).init(arena); - var resolve_buf = std.ArrayList(u8).init(arena); + var buffer: std.ArrayListUnmanaged(u8) = .empty; + var resolve_buf: std.ArrayListUnmanaged(u8) = .empty; var i: usize = 0; while (it.next()) |token| { - if (i != 0) try buffer.appendSlice("\n"); + if (i != 0) try buffer.appendSlice(arena, "\n"); switch (token) { .target, .prereq => |bytes| { - try buffer.appendSlice(@tagName(token)); - try buffer.appendSlice(" = {"); + try buffer.appendSlice(arena, @tagName(token)); + try buffer.appendSlice(arena, " = {"); for (bytes) |b| { - try buffer.append(printable_char_tab[b]); + try buffer.append(arena, printable_char_tab[b]); } - try buffer.appendSlice("}"); + try buffer.appendSlice(arena, "}"); }, .target_must_resolve => { - try buffer.appendSlice("target = {"); - try token.resolve(resolve_buf.writer()); + try buffer.appendSlice(arena, "target = {"); + try token.resolve(arena, &resolve_buf); for (resolve_buf.items) |b| { - try buffer.append(printable_char_tab[b]); + try buffer.append(arena, printable_char_tab[b]); } resolve_buf.items.len = 0; - try buffer.appendSlice("}"); + try buffer.appendSlice(arena, "}"); }, .prereq_must_resolve => { - try buffer.appendSlice("prereq = {"); - try token.resolve(resolve_buf.writer()); + try buffer.appendSlice(arena, "prereq = {"); + try token.resolve(arena, &resolve_buf); for (resolve_buf.items) |b| { - try buffer.append(printable_char_tab[b]); + try buffer.append(arena, printable_char_tab[b]); } resolve_buf.items.len = 0; - try buffer.appendSlice("}"); + try buffer.appendSlice(arena, "}"); }, else => { - try buffer.appendSlice("ERROR: "); - try token.printError(buffer.writer()); + try buffer.appendSlice(arena, "ERROR: "); + try token.printError(arena, &buffer); break; }, } @@ -1072,134 +1073,18 @@ fn depTokenizer(input: []const u8, expect: []const u8) !void { return; } - const out = std.fs.File.stderr().writer(); - - try out.writeAll("\n"); - try printSection(out, "<<<< input", input); - try printSection(out, "==== expect", expect); - try printSection(out, ">>>> got", buffer.items); - try printRuler(out); - - try testing.expect(false); + try testing.expectEqualStrings(expect, buffer.items); } -fn printSection(out: anytype, label: []const u8, bytes: []const u8) !void { - try printLabel(out, label, bytes); - try hexDump(out, bytes); - try printRuler(out); - try out.writeAll(bytes); - try out.writeAll("\n"); +fn printCharValues(gpa: Allocator, list: *std.ArrayListUnmanaged(u8), bytes: []const u8) !void { + for (bytes) |b| try list.append(gpa, printable_char_tab[b]); } -fn printLabel(out: anytype, label: []const u8, bytes: []const u8) !void { - var buf: [80]u8 = undefined; - const text = try std.fmt.bufPrint(buf[0..], "{s} {d} bytes ", .{ label, bytes.len }); - try out.writeAll(text); - var i: usize = text.len; - const end = 79; - while (i < end) : (i += 1) { - try out.writeAll(&[_]u8{label[0]}); - } - try out.writeAll("\n"); -} - -fn printRuler(out: anytype) !void { - var i: usize = 0; - const end = 79; - while (i < end) : (i += 1) { - try out.writeAll("-"); - } - try out.writeAll("\n"); -} - -fn hexDump(out: anytype, bytes: []const u8) !void { - const n16 = bytes.len >> 4; - var line: usize = 0; - var offset: usize = 0; - while (line < n16) : (line += 1) { - try hexDump16(out, offset, bytes[offset..][0..16]); - offset += 16; - } - - const n = bytes.len & 0x0f; - if (n > 0) { - try printDecValue(out, offset, 8); - try out.writeAll(":"); - try out.writeAll(" "); - const end1 = @min(offset + n, offset + 8); - for (bytes[offset..end1]) |b| { - try out.writeAll(" "); - try printHexValue(out, b, 2); - } - const end2 = offset + n; - if (end2 > end1) { - try out.writeAll(" "); - for (bytes[end1..end2]) |b| { - try out.writeAll(" "); - try printHexValue(out, b, 2); - } - } - const short = 16 - n; - var i: usize = 0; - while (i < short) : (i += 1) { - try out.writeAll(" "); - } - if (end2 > end1) { - try out.writeAll(" |"); - } else { - try out.writeAll(" |"); - } - try printCharValues(out, bytes[offset..end2]); - try out.writeAll("|\n"); - offset += n; - } - - try printDecValue(out, offset, 8); - try out.writeAll(":"); - try out.writeAll("\n"); -} - -fn hexDump16(out: anytype, offset: usize, bytes: []const u8) !void { - try printDecValue(out, offset, 8); - try out.writeAll(":"); - try out.writeAll(" "); - for (bytes[0..8]) |b| { - try out.writeAll(" "); - try printHexValue(out, b, 2); - } - try out.writeAll(" "); - for (bytes[8..16]) |b| { - try out.writeAll(" "); - try printHexValue(out, b, 2); - } - try out.writeAll(" |"); - try printCharValues(out, bytes); - try out.writeAll("|\n"); -} - -fn printDecValue(out: anytype, value: u64, width: u8) !void { - var buffer: [20]u8 = undefined; - const len = std.fmt.formatIntBuf(buffer[0..], value, 10, .lower, .{ .width = width, .fill = '0' }); - try out.writeAll(buffer[0..len]); -} - -fn printHexValue(out: anytype, value: u64, width: u8) !void { - var buffer: [16]u8 = undefined; - const len = std.fmt.formatIntBuf(buffer[0..], value, 16, .lower, .{ .width = width, .fill = '0' }); - try out.writeAll(buffer[0..len]); -} - -fn printCharValues(out: anytype, bytes: []const u8) !void { - for (bytes) |b| { - try out.writeAll(&[_]u8{printable_char_tab[b]}); - } -} - -fn printUnderstandableChar(out: anytype, char: u8) !void { +fn printUnderstandableChar(gpa: Allocator, list: *std.ArrayListUnmanaged(u8), char: u8) !void { if (std.ascii.isPrint(char)) { - try out.print("'{c}'", .{char}); + try list.print(gpa, "'{c}'", .{char}); } else { - try out.print("\\x{X:0>2}", .{char}); + try list.print(gpa, "\\x{X:0>2}", .{char}); } } diff --git a/lib/std/Build/Cache/Directory.zig b/lib/std/Build/Cache/Directory.zig index 4de1cc18f1..cc6b930c23 100644 --- a/lib/std/Build/Cache/Directory.zig +++ b/lib/std/Build/Cache/Directory.zig @@ -1,5 +1,6 @@ const Directory = @This(); const std = @import("../../std.zig"); +const assert = std.debug.assert; const fs = std.fs; const fmt = std.fmt; const Allocator = std.mem.Allocator; @@ -55,14 +56,8 @@ pub fn closeAndFree(self: *Directory, gpa: Allocator) void { self.* = undefined; } -pub fn format( - self: Directory, - comptime fmt_string: []const u8, - options: fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; - if (fmt_string.len != 0) fmt.invalidFmtError(fmt_string, self); +pub fn format(self: Directory, writer: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { + comptime assert(f.len == 0); if (self.path) |p| { try writer.writeAll(p); try writer.writeAll(fs.path.sep_str); diff --git a/lib/std/Build/Cache/Path.zig b/lib/std/Build/Cache/Path.zig index 8822fb64be..55af4fdbfa 100644 --- a/lib/std/Build/Cache/Path.zig +++ b/lib/std/Build/Cache/Path.zig @@ -1,3 +1,10 @@ +const Path = @This(); +const std = @import("../../std.zig"); +const assert = std.debug.assert; +const fs = std.fs; +const Allocator = std.mem.Allocator; +const Cache = std.Build.Cache; + root_dir: Cache.Directory, /// The path, relative to the root dir, that this `Path` represents. /// Empty string means the root_dir is the path. @@ -133,38 +140,32 @@ pub fn makePath(p: Path, sub_path: []const u8) !void { } pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 { - return std.fmt.allocPrint(allocator, "{}", .{p}); + return std.fmt.allocPrint(allocator, "{f}", .{p}); } pub fn toStringZ(p: Path, allocator: Allocator) Allocator.Error![:0]u8 { - return std.fmt.allocPrintZ(allocator, "{}", .{p}); + return std.fmt.allocPrintSentinel(allocator, "{f}", .{p}, 0); } -pub fn format( - self: Path, - comptime fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - if (fmt_string.len == 1) { +pub fn format(self: Path, writer: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { + if (f.len == 1) { // Quote-escape the string. - const stringEscape = std.zig.stringEscape; - const f = switch (fmt_string[0]) { - 'q' => "", - '\'' => "\'", - else => @compileError("unsupported format string: " ++ fmt_string), + const zigEscape = switch (f[0]) { + 'q' => std.zig.stringEscape, + '\'' => std.zig.charEscape, + else => @compileError("unsupported format string: " ++ f), }; if (self.root_dir.path) |p| { - try stringEscape(p, f, options, writer); - if (self.sub_path.len > 0) try stringEscape(fs.path.sep_str, f, options, writer); + try zigEscape(p, writer); + if (self.sub_path.len > 0) try zigEscape(fs.path.sep_str, writer); } if (self.sub_path.len > 0) { - try stringEscape(self.sub_path, f, options, writer); + try zigEscape(self.sub_path, writer); } return; } - if (fmt_string.len > 0) - std.fmt.invalidFmtError(fmt_string, self); + if (f.len > 0) + std.fmt.invalidFmtError(f, self); if (std.fs.path.isAbsolute(self.sub_path)) { try writer.writeAll(self.sub_path); return; @@ -223,9 +224,3 @@ pub const TableAdapter = struct { return a.eql(b); } }; - -const Path = @This(); -const std = @import("../../std.zig"); -const fs = std.fs; -const Allocator = std.mem.Allocator; -const Cache = std.Build.Cache; diff --git a/lib/std/Build/Fuzz/WebServer.zig b/lib/std/Build/Fuzz/WebServer.zig index ab44d4e7af..b28a6e185c 100644 --- a/lib/std/Build/Fuzz/WebServer.zig +++ b/lib/std/Build/Fuzz/WebServer.zig @@ -170,7 +170,7 @@ fn serveFile( // We load the file with every request so that the user can make changes to the file // and refresh the HTML page without restarting this server. const file_contents = ws.zig_lib_directory.handle.readFileAlloc(gpa, name, 10 * 1024 * 1024) catch |err| { - log.err("failed to read '{}{s}': {s}", .{ ws.zig_lib_directory, name, @errorName(err) }); + log.err("failed to read '{f}{s}': {s}", .{ ws.zig_lib_directory, name, @errorName(err) }); return error.AlreadyReported; }; defer gpa.free(file_contents); @@ -251,10 +251,10 @@ fn buildWasmBinary( "-fsingle-threaded", // "--dep", "Walk", // "--dep", "html_render", // - try std.fmt.allocPrint(arena, "-Mroot={}", .{main_src_path}), // - try std.fmt.allocPrint(arena, "-MWalk={}", .{walk_src_path}), // + try std.fmt.allocPrint(arena, "-Mroot={f}", .{main_src_path}), // + try std.fmt.allocPrint(arena, "-MWalk={f}", .{walk_src_path}), // "--dep", "Walk", // - try std.fmt.allocPrint(arena, "-Mhtml_render={}", .{html_render_src_path}), // + try std.fmt.allocPrint(arena, "-Mhtml_render={f}", .{html_render_src_path}), // "--listen=-", }); @@ -526,7 +526,7 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { for (deduped_paths) |joined_path| { var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| { - log.err("failed to open {}: {s}", .{ joined_path, @errorName(err) }); + log.err("failed to open {f}: {s}", .{ joined_path, @errorName(err) }); continue; }; defer file.close(); @@ -604,7 +604,7 @@ fn prepareTables( const rebuilt_exe_path = run_step.rebuilt_executable.?; var debug_info = std.debug.Info.load(gpa, rebuilt_exe_path, &gop.value_ptr.coverage) catch |err| { - log.err("step '{s}': failed to load debug information for '{}': {s}", .{ + log.err("step '{s}': failed to load debug information for '{f}': {s}", .{ run_step.step.name, rebuilt_exe_path, @errorName(err), }); return error.AlreadyReported; @@ -616,7 +616,7 @@ fn prepareTables( .sub_path = "v/" ++ std.fmt.hex(coverage_id), }; var coverage_file = coverage_file_path.root_dir.handle.openFile(coverage_file_path.sub_path, .{}) catch |err| { - log.err("step '{s}': failed to load coverage file '{}': {s}", .{ + log.err("step '{s}': failed to load coverage file '{f}': {s}", .{ run_step.step.name, coverage_file_path, @errorName(err), }); return error.AlreadyReported; @@ -624,7 +624,7 @@ fn prepareTables( defer coverage_file.close(); const file_size = coverage_file.getEndPos() catch |err| { - log.err("unable to check len of coverage file '{}': {s}", .{ coverage_file_path, @errorName(err) }); + log.err("unable to check len of coverage file '{f}': {s}", .{ coverage_file_path, @errorName(err) }); return error.AlreadyReported; }; @@ -636,7 +636,7 @@ fn prepareTables( coverage_file.handle, 0, ) catch |err| { - log.err("failed to map coverage file '{}': {s}", .{ coverage_file_path, @errorName(err) }); + log.err("failed to map coverage file '{f}': {s}", .{ coverage_file_path, @errorName(err) }); return error.AlreadyReported; }; gop.value_ptr.mapped_memory = mapped_memory; diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index cc57aeb521..0fa8a9a623 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -186,7 +186,7 @@ pub const IncludeDir = union(enum) { .embed_path => |lazy_path| { // Special case: this is a single arg. const resolved = lazy_path.getPath3(b, asking_step); - const arg = b.fmt("--embed-dir={}", .{resolved}); + const arg = b.fmt("--embed-dir={f}", .{resolved}); return zig_args.append(arg); }, }; diff --git a/lib/std/Build/Step.zig b/lib/std/Build/Step.zig index 9d4802fbbc..77e259795b 100644 --- a/lib/std/Build/Step.zig +++ b/lib/std/Build/Step.zig @@ -287,7 +287,8 @@ pub fn cast(step: *Step, comptime T: type) ?*T { /// For debugging purposes, prints identifying information about this Step. pub fn dump(step: *Step, file: std.fs.File) void { - const w = file.writer(); + var fw = file.writer(&.{}); + const w = &fw.interface; const tty_config = std.io.tty.detectConfig(file); const debug_info = std.debug.getSelfDebugInfo() catch |err| { w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{ @@ -482,9 +483,9 @@ pub fn evalZigProcess( pub fn installFile(s: *Step, src_lazy_path: Build.LazyPath, dest_path: []const u8) !std.fs.Dir.PrevStatus { const b = s.owner; const src_path = src_lazy_path.getPath3(b, s); - try handleVerbose(b, null, &.{ "install", "-C", b.fmt("{}", .{src_path}), dest_path }); + try handleVerbose(b, null, &.{ "install", "-C", b.fmt("{f}", .{src_path}), dest_path }); return src_path.root_dir.handle.updateFile(src_path.sub_path, std.fs.cwd(), dest_path, .{}) catch |err| { - return s.fail("unable to update file from '{}' to '{s}': {s}", .{ + return s.fail("unable to update file from '{f}' to '{s}': {s}", .{ src_path, dest_path, @errorName(err), }); }; @@ -821,7 +822,7 @@ fn failWithCacheError(s: *Step, man: *const Build.Cache.Manifest, err: Build.Cac switch (err) { error.CacheCheckFailed => switch (man.diagnostic) { .none => unreachable, - .manifest_create, .manifest_read, .manifest_lock, .manifest_seek => |e| return s.fail("failed to check cache: {s} {s}", .{ + .manifest_create, .manifest_read, .manifest_lock => |e| return s.fail("failed to check cache: {s} {s}", .{ @tagName(man.diagnostic), @errorName(e), }), .file_open, .file_stat, .file_read, .file_hash => |op| { diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index 3b78258d1c..96fa443b1e 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -6,6 +6,7 @@ const macho = std.macho; const math = std.math; const mem = std.mem; const testing = std.testing; +const Writer = std.io.Writer; const CheckObject = @This(); @@ -28,14 +29,14 @@ pub fn create( const gpa = owner.allocator; const check_object = gpa.create(CheckObject) catch @panic("OOM"); check_object.* = .{ - .step = Step.init(.{ + .step = .init(.{ .id = base_id, .name = "CheckObject", .owner = owner, .makeFn = make, }), .source = source.dupe(owner), - .checks = std.ArrayList(Check).init(gpa), + .checks = .init(gpa), .obj_format = obj_format, }; check_object.source.addStepDependencies(&check_object.step); @@ -74,13 +75,13 @@ const Action = struct { b: *std.Build, step: *Step, haystack: []const u8, - global_vars: anytype, + global_vars: *std.StringHashMap(u64), ) !bool { assert(act.tag == .extract); const hay = mem.trim(u8, haystack, " "); const phrase = mem.trim(u8, act.phrase.resolve(b, step), " "); - var candidate_vars = std.ArrayList(struct { name: []const u8, value: u64 }).init(b.allocator); + var candidate_vars: std.ArrayList(struct { name: []const u8, value: u64 }) = .init(b.allocator); var hay_it = mem.tokenizeScalar(u8, hay, ' '); var needle_it = mem.tokenizeScalar(u8, phrase, ' '); @@ -153,11 +154,11 @@ const Action = struct { /// Will return true if the `phrase` is correctly parsed into an RPN program and /// its reduced, computed value compares using `op` with the expected value, either /// a literal or another extracted variable. - fn computeCmp(act: Action, b: *std.Build, step: *Step, global_vars: anytype) !bool { + fn computeCmp(act: Action, b: *std.Build, step: *Step, global_vars: std.StringHashMap(u64)) !bool { const gpa = step.owner.allocator; const phrase = act.phrase.resolve(b, step); - var op_stack = std.ArrayList(enum { add, sub, mod, mul }).init(gpa); - var values = std.ArrayList(u64).init(gpa); + var op_stack: std.ArrayList(enum { add, sub, mod, mul }) = .init(gpa); + var values: std.ArrayList(u64) = .init(gpa); var it = mem.tokenizeScalar(u8, phrase, ' '); while (it.next()) |next| { @@ -230,17 +231,15 @@ const ComputeCompareExpected = struct { }, pub fn format( - value: @This(), + value: ComputeCompareExpected, + bw: *Writer, comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, ) !void { if (fmt.len != 0) std.fmt.invalidFmtError(fmt, value); - _ = options; - try writer.print("{s} ", .{@tagName(value.op)}); + try bw.print("{s} ", .{@tagName(value.op)}); switch (value.value) { - .variable => |name| try writer.writeAll(name), - .literal => |x| try writer.print("{x}", .{x}), + .variable => |name| try bw.writeAll(name), + .literal => |x| try bw.print("{x}", .{x}), } } }; @@ -248,56 +247,63 @@ const ComputeCompareExpected = struct { const Check = struct { kind: Kind, payload: Payload, - data: std.ArrayList(u8), - actions: std.ArrayList(Action), + allocator: Allocator, + data: std.ArrayListUnmanaged(u8), + actions: std.ArrayListUnmanaged(Action), fn create(allocator: Allocator, kind: Kind) Check { return .{ .kind = kind, .payload = .{ .none = {} }, - .data = std.ArrayList(u8).init(allocator), - .actions = std.ArrayList(Action).init(allocator), + .allocator = allocator, + .data = .empty, + .actions = .empty, }; } - fn dumpSection(allocator: Allocator, name: [:0]const u8) Check { - var check = Check.create(allocator, .dump_section); + fn dumpSection(gpa: Allocator, name: [:0]const u8) Check { + var check = Check.create(gpa, .dump_section); const off: u32 = @intCast(check.data.items.len); - check.data.writer().print("{s}\x00", .{name}) catch @panic("OOM"); + check.data.print(gpa, "{s}\x00", .{name}) catch @panic("OOM"); check.payload = .{ .dump_section = off }; return check; } fn extract(check: *Check, phrase: SearchPhrase) void { - check.actions.append(.{ + const gpa = check.allocator; + check.actions.append(gpa, .{ .tag = .extract, .phrase = phrase, }) catch @panic("OOM"); } fn exact(check: *Check, phrase: SearchPhrase) void { - check.actions.append(.{ + const gpa = check.allocator; + check.actions.append(gpa, .{ .tag = .exact, .phrase = phrase, }) catch @panic("OOM"); } fn contains(check: *Check, phrase: SearchPhrase) void { - check.actions.append(.{ + const gpa = check.allocator; + check.actions.append(gpa, .{ .tag = .contains, .phrase = phrase, }) catch @panic("OOM"); } fn notPresent(check: *Check, phrase: SearchPhrase) void { - check.actions.append(.{ + const gpa = check.allocator; + check.actions.append(gpa, .{ .tag = .not_present, .phrase = phrase, }) catch @panic("OOM"); } fn computeCmp(check: *Check, phrase: SearchPhrase, expected: ComputeCompareExpected) void { - check.actions.append(.{ + const gpa = check.allocator; + check.actions.append(gpa, .{ .tag = .compute_cmp, .phrase = phrase, .expected = expected, @@ -565,9 +571,9 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { null, .of(u64), null, - ) catch |err| return step.fail("unable to read '{'}': {s}", .{ src_path, @errorName(err) }); + ) catch |err| return step.fail("unable to read '{f'}': {s}", .{ src_path, @errorName(err) }); - var vars = std.StringHashMap(u64).init(gpa); + var vars: std.StringHashMap(u64) = .init(gpa); for (check_object.checks.items) |chk| { if (chk.kind == .compute_compare) { assert(chk.actions.items.len == 1); @@ -581,7 +587,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { return step.fail( \\ \\========= comparison failed for action: =========== - \\{s} {} + \\{s} {f} \\=================================================== , .{ act.phrase.resolve(b, step), act.expected.? }); } @@ -600,7 +606,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { // we either format message string with escaped codes, or not to aid debugging // the failed test. const fmtMessageString = struct { - fn fmtMessageString(kind: Check.Kind, msg: []const u8) std.fmt.Formatter(formatMessageString) { + fn fmtMessageString(kind: Check.Kind, msg: []const u8) std.fmt.Formatter(Ctx, formatMessageString) { return .{ .data = .{ .kind = kind, .msg = msg, @@ -612,17 +618,10 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { msg: []const u8, }; - fn formatMessageString( - ctx: Ctx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = unused_fmt_string; - _ = options; + fn formatMessageString(ctx: Ctx, w: *Writer) !void { switch (ctx.kind) { - .dump_section => try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ctx.msg)}), - else => try writer.writeAll(ctx.msg), + .dump_section => try w.print("{f}", .{std.ascii.hexEscape(ctx.msg, .lower)}), + else => try w.writeAll(ctx.msg), } } }.fmtMessageString; @@ -637,11 +636,11 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { return step.fail( \\ \\========= expected to find: ========================== - \\{s} + \\{f} \\========= but parsed file does not contain it: ======= - \\{s} + \\{f} \\========= file path: ================================= - \\{} + \\{f} , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output), @@ -657,11 +656,11 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { return step.fail( \\ \\========= expected to find: ========================== - \\*{s}* + \\*{f}* \\========= but parsed file does not contain it: ======= - \\{s} + \\{f} \\========= file path: ================================= - \\{} + \\{f} , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output), @@ -676,11 +675,11 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { return step.fail( \\ \\========= expected not to find: =================== - \\{s} + \\{f} \\========= but parsed file does contain it: ======== - \\{s} + \\{f} \\========= file path: ============================== - \\{} + \\{f} , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output), @@ -696,13 +695,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { return step.fail( \\ \\========= expected to find and extract: ============== - \\{s} + \\{f} \\========= but parsed file does not contain it: ======= - \\{s} + \\{f} \\========= file path: ============================== - \\{} + \\{f} , .{ - act.phrase.resolve(b, step), + fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output), src_path, }); @@ -755,14 +754,14 @@ const MachODumper = struct { }, .SYMTAB => { const lc = cmd.cast(macho.symtab_command).?; - const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(ctx.data.ptr + lc.symoff))[0..lc.nsyms]; + const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(ctx.data[lc.symoff..].ptr))[0..lc.nsyms]; const strtab = ctx.data[lc.stroff..][0..lc.strsize]; try ctx.symtab.appendUnalignedSlice(ctx.gpa, symtab); try ctx.strtab.appendSlice(ctx.gpa, strtab); }, .DYSYMTAB => { const lc = cmd.cast(macho.dysymtab_command).?; - const indexes = @as([*]align(1) const u32, @ptrCast(ctx.data.ptr + lc.indirectsymoff))[0..lc.nindirectsyms]; + const indexes = @as([*]align(1) const u32, @ptrCast(ctx.data[lc.indirectsymoff..].ptr))[0..lc.nindirectsyms]; try ctx.indsymtab.appendUnalignedSlice(ctx.gpa, indexes); }, .LOAD_DYLIB, @@ -780,7 +779,7 @@ const MachODumper = struct { fn getString(ctx: ObjectContext, off: u32) [:0]const u8 { assert(off < ctx.strtab.items.len); - return mem.sliceTo(@as([*:0]const u8, @ptrCast(ctx.strtab.items.ptr + off)), 0); + return mem.sliceTo(@as([*:0]const u8, @ptrCast(ctx.strtab.items[off..].ptr)), 0); } fn getLoadCommandIterator(ctx: ObjectContext) macho.LoadCommandIterator { @@ -810,7 +809,7 @@ const MachODumper = struct { return null; } - fn dumpHeader(hdr: macho.mach_header_64, writer: anytype) !void { + fn dumpHeader(hdr: macho.mach_header_64, bw: *Writer) !void { const cputype = switch (hdr.cputype) { macho.CPU_TYPE_ARM64 => "ARM64", macho.CPU_TYPE_X86_64 => "X86_64", @@ -831,7 +830,7 @@ const MachODumper = struct { else => "Unknown", }; - try writer.print( + try bw.print( \\header \\cputype {s} \\filetype {s} @@ -846,41 +845,41 @@ const MachODumper = struct { }); if (hdr.flags > 0) { - if (hdr.flags & macho.MH_NOUNDEFS != 0) try writer.writeAll(" NOUNDEFS"); - if (hdr.flags & macho.MH_INCRLINK != 0) try writer.writeAll(" INCRLINK"); - if (hdr.flags & macho.MH_DYLDLINK != 0) try writer.writeAll(" DYLDLINK"); - if (hdr.flags & macho.MH_BINDATLOAD != 0) try writer.writeAll(" BINDATLOAD"); - if (hdr.flags & macho.MH_PREBOUND != 0) try writer.writeAll(" PREBOUND"); - if (hdr.flags & macho.MH_SPLIT_SEGS != 0) try writer.writeAll(" SPLIT_SEGS"); - if (hdr.flags & macho.MH_LAZY_INIT != 0) try writer.writeAll(" LAZY_INIT"); - if (hdr.flags & macho.MH_TWOLEVEL != 0) try writer.writeAll(" TWOLEVEL"); - if (hdr.flags & macho.MH_FORCE_FLAT != 0) try writer.writeAll(" FORCE_FLAT"); - if (hdr.flags & macho.MH_NOMULTIDEFS != 0) try writer.writeAll(" NOMULTIDEFS"); - if (hdr.flags & macho.MH_NOFIXPREBINDING != 0) try writer.writeAll(" NOFIXPREBINDING"); - if (hdr.flags & macho.MH_PREBINDABLE != 0) try writer.writeAll(" PREBINDABLE"); - if (hdr.flags & macho.MH_ALLMODSBOUND != 0) try writer.writeAll(" ALLMODSBOUND"); - if (hdr.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0) try writer.writeAll(" SUBSECTIONS_VIA_SYMBOLS"); - if (hdr.flags & macho.MH_CANONICAL != 0) try writer.writeAll(" CANONICAL"); - if (hdr.flags & macho.MH_WEAK_DEFINES != 0) try writer.writeAll(" WEAK_DEFINES"); - if (hdr.flags & macho.MH_BINDS_TO_WEAK != 0) try writer.writeAll(" BINDS_TO_WEAK"); - if (hdr.flags & macho.MH_ALLOW_STACK_EXECUTION != 0) try writer.writeAll(" ALLOW_STACK_EXECUTION"); - if (hdr.flags & macho.MH_ROOT_SAFE != 0) try writer.writeAll(" ROOT_SAFE"); - if (hdr.flags & macho.MH_SETUID_SAFE != 0) try writer.writeAll(" SETUID_SAFE"); - if (hdr.flags & macho.MH_NO_REEXPORTED_DYLIBS != 0) try writer.writeAll(" NO_REEXPORTED_DYLIBS"); - if (hdr.flags & macho.MH_PIE != 0) try writer.writeAll(" PIE"); - if (hdr.flags & macho.MH_DEAD_STRIPPABLE_DYLIB != 0) try writer.writeAll(" DEAD_STRIPPABLE_DYLIB"); - if (hdr.flags & macho.MH_HAS_TLV_DESCRIPTORS != 0) try writer.writeAll(" HAS_TLV_DESCRIPTORS"); - if (hdr.flags & macho.MH_NO_HEAP_EXECUTION != 0) try writer.writeAll(" NO_HEAP_EXECUTION"); - if (hdr.flags & macho.MH_APP_EXTENSION_SAFE != 0) try writer.writeAll(" APP_EXTENSION_SAFE"); - if (hdr.flags & macho.MH_NLIST_OUTOFSYNC_WITH_DYLDINFO != 0) try writer.writeAll(" NLIST_OUTOFSYNC_WITH_DYLDINFO"); + if (hdr.flags & macho.MH_NOUNDEFS != 0) try bw.writeAll(" NOUNDEFS"); + if (hdr.flags & macho.MH_INCRLINK != 0) try bw.writeAll(" INCRLINK"); + if (hdr.flags & macho.MH_DYLDLINK != 0) try bw.writeAll(" DYLDLINK"); + if (hdr.flags & macho.MH_BINDATLOAD != 0) try bw.writeAll(" BINDATLOAD"); + if (hdr.flags & macho.MH_PREBOUND != 0) try bw.writeAll(" PREBOUND"); + if (hdr.flags & macho.MH_SPLIT_SEGS != 0) try bw.writeAll(" SPLIT_SEGS"); + if (hdr.flags & macho.MH_LAZY_INIT != 0) try bw.writeAll(" LAZY_INIT"); + if (hdr.flags & macho.MH_TWOLEVEL != 0) try bw.writeAll(" TWOLEVEL"); + if (hdr.flags & macho.MH_FORCE_FLAT != 0) try bw.writeAll(" FORCE_FLAT"); + if (hdr.flags & macho.MH_NOMULTIDEFS != 0) try bw.writeAll(" NOMULTIDEFS"); + if (hdr.flags & macho.MH_NOFIXPREBINDING != 0) try bw.writeAll(" NOFIXPREBINDING"); + if (hdr.flags & macho.MH_PREBINDABLE != 0) try bw.writeAll(" PREBINDABLE"); + if (hdr.flags & macho.MH_ALLMODSBOUND != 0) try bw.writeAll(" ALLMODSBOUND"); + if (hdr.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0) try bw.writeAll(" SUBSECTIONS_VIA_SYMBOLS"); + if (hdr.flags & macho.MH_CANONICAL != 0) try bw.writeAll(" CANONICAL"); + if (hdr.flags & macho.MH_WEAK_DEFINES != 0) try bw.writeAll(" WEAK_DEFINES"); + if (hdr.flags & macho.MH_BINDS_TO_WEAK != 0) try bw.writeAll(" BINDS_TO_WEAK"); + if (hdr.flags & macho.MH_ALLOW_STACK_EXECUTION != 0) try bw.writeAll(" ALLOW_STACK_EXECUTION"); + if (hdr.flags & macho.MH_ROOT_SAFE != 0) try bw.writeAll(" ROOT_SAFE"); + if (hdr.flags & macho.MH_SETUID_SAFE != 0) try bw.writeAll(" SETUID_SAFE"); + if (hdr.flags & macho.MH_NO_REEXPORTED_DYLIBS != 0) try bw.writeAll(" NO_REEXPORTED_DYLIBS"); + if (hdr.flags & macho.MH_PIE != 0) try bw.writeAll(" PIE"); + if (hdr.flags & macho.MH_DEAD_STRIPPABLE_DYLIB != 0) try bw.writeAll(" DEAD_STRIPPABLE_DYLIB"); + if (hdr.flags & macho.MH_HAS_TLV_DESCRIPTORS != 0) try bw.writeAll(" HAS_TLV_DESCRIPTORS"); + if (hdr.flags & macho.MH_NO_HEAP_EXECUTION != 0) try bw.writeAll(" NO_HEAP_EXECUTION"); + if (hdr.flags & macho.MH_APP_EXTENSION_SAFE != 0) try bw.writeAll(" APP_EXTENSION_SAFE"); + if (hdr.flags & macho.MH_NLIST_OUTOFSYNC_WITH_DYLDINFO != 0) try bw.writeAll(" NLIST_OUTOFSYNC_WITH_DYLDINFO"); } - try writer.writeByte('\n'); + try bw.writeByte('\n'); } - fn dumpLoadCommand(lc: macho.LoadCommandIterator.LoadCommand, index: usize, writer: anytype) !void { + fn dumpLoadCommand(lc: macho.LoadCommandIterator.LoadCommand, index: usize, bw: *Writer) !void { // print header first - try writer.print( + try bw.print( \\LC {d} \\cmd {s} \\cmdsize {d} @@ -889,8 +888,8 @@ const MachODumper = struct { switch (lc.cmd()) { .SEGMENT_64 => { const seg = lc.cast(macho.segment_command_64).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\segname {s} \\vmaddr {x} \\vmsize {x} @@ -905,8 +904,8 @@ const MachODumper = struct { }); for (lc.getSections()) |sect| { - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\sectname {s} \\addr {x} \\size {x} @@ -928,8 +927,8 @@ const MachODumper = struct { .REEXPORT_DYLIB, => { const dylib = lc.cast(macho.dylib_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\name {s} \\timestamp {d} \\current version {x} @@ -944,16 +943,16 @@ const MachODumper = struct { .MAIN => { const main = lc.cast(macho.entry_point_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\entryoff {x} \\stacksize {x} , .{ main.entryoff, main.stacksize }); }, .RPATH => { - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\path {s} , .{ lc.getRpathPathName(), @@ -962,8 +961,8 @@ const MachODumper = struct { .UUID => { const uuid = lc.cast(macho.uuid_command).?; - try writer.writeByte('\n'); - try writer.print("uuid {x}", .{std.fmt.fmtSliceHexLower(&uuid.uuid)}); + try bw.writeByte('\n'); + try bw.print("uuid {x}", .{&uuid.uuid}); }, .DATA_IN_CODE, @@ -971,8 +970,8 @@ const MachODumper = struct { .CODE_SIGNATURE, => { const llc = lc.cast(macho.linkedit_data_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\dataoff {x} \\datasize {x} , .{ llc.dataoff, llc.datasize }); @@ -980,8 +979,8 @@ const MachODumper = struct { .DYLD_INFO_ONLY => { const dlc = lc.cast(macho.dyld_info_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\rebaseoff {x} \\rebasesize {x} \\bindoff {x} @@ -1008,8 +1007,8 @@ const MachODumper = struct { .SYMTAB => { const slc = lc.cast(macho.symtab_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\symoff {x} \\nsyms {x} \\stroff {x} @@ -1024,8 +1023,8 @@ const MachODumper = struct { .DYSYMTAB => { const dlc = lc.cast(macho.dysymtab_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\ilocalsym {x} \\nlocalsym {x} \\iextdefsym {x} @@ -1048,8 +1047,8 @@ const MachODumper = struct { .BUILD_VERSION => { const blc = lc.cast(macho.build_version_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\platform {s} \\minos {d}.{d}.{d} \\sdk {d}.{d}.{d} @@ -1065,12 +1064,12 @@ const MachODumper = struct { blc.ntools, }); for (lc.getBuildVersionTools()) |tool| { - try writer.writeByte('\n'); + try bw.writeByte('\n'); switch (tool.tool) { - .CLANG, .SWIFT, .LD, .LLD, .ZIG => try writer.print("tool {s}\n", .{@tagName(tool.tool)}), - else => |x| try writer.print("tool {d}\n", .{@intFromEnum(x)}), + .CLANG, .SWIFT, .LD, .LLD, .ZIG => try bw.print("tool {s}\n", .{@tagName(tool.tool)}), + else => |x| try bw.print("tool {d}\n", .{@intFromEnum(x)}), } - try writer.print( + try bw.print( \\version {d}.{d}.{d} , .{ tool.version >> 16, @@ -1086,8 +1085,8 @@ const MachODumper = struct { .VERSION_MIN_TVOS, => { const vlc = lc.cast(macho.version_min_command).?; - try writer.writeByte('\n'); - try writer.print( + try bw.writeByte('\n'); + try bw.print( \\version {d}.{d}.{d} \\sdk {d}.{d}.{d} , .{ @@ -1104,8 +1103,8 @@ const MachODumper = struct { } } - fn dumpSymtab(ctx: ObjectContext, writer: anytype) !void { - try writer.writeAll(symtab_label ++ "\n"); + fn dumpSymtab(ctx: ObjectContext, bw: *Writer) !void { + try bw.writeAll(symtab_label ++ "\n"); for (ctx.symtab.items) |sym| { const sym_name = ctx.getString(sym.n_strx); @@ -1120,32 +1119,32 @@ const MachODumper = struct { macho.N_STSYM => "STSYM", else => "UNKNOWN STAB", }; - try writer.print("{x}", .{sym.n_value}); + try bw.print("{x}", .{sym.n_value}); if (sym.n_sect > 0) { const sect = ctx.sections.items[sym.n_sect - 1]; - try writer.print(" ({s},{s})", .{ sect.segName(), sect.sectName() }); + try bw.print(" ({s},{s})", .{ sect.segName(), sect.sectName() }); } - try writer.print(" {s} (stab) {s}\n", .{ tt, sym_name }); + try bw.print(" {s} (stab) {s}\n", .{ tt, sym_name }); } else if (sym.sect()) { const sect = ctx.sections.items[sym.n_sect - 1]; - try writer.print("{x} ({s},{s})", .{ + try bw.print("{x} ({s},{s})", .{ sym.n_value, sect.segName(), sect.sectName(), }); - if (sym.n_desc & macho.REFERENCED_DYNAMICALLY != 0) try writer.writeAll(" [referenced dynamically]"); - if (sym.weakDef()) try writer.writeAll(" weak"); - if (sym.weakRef()) try writer.writeAll(" weakref"); + if (sym.n_desc & macho.REFERENCED_DYNAMICALLY != 0) try bw.writeAll(" [referenced dynamically]"); + if (sym.weakDef()) try bw.writeAll(" weak"); + if (sym.weakRef()) try bw.writeAll(" weakref"); if (sym.ext()) { - if (sym.pext()) try writer.writeAll(" private"); - try writer.writeAll(" external"); - } else if (sym.pext()) try writer.writeAll(" (was private external)"); - try writer.print(" {s}\n", .{sym_name}); + if (sym.pext()) try bw.writeAll(" private"); + try bw.writeAll(" external"); + } else if (sym.pext()) try bw.writeAll(" (was private external)"); + try bw.print(" {s}\n", .{sym_name}); } else if (sym.tentative()) { const alignment = (sym.n_desc >> 8) & 0x0F; - try writer.print(" 0x{x:0>16} (common) (alignment 2^{d})", .{ sym.n_value, alignment }); - if (sym.ext()) try writer.writeAll(" external"); - try writer.print(" {s}\n", .{sym_name}); + try bw.print(" 0x{x:0>16} (common) (alignment 2^{d})", .{ sym.n_value, alignment }); + if (sym.ext()) try bw.writeAll(" external"); + try bw.print(" {s}\n", .{sym_name}); } else if (sym.undf()) { const ordinal = @divFloor(@as(i16, @bitCast(sym.n_desc)), macho.N_SYMBOL_RESOLVER); const import_name = blk: { @@ -1164,10 +1163,10 @@ const MachODumper = struct { const ext = mem.lastIndexOfScalar(u8, basename, '.') orelse basename.len; break :blk basename[0..ext]; }; - try writer.writeAll("(undefined)"); - if (sym.weakRef()) try writer.writeAll(" weakref"); - if (sym.ext()) try writer.writeAll(" external"); - try writer.print(" {s} (from {s})\n", .{ + try bw.writeAll("(undefined)"); + if (sym.weakRef()) try bw.writeAll(" weakref"); + if (sym.ext()) try bw.writeAll(" external"); + try bw.print(" {s} (from {s})\n", .{ sym_name, import_name, }); @@ -1175,8 +1174,8 @@ const MachODumper = struct { } } - fn dumpIndirectSymtab(ctx: ObjectContext, writer: anytype) !void { - try writer.writeAll(indirect_symtab_label ++ "\n"); + fn dumpIndirectSymtab(ctx: ObjectContext, bw: *Writer) !void { + try bw.writeAll(indirect_symtab_label ++ "\n"); var sects_buffer: [3]macho.section_64 = undefined; const sects = blk: { @@ -1214,35 +1213,33 @@ const MachODumper = struct { break :blk @sizeOf(u64); }; - try writer.print("{s},{s}\n", .{ sect.segName(), sect.sectName() }); - try writer.print("nentries {d}\n", .{end - start}); + try bw.print("{s},{s}\n", .{ sect.segName(), sect.sectName() }); + try bw.print("nentries {d}\n", .{end - start}); for (ctx.indsymtab.items[start..end], 0..) |index, j| { const sym = ctx.symtab.items[index]; const addr = sect.addr + entry_size * j; - try writer.print("0x{x} {d} {s}\n", .{ addr, index, ctx.getString(sym.n_strx) }); + try bw.print("0x{x} {d} {s}\n", .{ addr, index, ctx.getString(sym.n_strx) }); } } } - fn dumpRebaseInfo(ctx: ObjectContext, data: []const u8, writer: anytype) !void { - var rebases = std.ArrayList(u64).init(ctx.gpa); + fn dumpRebaseInfo(ctx: ObjectContext, data: []const u8, bw: *Writer) !void { + var rebases: std.ArrayList(u64) = .init(ctx.gpa); defer rebases.deinit(); try ctx.parseRebaseInfo(data, &rebases); mem.sort(u64, rebases.items, {}, std.sort.asc(u64)); for (rebases.items) |addr| { - try writer.print("0x{x}\n", .{addr}); + try bw.print("0x{x}\n", .{addr}); } } fn parseRebaseInfo(ctx: ObjectContext, data: []const u8, rebases: *std.ArrayList(u64)) !void { - var stream = std.io.fixedBufferStream(data); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); + var br: std.io.Reader = .fixed(data); var seg_id: ?u8 = null; var offset: u64 = 0; while (true) { - const byte = reader.readByte() catch break; + const byte = br.takeByte() catch break; const opc = byte & macho.REBASE_OPCODE_MASK; const imm = byte & macho.REBASE_IMMEDIATE_MASK; switch (opc) { @@ -1250,17 +1247,17 @@ const MachODumper = struct { macho.REBASE_OPCODE_SET_TYPE_IMM => {}, macho.REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { seg_id = imm; - offset = try std.leb.readUleb128(u64, reader); + offset = try br.takeLeb128(u64); }, macho.REBASE_OPCODE_ADD_ADDR_IMM_SCALED => { offset += imm * @sizeOf(u64); }, macho.REBASE_OPCODE_ADD_ADDR_ULEB => { - const addend = try std.leb.readUleb128(u64, reader); + const addend = try br.takeLeb128(u64); offset += addend; }, macho.REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB => { - const addend = try std.leb.readUleb128(u64, reader); + const addend = try br.takeLeb128(u64); const seg = ctx.segments.items[seg_id.?]; const addr = seg.vmaddr + offset; try rebases.append(addr); @@ -1277,11 +1274,11 @@ const MachODumper = struct { ntimes = imm; }, macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES => { - ntimes = try std.leb.readUleb128(u64, reader); + ntimes = try br.takeLeb128(u64); }, macho.REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB => { - ntimes = try std.leb.readUleb128(u64, reader); - skip = try std.leb.readUleb128(u64, reader); + ntimes = try br.takeLeb128(u64); + skip = try br.takeLeb128(u64); }, else => unreachable, } @@ -1323,8 +1320,8 @@ const MachODumper = struct { }; }; - fn dumpBindInfo(ctx: ObjectContext, data: []const u8, writer: anytype) !void { - var bindings = std.ArrayList(Binding).init(ctx.gpa); + fn dumpBindInfo(ctx: ObjectContext, data: []const u8, bw: *Writer) !void { + var bindings: std.ArrayList(Binding) = .init(ctx.gpa); defer { for (bindings.items) |*b| { b.deinit(ctx.gpa); @@ -1334,22 +1331,20 @@ const MachODumper = struct { try ctx.parseBindInfo(data, &bindings); mem.sort(Binding, bindings.items, {}, Binding.lessThan); for (bindings.items) |binding| { - try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend }); - try writer.writeAll(" ("); + try bw.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend }); + try bw.writeAll(" ("); switch (binding.tag) { - .self => try writer.writeAll("self"), - .exe => try writer.writeAll("main executable"), - .flat => try writer.writeAll("flat lookup"), - .ord => try writer.writeAll(std.fs.path.basename(ctx.imports.items[binding.ordinal - 1])), + .self => try bw.writeAll("self"), + .exe => try bw.writeAll("main executable"), + .flat => try bw.writeAll("flat lookup"), + .ord => try bw.writeAll(std.fs.path.basename(ctx.imports.items[binding.ordinal - 1])), } - try writer.print(") {s}\n", .{binding.name}); + try bw.print(") {s}\n", .{binding.name}); } } fn parseBindInfo(ctx: ObjectContext, data: []const u8, bindings: *std.ArrayList(Binding)) !void { - var stream = std.io.fixedBufferStream(data); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); + var br: std.io.Reader = .fixed(data); var seg_id: ?u8 = null; var tag: Binding.Tag = .self; @@ -1357,11 +1352,10 @@ const MachODumper = struct { var offset: u64 = 0; var addend: i64 = 0; - var name_buf = std.ArrayList(u8).init(ctx.gpa); + var name_buf: std.ArrayList(u8) = .init(ctx.gpa); defer name_buf.deinit(); - while (true) { - const byte = reader.readByte() catch break; + while (br.takeByte()) |byte| { const opc = byte & macho.BIND_OPCODE_MASK; const imm = byte & macho.BIND_IMMEDIATE_MASK; switch (opc) { @@ -1382,18 +1376,19 @@ const MachODumper = struct { }, macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => { seg_id = imm; - offset = try std.leb.readUleb128(u64, reader); + offset = try br.takeLeb128(u64); }, macho.BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM => { name_buf.clearRetainingCapacity(); - try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32)); + if (true) @panic("TODO fix this"); + //try reader.readUntilDelimiterArrayList(&name_buf, 0, std.math.maxInt(u32)); try name_buf.append(0); }, macho.BIND_OPCODE_SET_ADDEND_SLEB => { - addend = try std.leb.readIleb128(i64, reader); + addend = try br.takeLeb128(i64); }, macho.BIND_OPCODE_ADD_ADDR_ULEB => { - const x = try std.leb.readUleb128(u64, reader); + const x = try br.takeLeb128(u64); offset = @intCast(@as(i64, @intCast(offset)) + @as(i64, @bitCast(x))); }, macho.BIND_OPCODE_DO_BIND, @@ -1408,14 +1403,14 @@ const MachODumper = struct { switch (opc) { macho.BIND_OPCODE_DO_BIND => {}, macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB => { - add_addr = try std.leb.readUleb128(u64, reader); + add_addr = try br.takeLeb128(u64); }, macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED => { add_addr = imm * @sizeOf(u64); }, macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB => { - count = try std.leb.readUleb128(u64, reader); - skip = try std.leb.readUleb128(u64, reader); + count = try br.takeLeb128(u64); + skip = try br.takeLeb128(u64); }, else => unreachable, } @@ -1436,18 +1431,18 @@ const MachODumper = struct { }, else => break, } - } + } else |_| {} } - fn dumpExportsTrie(ctx: ObjectContext, data: []const u8, writer: anytype) !void { + fn dumpExportsTrie(ctx: ObjectContext, data: []const u8, bw: *Writer) !void { const seg = ctx.getSegmentByName("__TEXT") orelse return; var arena = std.heap.ArenaAllocator.init(ctx.gpa); defer arena.deinit(); - var exports = std.ArrayList(Export).init(arena.allocator()); - var it = TrieIterator{ .data = data }; - try parseTrieNode(arena.allocator(), &it, "", &exports); + var exports: std.ArrayList(Export) = .init(arena.allocator()); + var br: std.io.Reader = .fixed(data); + try parseTrieNode(arena.allocator(), &br, "", &exports); mem.sort(Export, exports.items, {}, Export.lessThan); @@ -1456,66 +1451,26 @@ const MachODumper = struct { .@"export" => { const info = exp.data.@"export"; if (info.kind != .regular or info.weak) { - try writer.writeByte('['); + try bw.writeByte('['); } switch (info.kind) { .regular => {}, - .absolute => try writer.writeAll("ABS, "), - .tlv => try writer.writeAll("THREAD_LOCAL, "), + .absolute => try bw.writeAll("ABS, "), + .tlv => try bw.writeAll("THREAD_LOCAL, "), } - if (info.weak) try writer.writeAll("WEAK"); + if (info.weak) try bw.writeAll("WEAK"); if (info.kind != .regular or info.weak) { - try writer.writeAll("] "); + try bw.writeAll("] "); } - try writer.print("{x} ", .{seg.vmaddr + info.vmoffset}); + try bw.print("{x} ", .{seg.vmaddr + info.vmoffset}); }, else => {}, } - try writer.print("{s}\n", .{exp.name}); + try bw.print("{s}\n", .{exp.name}); } } - const TrieIterator = struct { - data: []const u8, - pos: usize = 0, - - fn getStream(it: *TrieIterator) std.io.FixedBufferStream([]const u8) { - return std.io.fixedBufferStream(it.data[it.pos..]); - } - - fn readUleb128(it: *TrieIterator) !u64 { - var stream = it.getStream(); - var creader = std.io.countingReader(stream.reader()); - const reader = creader.reader(); - const value = try std.leb.readUleb128(u64, reader); - it.pos += creader.bytes_read; - return value; - } - - fn readString(it: *TrieIterator) ![:0]const u8 { - var stream = it.getStream(); - const reader = stream.reader(); - - var count: usize = 0; - while (true) : (count += 1) { - const byte = try reader.readByte(); - if (byte == 0) break; - } - - const str = @as([*:0]const u8, @ptrCast(it.data.ptr + it.pos))[0..count :0]; - it.pos += count + 1; - return str; - } - - fn readByte(it: *TrieIterator) !u8 { - var stream = it.getStream(); - const value = try stream.reader().readByte(); - it.pos += 1; - return value; - } - }; - const Export = struct { name: []const u8, tag: enum { @"export", reexport, stub_resolver }, @@ -1555,17 +1510,17 @@ const MachODumper = struct { fn parseTrieNode( arena: Allocator, - it: *TrieIterator, + br: *std.io.Reader, prefix: []const u8, exports: *std.ArrayList(Export), ) !void { - const size = try it.readUleb128(); + const size = try br.takeLeb128(u64); if (size > 0) { - const flags = try it.readUleb128(); + const flags = try br.takeLeb128(u8); switch (flags) { macho.EXPORT_SYMBOL_FLAGS_REEXPORT => { - const ord = try it.readUleb128(); - const name = try arena.dupe(u8, try it.readString()); + const ord = try br.takeLeb128(u64); + const name = try br.takeSentinel(0); try exports.append(.{ .name = if (name.len > 0) name else prefix, .tag = .reexport, @@ -1573,8 +1528,8 @@ const MachODumper = struct { }); }, macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER => { - const stub_offset = try it.readUleb128(); - const resolver_offset = try it.readUleb128(); + const stub_offset = try br.takeLeb128(u64); + const resolver_offset = try br.takeLeb128(u64); try exports.append(.{ .name = prefix, .tag = .stub_resolver, @@ -1585,7 +1540,7 @@ const MachODumper = struct { }); }, else => { - const vmoff = try it.readUleb128(); + const vmoff = try br.takeLeb128(u64); try exports.append(.{ .name = prefix, .tag = .@"export", @@ -1604,21 +1559,21 @@ const MachODumper = struct { } } - const nedges = try it.readByte(); + const nedges = try br.takeByte(); for (0..nedges) |_| { - const label = try it.readString(); - const off = try it.readUleb128(); + const label = try br.takeSentinel(0); + const off = try br.takeLeb128(usize); const prefix_label = try std.fmt.allocPrint(arena, "{s}{s}", .{ prefix, label }); - const curr = it.pos; - it.pos = off; - try parseTrieNode(arena, it, prefix_label, exports); - it.pos = curr; + const seek = br.seek; + br.seek = off; + try parseTrieNode(arena, br, prefix_label, exports); + br.seek = seek; } } - fn dumpSection(ctx: ObjectContext, sect: macho.section_64, writer: anytype) !void { + fn dumpSection(ctx: ObjectContext, sect: macho.section_64, bw: *Writer) !void { const data = ctx.data[sect.offset..][0..sect.size]; - try writer.print("{s}", .{data}); + try bw.print("{s}", .{data}); } }; @@ -1632,29 +1587,30 @@ const MachODumper = struct { var ctx = ObjectContext{ .gpa = gpa, .data = bytes, .header = hdr }; try ctx.parse(); - var output = std.ArrayList(u8).init(gpa); - const writer = output.writer(); + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; switch (check.kind) { .headers => { - try ObjectContext.dumpHeader(ctx.header, writer); + try ObjectContext.dumpHeader(ctx.header, bw); var it = ctx.getLoadCommandIterator(); var i: usize = 0; while (it.next()) |cmd| { - try ObjectContext.dumpLoadCommand(cmd, i, writer); - try writer.writeByte('\n'); + try ObjectContext.dumpLoadCommand(cmd, i, bw); + try bw.writeByte('\n'); i += 1; } }, .symtab => if (ctx.symtab.items.len > 0) { - try ctx.dumpSymtab(writer); + try ctx.dumpSymtab(bw); } else return step.fail("no symbol table found", .{}), .indirect_symtab => if (ctx.symtab.items.len > 0 and ctx.indsymtab.items.len > 0) { - try ctx.dumpIndirectSymtab(writer); + try ctx.dumpIndirectSymtab(bw); } else return step.fail("no indirect symbol table found", .{}), .dyld_rebase, @@ -1669,26 +1625,26 @@ const MachODumper = struct { switch (check.kind) { .dyld_rebase => if (lc.rebase_size > 0) { const data = ctx.data[lc.rebase_off..][0..lc.rebase_size]; - try writer.writeAll(dyld_rebase_label ++ "\n"); - try ctx.dumpRebaseInfo(data, writer); + try bw.writeAll(dyld_rebase_label ++ "\n"); + try ctx.dumpRebaseInfo(data, bw); } else return step.fail("no rebase data found", .{}), .dyld_bind => if (lc.bind_size > 0) { const data = ctx.data[lc.bind_off..][0..lc.bind_size]; - try writer.writeAll(dyld_bind_label ++ "\n"); - try ctx.dumpBindInfo(data, writer); + try bw.writeAll(dyld_bind_label ++ "\n"); + try ctx.dumpBindInfo(data, bw); } else return step.fail("no bind data found", .{}), .dyld_weak_bind => if (lc.weak_bind_size > 0) { const data = ctx.data[lc.weak_bind_off..][0..lc.weak_bind_size]; - try writer.writeAll(dyld_weak_bind_label ++ "\n"); - try ctx.dumpBindInfo(data, writer); + try bw.writeAll(dyld_weak_bind_label ++ "\n"); + try ctx.dumpBindInfo(data, bw); } else return step.fail("no weak bind data found", .{}), .dyld_lazy_bind => if (lc.lazy_bind_size > 0) { const data = ctx.data[lc.lazy_bind_off..][0..lc.lazy_bind_size]; - try writer.writeAll(dyld_lazy_bind_label ++ "\n"); - try ctx.dumpBindInfo(data, writer); + try bw.writeAll(dyld_lazy_bind_label ++ "\n"); + try ctx.dumpBindInfo(data, bw); } else return step.fail("no lazy bind data found", .{}), else => unreachable, @@ -1700,8 +1656,8 @@ const MachODumper = struct { const lc = cmd.cast(macho.dyld_info_command).?; if (lc.export_size > 0) { const data = ctx.data[lc.export_off..][0..lc.export_size]; - try writer.writeAll(exports_label ++ "\n"); - try ctx.dumpExportsTrie(data, writer); + try bw.writeAll(exports_label ++ "\n"); + try ctx.dumpExportsTrie(data, bw); break :blk; } } @@ -1709,20 +1665,20 @@ const MachODumper = struct { }, .dump_section => { - const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items.ptr + check.payload.dump_section)), 0); + const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items[check.payload.dump_section..].ptr)), 0); const sep_index = mem.indexOfScalar(u8, name, ',') orelse return step.fail("invalid section name: {s}", .{name}); const segname = name[0..sep_index]; const sectname = name[sep_index + 1 ..]; const sect = ctx.getSectionByName(segname, sectname) orelse return step.fail("section '{s}' not found", .{name}); - try ctx.dumpSection(sect, writer); + try ctx.dumpSection(sect, bw); }, else => return step.fail("invalid check kind for MachO file format: {s}", .{@tagName(check.kind)}), } - return output.toOwnedSlice(); + return aw.toOwnedSlice(); } }; @@ -1741,161 +1697,138 @@ const ElfDumper = struct { fn parseAndDumpArchive(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; - var stream = std.io.fixedBufferStream(bytes); - const reader = stream.reader(); + var br: std.io.Reader = .fixed(bytes); - const magic = try reader.readBytesNoEof(elf.ARMAG.len); - if (!mem.eql(u8, &magic, elf.ARMAG)) { - return error.InvalidArchiveMagicNumber; - } + if (!mem.eql(u8, try br.takeArray(elf.ARMAG.len), elf.ARMAG)) return error.InvalidArchiveMagicNumber; - var ctx = ArchiveContext{ + var ctx: ArchiveContext = .{ .gpa = gpa, .data = bytes, - .strtab = &[0]u8{}, + .symtab = &.{}, + .strtab = &.{}, + .objects = .empty, }; - defer { - for (ctx.objects.items) |*object| { - gpa.free(object.name); - } - ctx.objects.deinit(gpa); - } + defer ctx.deinit(); - while (true) { - if (stream.pos >= ctx.data.len) break; - if (!mem.isAligned(stream.pos, 2)) stream.pos += 1; - - const hdr = try reader.readStruct(elf.ar_hdr); + while (br.seek < bytes.len) { + const hdr_seek = std.mem.alignForward(usize, br.seek, 2); + br.seek = hdr_seek; + const hdr = try br.takeStruct(elf.ar_hdr); if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) return error.InvalidArchiveHeaderMagicNumber; - const size = try hdr.size(); - defer { - _ = stream.seekBy(size) catch {}; - } + const data = try br.take(try hdr.size()); if (hdr.isSymtab()) { - try ctx.parseSymtab(ctx.data[stream.pos..][0..size], .p32); + try ctx.parseSymtab(data, .p32); continue; } if (hdr.isSymtab64()) { - try ctx.parseSymtab(ctx.data[stream.pos..][0..size], .p64); + try ctx.parseSymtab(data, .p64); continue; } if (hdr.isStrtab()) { - ctx.strtab = ctx.data[stream.pos..][0..size]; + ctx.strtab = data; continue; } if (hdr.isSymdef() or hdr.isSymdefSorted()) continue; - const name = if (hdr.name()) |name| - try gpa.dupe(u8, name) - else if (try hdr.nameOffset()) |off| - try gpa.dupe(u8, ctx.getString(off)) - else - unreachable; - - try ctx.objects.append(gpa, .{ .name = name, .off = stream.pos, .len = size }); + const name = hdr.name() orelse ctx.getString((try hdr.nameOffset()).?); + try ctx.objects.putNoClobber(gpa, hdr_seek, .{ + .name = name, + .data = data, + }); } - var output = std.ArrayList(u8).init(gpa); - const writer = output.writer(); + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; switch (check.kind) { - .archive_symtab => if (ctx.symtab.items.len > 0) { - try ctx.dumpSymtab(writer); + .archive_symtab => if (ctx.symtab.len > 0) { + try ctx.dumpSymtab(bw); } else return step.fail("no archive symbol table found", .{}), - else => if (ctx.objects.items.len > 0) { - try ctx.dumpObjects(step, check, writer); + else => if (ctx.objects.count() > 0) { + try ctx.dumpObjects(step, check, bw); } else return step.fail("empty archive", .{}), } - return output.toOwnedSlice(); + return aw.toOwnedSlice(); } const ArchiveContext = struct { gpa: Allocator, data: []const u8, - symtab: std.ArrayListUnmanaged(ArSymtabEntry) = .empty, + symtab: []ArSymtabEntry, strtab: []const u8, - objects: std.ArrayListUnmanaged(struct { name: []const u8, off: usize, len: usize }) = .empty, + objects: std.AutoArrayHashMapUnmanaged(usize, struct { name: []const u8, data: []const u8 }), - fn parseSymtab(ctx: *ArchiveContext, raw: []const u8, ptr_width: enum { p32, p64 }) !void { - var stream = std.io.fixedBufferStream(raw); - const reader = stream.reader(); + fn deinit(ctx: *ArchiveContext) void { + ctx.gpa.free(ctx.symtab); + ctx.objects.deinit(ctx.gpa); + } + + fn parseSymtab(ctx: *ArchiveContext, data: []const u8, ptr_width: enum { p32, p64 }) !void { + var br: std.io.Reader = .fixed(data); const num = switch (ptr_width) { - .p32 => try reader.readInt(u32, .big), - .p64 => try reader.readInt(u64, .big), + .p32 => try br.takeInt(u32, .big), + .p64 => try br.takeInt(u64, .big), }; const ptr_size: usize = switch (ptr_width) { .p32 => @sizeOf(u32), .p64 => @sizeOf(u64), }; - const strtab_off = (num + 1) * ptr_size; - const strtab_len = raw.len - strtab_off; - const strtab = raw[strtab_off..][0..strtab_len]; + _ = try br.discard(.limited(num * ptr_size)); + const strtab = br.buffered(); - try ctx.symtab.ensureTotalCapacityPrecise(ctx.gpa, num); + assert(ctx.symtab.len == 0); + ctx.symtab = try ctx.gpa.alloc(ArSymtabEntry, num); var stroff: usize = 0; - for (0..num) |_| { + for (ctx.symtab) |*entry| { const off = switch (ptr_width) { - .p32 => try reader.readInt(u32, .big), - .p64 => try reader.readInt(u64, .big), + .p32 => try br.takeInt(u32, .big), + .p64 => try br.takeInt(u64, .big), }; - const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(strtab.ptr + stroff)), 0); + const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(strtab[stroff..].ptr)), 0); stroff += name.len + 1; - ctx.symtab.appendAssumeCapacity(.{ .off = off, .name = name }); + entry.* = .{ .off = off, .name = name }; } } - fn dumpSymtab(ctx: ArchiveContext, writer: anytype) !void { - var files = std.AutoHashMap(usize, []const u8).init(ctx.gpa); - defer files.deinit(); - try files.ensureUnusedCapacity(@intCast(ctx.objects.items.len)); - - for (ctx.objects.items) |object| { - files.putAssumeCapacityNoClobber(object.off - @sizeOf(elf.ar_hdr), object.name); - } - - var symbols = std.AutoArrayHashMap(usize, std.ArrayList([]const u8)).init(ctx.gpa); + fn dumpSymtab(ctx: ArchiveContext, bw: *Writer) !void { + var symbols: std.AutoArrayHashMap(usize, std.ArrayList([]const u8)) = .init(ctx.gpa); defer { - for (symbols.values()) |*value| { - value.deinit(); - } + for (symbols.values()) |*value| value.deinit(); symbols.deinit(); } - for (ctx.symtab.items) |entry| { + for (ctx.symtab) |entry| { const gop = try symbols.getOrPut(@intCast(entry.off)); - if (!gop.found_existing) { - gop.value_ptr.* = std.ArrayList([]const u8).init(ctx.gpa); - } + if (!gop.found_existing) gop.value_ptr.* = .init(ctx.gpa); try gop.value_ptr.append(entry.name); } - try writer.print("{s}\n", .{archive_symtab_label}); + try bw.print("{s}\n", .{archive_symtab_label}); for (symbols.keys(), symbols.values()) |off, values| { - try writer.print("in object {s}\n", .{files.get(off).?}); - for (values.items) |value| { - try writer.print("{s}\n", .{value}); - } + try bw.print("in object {s}\n", .{ctx.objects.get(off).?.name}); + for (values.items) |value| try bw.print("{s}\n", .{value}); } } - fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, writer: anytype) !void { - for (ctx.objects.items) |object| { - try writer.print("object {s}\n", .{object.name}); - const output = try parseAndDumpObject(step, check, ctx.data[object.off..][0..object.len]); + fn dumpObjects(ctx: ArchiveContext, step: *Step, check: Check, bw: *Writer) !void { + for (ctx.objects.values()) |object| { + try bw.print("object {s}\n", .{object.name}); + const output = try parseAndDumpObject(step, check, object.data); defer ctx.gpa.free(output); - try writer.print("{s}\n", .{output}); + try bw.print("{s}\n", .{output}); } } fn getString(ctx: ArchiveContext, off: u32) []const u8 { assert(off < ctx.strtab.len); - const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(ctx.strtab.ptr + off)), 0); + const name = mem.sliceTo(@as([*:'\n']const u8, @ptrCast(ctx.strtab[off..].ptr)), 0); return name[0 .. name.len - 1]; } @@ -1907,24 +1840,23 @@ const ElfDumper = struct { fn parseAndDumpObject(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; - var stream = std.io.fixedBufferStream(bytes); - const reader = stream.reader(); + var br: std.io.Reader = .fixed(bytes); - const hdr = try reader.readStruct(elf.Elf64_Ehdr); - if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) { - return error.InvalidMagicNumber; - } + const hdr = try br.takeStruct(elf.Elf64_Ehdr); + if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidMagicNumber; - const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(bytes.ptr + hdr.e_shoff))[0..hdr.e_shnum]; - const phdrs = @as([*]align(1) const elf.Elf64_Phdr, @ptrCast(bytes.ptr + hdr.e_phoff))[0..hdr.e_phnum]; + const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(bytes[hdr.e_shoff..].ptr))[0..hdr.e_shnum]; + const phdrs = @as([*]align(1) const elf.Elf64_Phdr, @ptrCast(bytes[hdr.e_phoff..].ptr))[0..hdr.e_phnum]; - var ctx = ObjectContext{ + var ctx: ObjectContext = .{ .gpa = gpa, .data = bytes, .hdr = hdr, .shdrs = shdrs, .phdrs = phdrs, .shstrtab = undefined, + .symtab = .{}, + .dysymtab = .{}, }; ctx.shstrtab = ctx.getSectionContents(ctx.hdr.e_shstrndx); @@ -1955,120 +1887,121 @@ const ElfDumper = struct { else => {}, }; - var output = std.ArrayList(u8).init(gpa); - const writer = output.writer(); + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; switch (check.kind) { .headers => { - try ctx.dumpHeader(writer); - try ctx.dumpShdrs(writer); - try ctx.dumpPhdrs(writer); + try ctx.dumpHeader(bw); + try ctx.dumpShdrs(bw); + try ctx.dumpPhdrs(bw); }, .symtab => if (ctx.symtab.symbols.len > 0) { - try ctx.dumpSymtab(.symtab, writer); + try ctx.dumpSymtab(.symtab, bw); } else return step.fail("no symbol table found", .{}), .dynamic_symtab => if (ctx.dysymtab.symbols.len > 0) { - try ctx.dumpSymtab(.dysymtab, writer); + try ctx.dumpSymtab(.dysymtab, bw); } else return step.fail("no dynamic symbol table found", .{}), .dynamic_section => if (ctx.getSectionByName(".dynamic")) |shndx| { - try ctx.dumpDynamicSection(shndx, writer); + try ctx.dumpDynamicSection(shndx, bw); } else return step.fail("no .dynamic section found", .{}), .dump_section => { - const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items.ptr + check.payload.dump_section)), 0); + const name = mem.sliceTo(@as([*:0]const u8, @ptrCast(check.data.items[check.payload.dump_section..].ptr)), 0); const shndx = ctx.getSectionByName(name) orelse return step.fail("no '{s}' section found", .{name}); - try ctx.dumpSection(shndx, writer); + try ctx.dumpSection(shndx, bw); }, else => return step.fail("invalid check kind for ELF file format: {s}", .{@tagName(check.kind)}), } - return output.toOwnedSlice(); + return aw.toOwnedSlice(); } const ObjectContext = struct { gpa: Allocator, data: []const u8, - hdr: elf.Elf64_Ehdr, + hdr: *align(1) const elf.Elf64_Ehdr, shdrs: []align(1) const elf.Elf64_Shdr, phdrs: []align(1) const elf.Elf64_Phdr, shstrtab: []const u8, - symtab: Symtab = .{}, - dysymtab: Symtab = .{}, + symtab: Symtab, + dysymtab: Symtab, - fn dumpHeader(ctx: ObjectContext, writer: anytype) !void { - try writer.writeAll("header\n"); - try writer.print("type {s}\n", .{@tagName(ctx.hdr.e_type)}); - try writer.print("entry {x}\n", .{ctx.hdr.e_entry}); + fn dumpHeader(ctx: ObjectContext, bw: *Writer) !void { + try bw.writeAll("header\n"); + try bw.print("type {s}\n", .{@tagName(ctx.hdr.e_type)}); + try bw.print("entry {x}\n", .{ctx.hdr.e_entry}); } - fn dumpPhdrs(ctx: ObjectContext, writer: anytype) !void { + fn dumpPhdrs(ctx: ObjectContext, bw: *Writer) !void { if (ctx.phdrs.len == 0) return; - try writer.writeAll("program headers\n"); + try bw.writeAll("program headers\n"); for (ctx.phdrs, 0..) |phdr, phndx| { - try writer.print("phdr {d}\n", .{phndx}); - try writer.print("type {s}\n", .{fmtPhType(phdr.p_type)}); - try writer.print("vaddr {x}\n", .{phdr.p_vaddr}); - try writer.print("paddr {x}\n", .{phdr.p_paddr}); - try writer.print("offset {x}\n", .{phdr.p_offset}); - try writer.print("memsz {x}\n", .{phdr.p_memsz}); - try writer.print("filesz {x}\n", .{phdr.p_filesz}); - try writer.print("align {x}\n", .{phdr.p_align}); + try bw.print("phdr {d}\n", .{phndx}); + try bw.print("type {f}\n", .{fmtPhType(phdr.p_type)}); + try bw.print("vaddr {x}\n", .{phdr.p_vaddr}); + try bw.print("paddr {x}\n", .{phdr.p_paddr}); + try bw.print("offset {x}\n", .{phdr.p_offset}); + try bw.print("memsz {x}\n", .{phdr.p_memsz}); + try bw.print("filesz {x}\n", .{phdr.p_filesz}); + try bw.print("align {x}\n", .{phdr.p_align}); { const flags = phdr.p_flags; - try writer.writeAll("flags"); - if (flags > 0) try writer.writeByte(' '); + try bw.writeAll("flags"); + if (flags > 0) try bw.writeByte(' '); if (flags & elf.PF_R != 0) { - try writer.writeByte('R'); + try bw.writeByte('R'); } if (flags & elf.PF_W != 0) { - try writer.writeByte('W'); + try bw.writeByte('W'); } if (flags & elf.PF_X != 0) { - try writer.writeByte('E'); + try bw.writeByte('E'); } if (flags & elf.PF_MASKOS != 0) { - try writer.writeAll("OS"); + try bw.writeAll("OS"); } if (flags & elf.PF_MASKPROC != 0) { - try writer.writeAll("PROC"); + try bw.writeAll("PROC"); } - try writer.writeByte('\n'); + try bw.writeByte('\n'); } } } - fn dumpShdrs(ctx: ObjectContext, writer: anytype) !void { + fn dumpShdrs(ctx: ObjectContext, bw: *Writer) !void { if (ctx.shdrs.len == 0) return; - try writer.writeAll("section headers\n"); + try bw.writeAll("section headers\n"); for (ctx.shdrs, 0..) |shdr, shndx| { - try writer.print("shdr {d}\n", .{shndx}); - try writer.print("name {s}\n", .{ctx.getSectionName(shndx)}); - try writer.print("type {s}\n", .{fmtShType(shdr.sh_type)}); - try writer.print("addr {x}\n", .{shdr.sh_addr}); - try writer.print("offset {x}\n", .{shdr.sh_offset}); - try writer.print("size {x}\n", .{shdr.sh_size}); - try writer.print("addralign {x}\n", .{shdr.sh_addralign}); + try bw.print("shdr {d}\n", .{shndx}); + try bw.print("name {s}\n", .{ctx.getSectionName(shndx)}); + try bw.print("type {f}\n", .{fmtShType(shdr.sh_type)}); + try bw.print("addr {x}\n", .{shdr.sh_addr}); + try bw.print("offset {x}\n", .{shdr.sh_offset}); + try bw.print("size {x}\n", .{shdr.sh_size}); + try bw.print("addralign {x}\n", .{shdr.sh_addralign}); // TODO dump formatted sh_flags } } - fn dumpDynamicSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void { + fn dumpDynamicSection(ctx: ObjectContext, shndx: usize, bw: *Writer) !void { const shdr = ctx.shdrs[shndx]; const strtab = ctx.getSectionContents(shdr.sh_link); const data = ctx.getSectionContents(shndx); const nentries = @divExact(data.len, @sizeOf(elf.Elf64_Dyn)); const entries = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(data.ptr))[0..nentries]; - try writer.writeAll(ElfDumper.dynamic_section_label ++ "\n"); + try bw.writeAll(ElfDumper.dynamic_section_label ++ "\n"); for (entries) |entry| { const key = @as(u64, @bitCast(entry.d_tag)); @@ -2109,7 +2042,7 @@ const ElfDumper = struct { elf.DT_NULL => "NULL", else => "UNKNOWN", }; - try writer.print("{s}", .{key_str}); + try bw.print("{s}", .{key_str}); switch (key) { elf.DT_NEEDED, @@ -2118,7 +2051,7 @@ const ElfDumper = struct { elf.DT_RUNPATH, => { const name = getString(strtab, @intCast(value)); - try writer.print(" {s}", .{name}); + try bw.print(" {s}", .{name}); }, elf.DT_INIT_ARRAY, @@ -2136,7 +2069,7 @@ const ElfDumper = struct { elf.DT_INIT, elf.DT_FINI, elf.DT_NULL, - => try writer.print(" {x}", .{value}), + => try bw.print(" {x}", .{value}), elf.DT_INIT_ARRAYSZ, elf.DT_FINI_ARRAYSZ, @@ -2146,77 +2079,77 @@ const ElfDumper = struct { elf.DT_RELASZ, elf.DT_RELAENT, elf.DT_RELACOUNT, - => try writer.print(" {d}", .{value}), + => try bw.print(" {d}", .{value}), - elf.DT_PLTREL => try writer.writeAll(switch (value) { + elf.DT_PLTREL => try bw.writeAll(switch (value) { elf.DT_REL => " REL", elf.DT_RELA => " RELA", else => " UNKNOWN", }), elf.DT_FLAGS => if (value > 0) { - if (value & elf.DF_ORIGIN != 0) try writer.writeAll(" ORIGIN"); - if (value & elf.DF_SYMBOLIC != 0) try writer.writeAll(" SYMBOLIC"); - if (value & elf.DF_TEXTREL != 0) try writer.writeAll(" TEXTREL"); - if (value & elf.DF_BIND_NOW != 0) try writer.writeAll(" BIND_NOW"); - if (value & elf.DF_STATIC_TLS != 0) try writer.writeAll(" STATIC_TLS"); + if (value & elf.DF_ORIGIN != 0) try bw.writeAll(" ORIGIN"); + if (value & elf.DF_SYMBOLIC != 0) try bw.writeAll(" SYMBOLIC"); + if (value & elf.DF_TEXTREL != 0) try bw.writeAll(" TEXTREL"); + if (value & elf.DF_BIND_NOW != 0) try bw.writeAll(" BIND_NOW"); + if (value & elf.DF_STATIC_TLS != 0) try bw.writeAll(" STATIC_TLS"); }, elf.DT_FLAGS_1 => if (value > 0) { - if (value & elf.DF_1_NOW != 0) try writer.writeAll(" NOW"); - if (value & elf.DF_1_GLOBAL != 0) try writer.writeAll(" GLOBAL"); - if (value & elf.DF_1_GROUP != 0) try writer.writeAll(" GROUP"); - if (value & elf.DF_1_NODELETE != 0) try writer.writeAll(" NODELETE"); - if (value & elf.DF_1_LOADFLTR != 0) try writer.writeAll(" LOADFLTR"); - if (value & elf.DF_1_INITFIRST != 0) try writer.writeAll(" INITFIRST"); - if (value & elf.DF_1_NOOPEN != 0) try writer.writeAll(" NOOPEN"); - if (value & elf.DF_1_ORIGIN != 0) try writer.writeAll(" ORIGIN"); - if (value & elf.DF_1_DIRECT != 0) try writer.writeAll(" DIRECT"); - if (value & elf.DF_1_TRANS != 0) try writer.writeAll(" TRANS"); - if (value & elf.DF_1_INTERPOSE != 0) try writer.writeAll(" INTERPOSE"); - if (value & elf.DF_1_NODEFLIB != 0) try writer.writeAll(" NODEFLIB"); - if (value & elf.DF_1_NODUMP != 0) try writer.writeAll(" NODUMP"); - if (value & elf.DF_1_CONFALT != 0) try writer.writeAll(" CONFALT"); - if (value & elf.DF_1_ENDFILTEE != 0) try writer.writeAll(" ENDFILTEE"); - if (value & elf.DF_1_DISPRELDNE != 0) try writer.writeAll(" DISPRELDNE"); - if (value & elf.DF_1_DISPRELPND != 0) try writer.writeAll(" DISPRELPND"); - if (value & elf.DF_1_NODIRECT != 0) try writer.writeAll(" NODIRECT"); - if (value & elf.DF_1_IGNMULDEF != 0) try writer.writeAll(" IGNMULDEF"); - if (value & elf.DF_1_NOKSYMS != 0) try writer.writeAll(" NOKSYMS"); - if (value & elf.DF_1_NOHDR != 0) try writer.writeAll(" NOHDR"); - if (value & elf.DF_1_EDITED != 0) try writer.writeAll(" EDITED"); - if (value & elf.DF_1_NORELOC != 0) try writer.writeAll(" NORELOC"); - if (value & elf.DF_1_SYMINTPOSE != 0) try writer.writeAll(" SYMINTPOSE"); - if (value & elf.DF_1_GLOBAUDIT != 0) try writer.writeAll(" GLOBAUDIT"); - if (value & elf.DF_1_SINGLETON != 0) try writer.writeAll(" SINGLETON"); - if (value & elf.DF_1_STUB != 0) try writer.writeAll(" STUB"); - if (value & elf.DF_1_PIE != 0) try writer.writeAll(" PIE"); + if (value & elf.DF_1_NOW != 0) try bw.writeAll(" NOW"); + if (value & elf.DF_1_GLOBAL != 0) try bw.writeAll(" GLOBAL"); + if (value & elf.DF_1_GROUP != 0) try bw.writeAll(" GROUP"); + if (value & elf.DF_1_NODELETE != 0) try bw.writeAll(" NODELETE"); + if (value & elf.DF_1_LOADFLTR != 0) try bw.writeAll(" LOADFLTR"); + if (value & elf.DF_1_INITFIRST != 0) try bw.writeAll(" INITFIRST"); + if (value & elf.DF_1_NOOPEN != 0) try bw.writeAll(" NOOPEN"); + if (value & elf.DF_1_ORIGIN != 0) try bw.writeAll(" ORIGIN"); + if (value & elf.DF_1_DIRECT != 0) try bw.writeAll(" DIRECT"); + if (value & elf.DF_1_TRANS != 0) try bw.writeAll(" TRANS"); + if (value & elf.DF_1_INTERPOSE != 0) try bw.writeAll(" INTERPOSE"); + if (value & elf.DF_1_NODEFLIB != 0) try bw.writeAll(" NODEFLIB"); + if (value & elf.DF_1_NODUMP != 0) try bw.writeAll(" NODUMP"); + if (value & elf.DF_1_CONFALT != 0) try bw.writeAll(" CONFALT"); + if (value & elf.DF_1_ENDFILTEE != 0) try bw.writeAll(" ENDFILTEE"); + if (value & elf.DF_1_DISPRELDNE != 0) try bw.writeAll(" DISPRELDNE"); + if (value & elf.DF_1_DISPRELPND != 0) try bw.writeAll(" DISPRELPND"); + if (value & elf.DF_1_NODIRECT != 0) try bw.writeAll(" NODIRECT"); + if (value & elf.DF_1_IGNMULDEF != 0) try bw.writeAll(" IGNMULDEF"); + if (value & elf.DF_1_NOKSYMS != 0) try bw.writeAll(" NOKSYMS"); + if (value & elf.DF_1_NOHDR != 0) try bw.writeAll(" NOHDR"); + if (value & elf.DF_1_EDITED != 0) try bw.writeAll(" EDITED"); + if (value & elf.DF_1_NORELOC != 0) try bw.writeAll(" NORELOC"); + if (value & elf.DF_1_SYMINTPOSE != 0) try bw.writeAll(" SYMINTPOSE"); + if (value & elf.DF_1_GLOBAUDIT != 0) try bw.writeAll(" GLOBAUDIT"); + if (value & elf.DF_1_SINGLETON != 0) try bw.writeAll(" SINGLETON"); + if (value & elf.DF_1_STUB != 0) try bw.writeAll(" STUB"); + if (value & elf.DF_1_PIE != 0) try bw.writeAll(" PIE"); }, - else => try writer.print(" {x}", .{value}), + else => try bw.print(" {x}", .{value}), } - try writer.writeByte('\n'); + try bw.writeByte('\n'); } } - fn dumpSymtab(ctx: ObjectContext, comptime @"type": enum { symtab, dysymtab }, writer: anytype) !void { + fn dumpSymtab(ctx: ObjectContext, comptime @"type": enum { symtab, dysymtab }, bw: *Writer) !void { const symtab = switch (@"type") { .symtab => ctx.symtab, .dysymtab => ctx.dysymtab, }; - try writer.writeAll(switch (@"type") { + try bw.writeAll(switch (@"type") { .symtab => symtab_label, .dysymtab => dynamic_symtab_label, } ++ "\n"); for (symtab.symbols, 0..) |sym, index| { - try writer.print("{x} {x}", .{ sym.st_value, sym.st_size }); + try bw.print("{x} {x}", .{ sym.st_value, sym.st_size }); { if (elf.SHN_LORESERVE <= sym.st_shndx and sym.st_shndx < elf.SHN_HIRESERVE) { if (elf.SHN_LOPROC <= sym.st_shndx and sym.st_shndx < elf.SHN_HIPROC) { - try writer.print(" LO+{d}", .{sym.st_shndx - elf.SHN_LOPROC}); + try bw.print(" LO+{d}", .{sym.st_shndx - elf.SHN_LOPROC}); } else { const sym_ndx = switch (sym.st_shndx) { elf.SHN_ABS => "ABS", @@ -2224,12 +2157,12 @@ const ElfDumper = struct { elf.SHN_LIVEPATCH => "LIV", else => "UNK", }; - try writer.print(" {s}", .{sym_ndx}); + try bw.print(" {s}", .{sym_ndx}); } } else if (sym.st_shndx == elf.SHN_UNDEF) { - try writer.writeAll(" UND"); + try bw.writeAll(" UND"); } else { - try writer.print(" {x}", .{sym.st_shndx}); + try bw.print(" {x}", .{sym.st_shndx}); } } @@ -2246,12 +2179,12 @@ const ElfDumper = struct { elf.STT_NUM => "NUM", elf.STT_GNU_IFUNC => "IFUNC", else => if (elf.STT_LOPROC <= tt and tt < elf.STT_HIPROC) { - break :blk try writer.print(" LOPROC+{d}", .{tt - elf.STT_LOPROC}); + break :blk try bw.print(" LOPROC+{d}", .{tt - elf.STT_LOPROC}); } else if (elf.STT_LOOS <= tt and tt < elf.STT_HIOS) { - break :blk try writer.print(" LOOS+{d}", .{tt - elf.STT_LOOS}); + break :blk try bw.print(" LOOS+{d}", .{tt - elf.STT_LOOS}); } else "UNK", }; - try writer.print(" {s}", .{sym_type}); + try bw.print(" {s}", .{sym_type}); } blk: { @@ -2262,28 +2195,28 @@ const ElfDumper = struct { elf.STB_WEAK => "WEAK", elf.STB_NUM => "NUM", else => if (elf.STB_LOPROC <= bind and bind < elf.STB_HIPROC) { - break :blk try writer.print(" LOPROC+{d}", .{bind - elf.STB_LOPROC}); + break :blk try bw.print(" LOPROC+{d}", .{bind - elf.STB_LOPROC}); } else if (elf.STB_LOOS <= bind and bind < elf.STB_HIOS) { - break :blk try writer.print(" LOOS+{d}", .{bind - elf.STB_LOOS}); + break :blk try bw.print(" LOOS+{d}", .{bind - elf.STB_LOOS}); } else "UNKNOWN", }; - try writer.print(" {s}", .{sym_bind}); + try bw.print(" {s}", .{sym_bind}); } const sym_vis = @as(elf.STV, @enumFromInt(@as(u2, @truncate(sym.st_other)))); - try writer.print(" {s}", .{@tagName(sym_vis)}); + try bw.print(" {s}", .{@tagName(sym_vis)}); const sym_name = switch (sym.st_type()) { elf.STT_SECTION => ctx.getSectionName(sym.st_shndx), else => symtab.getName(index).?, }; - try writer.print(" {s}\n", .{sym_name}); + try bw.print(" {s}\n", .{sym_name}); } } - fn dumpSection(ctx: ObjectContext, shndx: usize, writer: anytype) !void { + fn dumpSection(ctx: ObjectContext, shndx: usize, bw: *Writer) !void { const data = ctx.getSectionContents(shndx); - try writer.print("{s}", .{data}); + try bw.print("{s}", .{data}); } inline fn getSectionName(ctx: ObjectContext, shndx: usize) []const u8 { @@ -2321,22 +2254,15 @@ const ElfDumper = struct { }; fn getString(strtab: []const u8, off: u32) []const u8 { - assert(off < strtab.len); - return mem.sliceTo(@as([*:0]const u8, @ptrCast(strtab.ptr + off)), 0); + const str = strtab[off..]; + return str[0..std.mem.indexOfScalar(u8, str, 0).?]; } - fn fmtShType(sh_type: u32) std.fmt.Formatter(formatShType) { + fn fmtShType(sh_type: u32) std.fmt.Formatter(u32, formatShType) { return .{ .data = sh_type }; } - fn formatShType( - sh_type: u32, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = unused_fmt_string; - _ = options; + fn formatShType(sh_type: u32, w: *Writer) Writer.Error!void { const name = switch (sh_type) { elf.SHT_NULL => "NULL", elf.SHT_PROGBITS => "PROGBITS", @@ -2362,28 +2288,21 @@ const ElfDumper = struct { elf.SHT_GNU_VERNEED => "VERNEED", elf.SHT_GNU_VERSYM => "VERSYM", else => if (elf.SHT_LOOS <= sh_type and sh_type < elf.SHT_HIOS) { - return try writer.print("LOOS+0x{x}", .{sh_type - elf.SHT_LOOS}); + return try w.print("LOOS+0x{x}", .{sh_type - elf.SHT_LOOS}); } else if (elf.SHT_LOPROC <= sh_type and sh_type < elf.SHT_HIPROC) { - return try writer.print("LOPROC+0x{x}", .{sh_type - elf.SHT_LOPROC}); + return try w.print("LOPROC+0x{x}", .{sh_type - elf.SHT_LOPROC}); } else if (elf.SHT_LOUSER <= sh_type and sh_type < elf.SHT_HIUSER) { - return try writer.print("LOUSER+0x{x}", .{sh_type - elf.SHT_LOUSER}); + return try w.print("LOUSER+0x{x}", .{sh_type - elf.SHT_LOUSER}); } else "UNKNOWN", }; - try writer.writeAll(name); + try w.writeAll(name); } - fn fmtPhType(ph_type: u32) std.fmt.Formatter(formatPhType) { + fn fmtPhType(ph_type: u32) std.fmt.Formatter(u32, formatPhType) { return .{ .data = ph_type }; } - fn formatPhType( - ph_type: u32, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = unused_fmt_string; - _ = options; + fn formatPhType(ph_type: u32, w: *Writer) Writer.Error!void { const p_type = switch (ph_type) { elf.PT_NULL => "NULL", elf.PT_LOAD => "LOAD", @@ -2398,12 +2317,12 @@ const ElfDumper = struct { elf.PT_GNU_STACK => "GNU_STACK", elf.PT_GNU_RELRO => "GNU_RELRO", else => if (elf.PT_LOOS <= ph_type and ph_type < elf.PT_HIOS) { - return try writer.print("LOOS+0x{x}", .{ph_type - elf.PT_LOOS}); + return try w.print("LOOS+0x{x}", .{ph_type - elf.PT_LOOS}); } else if (elf.PT_LOPROC <= ph_type and ph_type < elf.PT_HIPROC) { - return try writer.print("LOPROC+0x{x}", .{ph_type - elf.PT_LOPROC}); + return try w.print("LOPROC+0x{x}", .{ph_type - elf.PT_LOPROC}); } else "UNKNOWN", }; - try writer.writeAll(p_type); + try w.writeAll(p_type); } }; @@ -2412,49 +2331,39 @@ const WasmDumper = struct { fn parseAndDump(step: *Step, check: Check, bytes: []const u8) ![]const u8 { const gpa = step.owner.allocator; - var fbs = std.io.fixedBufferStream(bytes); - const reader = fbs.reader(); + var br: std.io.Reader = .fixed(bytes); - const buf = try reader.readBytesNoEof(8); - if (!mem.eql(u8, buf[0..4], &std.wasm.magic)) { - return error.InvalidMagicByte; - } - if (!mem.eql(u8, buf[4..], &std.wasm.version)) { - return error.UnsupportedWasmVersion; - } + const buf = try br.takeArray(8); + if (!mem.eql(u8, buf[0..4], &std.wasm.magic)) return error.InvalidMagicByte; + if (!mem.eql(u8, buf[4..8], &std.wasm.version)) return error.UnsupportedWasmVersion; - var output = std.ArrayList(u8).init(gpa); - defer output.deinit(); - parseAndDumpInner(step, check, bytes, &fbs, &output) catch |err| switch (err) { - error.EndOfStream => try output.appendSlice("\n"), + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; + + parseAndDumpInner(step, check, &br, bw) catch |err| switch (err) { + error.EndOfStream => try bw.writeAll("\n"), else => |e| return e, }; - return output.toOwnedSlice(); + return aw.toOwnedSlice(); } fn parseAndDumpInner( step: *Step, check: Check, - bytes: []const u8, - fbs: *std.io.FixedBufferStream([]const u8), - output: *std.ArrayList(u8), + br: *std.io.Reader, + bw: *Writer, ) !void { - const reader = fbs.reader(); - const writer = output.writer(); - + var section_br: std.io.Reader = undefined; switch (check.kind) { - .headers => { - while (reader.readByte()) |current_byte| { - const section = std.enums.fromInt(std.wasm.Section, current_byte) orelse { - return step.fail("Found invalid section id '{d}'", .{current_byte}); - }; - - const section_length = try std.leb.readUleb128(u32, reader); - try parseAndDumpSection(step, section, bytes[fbs.pos..][0..section_length], writer); - fbs.pos += section_length; - } else |_| {} // reached end of stream + .headers => while (br.takeEnum(std.wasm.Section, .little)) |section| { + section_br = .fixed(try br.take(try br.takeLeb128(u32))); + try parseAndDumpSection(step, section, §ion_br, bw); + } else |err| switch (err) { + error.InvalidEnumTag => return step.fail("invalid section id", .{}), + error.EndOfStream => {}, + else => |e| return e, }, - else => return step.fail("invalid check kind for Wasm file format: {s}", .{@tagName(check.kind)}), } } @@ -2462,16 +2371,13 @@ const WasmDumper = struct { fn parseAndDumpSection( step: *Step, section: std.wasm.Section, - data: []const u8, - writer: anytype, + br: *std.io.Reader, + bw: *Writer, ) !void { - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); - - try writer.print( + try bw.print( \\Section {s} \\size {d} - , .{ @tagName(section), data.len }); + , .{ @tagName(section), br.buffer.len }); switch (section) { .type, @@ -2485,96 +2391,83 @@ const WasmDumper = struct { .code, .data, => { - const entries = try std.leb.readUleb128(u32, reader); - try writer.print("\nentries {d}\n", .{entries}); - try parseSection(step, section, data[fbs.pos..], entries, writer); + const entries = try br.takeLeb128(u32); + try bw.print("\nentries {d}\n", .{entries}); + try parseSection(step, section, br, entries, bw); }, .custom => { - const name_length = try std.leb.readUleb128(u32, reader); - const name = data[fbs.pos..][0..name_length]; - fbs.pos += name_length; - try writer.print("\nname {s}\n", .{name}); + const name = try br.take(try br.takeLeb128(u32)); + try bw.print("\nname {s}\n", .{name}); if (mem.eql(u8, name, "name")) { - try parseDumpNames(step, reader, writer, data); + try parseDumpNames(step, br, bw); } else if (mem.eql(u8, name, "producers")) { - try parseDumpProducers(reader, writer, data); + try parseDumpProducers(br, bw); } else if (mem.eql(u8, name, "target_features")) { - try parseDumpFeatures(reader, writer, data); + try parseDumpFeatures(br, bw); } // TODO: Implement parsing and dumping other custom sections (such as relocations) }, .start => { - const start = try std.leb.readUleb128(u32, reader); - try writer.print("\nstart {d}\n", .{start}); + const start = try br.takeLeb128(u32); + try bw.print("\nstart {d}\n", .{start}); }, .data_count => { - const count = try std.leb.readUleb128(u32, reader); - try writer.print("\ncount {d}\n", .{count}); + const count = try br.takeLeb128(u32); + try bw.print("\ncount {d}\n", .{count}); }, else => {}, // skip unknown sections } } - fn parseSection(step: *Step, section: std.wasm.Section, data: []const u8, entries: u32, writer: anytype) !void { - var fbs = std.io.fixedBufferStream(data); - const reader = fbs.reader(); - + fn parseSection(step: *Step, section: std.wasm.Section, br: *std.io.Reader, entries: u32, bw: *Writer) !void { switch (section) { .type => { var i: u32 = 0; while (i < entries) : (i += 1) { - const func_type = try reader.readByte(); + const func_type = try br.takeByte(); if (func_type != std.wasm.function_type) { return step.fail("expected function type, found byte '{d}'", .{func_type}); } - const params = try std.leb.readUleb128(u32, reader); - try writer.print("params {d}\n", .{params}); + const params = try br.takeLeb128(u32); + try bw.print("params {d}\n", .{params}); var index: u32 = 0; while (index < params) : (index += 1) { - _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); + _ = try parseDumpType(step, std.wasm.Valtype, br, bw); } else index = 0; - const returns = try std.leb.readUleb128(u32, reader); - try writer.print("returns {d}\n", .{returns}); + const returns = try br.takeLeb128(u32); + try bw.print("returns {d}\n", .{returns}); while (index < returns) : (index += 1) { - _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); + _ = try parseDumpType(step, std.wasm.Valtype, br, bw); } } }, .import => { var i: u32 = 0; while (i < entries) : (i += 1) { - const module_name_len = try std.leb.readUleb128(u32, reader); - const module_name = data[fbs.pos..][0..module_name_len]; - fbs.pos += module_name_len; - const name_len = try std.leb.readUleb128(u32, reader); - const name = data[fbs.pos..][0..name_len]; - fbs.pos += name_len; - - const kind = std.enums.fromInt(std.wasm.ExternalKind, try reader.readByte()) orelse { - return step.fail("invalid import kind", .{}); + const module_name = try br.take(try br.takeLeb128(u32)); + const name = try br.take(try br.takeLeb128(u32)); + const kind = br.takeEnum(std.wasm.ExternalKind, .little) catch |err| switch (err) { + error.InvalidEnumTag => return step.fail("invalid import kind", .{}), + else => |e| return e, }; - try writer.print( + try bw.print( \\module {s} \\name {s} \\kind {s} , .{ module_name, name, @tagName(kind) }); - try writer.writeByte('\n'); + try bw.writeByte('\n'); switch (kind) { - .function => { - try writer.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); - }, - .memory => { - try parseDumpLimits(reader, writer); - }, + .function => try bw.print("index {d}\n", .{try br.takeLeb128(u32)}), + .memory => try parseDumpLimits(br, bw), .global => { - _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); - try writer.print("mutable {}\n", .{0x01 == try std.leb.readUleb128(u32, reader)}); + _ = try parseDumpType(step, std.wasm.Valtype, br, bw); + try bw.print("mutable {}\n", .{0x01 == try br.takeLeb128(u32)}); }, .table => { - _ = try parseDumpType(step, std.wasm.RefType, reader, writer); - try parseDumpLimits(reader, writer); + _ = try parseDumpType(step, std.wasm.RefType, br, bw); + try parseDumpLimits(br, bw); }, } } @@ -2582,60 +2475,58 @@ const WasmDumper = struct { .function => { var i: u32 = 0; while (i < entries) : (i += 1) { - try writer.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); + try bw.print("index {d}\n", .{try br.takeLeb128(u32)}); } }, .table => { var i: u32 = 0; while (i < entries) : (i += 1) { - _ = try parseDumpType(step, std.wasm.RefType, reader, writer); - try parseDumpLimits(reader, writer); + _ = try parseDumpType(step, std.wasm.RefType, br, bw); + try parseDumpLimits(br, bw); } }, .memory => { var i: u32 = 0; while (i < entries) : (i += 1) { - try parseDumpLimits(reader, writer); + try parseDumpLimits(br, bw); } }, .global => { var i: u32 = 0; while (i < entries) : (i += 1) { - _ = try parseDumpType(step, std.wasm.Valtype, reader, writer); - try writer.print("mutable {}\n", .{0x01 == try std.leb.readUleb128(u1, reader)}); - try parseDumpInit(step, reader, writer); + _ = try parseDumpType(step, std.wasm.Valtype, br, bw); + try bw.print("mutable {}\n", .{0x01 == try br.takeLeb128(u1)}); + try parseDumpInit(step, br, bw); } }, .@"export" => { var i: u32 = 0; while (i < entries) : (i += 1) { - const name_len = try std.leb.readUleb128(u32, reader); - const name = data[fbs.pos..][0..name_len]; - fbs.pos += name_len; - const kind_byte = try std.leb.readUleb128(u8, reader); - const kind = std.enums.fromInt(std.wasm.ExternalKind, kind_byte) orelse { - return step.fail("invalid export kind value '{d}'", .{kind_byte}); + const name = try br.take(try br.takeLeb128(u32)); + const kind = br.takeEnum(std.wasm.ExternalKind, .little) catch |err| switch (err) { + error.InvalidEnumTag => return step.fail("invalid export kind value", .{}), + else => |e| return e, }; - const index = try std.leb.readUleb128(u32, reader); - try writer.print( + const index = try br.takeLeb128(u32); + try bw.print( \\name {s} \\kind {s} \\index {d} , .{ name, @tagName(kind), index }); - try writer.writeByte('\n'); + try bw.writeByte('\n'); } }, .element => { var i: u32 = 0; while (i < entries) : (i += 1) { - try writer.print("table index {d}\n", .{try std.leb.readUleb128(u32, reader)}); - try parseDumpInit(step, reader, writer); + try bw.print("table index {d}\n", .{try br.takeLeb128(u32)}); + try parseDumpInit(step, br, bw); - const function_indexes = try std.leb.readUleb128(u32, reader); + const function_indexes = try br.takeLeb128(u32); var function_index: u32 = 0; - try writer.print("indexes {d}\n", .{function_indexes}); + try bw.print("indexes {d}\n", .{function_indexes}); while (function_index < function_indexes) : (function_index += 1) { - try writer.print("index {d}\n", .{try std.leb.readUleb128(u32, reader)}); + try bw.print("index {d}\n", .{try br.takeLeb128(u32)}); } } }, @@ -2643,101 +2534,95 @@ const WasmDumper = struct { .data => { var i: u32 = 0; while (i < entries) : (i += 1) { - const flags = try std.leb.readUleb128(u32, reader); - const index = if (flags & 0x02 != 0) - try std.leb.readUleb128(u32, reader) - else - 0; - try writer.print("memory index 0x{x}\n", .{index}); - if (flags == 0) { - try parseDumpInit(step, reader, writer); - } - - const size = try std.leb.readUleb128(u32, reader); - try writer.print("size {d}\n", .{size}); - try reader.skipBytes(size, .{}); // we do not care about the content of the segments + const flags: packed struct(u32) { + passive: bool, + memidx: bool, + unused: u30, + } = @bitCast(try br.takeLeb128(u32)); + const index = if (flags.memidx) try br.takeLeb128(u32) else 0; + try bw.print("memory index 0x{x}\n", .{index}); + if (!flags.passive) try parseDumpInit(step, br, bw); + const size = try br.takeLeb128(u32); + try bw.print("size {d}\n", .{size}); + _ = try br.discard(.limited(size)); // we do not care about the content of the segments } }, else => unreachable, } } - fn parseDumpType(step: *Step, comptime E: type, reader: anytype, writer: anytype) !E { - const byte = try reader.readByte(); - const tag = std.enums.fromInt(E, byte) orelse { - return step.fail("invalid wasm type value '{d}'", .{byte}); + fn parseDumpType(step: *Step, comptime E: type, br: *std.io.Reader, bw: *Writer) !E { + const tag = br.takeEnum(E, .little) catch |err| switch (err) { + error.InvalidEnumTag => return step.fail("invalid wasm type value", .{}), + else => |e| return e, }; - try writer.print("type {s}\n", .{@tagName(tag)}); + try bw.print("type {s}\n", .{@tagName(tag)}); return tag; } - fn parseDumpLimits(reader: anytype, writer: anytype) !void { - const flags = try std.leb.readUleb128(u8, reader); - const min = try std.leb.readUleb128(u32, reader); + fn parseDumpLimits(br: *std.io.Reader, bw: *Writer) !void { + const flags = try br.takeLeb128(u8); + const min = try br.takeLeb128(u32); - try writer.print("min {x}\n", .{min}); - if (flags != 0) { - try writer.print("max {x}\n", .{try std.leb.readUleb128(u32, reader)}); - } + try bw.print("min {x}\n", .{min}); + if (flags != 0) try bw.print("max {x}\n", .{try br.takeLeb128(u32)}); } - fn parseDumpInit(step: *Step, reader: anytype, writer: anytype) !void { - const byte = try reader.readByte(); - const opcode = std.enums.fromInt(std.wasm.Opcode, byte) orelse { - return step.fail("invalid wasm opcode '{d}'", .{byte}); + fn parseDumpInit(step: *Step, br: *std.io.Reader, bw: *Writer) !void { + const opcode = br.takeEnum(std.wasm.Opcode, .little) catch |err| switch (err) { + error.InvalidEnumTag => return step.fail("invalid wasm opcode", .{}), + else => |e| return e, }; switch (opcode) { - .i32_const => try writer.print("i32.const {x}\n", .{try std.leb.readIleb128(i32, reader)}), - .i64_const => try writer.print("i64.const {x}\n", .{try std.leb.readIleb128(i64, reader)}), - .f32_const => try writer.print("f32.const {x}\n", .{@as(f32, @bitCast(try reader.readInt(u32, .little)))}), - .f64_const => try writer.print("f64.const {x}\n", .{@as(f64, @bitCast(try reader.readInt(u64, .little)))}), - .global_get => try writer.print("global.get {x}\n", .{try std.leb.readUleb128(u32, reader)}), + .i32_const => try bw.print("i32.const {x}\n", .{try br.takeLeb128(i32)}), + .i64_const => try bw.print("i64.const {x}\n", .{try br.takeLeb128(i64)}), + .f32_const => try bw.print("f32.const {x}\n", .{@as(f32, @bitCast(try br.takeInt(u32, .little)))}), + .f64_const => try bw.print("f64.const {x}\n", .{@as(f64, @bitCast(try br.takeInt(u64, .little)))}), + .global_get => try bw.print("global.get {x}\n", .{try br.takeLeb128(u32)}), else => unreachable, } - const end_opcode = try std.leb.readUleb128(u8, reader); + const end_opcode = try br.takeLeb128(u8); if (end_opcode != @intFromEnum(std.wasm.Opcode.end)) { return step.fail("expected 'end' opcode in init expression", .{}); } } /// https://webassembly.github.io/spec/core/appendix/custom.html - fn parseDumpNames(step: *Step, reader: anytype, writer: anytype, data: []const u8) !void { - while (reader.context.pos < data.len) { - switch (try parseDumpType(step, std.wasm.NameSubsection, reader, writer)) { + fn parseDumpNames(step: *Step, br: *std.io.Reader, bw: *Writer) !void { + var subsection_br: std.io.Reader = undefined; + while (br.seek < br.buffer.len) { + switch (try parseDumpType(step, std.wasm.NameSubsection, br, bw)) { // The module name subsection ... consists of a single name // that is assigned to the module itself. .module => { - const size = try std.leb.readUleb128(u32, reader); - const name_len = try std.leb.readUleb128(u32, reader); - if (size != name_len + 1) return error.BadSubsectionSize; - if (reader.context.pos + name_len > data.len) return error.UnexpectedEndOfStream; - try writer.print("name {s}\n", .{data[reader.context.pos..][0..name_len]}); - reader.context.pos += name_len; + subsection_br = .fixed(try br.take(try br.takeLeb128(u32))); + const name = try subsection_br.take(try subsection_br.takeLeb128(u32)); + try bw.print( + \\name {s} + \\ + , .{name}); + if (subsection_br.seek != subsection_br.buffer.len) return error.BadSubsectionSize; }, // The function name subsection ... consists of a name map // assigning function names to function indices. .function, .global, .data_segment => { - const size = try std.leb.readUleb128(u32, reader); - const entries = try std.leb.readUleb128(u32, reader); - try writer.print( - \\size {d} + subsection_br = .fixed(try br.take(try br.takeLeb128(u32))); + const entries = try br.takeLeb128(u32); + try bw.print( \\names {d} \\ - , .{ size, entries }); + , .{entries}); for (0..entries) |_| { - const index = try std.leb.readUleb128(u32, reader); - const name_len = try std.leb.readUleb128(u32, reader); - if (reader.context.pos + name_len > data.len) return error.UnexpectedEndOfStream; - const name = data[reader.context.pos..][0..name_len]; - reader.context.pos += name.len; - - try writer.print( + const index = try br.takeLeb128(u32); + const name = try br.take(try br.takeLeb128(u32)); + try bw.print( \\index {d} \\name {s} \\ , .{ index, name }); } + if (subsection_br.seek != subsection_br.buffer.len) return error.BadSubsectionSize; }, // The local name subsection ... consists of an indirect name @@ -2752,52 +2637,49 @@ const WasmDumper = struct { } } - fn parseDumpProducers(reader: anytype, writer: anytype, data: []const u8) !void { - const field_count = try std.leb.readUleb128(u32, reader); - try writer.print("fields {d}\n", .{field_count}); + fn parseDumpProducers(br: *std.io.Reader, bw: *Writer) !void { + const field_count = try br.takeLeb128(u32); + try bw.print( + \\fields {d} + \\ + , .{field_count}); var current_field: u32 = 0; while (current_field < field_count) : (current_field += 1) { - const field_name_length = try std.leb.readUleb128(u32, reader); - const field_name = data[reader.context.pos..][0..field_name_length]; - reader.context.pos += field_name_length; - - const value_count = try std.leb.readUleb128(u32, reader); - try writer.print( + const field_name = try br.take(try br.takeLeb128(u32)); + const value_count = try br.takeLeb128(u32); + try bw.print( \\field_name {s} \\values {d} + \\ , .{ field_name, value_count }); - try writer.writeByte('\n'); var current_value: u32 = 0; while (current_value < value_count) : (current_value += 1) { - const value_length = try std.leb.readUleb128(u32, reader); - const value = data[reader.context.pos..][0..value_length]; - reader.context.pos += value_length; - - const version_length = try std.leb.readUleb128(u32, reader); - const version = data[reader.context.pos..][0..version_length]; - reader.context.pos += version_length; - - try writer.print( + const value = try br.take(try br.takeLeb128(u32)); + const version = try br.take(try br.takeLeb128(u32)); + try bw.print( \\value_name {s} \\version {s} + \\ , .{ value, version }); - try writer.writeByte('\n'); } } } - fn parseDumpFeatures(reader: anytype, writer: anytype, data: []const u8) !void { - const feature_count = try std.leb.readUleb128(u32, reader); - try writer.print("features {d}\n", .{feature_count}); + fn parseDumpFeatures(br: *std.io.Reader, bw: *Writer) !void { + const feature_count = try br.takeLeb128(u32); + try bw.print( + \\features {d} + \\ + , .{feature_count}); var index: u32 = 0; while (index < feature_count) : (index += 1) { - const prefix_byte = try std.leb.readUleb128(u8, reader); - const name_length = try std.leb.readUleb128(u32, reader); - const feature_name = data[reader.context.pos..][0..name_length]; - reader.context.pos += name_length; - - try writer.print("{c} {s}\n", .{ prefix_byte, feature_name }); + const prefix_byte = try br.takeLeb128(u8); + const feature_name = try br.take(try br.takeLeb128(u32)); + try bw.print( + \\{c} {s} + \\ + , .{ prefix_byte, feature_name }); } } }; diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index eec0ce90bb..5b73bd2c76 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1542,7 +1542,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { if (compile.kind == .lib and compile.linkage != null and compile.linkage.? == .dynamic) { if (compile.version) |version| { try zig_args.append("--version"); - try zig_args.append(b.fmt("{}", .{version})); + try zig_args.append(b.fmt("{f}", .{version})); } if (compile.rootModuleTarget().os.tag.isDarwin()) { @@ -1696,9 +1696,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { if (compile.build_id orelse b.build_id) |build_id| { try zig_args.append(switch (build_id) { - .hexstring => |hs| b.fmt("--build-id=0x{s}", .{ - std.fmt.fmtSliceHexLower(hs.toSlice()), - }), + .hexstring => |hs| b.fmt("--build-id=0x{x}", .{hs.toSlice()}), .none, .fast, .uuid, .sha1, .md5 => b.fmt("--build-id={s}", .{@tagName(build_id)}), }); } @@ -1706,7 +1704,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { const opt_zig_lib_dir = if (compile.zig_lib_dir) |dir| dir.getPath2(b, step) else if (b.graph.zig_lib_directory.path) |_| - b.fmt("{}", .{b.graph.zig_lib_directory}) + b.fmt("{f}", .{b.graph.zig_lib_directory}) else null; @@ -1746,8 +1744,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { } if (compile.error_limit) |err_limit| try zig_args.appendSlice(&.{ - "--error-limit", - b.fmt("{}", .{err_limit}), + "--error-limit", b.fmt("{d}", .{err_limit}), }); try addFlag(&zig_args, "incremental", b.graph.incremental); @@ -1793,11 +1790,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { var args_hash: [Sha256.digest_length]u8 = undefined; Sha256.hash(args, &args_hash, .{}); var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined; - _ = try std.fmt.bufPrint( - &args_hex_hash, - "{s}", - .{std.fmt.fmtSliceHexLower(&args_hash)}, - ); + _ = try std.fmt.bufPrint(&args_hex_hash, "{x}", .{&args_hash}); const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash; try b.cache_root.handle.writeFile(.{ .sub_path = args_file, .data = args }); @@ -1836,7 +1829,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { // Update generated files if (maybe_output_dir) |output_dir| { if (compile.emit_directory) |lp| { - lp.path = b.fmt("{}", .{output_dir}); + lp.path = b.fmt("{f}", .{output_dir}); } // zig fmt: off diff --git a/lib/std/Build/Step/ConfigHeader.zig b/lib/std/Build/Step/ConfigHeader.zig index 967e1edd05..d8a7a08b33 100644 --- a/lib/std/Build/Step/ConfigHeader.zig +++ b/lib/std/Build/Step/ConfigHeader.zig @@ -2,6 +2,7 @@ const std = @import("std"); const ConfigHeader = @This(); const Step = std.Build.Step; const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; pub const Style = union(enum) { /// A configure format supported by autotools that uses `#undef foo` to @@ -87,7 +88,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { owner.fmt("configure {s} header to {s}", .{ @tagName(options.style), include_path }); config_header.* = .{ - .step = Step.init(.{ + .step = .init(.{ .id = base_id, .name = name, .owner = owner, @@ -95,7 +96,7 @@ pub fn create(owner: *std.Build, options: Options) *ConfigHeader { .first_ret_addr = options.first_ret_addr orelse @returnAddress(), }), .style = options.style, - .values = std.StringArrayHashMap(Value).init(owner.allocator), + .values = .init(owner.allocator), .max_bytes = options.max_bytes, .include_path = include_path, @@ -195,8 +196,9 @@ fn make(step: *Step, options: Step.MakeOptions) !void { man.hash.addBytes(config_header.include_path); man.hash.addOptionalBytes(config_header.include_guard_override); - var output = std.ArrayList(u8).init(gpa); - defer output.deinit(); + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; const header_text = "This file was generated by ConfigHeader using the Zig Build System."; const c_generated_line = "/* " ++ header_text ++ " */\n"; @@ -204,7 +206,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { switch (config_header.style) { .autoconf_undef, .autoconf, .autoconf_at => |file_source| { - try output.appendSlice(c_generated_line); + try bw.writeAll(c_generated_line); const src_path = file_source.getPath2(b, step); const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| { return step.fail("unable to read autoconf input file '{s}': {s}", .{ @@ -212,32 +214,33 @@ fn make(step: *Step, options: Step.MakeOptions) !void { }); }; switch (config_header.style) { - .autoconf_undef, .autoconf => try render_autoconf_undef(step, contents, &output, config_header.values, src_path), - .autoconf_at => try render_autoconf_at(step, contents, &output, config_header.values, src_path), + .autoconf_undef, .autoconf => try render_autoconf_undef(step, contents, bw, config_header.values, src_path), + .autoconf_at => try render_autoconf_at(step, contents, &aw, config_header.values, src_path), else => unreachable, } }, .cmake => |file_source| { - try output.appendSlice(c_generated_line); + try bw.writeAll(c_generated_line); const src_path = file_source.getPath2(b, step); const contents = std.fs.cwd().readFileAlloc(arena, src_path, config_header.max_bytes) catch |err| { return step.fail("unable to read cmake input file '{s}': {s}", .{ src_path, @errorName(err), }); }; - try render_cmake(step, contents, &output, config_header.values, src_path); + try render_cmake(step, contents, bw, config_header.values, src_path); }, .blank => { - try output.appendSlice(c_generated_line); - try render_blank(&output, config_header.values, config_header.include_path, config_header.include_guard_override); + try bw.writeAll(c_generated_line); + try render_blank(gpa, bw, config_header.values, config_header.include_path, config_header.include_guard_override); }, .nasm => { - try output.appendSlice(asm_generated_line); - try render_nasm(&output, config_header.values); + try bw.writeAll(asm_generated_line); + try render_nasm(bw, config_header.values); }, } - man.hash.addBytes(output.items); + const output = aw.getWritten(); + man.hash.addBytes(output); if (try step.cacheHit(&man)) { const digest = man.final(); @@ -256,13 +259,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void { const sub_path_dirname = std.fs.path.dirname(sub_path).?; b.cache_root.handle.makePath(sub_path_dirname) catch |err| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.cache_root, sub_path_dirname, @errorName(err), }); }; - b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = output.items }) catch |err| { - return step.fail("unable to write file '{}{s}': {s}", .{ + b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = output }) catch |err| { + return step.fail("unable to write file '{f}{s}': {s}", .{ b.cache_root, sub_path, @errorName(err), }); }; @@ -274,7 +277,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { fn render_autoconf_undef( step: *Step, contents: []const u8, - output: *std.ArrayList(u8), + bw: *Writer, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { @@ -289,15 +292,15 @@ fn render_autoconf_undef( var line_it = std.mem.splitScalar(u8, contents, '\n'); while (line_it.next()) |line| : (line_index += 1) { if (!std.mem.startsWith(u8, line, "#")) { - try output.appendSlice(line); - try output.appendSlice("\n"); + try bw.writeAll(line); + try bw.writeByte('\n'); continue; } var it = std.mem.tokenizeAny(u8, line[1..], " \t\r"); const undef = it.next().?; if (!std.mem.eql(u8, undef, "undef")) { - try output.appendSlice(line); - try output.appendSlice("\n"); + try bw.writeAll(line); + try bw.writeByte('\n'); continue; } const name = it.next().?; @@ -309,7 +312,7 @@ fn render_autoconf_undef( continue; }; is_used.set(index); - try renderValueC(output, name, values.values()[index]); + try renderValueC(bw, name, values.values()[index]); } var unused_value_it = is_used.iterator(.{ .kind = .unset }); @@ -326,12 +329,13 @@ fn render_autoconf_undef( fn render_autoconf_at( step: *Step, contents: []const u8, - output: *std.ArrayList(u8), + aw: *std.io.Writer.Allocating, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { const build = step.owner; const allocator = build.allocator; + const bw = &aw.interface; const used = allocator.alloc(bool, values.count()) catch @panic("OOM"); for (used) |*u| u.* = false; @@ -343,11 +347,11 @@ fn render_autoconf_at( while (line_it.next()) |line| : (line_index += 1) { const last_line = line_it.index == line_it.buffer.len; - const old_len = output.items.len; - expand_variables_autoconf_at(output, line, values, used) catch |err| switch (err) { + const old_len = aw.getWritten().len; + expand_variables_autoconf_at(bw, line, values, used) catch |err| switch (err) { error.MissingValue => { - const name = output.items[old_len..]; - defer output.shrinkRetainingCapacity(old_len); + const name = aw.getWritten()[old_len..]; + defer aw.shrinkRetainingCapacity(old_len); try step.addError("{s}:{d}: error: unspecified config header value: '{s}'", .{ src_path, line_index + 1, name, }); @@ -362,9 +366,7 @@ fn render_autoconf_at( continue; }, }; - if (!last_line) { - try output.append('\n'); - } + if (!last_line) try bw.writeByte('\n'); } for (values.unmanaged.entries.slice().items(.key), used) |name, u| { @@ -374,15 +376,13 @@ fn render_autoconf_at( } } - if (any_errors) { - return error.MakeFailed; - } + if (any_errors) return error.MakeFailed; } fn render_cmake( step: *Step, contents: []const u8, - output: *std.ArrayList(u8), + bw: *Writer, values: std.StringArrayHashMap(Value), src_path: []const u8, ) !void { @@ -417,10 +417,8 @@ fn render_cmake( defer allocator.free(line); if (!std.mem.startsWith(u8, line, "#")) { - try output.appendSlice(line); - if (!last_line) { - try output.appendSlice("\n"); - } + try bw.writeAll(line); + if (!last_line) try bw.writeByte('\n'); continue; } var it = std.mem.tokenizeAny(u8, line[1..], " \t\r"); @@ -428,10 +426,8 @@ fn render_cmake( if (!std.mem.eql(u8, cmakedefine, "cmakedefine") and !std.mem.eql(u8, cmakedefine, "cmakedefine01")) { - try output.appendSlice(line); - if (!last_line) { - try output.appendSlice("\n"); - } + try bw.writeAll(line); + if (!last_line) try bw.writeByte('\n'); continue; } @@ -502,7 +498,7 @@ fn render_cmake( value = Value{ .ident = it.rest() }; } - try renderValueC(output, name, value); + try renderValueC(bw, name, value); } if (any_errors) { @@ -511,13 +507,14 @@ fn render_cmake( } fn render_blank( - output: *std.ArrayList(u8), + gpa: std.mem.Allocator, + bw: *Writer, defines: std.StringArrayHashMap(Value), include_path: []const u8, include_guard_override: ?[]const u8, ) !void { const include_guard_name = include_guard_override orelse blk: { - const name = try output.allocator.dupe(u8, include_path); + const name = try gpa.dupe(u8, include_path); for (name) |*byte| { switch (byte.*) { 'a'...'z' => byte.* = byte.* - 'a' + 'A', @@ -527,92 +524,53 @@ fn render_blank( } break :blk name; }; + defer if (include_guard_override == null) gpa.free(include_guard_name); - try output.appendSlice("#ifndef "); - try output.appendSlice(include_guard_name); - try output.appendSlice("\n#define "); - try output.appendSlice(include_guard_name); - try output.appendSlice("\n"); + try bw.print( + \\#ifndef {[0]s} + \\#define {[0]s} + \\ + , .{include_guard_name}); const values = defines.values(); - for (defines.keys(), 0..) |name, i| { - try renderValueC(output, name, values[i]); - } + for (defines.keys(), 0..) |name, i| try renderValueC(bw, name, values[i]); - try output.appendSlice("#endif /* "); - try output.appendSlice(include_guard_name); - try output.appendSlice(" */\n"); + try bw.print( + \\#endif /* {s} */ + \\ + , .{include_guard_name}); } -fn render_nasm(output: *std.ArrayList(u8), defines: std.StringArrayHashMap(Value)) !void { - const values = defines.values(); - for (defines.keys(), 0..) |name, i| { - try renderValueNasm(output, name, values[i]); - } +fn render_nasm(bw: *Writer, defines: std.StringArrayHashMap(Value)) !void { + for (defines.keys(), defines.values()) |name, value| try renderValueNasm(bw, name, value); } -fn renderValueC(output: *std.ArrayList(u8), name: []const u8, value: Value) !void { +fn renderValueC(bw: *Writer, name: []const u8, value: Value) !void { switch (value) { - .undef => { - try output.appendSlice("/* #undef "); - try output.appendSlice(name); - try output.appendSlice(" */\n"); - }, - .defined => { - try output.appendSlice("#define "); - try output.appendSlice(name); - try output.appendSlice("\n"); - }, - .boolean => |b| { - try output.appendSlice("#define "); - try output.appendSlice(name); - try output.appendSlice(if (b) " 1\n" else " 0\n"); - }, - .int => |i| { - try output.writer().print("#define {s} {d}\n", .{ name, i }); - }, - .ident => |ident| { - try output.writer().print("#define {s} {s}\n", .{ name, ident }); - }, - .string => |string| { - // TODO: use C-specific escaping instead of zig string literals - try output.writer().print("#define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) }); - }, + .undef => try bw.print("/* #undef {s} */\n", .{name}), + .defined => try bw.print("#define {s}\n", .{name}), + .boolean => |b| try bw.print("#define {s} {c}\n", .{ name, @as(u8, '0') + @intFromBool(b) }), + .int => |i| try bw.print("#define {s} {d}\n", .{ name, i }), + .ident => |ident| try bw.print("#define {s} {s}\n", .{ name, ident }), + // TODO: use C-specific escaping instead of zig string literals + .string => |string| try bw.print("#define {s} \"{f}\"\n", .{ name, std.zig.fmtString(string) }), } } -fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !void { +fn renderValueNasm(bw: *Writer, name: []const u8, value: Value) !void { switch (value) { - .undef => { - try output.appendSlice("; %undef "); - try output.appendSlice(name); - try output.appendSlice("\n"); - }, - .defined => { - try output.appendSlice("%define "); - try output.appendSlice(name); - try output.appendSlice("\n"); - }, - .boolean => |b| { - try output.appendSlice("%define "); - try output.appendSlice(name); - try output.appendSlice(if (b) " 1\n" else " 0\n"); - }, - .int => |i| { - try output.writer().print("%define {s} {d}\n", .{ name, i }); - }, - .ident => |ident| { - try output.writer().print("%define {s} {s}\n", .{ name, ident }); - }, - .string => |string| { - // TODO: use nasm-specific escaping instead of zig string literals - try output.writer().print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) }); - }, + .undef => try bw.print("; %undef {s}\n", .{name}), + .defined => try bw.print("%define {s}\n", .{name}), + .boolean => |b| try bw.print("%define {s} {c}\n", .{ name, @as(u8, '0') + @intFromBool(b) }), + .int => |i| try bw.print("%define {s} {d}\n", .{ name, i }), + .ident => |ident| try bw.print("%define {s} {s}\n", .{ name, ident }), + // TODO: use nasm-specific escaping instead of zig string literals + .string => |string| try bw.print("%define {s} \"{f}\"\n", .{ name, std.zig.fmtString(string) }), } } fn expand_variables_autoconf_at( - output: *std.ArrayList(u8), + bw: *Writer, contents: []const u8, values: std.StringArrayHashMap(Value), used: []bool, @@ -637,23 +595,17 @@ fn expand_variables_autoconf_at( const key = contents[curr + 1 .. close_pos]; const index = values.getIndex(key) orelse { // Report the missing key to the caller. - try output.appendSlice(key); + try bw.writeAll(key); return error.MissingValue; }; const value = values.unmanaged.entries.slice().items(.value)[index]; used[index] = true; - try output.appendSlice(contents[source_offset..curr]); + try bw.writeAll(contents[source_offset..curr]); switch (value) { .undef, .defined => {}, - .boolean => |b| { - try output.append(if (b) '1' else '0'); - }, - .int => |i| { - try output.writer().print("{d}", .{i}); - }, - .ident, .string => |s| { - try output.appendSlice(s); - }, + .boolean => |b| try bw.writeByte(@as(u8, '0') + @intFromBool(b)), + .int => |i| try bw.print("{d}", .{i}), + .ident, .string => |s| try bw.writeAll(s), } curr = close_pos; @@ -661,7 +613,7 @@ fn expand_variables_autoconf_at( } } - try output.appendSlice(contents[source_offset..]); + try bw.writeAll(contents[source_offset..]); } fn expand_variables_cmake( @@ -669,7 +621,7 @@ fn expand_variables_cmake( contents: []const u8, values: std.StringArrayHashMap(Value), ) ![]const u8 { - var result = std.ArrayList(u8).init(allocator); + var result: std.ArrayList(u8) = .init(allocator); errdefer result.deinit(); const valid_varname_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_.+-"; @@ -681,7 +633,7 @@ fn expand_variables_cmake( source: usize, target: usize, }; - var var_stack = std.ArrayList(Position).init(allocator); + var var_stack: std.ArrayList(Position) = .init(allocator); defer var_stack.deinit(); loop: while (curr < contents.len) : (curr += 1) { switch (contents[curr]) { @@ -707,7 +659,7 @@ fn expand_variables_cmake( try result.append(if (b) '1' else '0'); }, .int => |i| { - try result.writer().print("{d}", .{i}); + try result.print("{d}", .{i}); }, .ident, .string => |s| { try result.appendSlice(s); @@ -764,7 +716,7 @@ fn expand_variables_cmake( try result.append(if (b) '1' else '0'); }, .int => |i| { - try result.writer().print("{d}", .{i}); + try result.print("{d}", .{i}); }, .ident, .string => |s| { try result.appendSlice(s); @@ -801,17 +753,17 @@ fn testReplaceVariablesAutoconfAt( expected: []const u8, values: std.StringArrayHashMap(Value), ) !void { - var output = std.ArrayList(u8).init(allocator); + var output: std.io.Writer.Allocating = .init(allocator); defer output.deinit(); const used = try allocator.alloc(bool, values.count()); for (used) |*u| u.* = false; defer allocator.free(used); - try expand_variables_autoconf_at(&output, contents, values, used); + try expand_variables_autoconf_at(&output.interface, contents, values, used); for (used) |u| if (!u) return error.UnusedValue; - try std.testing.expectEqualStrings(expected, output.items); + try std.testing.expectEqualStrings(expected, output.getWritten()); } fn testReplaceVariablesCMake( @@ -828,7 +780,7 @@ fn testReplaceVariablesCMake( test "expand_variables_autoconf_at simple cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); // empty strings are preserved @@ -924,7 +876,7 @@ test "expand_variables_autoconf_at simple cases" { test "expand_variables_autoconf_at edge cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); // @-vars resolved only when they wrap valid characters, otherwise considered literals @@ -940,7 +892,7 @@ test "expand_variables_autoconf_at edge cases" { test "expand_variables_cmake simple cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); try values.putNoClobber("undef", .undef); @@ -1028,7 +980,7 @@ test "expand_variables_cmake simple cases" { test "expand_variables_cmake edge cases" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); // special symbols @@ -1089,7 +1041,7 @@ test "expand_variables_cmake edge cases" { test "expand_variables_cmake escaped characters" { const allocator = std.testing.allocator; - var values = std.StringArrayHashMap(Value).init(allocator); + var values: std.StringArrayHashMap(Value) = .init(allocator); defer values.deinit(); try values.putNoClobber("string", Value{ .string = "text" }); diff --git a/lib/std/Build/Step/InstallArtifact.zig b/lib/std/Build/Step/InstallArtifact.zig index 6a5b834cae..c203ae924b 100644 --- a/lib/std/Build/Step/InstallArtifact.zig +++ b/lib/std/Build/Step/InstallArtifact.zig @@ -164,7 +164,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { const full_h_prefix = b.getInstallPath(h_dir, dir.dest_rel_path); var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { - return step.fail("unable to open source directory '{}': {s}", .{ + return step.fail("unable to open source directory '{f}': {s}", .{ src_dir_path, @errorName(err), }); }; diff --git a/lib/std/Build/Step/InstallDir.zig b/lib/std/Build/Step/InstallDir.zig index ece1184d8f..fd8a7d113f 100644 --- a/lib/std/Build/Step/InstallDir.zig +++ b/lib/std/Build/Step/InstallDir.zig @@ -65,7 +65,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { const src_dir_path = install_dir.options.source_dir.getPath3(b, step); const need_derived_inputs = try step.addDirectoryWatchInput(install_dir.options.source_dir); var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { - return step.fail("unable to open source directory '{}': {s}", .{ + return step.fail("unable to open source directory '{f}': {s}", .{ src_dir_path, @errorName(err), }); }; diff --git a/lib/std/Build/Step/Options.zig b/lib/std/Build/Step/Options.zig index dd09c0b5c0..d52f735f6d 100644 --- a/lib/std/Build/Step/Options.zig +++ b/lib/std/Build/Step/Options.zig @@ -12,23 +12,23 @@ pub const base_id: Step.Id = .options; step: Step, generated_file: GeneratedFile, -contents: std.ArrayList(u8), -args: std.ArrayList(Arg), -encountered_types: std.StringHashMap(void), +contents: std.ArrayListUnmanaged(u8), +args: std.ArrayListUnmanaged(Arg), +encountered_types: std.StringHashMapUnmanaged(void), pub fn create(owner: *std.Build) *Options { const options = owner.allocator.create(Options) catch @panic("OOM"); options.* = .{ - .step = Step.init(.{ + .step = .init(.{ .id = base_id, .name = "options", .owner = owner, .makeFn = make, }), .generated_file = undefined, - .contents = std.ArrayList(u8).init(owner.allocator), - .args = std.ArrayList(Arg).init(owner.allocator), - .encountered_types = std.StringHashMap(void).init(owner.allocator), + .contents = .empty, + .args = .empty, + .encountered_types = .empty, }; options.generated_file = .{ .step = &options.step }; @@ -40,110 +40,119 @@ pub fn addOption(options: *Options, comptime T: type, name: []const u8, value: T } fn addOptionFallible(options: *Options, comptime T: type, name: []const u8, value: T) !void { - const out = options.contents.writer(); - try printType(options, out, T, value, 0, name); + try printType(options, &options.contents, T, value, 0, name); } -fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent: u8, name: ?[]const u8) !void { +fn printType( + options: *Options, + out: *std.ArrayListUnmanaged(u8), + comptime T: type, + value: T, + indent: u8, + name: ?[]const u8, +) !void { + const gpa = options.step.owner.allocator; switch (T) { []const []const u8 => { if (name) |payload| { - try out.print("pub const {}: []const []const u8 = ", .{std.zig.fmtId(payload)}); + try out.print(gpa, "pub const {f}: []const []const u8 = ", .{std.zig.fmtId(payload)}); } - try out.writeAll("&[_][]const u8{\n"); + try out.appendSlice(gpa, "&[_][]const u8{\n"); for (value) |slice| { - try out.writeByteNTimes(' ', indent); - try out.print(" \"{}\",\n", .{std.zig.fmtEscapes(slice)}); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " \"{f}\",\n", .{std.zig.fmtString(slice)}); } if (name != null) { - try out.writeAll("};\n"); + try out.appendSlice(gpa, "};\n"); } else { - try out.writeAll("},\n"); + try out.appendSlice(gpa, "},\n"); } return; }, []const u8 => { if (name) |some| { - try out.print("pub const {}: []const u8 = \"{}\";", .{ std.zig.fmtId(some), std.zig.fmtEscapes(value) }); + try out.print(gpa, "pub const {f}: []const u8 = \"{f}\";", .{ + std.zig.fmtId(some), std.zig.fmtString(value), + }); } else { - try out.print("\"{}\",", .{std.zig.fmtEscapes(value)}); + try out.print(gpa, "\"{f}\",", .{std.zig.fmtString(value)}); } - return out.writeAll("\n"); + return out.appendSlice(gpa, "\n"); }, [:0]const u8 => { if (name) |some| { - try out.print("pub const {}: [:0]const u8 = \"{}\";", .{ std.zig.fmtId(some), std.zig.fmtEscapes(value) }); + try out.print(gpa, "pub const {f}: [:0]const u8 = \"{f}\";", .{ std.zig.fmtId(some), std.zig.fmtString(value) }); } else { - try out.print("\"{}\",", .{std.zig.fmtEscapes(value)}); + try out.print(gpa, "\"{f}\",", .{std.zig.fmtString(value)}); } - return out.writeAll("\n"); + return out.appendSlice(gpa, "\n"); }, ?[]const u8 => { if (name) |some| { - try out.print("pub const {}: ?[]const u8 = ", .{std.zig.fmtId(some)}); + try out.print(gpa, "pub const {f}: ?[]const u8 = ", .{std.zig.fmtId(some)}); } if (value) |payload| { - try out.print("\"{}\"", .{std.zig.fmtEscapes(payload)}); + try out.print(gpa, "\"{f}\"", .{std.zig.fmtString(payload)}); } else { - try out.writeAll("null"); + try out.appendSlice(gpa, "null"); } if (name != null) { - try out.writeAll(";\n"); + try out.appendSlice(gpa, ";\n"); } else { - try out.writeAll(",\n"); + try out.appendSlice(gpa, ",\n"); } return; }, ?[:0]const u8 => { if (name) |some| { - try out.print("pub const {}: ?[:0]const u8 = ", .{std.zig.fmtId(some)}); + try out.print(gpa, "pub const {f}: ?[:0]const u8 = ", .{std.zig.fmtId(some)}); } if (value) |payload| { - try out.print("\"{}\"", .{std.zig.fmtEscapes(payload)}); + try out.print(gpa, "\"{f}\"", .{std.zig.fmtString(payload)}); } else { - try out.writeAll("null"); + try out.appendSlice(gpa, "null"); } if (name != null) { - try out.writeAll(";\n"); + try out.appendSlice(gpa, ";\n"); } else { - try out.writeAll(",\n"); + try out.appendSlice(gpa, ",\n"); } return; }, std.SemanticVersion => { if (name) |some| { - try out.print("pub const {}: @import(\"std\").SemanticVersion = ", .{std.zig.fmtId(some)}); + try out.print(gpa, "pub const {f}: @import(\"std\").SemanticVersion = ", .{std.zig.fmtId(some)}); } - try out.writeAll(".{\n"); - try out.writeByteNTimes(' ', indent); - try out.print(" .major = {d},\n", .{value.major}); - try out.writeByteNTimes(' ', indent); - try out.print(" .minor = {d},\n", .{value.minor}); - try out.writeByteNTimes(' ', indent); - try out.print(" .patch = {d},\n", .{value.patch}); + try out.appendSlice(gpa, ".{\n"); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " .major = {d},\n", .{value.major}); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " .minor = {d},\n", .{value.minor}); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " .patch = {d},\n", .{value.patch}); if (value.pre) |some| { - try out.writeByteNTimes(' ', indent); - try out.print(" .pre = \"{}\",\n", .{std.zig.fmtEscapes(some)}); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " .pre = \"{f}\",\n", .{std.zig.fmtString(some)}); } if (value.build) |some| { - try out.writeByteNTimes(' ', indent); - try out.print(" .build = \"{}\",\n", .{std.zig.fmtEscapes(some)}); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " .build = \"{f}\",\n", .{std.zig.fmtString(some)}); } if (name != null) { - try out.writeAll("};\n"); + try out.appendSlice(gpa, "};\n"); } else { - try out.writeAll("},\n"); + try out.appendSlice(gpa, "},\n"); } return; }, @@ -153,21 +162,21 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent switch (@typeInfo(T)) { .array => { if (name) |some| { - try out.print("pub const {}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) }); + try out.print(gpa, "pub const {f}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) }); } - try out.print("{s} {{\n", .{@typeName(T)}); + try out.print(gpa, "{s} {{\n", .{@typeName(T)}); for (value) |item| { - try out.writeByteNTimes(' ', indent + 4); + try out.appendNTimes(gpa, ' ', indent + 4); try printType(options, out, @TypeOf(item), item, indent + 4, null); } - try out.writeByteNTimes(' ', indent); - try out.writeAll("}"); + try out.appendNTimes(gpa, ' ', indent); + try out.appendSlice(gpa, "}"); if (name != null) { - try out.writeAll(";\n"); + try out.appendSlice(gpa, ";\n"); } else { - try out.writeAll(",\n"); + try out.appendSlice(gpa, ",\n"); } return; }, @@ -177,27 +186,27 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent } if (name) |some| { - try out.print("pub const {}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) }); + try out.print(gpa, "pub const {f}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) }); } - try out.print("&[_]{s} {{\n", .{@typeName(p.child)}); + try out.print(gpa, "&[_]{s} {{\n", .{@typeName(p.child)}); for (value) |item| { - try out.writeByteNTimes(' ', indent + 4); + try out.appendNTimes(gpa, ' ', indent + 4); try printType(options, out, @TypeOf(item), item, indent + 4, null); } - try out.writeByteNTimes(' ', indent); - try out.writeAll("}"); + try out.appendNTimes(gpa, ' ', indent); + try out.appendSlice(gpa, "}"); if (name != null) { - try out.writeAll(";\n"); + try out.appendSlice(gpa, ";\n"); } else { - try out.writeAll(",\n"); + try out.appendSlice(gpa, ",\n"); } return; }, .optional => { if (name) |some| { - try out.print("pub const {}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) }); + try out.print(gpa, "pub const {f}: {s} = ", .{ std.zig.fmtId(some), @typeName(T) }); } if (value) |inner| { @@ -206,13 +215,13 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent _ = options.contents.pop(); _ = options.contents.pop(); } else { - try out.writeAll("null"); + try out.appendSlice(gpa, "null"); } if (name != null) { - try out.writeAll(";\n"); + try out.appendSlice(gpa, ";\n"); } else { - try out.writeAll(",\n"); + try out.appendSlice(gpa, ",\n"); } return; }, @@ -224,9 +233,9 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent .null, => { if (name) |some| { - try out.print("pub const {}: {s} = {any};\n", .{ std.zig.fmtId(some), @typeName(T), value }); + try out.print(gpa, "pub const {f}: {s} = {any};\n", .{ std.zig.fmtId(some), @typeName(T), value }); } else { - try out.print("{any},\n", .{value}); + try out.print(gpa, "{any},\n", .{value}); } return; }, @@ -234,10 +243,10 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent try printEnum(options, out, T, info, indent); if (name) |some| { - try out.print("pub const {}: {} = .{p_};\n", .{ + try out.print(gpa, "pub const {f}: {f} = .{f};\n", .{ std.zig.fmtId(some), std.zig.fmtId(@typeName(T)), - std.zig.fmtId(@tagName(value)), + std.zig.fmtIdFlags(@tagName(value), .{ .allow_underscore = true, .allow_primitive = true }), }); } return; @@ -246,7 +255,7 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent try printStruct(options, out, T, info, indent); if (name) |some| { - try out.print("pub const {}: {} = ", .{ + try out.print(gpa, "pub const {f}: {f} = ", .{ std.zig.fmtId(some), std.zig.fmtId(@typeName(T)), }); @@ -258,7 +267,7 @@ fn printType(options: *Options, out: anytype, comptime T: type, value: T, indent } } -fn printUserDefinedType(options: *Options, out: anytype, comptime T: type, indent: u8) !void { +fn printUserDefinedType(options: *Options, out: *std.ArrayListUnmanaged(u8), comptime T: type, indent: u8) !void { switch (@typeInfo(T)) { .@"enum" => |info| { return try printEnum(options, out, T, info, indent); @@ -270,94 +279,119 @@ fn printUserDefinedType(options: *Options, out: anytype, comptime T: type, inden } } -fn printEnum(options: *Options, out: anytype, comptime T: type, comptime val: std.builtin.Type.Enum, indent: u8) !void { - const gop = try options.encountered_types.getOrPut(@typeName(T)); +fn printEnum( + options: *Options, + out: *std.ArrayListUnmanaged(u8), + comptime T: type, + comptime val: std.builtin.Type.Enum, + indent: u8, +) !void { + const gpa = options.step.owner.allocator; + const gop = try options.encountered_types.getOrPut(gpa, @typeName(T)); if (gop.found_existing) return; - try out.writeByteNTimes(' ', indent); - try out.print("pub const {} = enum ({s}) {{\n", .{ std.zig.fmtId(@typeName(T)), @typeName(val.tag_type) }); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, "pub const {f} = enum ({s}) {{\n", .{ std.zig.fmtId(@typeName(T)), @typeName(val.tag_type) }); inline for (val.fields) |field| { - try out.writeByteNTimes(' ', indent); - try out.print(" {p} = {d},\n", .{ std.zig.fmtId(field.name), field.value }); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " {f} = {d},\n", .{ + std.zig.fmtIdFlags(field.name, .{ .allow_primitive = true }), field.value, + }); } if (!val.is_exhaustive) { - try out.writeByteNTimes(' ', indent); - try out.writeAll(" _,\n"); + try out.appendNTimes(gpa, ' ', indent); + try out.appendSlice(gpa, " _,\n"); } - try out.writeByteNTimes(' ', indent); - try out.writeAll("};\n"); + try out.appendNTimes(gpa, ' ', indent); + try out.appendSlice(gpa, "};\n"); } -fn printStruct(options: *Options, out: anytype, comptime T: type, comptime val: std.builtin.Type.Struct, indent: u8) !void { - const gop = try options.encountered_types.getOrPut(@typeName(T)); +fn printStruct(options: *Options, out: *std.ArrayListUnmanaged(u8), comptime T: type, comptime val: std.builtin.Type.Struct, indent: u8) !void { + const gpa = options.step.owner.allocator; + const gop = try options.encountered_types.getOrPut(gpa, @typeName(T)); if (gop.found_existing) return; - try out.writeByteNTimes(' ', indent); - try out.print("pub const {} = ", .{std.zig.fmtId(@typeName(T))}); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, "pub const {f} = ", .{std.zig.fmtId(@typeName(T))}); switch (val.layout) { - .@"extern" => try out.writeAll("extern struct"), - .@"packed" => try out.writeAll("packed struct"), - else => try out.writeAll("struct"), + .@"extern" => try out.appendSlice(gpa, "extern struct"), + .@"packed" => try out.appendSlice(gpa, "packed struct"), + else => try out.appendSlice(gpa, "struct"), } - try out.writeAll(" {\n"); + try out.appendSlice(gpa, " {\n"); inline for (val.fields) |field| { - try out.writeByteNTimes(' ', indent); + try out.appendNTimes(gpa, ' ', indent); const type_name = @typeName(field.type); // If the type name doesn't contains a '.' the type is from zig builtins. if (std.mem.containsAtLeast(u8, type_name, 1, ".")) { - try out.print(" {p_}: {}", .{ std.zig.fmtId(field.name), std.zig.fmtId(type_name) }); + try out.print(gpa, " {f}: {f}", .{ + std.zig.fmtIdFlags(field.name, .{ .allow_underscore = true, .allow_primitive = true }), + std.zig.fmtId(type_name), + }); } else { - try out.print(" {p_}: {s}", .{ std.zig.fmtId(field.name), type_name }); + try out.print(gpa, " {f}: {s}", .{ + std.zig.fmtIdFlags(field.name, .{ .allow_underscore = true, .allow_primitive = true }), + type_name, + }); } if (field.defaultValue()) |default_value| { - try out.writeAll(" = "); + try out.appendSlice(gpa, " = "); switch (@typeInfo(@TypeOf(default_value))) { - .@"enum" => try out.print(".{s},\n", .{@tagName(default_value)}), + .@"enum" => try out.print(gpa, ".{s},\n", .{@tagName(default_value)}), .@"struct" => |info| { try printStructValue(options, out, info, default_value, indent + 4); }, else => try printType(options, out, @TypeOf(default_value), default_value, indent, null), } } else { - try out.writeAll(",\n"); + try out.appendSlice(gpa, ",\n"); } } // TODO: write declarations - try out.writeByteNTimes(' ', indent); - try out.writeAll("};\n"); + try out.appendNTimes(gpa, ' ', indent); + try out.appendSlice(gpa, "};\n"); inline for (val.fields) |field| { try printUserDefinedType(options, out, field.type, 0); } } -fn printStructValue(options: *Options, out: anytype, comptime struct_val: std.builtin.Type.Struct, val: anytype, indent: u8) !void { - try out.writeAll(".{\n"); +fn printStructValue( + options: *Options, + out: *std.ArrayListUnmanaged(u8), + comptime struct_val: std.builtin.Type.Struct, + val: anytype, + indent: u8, +) !void { + const gpa = options.step.owner.allocator; + try out.appendSlice(gpa, ".{\n"); if (struct_val.is_tuple) { inline for (struct_val.fields) |field| { - try out.writeByteNTimes(' ', indent); + try out.appendNTimes(gpa, ' ', indent); try printType(options, out, @TypeOf(@field(val, field.name)), @field(val, field.name), indent, null); } } else { inline for (struct_val.fields) |field| { - try out.writeByteNTimes(' ', indent); - try out.print(" .{p_} = ", .{std.zig.fmtId(field.name)}); + try out.appendNTimes(gpa, ' ', indent); + try out.print(gpa, " .{f} = ", .{ + std.zig.fmtIdFlags(field.name, .{ .allow_primitive = true, .allow_underscore = true }), + }); const field_name = @field(val, field.name); switch (@typeInfo(@TypeOf(field_name))) { - .@"enum" => try out.print(".{s},\n", .{@tagName(field_name)}), + .@"enum" => try out.print(gpa, ".{s},\n", .{@tagName(field_name)}), .@"struct" => |struct_info| { try printStructValue(options, out, struct_info, field_name, indent + 4); }, @@ -367,10 +401,10 @@ fn printStructValue(options: *Options, out: anytype, comptime struct_val: std.bu } if (indent == 0) { - try out.writeAll("};\n"); + try out.appendSlice(gpa, "};\n"); } else { - try out.writeByteNTimes(' ', indent); - try out.writeAll("},\n"); + try out.appendNTimes(gpa, ' ', indent); + try out.appendSlice(gpa, "},\n"); } } @@ -440,7 +474,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { error.FileNotFound => { const sub_dirname = fs.path.dirname(sub_path).?; b.cache_root.handle.makePath(sub_dirname) catch |e| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.cache_root, sub_dirname, @errorName(e), }); }; @@ -452,13 +486,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { const tmp_sub_path_dirname = fs.path.dirname(tmp_sub_path).?; b.cache_root.handle.makePath(tmp_sub_path_dirname) catch |err| { - return step.fail("unable to make temporary directory '{}{s}': {s}", .{ + return step.fail("unable to make temporary directory '{f}{s}': {s}", .{ b.cache_root, tmp_sub_path_dirname, @errorName(err), }); }; b.cache_root.handle.writeFile(.{ .sub_path = tmp_sub_path, .data = options.contents.items }) catch |err| { - return step.fail("unable to write options to '{}{s}': {s}", .{ + return step.fail("unable to write options to '{f}{s}': {s}", .{ b.cache_root, tmp_sub_path, @errorName(err), }); }; @@ -467,7 +501,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { error.PathAlreadyExists => { // Other process beat us to it. Clean up the temp file. b.cache_root.handle.deleteFile(tmp_sub_path) catch |e| { - try step.addError("warning: unable to delete temp file '{}{s}': {s}", .{ + try step.addError("warning: unable to delete temp file '{f}{s}': {s}", .{ b.cache_root, tmp_sub_path, @errorName(e), }); }; @@ -475,7 +509,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { return; }, else => { - return step.fail("unable to rename options from '{}{s}' to '{}{s}': {s}", .{ + return step.fail("unable to rename options from '{f}{s}' to '{f}{s}': {s}", .{ b.cache_root, tmp_sub_path, b.cache_root, sub_path, @errorName(err), @@ -483,7 +517,7 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void { }, }; }, - else => |e| return step.fail("unable to access options file '{}{s}': {s}", .{ + else => |e| return step.fail("unable to access options file '{f}{s}': {s}", .{ b.cache_root, sub_path, @errorName(e), }), } @@ -643,5 +677,5 @@ test Options { \\ , options.contents.items); - _ = try std.zig.Ast.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(0), .zig); + _ = try std.zig.Ast.parse(arena.allocator(), try options.contents.toOwnedSliceSentinel(arena.allocator(), 0), .zig); } diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index 4b8dabc14e..a835e137cf 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -832,7 +832,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { else => unreachable, }; b.cache_root.handle.makePath(output_sub_dir_path) catch |err| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.cache_root, output_sub_dir_path, @errorName(err), }); }; @@ -864,7 +864,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { else => unreachable, }; b.cache_root.handle.makePath(output_sub_dir_path) catch |err| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.cache_root, output_sub_dir_path, @errorName(err), }); }; @@ -903,21 +903,21 @@ fn make(step: *Step, options: Step.MakeOptions) !void { b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |err| { if (err == error.PathAlreadyExists) { b.cache_root.handle.deleteTree(o_sub_path) catch |del_err| { - return step.fail("unable to remove dir '{}'{s}: {s}", .{ + return step.fail("unable to remove dir '{f}'{s}: {s}", .{ b.cache_root, tmp_dir_path, @errorName(del_err), }); }; b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |retry_err| { - return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{ + return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {s}", .{ b.cache_root, tmp_dir_path, b.cache_root, o_sub_path, @errorName(retry_err), }); }; } else { - return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{ + return step.fail("unable to rename dir '{f}{s}' to '{f}{s}': {s}", .{ b.cache_root, tmp_dir_path, b.cache_root, o_sub_path, @errorName(err), @@ -964,7 +964,7 @@ pub fn rerunInFuzzMode( .artifact => |pa| { const artifact = pa.artifact; const file_path: []const u8 = p: { - if (artifact == run.producer.?) break :p b.fmt("{}", .{run.rebuilt_executable.?}); + if (artifact == run.producer.?) break :p b.fmt("{f}", .{run.rebuilt_executable.?}); break :p artifact.installed_path orelse artifact.generated_bin.?.path.?; }; try argv_list.append(arena, b.fmt("{s}{s}", .{ @@ -1011,24 +1011,17 @@ fn populateGeneratedPaths( } } -fn formatTerm( - term: ?std.process.Child.Term, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = fmt; - _ = options; +fn formatTerm(term: ?std.process.Child.Term, w: *std.io.Writer) std.io.Writer.Error!void { if (term) |t| switch (t) { - .Exited => |code| try writer.print("exited with code {}", .{code}), - .Signal => |sig| try writer.print("terminated with signal {}", .{sig}), - .Stopped => |sig| try writer.print("stopped with signal {}", .{sig}), - .Unknown => |code| try writer.print("terminated for unknown reason with code {}", .{code}), + .Exited => |code| try w.print("exited with code {d}", .{code}), + .Signal => |sig| try w.print("terminated with signal {d}", .{sig}), + .Stopped => |sig| try w.print("stopped with signal {d}", .{sig}), + .Unknown => |code| try w.print("terminated for unknown reason with code {d}", .{code}), } else { - try writer.writeAll("exited with any code"); + try w.writeAll("exited with any code"); } } -fn fmtTerm(term: ?std.process.Child.Term) std.fmt.Formatter(formatTerm) { +fn fmtTerm(term: ?std.process.Child.Term) std.fmt.Formatter(?std.process.Child.Term, formatTerm) { return .{ .data = term }; } @@ -1262,12 +1255,12 @@ fn runCommand( const sub_path = b.pathJoin(&output_components); const sub_path_dirname = fs.path.dirname(sub_path).?; b.cache_root.handle.makePath(sub_path_dirname) catch |err| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.cache_root, sub_path_dirname, @errorName(err), }); }; b.cache_root.handle.writeFile(.{ .sub_path = sub_path, .data = stream.bytes.? }) catch |err| { - return step.fail("unable to write file '{}{s}': {s}", .{ + return step.fail("unable to write file '{f}{s}': {s}", .{ b.cache_root, sub_path, @errorName(err), }); }; @@ -1346,7 +1339,7 @@ fn runCommand( }, .expect_term => |expected_term| { if (!termMatches(expected_term, result.term)) { - return step.fail("the following command {} (expected {}):\n{s}", .{ + return step.fail("the following command {f} (expected {f}):\n{s}", .{ fmtTerm(result.term), fmtTerm(expected_term), try Step.allocPrintCmd(arena, cwd, final_argv), @@ -1366,7 +1359,7 @@ fn runCommand( }; const expected_term: std.process.Child.Term = .{ .Exited = 0 }; if (!termMatches(expected_term, result.term)) { - return step.fail("{s}the following command {} (expected {}):\n{s}", .{ + return step.fail("{s}the following command {f} (expected {f}):\n{s}", .{ prefix, fmtTerm(result.term), fmtTerm(expected_term), @@ -1797,10 +1790,10 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult { stdout_bytes = try poller.fifo(.stdout).toOwnedSlice(); stderr_bytes = try poller.fifo(.stderr).toOwnedSlice(); } else { - stdout_bytes = try stdout.reader().readAllAlloc(arena, run.max_stdio_size); + stdout_bytes = try stdout.deprecatedReader().readAllAlloc(arena, run.max_stdio_size); } } else if (child.stderr) |stderr| { - stderr_bytes = try stderr.reader().readAllAlloc(arena, run.max_stdio_size); + stderr_bytes = try stderr.deprecatedReader().readAllAlloc(arena, run.max_stdio_size); } if (stderr_bytes) |bytes| if (bytes.len > 0) { diff --git a/lib/std/Build/Step/UpdateSourceFiles.zig b/lib/std/Build/Step/UpdateSourceFiles.zig index d4a9565083..674e2a01c6 100644 --- a/lib/std/Build/Step/UpdateSourceFiles.zig +++ b/lib/std/Build/Step/UpdateSourceFiles.zig @@ -76,7 +76,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { for (usf.output_source_files.items) |output_source_file| { if (fs.path.dirname(output_source_file.sub_path)) |dirname| { b.build_root.handle.makePath(dirname) catch |err| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.build_root, dirname, @errorName(err), }); }; @@ -84,7 +84,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { switch (output_source_file.contents) { .bytes => |bytes| { b.build_root.handle.writeFile(.{ .sub_path = output_source_file.sub_path, .data = bytes }) catch |err| { - return step.fail("unable to write file '{}{s}': {s}", .{ + return step.fail("unable to write file '{f}{s}': {s}", .{ b.build_root, output_source_file.sub_path, @errorName(err), }); }; @@ -101,7 +101,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { output_source_file.sub_path, .{}, ) catch |err| { - return step.fail("unable to update file from '{s}' to '{}{s}': {s}", .{ + return step.fail("unable to update file from '{s}' to '{f}{s}': {s}", .{ source_path, b.build_root, output_source_file.sub_path, @errorName(err), }); }; diff --git a/lib/std/Build/Step/WriteFile.zig b/lib/std/Build/Step/WriteFile.zig index 29fba1c871..b1cfb3b42a 100644 --- a/lib/std/Build/Step/WriteFile.zig +++ b/lib/std/Build/Step/WriteFile.zig @@ -217,7 +217,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { const src_dir_path = dir.source.getPath3(b, step); var src_dir = src_dir_path.root_dir.handle.openDir(src_dir_path.subPathOrDot(), .{ .iterate = true }) catch |err| { - return step.fail("unable to open source directory '{}': {s}", .{ + return step.fail("unable to open source directory '{f}': {s}", .{ src_dir_path, @errorName(err), }); }; @@ -258,7 +258,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { write_file.generated_directory.path = try b.cache_root.join(arena, &.{ "o", &digest }); var cache_dir = b.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| { - return step.fail("unable to make path '{}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}': {s}", .{ b.cache_root, cache_path, @errorName(err), }); }; @@ -269,7 +269,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { for (write_file.files.items) |file| { if (fs.path.dirname(file.sub_path)) |dirname| { cache_dir.makePath(dirname) catch |err| { - return step.fail("unable to make path '{}{s}{c}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{ b.cache_root, cache_path, fs.path.sep, dirname, @errorName(err), }); }; @@ -277,7 +277,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { switch (file.contents) { .bytes => |bytes| { cache_dir.writeFile(.{ .sub_path = file.sub_path, .data = bytes }) catch |err| { - return step.fail("unable to write file '{}{s}{c}{s}': {s}", .{ + return step.fail("unable to write file '{f}{s}{c}{s}': {s}", .{ b.cache_root, cache_path, fs.path.sep, file.sub_path, @errorName(err), }); }; @@ -291,7 +291,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { file.sub_path, .{}, ) catch |err| { - return step.fail("unable to update file from '{s}' to '{}{s}{c}{s}': {s}", .{ + return step.fail("unable to update file from '{s}' to '{f}{s}{c}{s}': {s}", .{ source_path, b.cache_root, cache_path, @@ -315,7 +315,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { if (dest_dirname.len != 0) { cache_dir.makePath(dest_dirname) catch |err| { - return step.fail("unable to make path '{}{s}{c}{s}': {s}", .{ + return step.fail("unable to make path '{f}{s}{c}{s}': {s}", .{ b.cache_root, cache_path, fs.path.sep, dest_dirname, @errorName(err), }); }; @@ -338,7 +338,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void { dest_path, .{}, ) catch |err| { - return step.fail("unable to update file from '{}' to '{}{s}{c}{s}': {s}", .{ + return step.fail("unable to update file from '{f}' to '{f}{s}{c}{s}': {s}", .{ src_entry_path, b.cache_root, cache_path, fs.path.sep, dest_path, @errorName(err), }); }; diff --git a/lib/std/Build/Watch.zig b/lib/std/Build/Watch.zig index c48f6a0532..d6dec68806 100644 --- a/lib/std/Build/Watch.zig +++ b/lib/std/Build/Watch.zig @@ -211,7 +211,7 @@ const Os = switch (builtin.os.tag) { .ADD = true, .ONLYDIR = true, }, fan_mask, path.root_dir.handle.fd, path.subPathOrDot()) catch |err| { - fatal("unable to watch {}: {s}", .{ path, @errorName(err) }); + fatal("unable to watch {f}: {s}", .{ path, @errorName(err) }); }; } break :rs &dh_gop.value_ptr.reaction_set; @@ -265,7 +265,7 @@ const Os = switch (builtin.os.tag) { .ONLYDIR = true, }, fan_mask, path.root_dir.handle.fd, path.subPathOrDot()) catch |err| switch (err) { error.FileNotFound => {}, // Expected, harmless. - else => |e| std.log.warn("unable to unwatch '{}': {s}", .{ path, @errorName(e) }), + else => |e| std.log.warn("unable to unwatch '{f}': {s}", .{ path, @errorName(e) }), }; w.dir_table.swapRemoveAt(i); @@ -659,7 +659,7 @@ const Os = switch (builtin.os.tag) { path.root_dir.handle.fd else posix.openat(path.root_dir.handle.fd, path.sub_path, dir_open_flags, 0) catch |err| { - fatal("failed to open directory {}: {s}", .{ path, @errorName(err) }); + fatal("failed to open directory {f}: {s}", .{ path, @errorName(err) }); }; // Empirically the dir has to stay open or else no events are triggered. errdefer if (!skip_open_dir) posix.close(dir_fd); diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig index ed5bfd75b9..c9a866b0c8 100644 --- a/lib/std/Progress.zig +++ b/lib/std/Progress.zig @@ -9,6 +9,7 @@ const Progress = @This(); const posix = std.posix; const is_big_endian = builtin.cpu.arch.endian() == .big; const is_windows = builtin.os.tag == .windows; +const Writer = std.io.Writer; /// `null` if the current node (and its children) should /// not print on update() @@ -606,6 +607,36 @@ pub fn unlockStdErr() void { stderr_mutex.unlock(); } +/// Protected by `stderr_mutex`. +const stderr_writer: *Writer = &stderr_file_writer.interface; +/// Protected by `stderr_mutex`. +var stderr_file_writer: std.fs.File.Writer = .{ + .interface = std.fs.File.Writer.initInterface(&.{}), + .file = if (is_windows) undefined else .stderr(), + .mode = .streaming, +}; + +/// Allows the caller to freely write to the returned `Writer`, +/// initialized with `buffer`, until `unlockStderrWriter` is called. +/// +/// During the lock, any `std.Progress` information is cleared from the terminal. +/// +/// The lock is recursive; the same thread may hold the lock multiple times. +pub fn lockStderrWriter(buffer: []u8) *Writer { + stderr_mutex.lock(); + clearWrittenWithEscapeCodes() catch {}; + if (is_windows) stderr_file_writer.file = .stderr(); + stderr_writer.flush() catch {}; + stderr_writer.buffer = buffer; + return stderr_writer; +} + +pub fn unlockStderrWriter() void { + stderr_writer.flush() catch {}; + stderr_writer.buffer = &.{}; + stderr_mutex.unlock(); +} + fn ipcThreadRun(fd: posix.fd_t) anyerror!void { // Store this data in the thread so that it does not need to be part of the // linker data of the main executable. diff --git a/lib/std/Random/benchmark.zig b/lib/std/Random/benchmark.zig index 853f473b03..3141be3c3c 100644 --- a/lib/std/Random/benchmark.zig +++ b/lib/std/Random/benchmark.zig @@ -122,7 +122,7 @@ fn mode(comptime x: comptime_int) comptime_int { } pub fn main() !void { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); var buffer: [1024]u8 = undefined; var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); diff --git a/lib/std/SemanticVersion.zig b/lib/std/SemanticVersion.zig index 7cb3888e54..50b146d74f 100644 --- a/lib/std/SemanticVersion.zig +++ b/lib/std/SemanticVersion.zig @@ -150,17 +150,11 @@ fn parseNum(text: []const u8) error{ InvalidVersion, Overflow }!usize { }; } -pub fn format( - self: Version, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, -) !void { - _ = options; +pub fn format(self: Version, w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); - try std.fmt.format(out_stream, "{d}.{d}.{d}", .{ self.major, self.minor, self.patch }); - if (self.pre) |pre| try std.fmt.format(out_stream, "-{s}", .{pre}); - if (self.build) |build| try std.fmt.format(out_stream, "+{s}", .{build}); + try w.print("{d}.{d}.{d}", .{ self.major, self.minor, self.patch }); + if (self.pre) |pre| try w.print("-{s}", .{pre}); + if (self.build) |build| try w.print("+{s}", .{build}); } const expect = std.testing.expect; @@ -202,7 +196,7 @@ test format { "1.0.0+0.build.1-rc.10000aaa-kk-0.1", "5.4.0-1018-raspi", "5.7.123", - }) |valid| try std.testing.expectFmt(valid, "{}", .{try parse(valid)}); + }) |valid| try std.testing.expectFmt(valid, "{f}", .{try parse(valid)}); // Invalid version strings should be rejected. for ([_][]const u8{ @@ -269,12 +263,12 @@ test format { // Valid version string that may overflow. const big_valid = "99999999999999999999999.999999999999999999.99999999999999999"; if (parse(big_valid)) |ver| { - try std.testing.expectFmt(big_valid, "{}", .{ver}); + try std.testing.expectFmt(big_valid, "{f}", .{ver}); } else |err| try expect(err == error.Overflow); // Invalid version string that may overflow. const big_invalid = "99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12"; - if (parse(big_invalid)) |ver| std.debug.panic("expected error, found {}", .{ver}) else |_| {} + if (parse(big_invalid)) |ver| std.debug.panic("expected error, found {f}", .{ver}) else |_| {} } test "precedence" { diff --git a/lib/std/Target.zig b/lib/std/Target.zig index c3b37abb7e..91eed5fee9 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -301,29 +301,24 @@ pub const Os = struct { /// This function is defined to serialize a Zig source code representation of this /// type, that, when parsed, will deserialize into the same data. - pub fn format( - ver: WindowsVersion, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(ver: WindowsVersion, w: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { const maybe_name = std.enums.tagName(WindowsVersion, ver); - if (comptime std.mem.eql(u8, fmt_str, "s")) { + if (comptime std.mem.eql(u8, f, "s")) { if (maybe_name) |name| - try writer.print(".{s}", .{name}) + try w.print(".{s}", .{name}) else - try writer.print(".{d}", .{@intFromEnum(ver)}); - } else if (comptime std.mem.eql(u8, fmt_str, "c")) { + try w.print(".{d}", .{@intFromEnum(ver)}); + } else if (comptime std.mem.eql(u8, f, "c")) { if (maybe_name) |name| - try writer.print(".{s}", .{name}) + try w.print(".{s}", .{name}) else - try writer.print("@enumFromInt(0x{X:0>8})", .{@intFromEnum(ver)}); - } else if (fmt_str.len == 0) { + try w.print("@enumFromInt(0x{X:0>8})", .{@intFromEnum(ver)}); + } else if (f.len == 0) { if (maybe_name) |name| - try writer.print("WindowsVersion.{s}", .{name}) + try w.print("WindowsVersion.{s}", .{name}) else - try writer.print("WindowsVersion(0x{X:0>8})", .{@intFromEnum(ver)}); - } else std.fmt.invalidFmtError(fmt_str, ver); + try w.print("WindowsVersion(0x{X:0>8})", .{@intFromEnum(ver)}); + } else std.fmt.invalidFmtError(f, ver); } }; diff --git a/lib/std/Target/Query.zig b/lib/std/Target/Query.zig index e453b70e5c..2d3b0f4436 100644 --- a/lib/std/Target/Query.zig +++ b/lib/std/Target/Query.zig @@ -394,25 +394,24 @@ pub fn canDetectLibC(self: Query) bool { /// Formats a version with the patch component omitted if it is zero, /// unlike SemanticVersion.format which formats all its version components regardless. -fn formatVersion(version: SemanticVersion, writer: anytype) !void { +fn formatVersion(version: SemanticVersion, gpa: Allocator, list: *std.ArrayListUnmanaged(u8)) !void { if (version.patch == 0) { - try writer.print("{d}.{d}", .{ version.major, version.minor }); + try list.print(gpa, "{d}.{d}", .{ version.major, version.minor }); } else { - try writer.print("{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); + try list.print(gpa, "{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); } } -pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 { - if (self.isNativeTriple()) - return allocator.dupe(u8, "native"); +pub fn zigTriple(self: Query, gpa: Allocator) Allocator.Error![]u8 { + if (self.isNativeTriple()) return gpa.dupe(u8, "native"); const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native"; const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native"; - var result = std.ArrayList(u8).init(allocator); - defer result.deinit(); + var result: std.ArrayListUnmanaged(u8) = .empty; + defer result.deinit(gpa); - try result.writer().print("{s}-{s}", .{ arch_name, os_name }); + try result.print(gpa, "{s}-{s}", .{ arch_name, os_name }); // The zig target syntax does not allow specifying a max os version with no min, so // if either are present, we need the min. @@ -420,11 +419,11 @@ pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 { switch (min) { .none => {}, .semver => |v| { - try result.writer().writeAll("."); - try formatVersion(v, result.writer()); + try result.appendSlice(gpa, "."); + try formatVersion(v, gpa, &result); }, .windows => |v| { - try result.writer().print("{s}", .{v}); + try result.print(gpa, "{d}", .{v}); }, } } @@ -432,39 +431,39 @@ pub fn zigTriple(self: Query, allocator: Allocator) Allocator.Error![]u8 { switch (max) { .none => {}, .semver => |v| { - try result.writer().writeAll("..."); - try formatVersion(v, result.writer()); + try result.appendSlice(gpa, "..."); + try formatVersion(v, gpa, &result); }, .windows => |v| { // This is counting on a custom format() function defined on `WindowsVersion` // to add a prefix '.' and make there be a total of three dots. - try result.writer().print("..{s}", .{v}); + try result.print(gpa, "..{d}", .{v}); }, } } if (self.glibc_version) |v| { const name = if (self.abi) |abi| @tagName(abi) else "gnu"; - try result.ensureUnusedCapacity(name.len + 2); + try result.ensureUnusedCapacity(gpa, name.len + 2); result.appendAssumeCapacity('-'); result.appendSliceAssumeCapacity(name); result.appendAssumeCapacity('.'); - try formatVersion(v, result.writer()); + try formatVersion(v, gpa, &result); } else if (self.android_api_level) |lvl| { const name = if (self.abi) |abi| @tagName(abi) else "android"; - try result.ensureUnusedCapacity(name.len + 2); + try result.ensureUnusedCapacity(gpa, name.len + 2); result.appendAssumeCapacity('-'); result.appendSliceAssumeCapacity(name); result.appendAssumeCapacity('.'); - try result.writer().print("{d}", .{lvl}); + try result.print(gpa, "{d}", .{lvl}); } else if (self.abi) |abi| { const name = @tagName(abi); - try result.ensureUnusedCapacity(name.len + 1); + try result.ensureUnusedCapacity(gpa, name.len + 1); result.appendAssumeCapacity('-'); result.appendSliceAssumeCapacity(name); } - return result.toOwnedSlice(); + return result.toOwnedSlice(gpa); } /// Renders the query into a textual representation that can be parsed via the diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index bb46bd3f24..fd2111da71 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -167,7 +167,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void { const file = try std.fs.cwd().openFile(path, .{ .mode = .write_only }); defer file.close(); - try file.writer().writeAll(name); + try file.deprecatedWriter().writeAll(name); return; }, .windows => { @@ -281,7 +281,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co const file = try std.fs.cwd().openFile(path, .{}); defer file.close(); - const data_len = try file.reader().readAll(buffer_ptr[0 .. max_name_len + 1]); + const data_len = try file.deprecatedReader().readAll(buffer_ptr[0 .. max_name_len + 1]); return if (data_len >= 1) buffer[0 .. data_len - 1] else null; }, @@ -1163,7 +1163,7 @@ const LinuxThreadImpl = struct { fn getCurrentId() Id { return tls_thread_id orelse { - const tid = @as(u32, @bitCast(linux.gettid())); + const tid: u32 = @bitCast(linux.gettid()); tls_thread_id = tid; return tid; }; diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index ee0c602125..b1dc845eb5 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -34,27 +34,22 @@ pub const Component = union(enum) { return switch (component) { .raw => |raw| raw, .percent_encoded => |percent_encoded| if (std.mem.indexOfScalar(u8, percent_encoded, '%')) |_| - try std.fmt.allocPrint(arena, "{raw}", .{component}) + try std.fmt.allocPrint(arena, "{fraw}", .{component}) else percent_encoded, }; } - pub fn format( - component: Component, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(component: Component, w: *std.io.Writer, comptime fmt_str: []const u8) std.io.Writer.Error!void { if (fmt_str.len == 0) { - try writer.print("std.Uri.Component{{ .{s} = \"{}\" }}", .{ + try w.print("std.Uri.Component{{ .{s} = \"{f}\" }}", .{ @tagName(component), - std.zig.fmtEscapes(switch (component) { + std.zig.fmtString(switch (component) { .raw, .percent_encoded => |string| string, }), }); } else if (comptime std.mem.eql(u8, fmt_str, "raw")) switch (component) { - .raw => |raw| try writer.writeAll(raw), + .raw => |raw| try w.writeAll(raw), .percent_encoded => |percent_encoded| { var start: usize = 0; var index: usize = 0; @@ -63,51 +58,47 @@ pub const Component = union(enum) { if (percent_encoded.len - index < 2) continue; const percent_encoded_char = std.fmt.parseInt(u8, percent_encoded[index..][0..2], 16) catch continue; - try writer.print("{s}{c}", .{ + try w.print("{s}{c}", .{ percent_encoded[start..percent], percent_encoded_char, }); start = percent + 3; index = percent + 3; } - try writer.writeAll(percent_encoded[start..]); + try w.writeAll(percent_encoded[start..]); }, } else if (comptime std.mem.eql(u8, fmt_str, "%")) switch (component) { - .raw => |raw| try percentEncode(writer, raw, isUnreserved), - .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded), + .raw => |raw| try percentEncode(w, raw, isUnreserved), + .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded), } else if (comptime std.mem.eql(u8, fmt_str, "user")) switch (component) { - .raw => |raw| try percentEncode(writer, raw, isUserChar), - .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded), + .raw => |raw| try percentEncode(w, raw, isUserChar), + .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded), } else if (comptime std.mem.eql(u8, fmt_str, "password")) switch (component) { - .raw => |raw| try percentEncode(writer, raw, isPasswordChar), - .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded), + .raw => |raw| try percentEncode(w, raw, isPasswordChar), + .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded), } else if (comptime std.mem.eql(u8, fmt_str, "host")) switch (component) { - .raw => |raw| try percentEncode(writer, raw, isHostChar), - .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded), + .raw => |raw| try percentEncode(w, raw, isHostChar), + .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded), } else if (comptime std.mem.eql(u8, fmt_str, "path")) switch (component) { - .raw => |raw| try percentEncode(writer, raw, isPathChar), - .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded), + .raw => |raw| try percentEncode(w, raw, isPathChar), + .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded), } else if (comptime std.mem.eql(u8, fmt_str, "query")) switch (component) { - .raw => |raw| try percentEncode(writer, raw, isQueryChar), - .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded), + .raw => |raw| try percentEncode(w, raw, isQueryChar), + .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded), } else if (comptime std.mem.eql(u8, fmt_str, "fragment")) switch (component) { - .raw => |raw| try percentEncode(writer, raw, isFragmentChar), - .percent_encoded => |percent_encoded| try writer.writeAll(percent_encoded), + .raw => |raw| try percentEncode(w, raw, isFragmentChar), + .percent_encoded => |percent_encoded| try w.writeAll(percent_encoded), } else @compileError("invalid format string '" ++ fmt_str ++ "'"); } - pub fn percentEncode( - writer: anytype, - raw: []const u8, - comptime isValidChar: fn (u8) bool, - ) @TypeOf(writer).Error!void { + pub fn percentEncode(w: *std.io.Writer, raw: []const u8, comptime isValidChar: fn (u8) bool) std.io.Writer.Error!void { var start: usize = 0; for (raw, 0..) |char, index| { if (isValidChar(char)) continue; - try writer.print("{s}%{X:0>2}", .{ raw[start..index], char }); + try w.print("{s}%{X:0>2}", .{ raw[start..index], char }); start = index + 1; } - try writer.writeAll(raw[start..]); + try w.writeAll(raw[start..]); } }; @@ -247,11 +238,7 @@ pub const WriteToStreamOptions = struct { port: bool = true, }; -pub fn writeToStream( - uri: Uri, - options: WriteToStreamOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +pub fn writeToStream(uri: Uri, writer: *std.io.Writer, options: WriteToStreamOptions) std.io.Writer.Error!void { if (options.scheme) { try writer.print("{s}:", .{uri.scheme}); if (options.authority and uri.host != null) { @@ -261,39 +248,34 @@ pub fn writeToStream( if (options.authority) { if (options.authentication and uri.host != null) { if (uri.user) |user| { - try writer.print("{user}", .{user}); + try writer.print("{fuser}", .{user}); if (uri.password) |password| { - try writer.print(":{password}", .{password}); + try writer.print(":{fpassword}", .{password}); } try writer.writeByte('@'); } } if (uri.host) |host| { - try writer.print("{host}", .{host}); + try writer.print("{fhost}", .{host}); if (options.port) { if (uri.port) |port| try writer.print(":{d}", .{port}); } } } if (options.path) { - try writer.print("{path}", .{ + try writer.print("{fpath}", .{ if (uri.path.isEmpty()) Uri.Component{ .percent_encoded = "/" } else uri.path, }); if (options.query) { - if (uri.query) |query| try writer.print("?{query}", .{query}); + if (uri.query) |query| try writer.print("?{fquery}", .{query}); } if (options.fragment) { - if (uri.fragment) |fragment| try writer.print("#{fragment}", .{fragment}); + if (uri.fragment) |fragment| try writer.print("#{ffragment}", .{fragment}); } } } -pub fn format( - uri: Uri, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, -) @TypeOf(writer).Error!void { +pub fn format(uri: Uri, writer: *std.io.Writer, comptime fmt_str: []const u8) std.io.Writer.Error!void { const scheme = comptime std.mem.indexOfScalar(u8, fmt_str, ';') != null or fmt_str.len == 0; const authentication = comptime std.mem.indexOfScalar(u8, fmt_str, '@') != null or fmt_str.len == 0; const authority = comptime std.mem.indexOfScalar(u8, fmt_str, '+') != null or fmt_str.len == 0; @@ -301,14 +283,14 @@ pub fn format( const query = comptime std.mem.indexOfScalar(u8, fmt_str, '?') != null or fmt_str.len == 0; const fragment = comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null or fmt_str.len == 0; - return writeToStream(uri, .{ + return writeToStream(uri, writer, .{ .scheme = scheme, .authentication = authentication, .authority = authority, .path = path, .query = query, .fragment = fragment, - }, writer); + }); } /// Parses the URI or returns an error. @@ -447,7 +429,7 @@ test remove_dot_segments { fn merge_paths(base: Component, new: []u8, aux_buf: *[]u8) error{NoSpaceLeft}!Component { var aux = std.io.fixedBufferStream(aux_buf.*); if (!base.isEmpty()) { - try aux.writer().print("{path}", .{base}); + try aux.writer().print("{fpath}", .{base}); aux.pos = std.mem.lastIndexOfScalar(u8, aux.getWritten(), '/') orelse return remove_dot_segments(new); } @@ -812,7 +794,7 @@ test "Special test" { test "URI percent encoding" { try std.testing.expectFmt( "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad", - "{%}", + "{f%}", .{Component{ .raw = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad" }}, ); } @@ -822,7 +804,7 @@ test "URI percent decoding" { const expected = "\\ö/ äöß ~~.adas-https://canvas:123/#ads&&sad"; var input = "%5C%C3%B6%2F%20%C3%A4%C3%B6%C3%9F%20~~.adas-https%3A%2F%2Fcanvas%3A123%2F%23ads%26%26sad".*; - try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }}); + try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }}); var output: [expected.len]u8 = undefined; try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected); @@ -834,7 +816,7 @@ test "URI percent decoding" { const expected = "/abc%"; var input = expected.*; - try std.testing.expectFmt(expected, "{raw}", .{Component{ .percent_encoded = &input }}); + try std.testing.expectFmt(expected, "{fraw}", .{Component{ .percent_encoded = &input }}); var output: [expected.len]u8 = undefined; try std.testing.expectEqualStrings(percentDecodeBackwards(&output, &input), expected); @@ -848,7 +830,7 @@ test "URI query encoding" { const parsed = try Uri.parse(address); // format the URI to percent encode it - try std.testing.expectFmt("/?response-content-type=application%2Foctet-stream", "{/?}", .{parsed}); + try std.testing.expectFmt("/?response-content-type=application%2Foctet-stream", "{f/?}", .{parsed}); } test "format" { @@ -862,7 +844,7 @@ test "format" { .query = null, .fragment = null, }; - try std.testing.expectFmt("file:/foo/bar/baz", "{;/?#}", .{uri}); + try std.testing.expectFmt("file:/foo/bar/baz", "{f;/?#}", .{uri}); } test "URI malformed input" { diff --git a/lib/std/ascii.zig b/lib/std/ascii.zig index a88b637ec0..2078d00fdf 100644 --- a/lib/std/ascii.zig +++ b/lib/std/ascii.zig @@ -435,3 +435,44 @@ pub fn orderIgnoreCase(lhs: []const u8, rhs: []const u8) std.math.Order { pub fn lessThanIgnoreCase(lhs: []const u8, rhs: []const u8) bool { return orderIgnoreCase(lhs, rhs) == .lt; } + +pub const HexEscape = struct { + bytes: []const u8, + charset: *const [16]u8, + + pub const upper_charset = "0123456789ABCDEF"; + pub const lower_charset = "0123456789abcdef"; + + pub fn format(se: HexEscape, w: *std.io.Writer) std.io.Writer.Error!void { + const charset = se.charset; + + var buf: [4]u8 = undefined; + buf[0] = '\\'; + buf[1] = 'x'; + + for (se.bytes) |c| { + if (std.ascii.isPrint(c)) { + try w.writeByte(c); + } else { + buf[2] = charset[c >> 4]; + buf[3] = charset[c & 15]; + try w.writeAll(&buf); + } + } + } +}; + +/// Replaces non-ASCII bytes with hex escapes. +pub fn hexEscape(bytes: []const u8, case: std.fmt.Case) std.fmt.Formatter(HexEscape, HexEscape.format) { + return .{ .data = .{ .bytes = bytes, .charset = switch (case) { + .lower => HexEscape.lower_charset, + .upper => HexEscape.upper_charset, + } } }; +} + +test hexEscape { + try std.testing.expectFmt("abc 123", "{f}", .{hexEscape("abc 123", .lower)}); + try std.testing.expectFmt("ab\\xffc", "{f}", .{hexEscape("ab\xffc", .lower)}); + try std.testing.expectFmt("abc 123", "{f}", .{hexEscape("abc 123", .upper)}); + try std.testing.expectFmt("ab\\xFFc", "{f}", .{hexEscape("ab\xffc", .upper)}); +} diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 40439dcbe0..03b4db10bb 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -34,20 +34,14 @@ pub const StackTrace = struct { index: usize, instruction_addresses: []usize, - pub fn format( - self: StackTrace, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); + pub fn format(self: StackTrace, writer: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + if (fmt.len != 0) unreachable; // TODO: re-evaluate whether to use format() methods at all. // Until then, avoid an error when using GeneralPurposeAllocator with WebAssembly // where it tries to call detectTTYConfig here. if (builtin.os.tag == .freestanding) return; - _ = options; const debug_info = std.debug.getSelfDebugInfo() catch |err| { return writer.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}); }; diff --git a/lib/std/crypto/25519/curve25519.zig b/lib/std/crypto/25519/curve25519.zig index 313dd577b0..825f0bd94c 100644 --- a/lib/std/crypto/25519/curve25519.zig +++ b/lib/std/crypto/25519/curve25519.zig @@ -124,9 +124,9 @@ test "curve25519" { const p = try Curve25519.basePoint.clampedMul(s); try p.rejectIdentity(); var buf: [128]u8 = undefined; - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&p.toBytes()}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145"); const q = try p.clampedMul(s); - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&q.toBytes()}), "3614E119FFE55EC55B87D6B19971A9F4CBC78EFE80BEC55B96392BABCC712537"); try Curve25519.rejectNonCanonical(s); s[31] |= 0x80; diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index 94dd370d01..8151228bf2 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -509,8 +509,8 @@ test "key pair creation" { _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); const key_pair = try Ed25519.KeyPair.generateDeterministic(seed); var buf: [256]u8 = undefined; - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.secret_key.toBytes())}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083"); - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key.toBytes())}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&key_pair.secret_key.toBytes()}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&key_pair.public_key.toBytes()}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083"); } test "signature" { @@ -520,7 +520,7 @@ test "signature" { const sig = try key_pair.sign("test", null); var buf: [128]u8 = undefined; - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&sig.toBytes())}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&sig.toBytes()}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808"); try sig.verify("test", key_pair.public_key); try std.testing.expectError(error.SignatureVerificationFailed, sig.verify("TEST", key_pair.public_key)); } diff --git a/lib/std/crypto/25519/edwards25519.zig b/lib/std/crypto/25519/edwards25519.zig index 527536f17d..47c07939ac 100644 --- a/lib/std/crypto/25519/edwards25519.zig +++ b/lib/std/crypto/25519/edwards25519.zig @@ -546,7 +546,7 @@ test "packing/unpacking" { var b = Edwards25519.basePoint; const pk = try b.mul(s); var buf: [128]u8 = undefined; - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&pk.toBytes())}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&pk.toBytes()}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6"); const small_order_ss: [7][32]u8 = .{ .{ diff --git a/lib/std/crypto/25519/ristretto255.zig b/lib/std/crypto/25519/ristretto255.zig index 5a00bf523a..dd1a8a236e 100644 --- a/lib/std/crypto/25519/ristretto255.zig +++ b/lib/std/crypto/25519/ristretto255.zig @@ -175,21 +175,21 @@ pub const Ristretto255 = struct { test "ristretto255" { const p = Ristretto255.basePoint; var buf: [256]u8 = undefined; - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&p.toBytes())}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76"); var r: [Ristretto255.encoded_length]u8 = undefined; _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919"); var q = try Ristretto255.fromBytes(r); q = q.dbl().add(p); - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&q.toBytes())}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E"); const s = [_]u8{15} ++ [_]u8{0} ** 31; const w = try p.mul(s); - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&w.toBytes())}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&w.toBytes()}), "E0C418F7C8D9C4CDD7395B93EA124F3AD99021BB681DFC3302A9D99A2E53E64E"); try std.testing.expect(p.dbl().dbl().dbl().dbl().equivalent(w.add(p))); const h = [_]u8{69} ** 32 ++ [_]u8{42} ** 32; const ph = Ristretto255.fromUniform(h); - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&ph.toBytes())}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&ph.toBytes()}), "DCCA54E037A4311EFBEEF413ACD21D35276518970B7A61DC88F8587B493D5E19"); } diff --git a/lib/std/crypto/25519/scalar.zig b/lib/std/crypto/25519/scalar.zig index e7e74bf618..b07b1c774c 100644 --- a/lib/std/crypto/25519/scalar.zig +++ b/lib/std/crypto/25519/scalar.zig @@ -850,10 +850,10 @@ test "scalar25519" { var y = x.toBytes(); try rejectNonCanonical(y); var buf: [128]u8 = undefined; - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&y)}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&y}), "1E979B917937F3DE71D18077F961F6CEFF01030405060708010203040506070F"); const reduced = reduce(field_order_s); - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&reduced)}), "0000000000000000000000000000000000000000000000000000000000000000"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&reduced}), "0000000000000000000000000000000000000000000000000000000000000000"); } test "non-canonical scalar25519" { @@ -867,7 +867,7 @@ test "mulAdd overflow check" { const c: [32]u8 = [_]u8{0xff} ** 32; const x = mulAdd(a, b, c); var buf: [128]u8 = undefined; - try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&x)}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903"); + try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&x}), "D14DF91389432C25AD60FF9791B9FD1D67BEF517D273ECCE3D9A307C1B419903"); } test "scalar field inversion" { diff --git a/lib/std/crypto/benchmark.zig b/lib/std/crypto/benchmark.zig index 31c8e3376c..d064149778 100644 --- a/lib/std/crypto/benchmark.zig +++ b/lib/std/crypto/benchmark.zig @@ -458,7 +458,7 @@ fn mode(comptime x: comptime_int) comptime_int { } pub fn main() !void { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index 287e664c2b..c605a6cb34 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -1145,7 +1145,7 @@ test "xchacha20" { var c: [m.len]u8 = undefined; XChaCha20IETF.xor(c[0..], m[0..], 0, key, nonce); var buf: [2 * c.len]u8 = undefined; - try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D"); + try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&c}), "E0A1BCF939654AFDBDC1746EC49832647C19D891F0D1A81FC0C1703B4514BDEA584B512F6908C2C5E9DD18D5CBC1805DE5803FE3B9CA5F193FB8359E91FAB0C3BB40309A292EB1CF49685C65C4A3ADF4F11DB0CD2B6B67FBC174BC2E860E8F769FD3565BBFAD1C845E05A0FED9BE167C240D"); } { const ad = "Additional data"; @@ -1154,7 +1154,7 @@ test "xchacha20" { var out: [m.len]u8 = undefined; try XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key); var buf: [2 * c.len]u8 = undefined; - try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&c)}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234"); + try testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{&c}), "994D2DD32333F48E53650C02C7A2ABB8E018B0836D7175AEC779F52E961780768F815C58F1AA52D211498DB89B9216763F569C9433A6BBFCEFB4D4A49387A4C5207FBB3B5A92B5941294DF30588C6740D39DC16FA1F0E634F7246CF7CDCB978E44347D89381B7A74EB7084F754B90BDE9AAF5A94B8F2A85EFD0B50692AE2D425E234"); try testing.expectEqualSlices(u8, out[0..], m); c[0] +%= 1; try testing.expectError(error.AuthenticationFailed, XChaCha20Poly1305.decrypt(out[0..], c[0..m.len], c[m.len..].*, ad, nonce, key)); diff --git a/lib/std/crypto/ml_kem.zig b/lib/std/crypto/ml_kem.zig index 99cb493b34..4c19095523 100644 --- a/lib/std/crypto/ml_kem.zig +++ b/lib/std/crypto/ml_kem.zig @@ -1737,11 +1737,11 @@ test "NIST KAT test" { var f = sha2.Sha256.init(.{}); const fw = f.writer(); var g = NistDRBG.init(seed); - try std.fmt.format(fw, "# {s}\n\n", .{mode.name}); + try std.fmt.deprecatedFormat(fw, "# {s}\n\n", .{mode.name}); for (0..100) |i| { g.fill(&seed); - try std.fmt.format(fw, "count = {}\n", .{i}); - try std.fmt.format(fw, "seed = {s}\n", .{std.fmt.fmtSliceHexUpper(&seed)}); + try std.fmt.deprecatedFormat(fw, "count = {}\n", .{i}); + try std.fmt.deprecatedFormat(fw, "seed = {X}\n", .{&seed}); var g2 = NistDRBG.init(seed); // This is not equivalent to g2.fill(kseed[:]). As the reference @@ -1756,16 +1756,16 @@ test "NIST KAT test" { const e = kp.public_key.encaps(eseed); const ss2 = try kp.secret_key.decaps(&e.ciphertext); try testing.expectEqual(ss2, e.shared_secret); - try std.fmt.format(fw, "pk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.public_key.toBytes())}); - try std.fmt.format(fw, "sk = {s}\n", .{std.fmt.fmtSliceHexUpper(&kp.secret_key.toBytes())}); - try std.fmt.format(fw, "ct = {s}\n", .{std.fmt.fmtSliceHexUpper(&e.ciphertext)}); - try std.fmt.format(fw, "ss = {s}\n\n", .{std.fmt.fmtSliceHexUpper(&e.shared_secret)}); + try std.fmt.deprecatedFormat(fw, "pk = {X}\n", .{&kp.public_key.toBytes()}); + try std.fmt.deprecatedFormat(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()}); + try std.fmt.deprecatedFormat(fw, "ct = {X}\n", .{&e.ciphertext}); + try std.fmt.deprecatedFormat(fw, "ss = {X}\n\n", .{&e.shared_secret}); } var out: [32]u8 = undefined; f.final(&out); var outHex: [64]u8 = undefined; - _ = try std.fmt.bufPrint(&outHex, "{s}", .{std.fmt.fmtSliceHexLower(&out)}); + _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out}); try testing.expectEqual(outHex, modeHash[1].*); } } diff --git a/lib/std/crypto/tls/Client.zig b/lib/std/crypto/tls/Client.zig index bd5a74c2cb..d0cf762521 100644 --- a/lib/std/crypto/tls/Client.zig +++ b/lib/std/crypto/tls/Client.zig @@ -1512,11 +1512,11 @@ fn logSecrets(key_log_file: std.fs.File, context: anytype, secrets: anytype) voi const locked = if (key_log_file.lock(.exclusive)) |_| true else |_| false; defer if (locked) key_log_file.unlock(); key_log_file.seekFromEnd(0) catch {}; - inline for (@typeInfo(@TypeOf(secrets)).@"struct".fields) |field| key_log_file.writer().print("{s}" ++ - (if (@hasField(@TypeOf(context), "counter")) "_{d}" else "") ++ " {} {}\n", .{field.name} ++ + inline for (@typeInfo(@TypeOf(secrets)).@"struct".fields) |field| key_log_file.deprecatedWriter().print("{s}" ++ + (if (@hasField(@TypeOf(context), "counter")) "_{d}" else "") ++ " {x} {x}\n", .{field.name} ++ (if (@hasField(@TypeOf(context), "counter")) .{context.counter} else .{}) ++ .{ - std.fmt.fmtSliceHexLower(context.client_random), - std.fmt.fmtSliceHexLower(@field(secrets, field.name)), + context.client_random, + @field(secrets, field.name), }) catch {}; } diff --git a/lib/std/debug.zig b/lib/std/debug.zig index f2b8fcc889..60288bdecc 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -12,6 +12,7 @@ const windows = std.os.windows; const native_arch = builtin.cpu.arch; const native_os = builtin.os.tag; const native_endian = native_arch.endian(); +const Writer = std.io.Writer; pub const MemoryAccessor = @import("debug/MemoryAccessor.zig"); pub const FixedBufferReader = @import("debug/FixedBufferReader.zig"); @@ -204,13 +205,26 @@ pub fn unlockStdErr() void { std.Progress.unlockStdErr(); } +/// Allows the caller to freely write to stderr until `unlockStdErr` is called. +/// +/// During the lock, any `std.Progress` information is cleared from the terminal. +/// +/// Returns a `Writer` with empty buffer, meaning that it is +/// in fact unbuffered and does not need to be flushed. +pub fn lockStderrWriter(buffer: []u8) *Writer { + return std.Progress.lockStderrWriter(buffer); +} + +pub fn unlockStderrWriter() void { + std.Progress.unlockStderrWriter(); +} + /// Print to stderr, unbuffered, and silently returning on failure. Intended -/// for use in "printf debugging." Use `std.log` functions for proper logging. +/// for use in "printf debugging". Use `std.log` functions for proper logging. pub fn print(comptime fmt: []const u8, args: anytype) void { - lockStdErr(); - defer unlockStdErr(); - const stderr = fs.File.stderr().writer(); - nosuspend stderr.print(fmt, args) catch return; + const bw = lockStderrWriter(&.{}); + defer unlockStderrWriter(); + nosuspend bw.print(fmt, args) catch return; } pub fn getStderrMutex() *std.Thread.Mutex { @@ -232,50 +246,44 @@ pub fn getSelfDebugInfo() !*SelfInfo { /// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned. /// Obtains the stderr mutex while dumping. pub fn dumpHex(bytes: []const u8) void { - lockStdErr(); - defer unlockStdErr(); - dumpHexFallible(bytes) catch {}; + const bw = lockStderrWriter(&.{}); + defer unlockStderrWriter(); + const ttyconf = std.io.tty.detectConfig(.stderr()); + dumpHexFallible(bw, ttyconf, bytes) catch {}; } -/// Prints a hexadecimal view of the bytes, unbuffered, returning any error that occurs. -pub fn dumpHexFallible(bytes: []const u8) !void { - const stderr: fs.File = .stderr(); - const ttyconf = std.io.tty.detectConfig(stderr); - const writer = stderr.writer(); - try dumpHexInternal(bytes, ttyconf, writer); -} - -fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytype) !void { +/// Prints a hexadecimal view of the bytes, returning any error that occurs. +pub fn dumpHexFallible(bw: *Writer, ttyconf: std.io.tty.Config, bytes: []const u8) !void { var chunks = mem.window(u8, bytes, 16, 16); while (chunks.next()) |window| { // 1. Print the address. const address = (@intFromPtr(bytes.ptr) + 0x10 * (std.math.divCeil(usize, chunks.index orelse bytes.len, 16) catch unreachable)) - 0x10; - try ttyconf.setColor(writer, .dim); + try ttyconf.setColor(bw, .dim); // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more. // Also, make sure all lines are aligned by padding the address. - try writer.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 }); - try ttyconf.setColor(writer, .reset); + try bw.print("{x:0>[1]} ", .{ address, @sizeOf(usize) * 2 }); + try ttyconf.setColor(bw, .reset); // 2. Print the bytes. for (window, 0..) |byte, index| { - try writer.print("{X:0>2} ", .{byte}); - if (index == 7) try writer.writeByte(' '); + try bw.print("{X:0>2} ", .{byte}); + if (index == 7) try bw.writeByte(' '); } - try writer.writeByte(' '); + try bw.writeByte(' '); if (window.len < 16) { var missing_columns = (16 - window.len) * 3; if (window.len < 8) missing_columns += 1; - try writer.writeByteNTimes(' ', missing_columns); + try bw.splatByteAll(' ', missing_columns); } // 3. Print the characters. for (window) |byte| { if (std.ascii.isPrint(byte)) { - try writer.writeByte(byte); + try bw.writeByte(byte); } else { // Related: https://github.com/ziglang/zig/issues/7600 if (ttyconf == .windows_api) { - try writer.writeByte('.'); + try bw.writeByte('.'); continue; } @@ -283,22 +291,23 @@ fn dumpHexInternal(bytes: []const u8, ttyconf: std.io.tty.Config, writer: anytyp // We don't want to do this for all control codes because most control codes apart from // the ones that Zig has escape sequences for are likely not very useful to print as symbols. switch (byte) { - '\n' => try writer.writeAll("␊"), - '\r' => try writer.writeAll("␍"), - '\t' => try writer.writeAll("␉"), - else => try writer.writeByte('.'), + '\n' => try bw.writeAll("␊"), + '\r' => try bw.writeAll("␍"), + '\t' => try bw.writeAll("␉"), + else => try bw.writeByte('.'), } } } - try writer.writeByte('\n'); + try bw.writeByte('\n'); } } -test dumpHexInternal { +test dumpHexFallible { const bytes: []const u8 = &.{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x12, 0x13 }; - var output = std.ArrayList(u8).init(std.testing.allocator); - defer output.deinit(); - try dumpHexInternal(bytes, .no_color, output.writer()); + var aw: std.io.Writer.Allocating = .init(std.testing.allocator); + defer aw.deinit(); + + try dumpHexFallible(&aw.interface, .no_color, bytes); const expected = try std.fmt.allocPrint(std.testing.allocator, \\{x:0>[2]} 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........ \\{x:0>[2]} 01 12 13 ... @@ -309,34 +318,36 @@ test dumpHexInternal { @sizeOf(usize) * 2, }); defer std.testing.allocator.free(expected); - try std.testing.expectEqualStrings(expected, output.items); + try std.testing.expectEqualStrings(expected, aw.getWritten()); } /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. -/// TODO multithreaded awareness pub fn dumpCurrentStackTrace(start_addr: ?usize) void { - nosuspend { - if (builtin.target.cpu.arch.isWasm()) { - if (native_os == .wasi) { - const stderr = fs.File.stderr().writer(); - stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return; - } - return; + const stderr = lockStderrWriter(&.{}); + defer unlockStderrWriter(); + nosuspend dumpCurrentStackTraceToWriter(start_addr, stderr) catch return; +} + +/// Prints the current stack trace to the provided writer. +pub fn dumpCurrentStackTraceToWriter(start_addr: ?usize, writer: *Writer) !void { + if (builtin.target.cpu.arch.isWasm()) { + if (native_os == .wasi) { + try writer.writeAll("Unable to dump stack trace: not implemented for Wasm\n"); } - const stderr = fs.File.stderr().writer(); - if (builtin.strip_debug_info) { - stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return; - return; - } - const debug_info = getSelfDebugInfo() catch |err| { - stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; - return; - }; - writeCurrentStackTrace(stderr, debug_info, io.tty.detectConfig(fs.File.stderr()), start_addr) catch |err| { - stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return; - return; - }; + return; } + if (builtin.strip_debug_info) { + try writer.writeAll("Unable to dump stack trace: debug info stripped\n"); + return; + } + const debug_info = getSelfDebugInfo() catch |err| { + try writer.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}); + return; + }; + writeCurrentStackTrace(writer, debug_info, io.tty.detectConfig(.stderr()), start_addr) catch |err| { + try writer.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}); + return; + }; } pub const have_ucontext = posix.ucontext_t != void; @@ -402,16 +413,14 @@ pub inline fn getContext(context: *ThreadContext) bool { /// Tries to print the stack trace starting from the supplied base pointer to stderr, /// unbuffered, and ignores any error returned. /// TODO multithreaded awareness -pub fn dumpStackTraceFromBase(context: *ThreadContext) void { +pub fn dumpStackTraceFromBase(context: *ThreadContext, stderr: *Writer) void { nosuspend { if (builtin.target.cpu.arch.isWasm()) { if (native_os == .wasi) { - const stderr = fs.File.stderr().writer(); stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return; } return; } - const stderr = fs.File.stderr().writer(); if (builtin.strip_debug_info) { stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return; return; @@ -420,7 +429,7 @@ pub fn dumpStackTraceFromBase(context: *ThreadContext) void { stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; return; }; - const tty_config = io.tty.detectConfig(fs.File.stderr()); + const tty_config = io.tty.detectConfig(.stderr()); if (native_os == .windows) { // On x86_64 and aarch64, the stack will be unwound using RtlVirtualUnwind using the context // provided by the exception handler. On x86, RtlVirtualUnwind doesn't exist. Instead, a new backtrace @@ -510,21 +519,23 @@ pub fn dumpStackTrace(stack_trace: std.builtin.StackTrace) void { nosuspend { if (builtin.target.cpu.arch.isWasm()) { if (native_os == .wasi) { - const stderr = fs.File.stderr().writer(); - stderr.print("Unable to dump stack trace: not implemented for Wasm\n", .{}) catch return; + const stderr = lockStderrWriter(&.{}); + defer unlockStderrWriter(); + stderr.writeAll("Unable to dump stack trace: not implemented for Wasm\n") catch return; } return; } - const stderr = fs.File.stderr().writer(); + const stderr = lockStderrWriter(&.{}); + defer unlockStderrWriter(); if (builtin.strip_debug_info) { - stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return; + stderr.writeAll("Unable to dump stack trace: debug info stripped\n") catch return; return; } const debug_info = getSelfDebugInfo() catch |err| { stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; return; }; - writeStackTrace(stack_trace, stderr, debug_info, io.tty.detectConfig(fs.File.stderr())) catch |err| { + writeStackTrace(stack_trace, stderr, debug_info, io.tty.detectConfig(.stderr())) catch |err| { stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return; return; }; @@ -573,14 +584,13 @@ pub fn panicExtra( const size = 0x1000; const trunc_msg = "(msg truncated)"; var buf: [size + trunc_msg.len]u8 = undefined; + var bw: Writer = .fixed(buf[0..size]); // a minor annoyance with this is that it will result in the NoSpaceLeft // error being part of the @panic stack trace (but that error should // only happen rarely) - const msg = std.fmt.bufPrint(buf[0..size], format, args) catch |err| switch (err) { - error.NoSpaceLeft => blk: { - @memcpy(buf[size..], trunc_msg); - break :blk &buf; - }, + const msg = if (bw.print(format, args)) |_| bw.buffered() else |_| blk: { + @memcpy(buf[size..], trunc_msg); + break :blk &buf; }; std.builtin.panic.call(msg, ret_addr); } @@ -675,10 +685,9 @@ pub fn defaultPanic( _ = panicking.fetchAdd(1, .seq_cst); { - lockStdErr(); - defer unlockStdErr(); + const stderr = lockStderrWriter(&.{}); + defer unlockStderrWriter(); - const stderr = fs.File.stderr().writer(); if (builtin.single_threaded) { stderr.print("panic: ", .{}) catch posix.abort(); } else { @@ -688,7 +697,7 @@ pub fn defaultPanic( stderr.print("{s}\n", .{msg}) catch posix.abort(); if (@errorReturnTrace()) |t| dumpStackTrace(t.*); - dumpCurrentStackTrace(first_trace_addr orelse @returnAddress()); + dumpCurrentStackTraceToWriter(first_trace_addr orelse @returnAddress(), stderr) catch {}; } waitForOtherThreadToFinishPanicking(); @@ -723,7 +732,7 @@ fn waitForOtherThreadToFinishPanicking() void { pub fn writeStackTrace( stack_trace: std.builtin.StackTrace, - out_stream: anytype, + writer: *Writer, debug_info: *SelfInfo, tty_config: io.tty.Config, ) !void { @@ -736,15 +745,15 @@ pub fn writeStackTrace( frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; }) { const return_address = stack_trace.instruction_addresses[frame_index]; - try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config); + try printSourceAtAddress(debug_info, writer, return_address - 1, tty_config); } if (stack_trace.index > stack_trace.instruction_addresses.len) { const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len; - tty_config.setColor(out_stream, .bold) catch {}; - try out_stream.print("({d} additional stack frames skipped...)\n", .{dropped_frames}); - tty_config.setColor(out_stream, .reset) catch {}; + tty_config.setColor(writer, .bold) catch {}; + try writer.print("({d} additional stack frames skipped...)\n", .{dropped_frames}); + tty_config.setColor(writer, .reset) catch {}; } } @@ -954,7 +963,7 @@ pub const StackIterator = struct { }; pub fn writeCurrentStackTrace( - out_stream: anytype, + writer: *Writer, debug_info: *SelfInfo, tty_config: io.tty.Config, start_addr: ?usize, @@ -962,7 +971,7 @@ pub fn writeCurrentStackTrace( if (native_os == .windows) { var context: ThreadContext = undefined; assert(getContext(&context)); - return writeStackTraceWindows(out_stream, debug_info, tty_config, &context, start_addr); + return writeStackTraceWindows(writer, debug_info, tty_config, &context, start_addr); } var context: ThreadContext = undefined; const has_context = getContext(&context); @@ -973,7 +982,7 @@ pub fn writeCurrentStackTrace( defer it.deinit(); while (it.next()) |return_address| { - printLastUnwindError(&it, debug_info, out_stream, tty_config); + printLastUnwindError(&it, debug_info, writer, tty_config); // On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS, // therefore, we do a check for `return_address == 0` before subtracting 1 from it to avoid @@ -981,8 +990,8 @@ pub fn writeCurrentStackTrace( // condition on the subsequent iteration and return `null` thus terminating the loop. // same behaviour for x86-windows-msvc const address = return_address -| 1; - try printSourceAtAddress(debug_info, out_stream, address, tty_config); - } else printLastUnwindError(&it, debug_info, out_stream, tty_config); + try printSourceAtAddress(debug_info, writer, address, tty_config); + } else printLastUnwindError(&it, debug_info, writer, tty_config); } pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const windows.CONTEXT) usize { @@ -1042,7 +1051,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w } pub fn writeStackTraceWindows( - out_stream: anytype, + writer: *Writer, debug_info: *SelfInfo, tty_config: io.tty.Config, context: *const windows.CONTEXT, @@ -1058,14 +1067,14 @@ pub fn writeStackTraceWindows( return; } else 0; for (addrs[start_i..]) |addr| { - try printSourceAtAddress(debug_info, out_stream, addr - 1, tty_config); + try printSourceAtAddress(debug_info, writer, addr - 1, tty_config); } } -fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void { +fn printUnknownSource(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: io.tty.Config) !void { const module_name = debug_info.getModuleNameForAddress(address); return printLineInfo( - out_stream, + writer, null, address, "???", @@ -1075,38 +1084,38 @@ fn printUnknownSource(debug_info: *SelfInfo, out_stream: anytype, address: usize ); } -fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, out_stream: anytype, tty_config: io.tty.Config) void { +fn printLastUnwindError(it: *StackIterator, debug_info: *SelfInfo, writer: *Writer, tty_config: io.tty.Config) void { if (!have_ucontext) return; if (it.getLastError()) |unwind_error| { - printUnwindError(debug_info, out_stream, unwind_error.address, unwind_error.err, tty_config) catch {}; + printUnwindError(debug_info, writer, unwind_error.address, unwind_error.err, tty_config) catch {}; } } -fn printUnwindError(debug_info: *SelfInfo, out_stream: anytype, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { +fn printUnwindError(debug_info: *SelfInfo, writer: *Writer, address: usize, err: UnwindError, tty_config: io.tty.Config) !void { const module_name = debug_info.getModuleNameForAddress(address) orelse "???"; - try tty_config.setColor(out_stream, .dim); + try tty_config.setColor(writer, .dim); if (err == error.MissingDebugInfo) { - try out_stream.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); + try writer.print("Unwind information for `{s}:0x{x}` was not available, trace may be incomplete\n\n", .{ module_name, address }); } else { - try out_stream.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err }); + try writer.print("Unwind error at address `{s}:0x{x}` ({}), trace may be incomplete\n\n", .{ module_name, address, err }); } - try tty_config.setColor(out_stream, .reset); + try tty_config.setColor(writer, .reset); } -pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: usize, tty_config: io.tty.Config) !void { +pub fn printSourceAtAddress(debug_info: *SelfInfo, writer: *Writer, address: usize, tty_config: io.tty.Config) !void { const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), + error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config), else => return err, }; const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, out_stream, address, tty_config), + error.MissingDebugInfo, error.InvalidDebugInfo => return printUnknownSource(debug_info, writer, address, tty_config), else => return err, }; defer if (symbol_info.source_location) |sl| debug_info.allocator.free(sl.file_name); return printLineInfo( - out_stream, + writer, symbol_info.source_location, address, symbol_info.name, @@ -1117,7 +1126,7 @@ pub fn printSourceAtAddress(debug_info: *SelfInfo, out_stream: anytype, address: } fn printLineInfo( - out_stream: anytype, + writer: *Writer, source_location: ?SourceLocation, address: usize, symbol_name: []const u8, @@ -1126,34 +1135,34 @@ fn printLineInfo( comptime printLineFromFile: anytype, ) !void { nosuspend { - try tty_config.setColor(out_stream, .bold); + try tty_config.setColor(writer, .bold); if (source_location) |*sl| { - try out_stream.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column }); + try writer.print("{s}:{d}:{d}", .{ sl.file_name, sl.line, sl.column }); } else { - try out_stream.writeAll("???:?:?"); + try writer.writeAll("???:?:?"); } - try tty_config.setColor(out_stream, .reset); - try out_stream.writeAll(": "); - try tty_config.setColor(out_stream, .dim); - try out_stream.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name }); - try tty_config.setColor(out_stream, .reset); - try out_stream.writeAll("\n"); + try tty_config.setColor(writer, .reset); + try writer.writeAll(": "); + try tty_config.setColor(writer, .dim); + try writer.print("0x{x} in {s} ({s})", .{ address, symbol_name, compile_unit_name }); + try tty_config.setColor(writer, .reset); + try writer.writeAll("\n"); // Show the matching source code line if possible if (source_location) |sl| { - if (printLineFromFile(out_stream, sl)) { + if (printLineFromFile(writer, sl)) { if (sl.column > 0) { // The caret already takes one char const space_needed = @as(usize, @intCast(sl.column - 1)); - try out_stream.writeByteNTimes(' ', space_needed); - try tty_config.setColor(out_stream, .green); - try out_stream.writeAll("^"); - try tty_config.setColor(out_stream, .reset); + try writer.splatByteAll(' ', space_needed); + try tty_config.setColor(writer, .green); + try writer.writeAll("^"); + try tty_config.setColor(writer, .reset); } - try out_stream.writeAll("\n"); + try writer.writeAll("\n"); } else |err| switch (err) { error.EndOfFile, error.FileNotFound => {}, error.BadPathName => {}, @@ -1164,7 +1173,7 @@ fn printLineInfo( } } -fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation) !void { +fn printLineFromFileAnyOs(writer: *Writer, source_location: SourceLocation) !void { // Need this to always block even in async I/O mode, because this could potentially // be called from e.g. the event loop code crashing. var f = try fs.cwd().openFile(source_location.file_name, .{}); @@ -1197,31 +1206,31 @@ fn printLineFromFileAnyOs(out_stream: anytype, source_location: SourceLocation) if (mem.indexOfScalar(u8, slice, '\n')) |pos| { const line = slice[0 .. pos + 1]; mem.replaceScalar(u8, line, '\t', ' '); - return out_stream.writeAll(line); + return writer.writeAll(line); } else { // Line is the last inside the buffer, and requires another read to find delimiter. Alternatively the file ends. mem.replaceScalar(u8, slice, '\t', ' '); - try out_stream.writeAll(slice); + try writer.writeAll(slice); while (amt_read == buf.len) { amt_read = try f.read(buf[0..]); if (mem.indexOfScalar(u8, buf[0..amt_read], '\n')) |pos| { const line = buf[0 .. pos + 1]; mem.replaceScalar(u8, line, '\t', ' '); - return out_stream.writeAll(line); + return writer.writeAll(line); } else { const line = buf[0..amt_read]; mem.replaceScalar(u8, line, '\t', ' '); - try out_stream.writeAll(line); + try writer.writeAll(line); } } // Make sure printing last line of file inserts extra newline - try out_stream.writeByte('\n'); + try writer.writeByte('\n'); } } test printLineFromFileAnyOs { - var output = std.ArrayList(u8).init(std.testing.allocator); - defer output.deinit(); - const output_stream = output.writer(); + var aw: Writer.Allocating = .init(std.testing.allocator); + defer aw.deinit(); + const output_stream = &aw.interface; const allocator = std.testing.allocator; const join = std.fs.path.join; @@ -1243,8 +1252,8 @@ test printLineFromFileAnyOs { try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 })); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); - try expectEqualStrings("no new lines in this file, but one is printed anyway\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings("no new lines in this file, but one is printed anyway\n", aw.getWritten()); + aw.clearRetainingCapacity(); } { const path = try fs.path.join(allocator, &.{ test_dir_path, "three_lines.zig" }); @@ -1259,12 +1268,12 @@ test printLineFromFileAnyOs { }); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); - try expectEqualStrings("1\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings("1\n", aw.getWritten()); + aw.clearRetainingCapacity(); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 3, .column = 0 }); - try expectEqualStrings("3\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings("3\n", aw.getWritten()); + aw.clearRetainingCapacity(); } { const file = try test_dir.dir.createFile("line_overlaps_page_boundary.zig", .{}); @@ -1273,14 +1282,15 @@ test printLineFromFileAnyOs { defer allocator.free(path); const overlap = 10; - var writer = file.writer(); - try writer.writeByteNTimes('a', std.heap.page_size_min - overlap); + var file_writer = file.writer(&.{}); + const writer = &file_writer.interface; + try writer.splatByteAll('a', std.heap.page_size_min - overlap); try writer.writeByte('\n'); - try writer.writeByteNTimes('a', overlap); + try writer.splatByteAll('a', overlap); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }); - try expectEqualStrings(("a" ** overlap) ++ "\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings(("a" ** overlap) ++ "\n", aw.getWritten()); + aw.clearRetainingCapacity(); } { const file = try test_dir.dir.createFile("file_ends_on_page_boundary.zig", .{}); @@ -1288,12 +1298,13 @@ test printLineFromFileAnyOs { const path = try fs.path.join(allocator, &.{ test_dir_path, "file_ends_on_page_boundary.zig" }); defer allocator.free(path); - var writer = file.writer(); - try writer.writeByteNTimes('a', std.heap.page_size_max); + var file_writer = file.writer(&.{}); + const writer = &file_writer.interface; + try writer.splatByteAll('a', std.heap.page_size_max); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); - try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings(("a" ** std.heap.page_size_max) ++ "\n", aw.getWritten()); + aw.clearRetainingCapacity(); } { const file = try test_dir.dir.createFile("very_long_first_line_spanning_multiple_pages.zig", .{}); @@ -1301,24 +1312,25 @@ test printLineFromFileAnyOs { const path = try fs.path.join(allocator, &.{ test_dir_path, "very_long_first_line_spanning_multiple_pages.zig" }); defer allocator.free(path); - var writer = file.writer(); - try writer.writeByteNTimes('a', 3 * std.heap.page_size_max); + var file_writer = file.writer(&.{}); + const writer = &file_writer.interface; + try writer.splatByteAll('a', 3 * std.heap.page_size_max); try expectError(error.EndOfFile, printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 })); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); - try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "\n", aw.getWritten()); + aw.clearRetainingCapacity(); try writer.writeAll("a\na"); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 1, .column = 0 }); - try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "a\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings(("a" ** (3 * std.heap.page_size_max)) ++ "a\n", aw.getWritten()); + aw.clearRetainingCapacity(); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = 2, .column = 0 }); - try expectEqualStrings("a\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings("a\n", aw.getWritten()); + aw.clearRetainingCapacity(); } { const file = try test_dir.dir.createFile("file_of_newlines.zig", .{}); @@ -1326,18 +1338,19 @@ test printLineFromFileAnyOs { const path = try fs.path.join(allocator, &.{ test_dir_path, "file_of_newlines.zig" }); defer allocator.free(path); - var writer = file.writer(); + var file_writer = file.writer(&.{}); + const writer = &file_writer.interface; const real_file_start = 3 * std.heap.page_size_min; - try writer.writeByteNTimes('\n', real_file_start); + try writer.splatByteAll('\n', real_file_start); try writer.writeAll("abc\ndef"); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = real_file_start + 1, .column = 0 }); - try expectEqualStrings("abc\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings("abc\n", aw.getWritten()); + aw.clearRetainingCapacity(); try printLineFromFileAnyOs(output_stream, .{ .file_name = path, .line = real_file_start + 2, .column = 0 }); - try expectEqualStrings("def\n", output.items); - output.clearRetainingCapacity(); + try expectEqualStrings("def\n", aw.getWritten()); + aw.clearRetainingCapacity(); } } @@ -1461,7 +1474,8 @@ fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopa } fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) void { - const stderr = fs.File.stderr().writer(); + const stderr = lockStderrWriter(&.{}); + defer unlockStderrWriter(); _ = switch (sig) { posix.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL // x86_64 doesn't have a full 64-bit virtual address space. @@ -1471,7 +1485,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) // but can also happen when no addressable memory is involved; // for example when reading/writing model-specific registers // by executing `rdmsr` or `wrmsr` in user-space (unprivileged mode). - stderr.print("General protection exception (no address available)\n", .{}) + stderr.writeAll("General protection exception (no address available)\n") else stderr.print("Segmentation fault at address 0x{x}\n", .{addr}), posix.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}), @@ -1509,7 +1523,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*anyopaque) }, @ptrCast(ctx)).__mcontext_data; } relocateContext(&new_ctx); - dumpStackTraceFromBase(&new_ctx); + dumpStackTraceFromBase(&new_ctx, stderr); }, else => {}, } @@ -1539,10 +1553,10 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: _ = panicking.fetchAdd(1, .seq_cst); { - lockStdErr(); - defer unlockStdErr(); + const stderr = lockStderrWriter(&.{}); + defer unlockStderrWriter(); - dumpSegfaultInfoWindows(info, msg, label); + dumpSegfaultInfoWindows(info, msg, label, stderr); } waitForOtherThreadToFinishPanicking(); @@ -1556,8 +1570,7 @@ fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: posix.abort(); } -fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void { - const stderr = fs.File.stderr().writer(); +fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8, stderr: *Writer) void { _ = switch (msg) { 0 => stderr.print("{s}\n", .{label.?}), 1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}), @@ -1565,7 +1578,7 @@ fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[ else => unreachable, } catch posix.abort(); - dumpStackTraceFromBase(info.ContextRecord); + dumpStackTraceFromBase(info.ContextRecord, stderr); } pub fn dumpStackPointerAddr(prefix: []const u8) void { @@ -1588,10 +1601,10 @@ test "manage resources correctly" { // self-hosted debug info is still too buggy if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest; - const writer = std.io.null_writer; + var writer: std.io.Writer = .discarding(&.{}); var di = try SelfInfo.open(testing.allocator); defer di.deinit(); - try printSourceAtAddress(&di, writer, showMyTrace(), io.tty.detectConfig(std.fs.File.stderr())); + try printSourceAtAddress(&di, &writer, showMyTrace(), io.tty.detectConfig(.stderr())); } noinline fn showMyTrace() usize { @@ -1657,8 +1670,9 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize pub fn dump(t: @This()) void { if (!enabled) return; - const tty_config = io.tty.detectConfig(std.fs.File.stderr()); - const stderr = fs.File.stderr().writer(); + const tty_config = io.tty.detectConfig(.stderr()); + const stderr = lockStderrWriter(&.{}); + defer unlockStderrWriter(); const end = @min(t.index, size); const debug_info = getSelfDebugInfo() catch |err| { stderr.print( @@ -1688,7 +1702,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize t: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, - writer: anytype, + writer: *Writer, ) !void { if (fmt.len != 0) std.fmt.invalidFmtError(fmt, t); _ = options; diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 06b6c81075..3f1fc41feb 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -2302,11 +2302,7 @@ pub const ElfModule = struct { }; defer debuginfod_dir.close(); - const filename = std.fmt.allocPrint( - gpa, - "{s}/debuginfo", - .{std.fmt.fmtSliceHexLower(id)}, - ) catch break :blk; + const filename = std.fmt.allocPrint(gpa, "{x}/debuginfo", .{id}) catch break :blk; defer gpa.free(filename); const path: Path = .{ @@ -2330,12 +2326,8 @@ pub const ElfModule = struct { var id_prefix_buf: [2]u8 = undefined; var filename_buf: [38 + extension.len]u8 = undefined; - _ = std.fmt.bufPrint(&id_prefix_buf, "{s}", .{std.fmt.fmtSliceHexLower(id[0..1])}) catch unreachable; - const filename = std.fmt.bufPrint( - &filename_buf, - "{s}" ++ extension, - .{std.fmt.fmtSliceHexLower(id[1..])}, - ) catch break :blk; + _ = std.fmt.bufPrint(&id_prefix_buf, "{x}", .{id[0..1]}) catch unreachable; + const filename = std.fmt.bufPrint(&filename_buf, "{x}" ++ extension, .{id[1..]}) catch break :blk; for (global_debug_directories) |global_directory| { const path: Path = .{ diff --git a/lib/std/debug/Pdb.zig b/lib/std/debug/Pdb.zig index f8e135b037..c8dccca497 100644 --- a/lib/std/debug/Pdb.zig +++ b/lib/std/debug/Pdb.zig @@ -395,7 +395,7 @@ const Msf = struct { streams: []MsfStream, fn init(allocator: Allocator, file: File) !Msf { - const in = file.reader(); + const in = file.deprecatedReader(); const superblock = try in.readStruct(pdb.SuperBlock); @@ -514,7 +514,7 @@ const MsfStream = struct { var offset = self.pos % self.block_size; try self.in_file.seekTo(block * self.block_size + offset); - const in = self.in_file.reader(); + const in = self.in_file.deprecatedReader(); var size: usize = 0; var rem_buffer = buffer; diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index efd5ffd3a2..9c368fda56 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1,17 +1,20 @@ //! String formatting and parsing. -const std = @import("std.zig"); const builtin = @import("builtin"); +const std = @import("std.zig"); const io = std.io; const math = std.math; const assert = std.debug.assert; const mem = std.mem; -const unicode = std.unicode; const meta = std.meta; const lossyCast = math.lossyCast; const expectFmt = std.testing.expectFmt; const testing = std.testing; +const Allocator = std.mem.Allocator; +const Writer = std.io.Writer; + +pub const float = @import("fmt/float.zig"); pub const default_max_depth = 3; @@ -24,11 +27,14 @@ pub const Alignment = enum { const default_alignment = .right; const default_fill_char = ' '; -pub const FormatOptions = struct { +/// Deprecated in favor of `Options`. +pub const FormatOptions = Options; + +pub const Options = struct { precision: ?usize = null, width: ?usize = null, alignment: Alignment = default_alignment, - fill: u21 = default_fill_char, + fill: u8 = default_fill_char, }; /// Renders fmt string with args, calling `writer` with slices of bytes. @@ -45,9 +51,10 @@ pub const FormatOptions = struct { /// - when using a field name, you are required to enclose the field name (an identifier) in square /// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...} /// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below) -/// - *fill* is a single unicode codepoint which is used to pad the formatted text +/// - *fill* is a single byte which is used to pad the formatted text /// - *alignment* is one of the three bytes '<', '^', or '>' to make the text left-, center-, or right-aligned, respectively -/// - *width* is the total width of the field in unicode codepoints +/// - *width* is the total width of the field in bytes. This is generally only +/// useful for ASCII text, such as numbers. /// - *precision* specifies how many decimals a formatted number should have /// /// Note that most of the parameters are optional and may be omitted. Also you can leave out separators like `:` and `.` when @@ -56,16 +63,20 @@ pub const FormatOptions = struct { /// one has to specify *alignment* as well, as otherwise the digit following `:` is interpreted as *width*, not *fill*. /// /// The *specifier* has several options for types: -/// - `x` and `X`: output numeric value in hexadecimal notation +/// - `x` and `X`: output numeric value in hexadecimal notation, or string in hexadecimal bytes /// - `s`: /// - for pointer-to-many and C pointers of u8, print as a C-string using zero-termination /// - for slices of u8, print the entire slice as a string without zero-termination +/// - `b64`: output string as standard base64 /// - `e`: output floating point value in scientific notation /// - `d`: output numeric value in decimal notation /// - `b`: output integer value in binary notation /// - `o`: output integer value in octal notation /// - `c`: output integer as an ASCII character. Integer type must have 8 bits at max. /// - `u`: output integer as an UTF-8 sequence. Integer type must have 21 bits at max. +/// - `D`: output nanoseconds as duration +/// - `B`: output bytes in SI units (decimal) +/// - `Bi`: output bytes in IEC units (binary) /// - `?`: output optional value as either the unwrapped value, or `null`; may be followed by a format specifier for the underlying value. /// - `!`: output error union value as either the unwrapped value, or the formatted error value; may be followed by a format specifier for the underlying value. /// - `*`: output the address of the value instead of the value itself. @@ -73,7 +84,7 @@ pub const FormatOptions = struct { /// /// If a formatted user type contains a function of the type /// ``` -/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void +/// pub fn format(value: ?, comptime fmt: []const u8, options: std.fmt.Options, writer: anytype) !void /// ``` /// with `?` being the type formatted, this function will be called instead of the default implementation. /// This allows user types to be formatted in a logical manner instead of dumping all fields of the type. @@ -81,11 +92,7 @@ pub const FormatOptions = struct { /// A user type may be a `struct`, `vector`, `union` or `enum` type. /// /// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`. -pub fn format( - writer: anytype, - comptime fmt: []const u8, - args: anytype, -) !void { +pub fn format(w: *Writer, comptime fmt: []const u8, args: anytype) Writer.Error!void { const ArgsType = @TypeOf(args); const args_type_info = @typeInfo(ArgsType); if (args_type_info != .@"struct") { @@ -97,7 +104,7 @@ pub fn format( @compileError("32 arguments max are supported per format call"); } - @setEvalBranchQuota(2000000); + @setEvalBranchQuota(fmt.len * 1000); comptime var arg_state: ArgState = .{ .args_len = fields_info.len }; comptime var i = 0; comptime var literal: []const u8 = ""; @@ -130,7 +137,7 @@ pub fn format( // Write out the literal if (literal.len != 0) { - try writer.writeAll(literal); + try w.writeAll(literal); literal = ""; } @@ -157,7 +164,7 @@ pub fn format( comptime assert(fmt[i] == '}'); i += 1; - const placeholder = comptime Placeholder.parse(fmt[fmt_begin..fmt_end].*); + const placeholder = comptime Placeholder.parse(&(fmt[fmt_begin..fmt_end].*)); const arg_pos = comptime switch (placeholder.arg) { .none => null, .number => |pos| pos, @@ -190,16 +197,15 @@ pub fn format( const arg_to_print = comptime arg_state.nextArg(arg_pos) orelse @compileError("too few arguments"); - try formatType( - @field(args, fields_info[arg_to_print].name), + try w.printValue( placeholder.specifier_arg, - FormatOptions{ + .{ .fill = placeholder.fill, .alignment = placeholder.alignment, .width = width, .precision = precision, }, - writer, + @field(args, fields_info[arg_to_print].name), std.options.fmt_max_depth, ); } @@ -214,44 +220,41 @@ pub fn format( } } +/// Deprecated in favor of `format`. +pub fn deprecatedFormat(writer: anytype, comptime fmt: []const u8, args: anytype) !void { + var adapter = writer.adaptToNewApi(); + return format(&adapter.new_interface, fmt, args) catch |err| switch (err) { + error.WriteFailed => return adapter.err.?, + }; +} + fn cacheString(str: anytype) []const u8 { return &str; } pub const Placeholder = struct { specifier_arg: []const u8, - fill: u21, + fill: u8, alignment: Alignment, arg: Specifier, width: Specifier, precision: Specifier, - pub fn parse(comptime str: anytype) Placeholder { - const view = std.unicode.Utf8View.initComptime(&str); - comptime var parser = Parser{ - .iter = view.iterator(), - }; - - // Parse the positional argument number - const arg = comptime parser.specifier() catch |err| - @compileError(@errorName(err)); - - // Parse the format specifier - const specifier_arg = comptime parser.until(':'); - - // Skip the colon, if present - if (comptime parser.char()) |ch| { - if (ch != ':') { - @compileError("expected : or }, found '" ++ unicode.utf8EncodeComptime(ch) ++ "'"); - } + pub fn parse(bytes: []const u8) Placeholder { + var parser: Parser = .{ .bytes = bytes, .i = 0 }; + const arg = parser.specifier() catch |err| @compileError(@errorName(err)); + const specifier_arg = parser.until(':'); + if (parser.char()) |b| { + if (b != ':') @compileError("expected : or }, found '" ++ &[1]u8{b} ++ "'"); } - // Parse the fill character, if present. - // When the width field is also specified, the fill character must + // Parse the fill byte, if present. + // + // When the width field is also specified, the fill byte must // be followed by an alignment specifier, unless it's '0' (zero) - // (in which case it's handled as part of the width specifier) - var fill: ?u21 = comptime if (parser.peek(1)) |ch| - switch (ch) { + // (in which case it's handled as part of the width specifier). + var fill: ?u8 = if (parser.peek(1)) |b| + switch (b) { '<', '^', '>' => parser.char(), else => null, } @@ -259,8 +262,8 @@ pub const Placeholder = struct { null; // Parse the alignment parameter - const alignment: ?Alignment = comptime if (parser.peek(0)) |ch| init: { - switch (ch) { + const alignment: ?Alignment = if (parser.peek(0)) |b| init: { + switch (b) { '<', '^', '>' => { // consume the character break :init switch (parser.char().?) { @@ -276,29 +279,23 @@ pub const Placeholder = struct { // When none of the fill character and the alignment specifier have // been provided, check whether the width starts with a zero. if (fill == null and alignment == null) { - fill = comptime if (parser.peek(0) == '0') '0' else null; + fill = if (parser.peek(0) == '0') '0' else null; } // Parse the width parameter - const width = comptime parser.specifier() catch |err| - @compileError(@errorName(err)); + const width = parser.specifier() catch |err| @compileError(@errorName(err)); // Skip the dot, if present - if (comptime parser.char()) |ch| { - if (ch != '.') { - @compileError("expected . or }, found '" ++ unicode.utf8EncodeComptime(ch) ++ "'"); - } + if (parser.char()) |b| { + if (b != '.') @compileError("expected . or }, found '" ++ &[1]u8{b} ++ "'"); } // Parse the precision parameter - const precision = comptime parser.specifier() catch |err| - @compileError(@errorName(err)); + const precision = parser.specifier() catch |err| @compileError(@errorName(err)); - if (comptime parser.char()) |ch| { - @compileError("extraneous trailing character '" ++ unicode.utf8EncodeComptime(ch) ++ "'"); - } + if (parser.char()) |b| @compileError("extraneous trailing character '" ++ &[1]u8{b} ++ "'"); - return Placeholder{ + return .{ .specifier_arg = cacheString(specifier_arg[0..specifier_arg.len].*), .fill = fill orelse default_fill_char, .alignment = alignment orelse default_alignment, @@ -320,88 +317,60 @@ pub const Specifier = union(enum) { /// Allows to implement formatters compatible with std.fmt without replicating /// the standard library behavior. pub const Parser = struct { - iter: std.unicode.Utf8Iterator, + bytes: []const u8, + i: usize, - // Returns a decimal number or null if the current character is not a - // digit pub fn number(self: *@This()) ?usize { var r: ?usize = null; - - while (self.peek(0)) |code_point| { - switch (code_point) { + while (self.peek(0)) |byte| { + switch (byte) { '0'...'9' => { if (r == null) r = 0; r.? *= 10; - r.? += code_point - '0'; + r.? += byte - '0'; }, else => break, } - _ = self.iter.nextCodepoint(); + self.i += 1; } - return r; } - // Returns a substring of the input starting from the current position - // and ending where `ch` is found or until the end if not found - pub fn until(self: *@This(), ch: u21) []const u8 { - const start = self.iter.i; - while (self.peek(0)) |code_point| { - if (code_point == ch) - break; - _ = self.iter.nextCodepoint(); - } - return self.iter.bytes[start..self.iter.i]; + pub fn until(self: *@This(), delimiter: u8) []const u8 { + const start = self.i; + self.i = std.mem.indexOfScalarPos(u8, self.bytes, self.i, delimiter) orelse self.bytes.len; + return self.bytes[start..self.i]; } - // Returns the character pointed to by the iterator if available, or - // null otherwise - pub fn char(self: *@This()) ?u21 { - if (self.iter.nextCodepoint()) |code_point| { - return code_point; - } - return null; + pub fn char(self: *@This()) ?u8 { + const i = self.i; + if (self.bytes.len - i == 0) return null; + self.i = i + 1; + return self.bytes[i]; } - // Returns true if the iterator points to an existing character and - // false otherwise - pub fn maybe(self: *@This(), val: u21) bool { - if (self.peek(0) == val) { - _ = self.iter.nextCodepoint(); + pub fn maybe(self: *@This(), byte: u8) bool { + if (self.peek(0) == byte) { + self.i += 1; return true; } return false; } - // Returns a decimal number or null if the current character is not a - // digit pub fn specifier(self: *@This()) !Specifier { if (self.maybe('[')) { const arg_name = self.until(']'); - - if (!self.maybe(']')) - return @field(anyerror, "Expected closing ]"); - - return Specifier{ .named = arg_name }; + if (!self.maybe(']')) return error.@"Expected closing ]"; + return .{ .named = arg_name }; } - if (self.number()) |i| - return Specifier{ .number = i }; - - return Specifier{ .none = {} }; + if (self.number()) |i| return .{ .number = i }; + return .{ .none = {} }; } - // Returns the n-th next character or null if that's past the end - pub fn peek(self: *@This(), n: usize) ?u21 { - const original_i = self.iter.i; - defer self.iter.i = original_i; - - var i: usize = 0; - var code_point: ?u21 = null; - while (i <= n) : (i += 1) { - code_point = self.iter.nextCodepoint(); - if (code_point == null) return null; - } - return code_point; + pub fn peek(self: *@This(), i: usize) ?u8 { + const peek_index = self.i + i; + if (peek_index >= self.bytes.len) return null; + return self.bytes[peek_index]; } }; @@ -434,822 +403,14 @@ pub const ArgState = struct { } }; -pub fn formatAddress(value: anytype, options: FormatOptions, writer: anytype) @TypeOf(writer).Error!void { - _ = options; - const T = @TypeOf(value); - - switch (@typeInfo(T)) { - .pointer => |info| { - try writer.writeAll(@typeName(info.child) ++ "@"); - if (info.size == .slice) - try formatInt(@intFromPtr(value.ptr), 16, .lower, FormatOptions{}, writer) - else - try formatInt(@intFromPtr(value), 16, .lower, FormatOptions{}, writer); - return; - }, - .optional => |info| { - if (@typeInfo(info.child) == .pointer) { - try writer.writeAll(@typeName(info.child) ++ "@"); - try formatInt(@intFromPtr(value), 16, .lower, FormatOptions{}, writer); - return; - } - }, - else => {}, - } - - @compileError("cannot format non-pointer type " ++ @typeName(T) ++ " with * specifier"); -} - -// This ANY const is a workaround for: https://github.com/ziglang/zig/issues/7948 -const ANY = "any"; - -pub fn defaultSpec(comptime T: type) [:0]const u8 { - switch (@typeInfo(T)) { - .array, .vector => return ANY, - .pointer => |ptr_info| switch (ptr_info.size) { - .one => switch (@typeInfo(ptr_info.child)) { - .array => return ANY, - else => {}, - }, - .many, .c => return "*", - .slice => return ANY, - }, - .optional => |info| return "?" ++ defaultSpec(info.child), - .error_union => |info| return "!" ++ defaultSpec(info.payload), - else => {}, - } - return ""; -} - -fn stripOptionalOrErrorUnionSpec(comptime fmt: []const u8) []const u8 { - return if (std.mem.eql(u8, fmt[1..], ANY)) - ANY - else - fmt[1..]; -} - -pub fn invalidFmtError(comptime fmt: []const u8, value: anytype) void { - @compileError("invalid format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'"); -} - -pub fn formatType( - value: anytype, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, - max_depth: usize, -) @TypeOf(writer).Error!void { - const T = @TypeOf(value); - const actual_fmt = comptime if (std.mem.eql(u8, fmt, ANY)) - defaultSpec(T) - else if (fmt.len != 0 and (fmt[0] == '?' or fmt[0] == '!')) switch (@typeInfo(T)) { - .optional, .error_union => fmt, - else => stripOptionalOrErrorUnionSpec(fmt), - } else fmt; - - if (comptime std.mem.eql(u8, actual_fmt, "*")) { - return formatAddress(value, options, writer); - } - - if (std.meta.hasMethod(T, "format")) { - return try value.format(actual_fmt, options, writer); - } - - switch (@typeInfo(T)) { - .comptime_int, .int, .comptime_float, .float => { - return formatValue(value, actual_fmt, options, writer); - }, - .void => { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return formatBuf("void", options, writer); - }, - .bool => { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return formatBuf(if (value) "true" else "false", options, writer); - }, - .optional => { - if (actual_fmt.len == 0 or actual_fmt[0] != '?') - @compileError("cannot format optional without a specifier (i.e. {?} or {any})"); - const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt); - if (value) |payload| { - return formatType(payload, remaining_fmt, options, writer, max_depth); - } else { - return formatBuf("null", options, writer); - } - }, - .error_union => { - if (actual_fmt.len == 0 or actual_fmt[0] != '!') - @compileError("cannot format error union without a specifier (i.e. {!} or {any})"); - const remaining_fmt = comptime stripOptionalOrErrorUnionSpec(actual_fmt); - if (value) |payload| { - return formatType(payload, remaining_fmt, options, writer, max_depth); - } else |err| { - return formatType(err, "", options, writer, max_depth); - } - }, - .error_set => { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - try writer.writeAll("error."); - return writer.writeAll(@errorName(value)); - }, - .@"enum" => |enumInfo| { - try writer.writeAll(@typeName(T)); - if (enumInfo.is_exhaustive) { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - try writer.writeAll("."); - try writer.writeAll(@tagName(value)); - return; - } - - // Use @tagName only if value is one of known fields - @setEvalBranchQuota(3 * enumInfo.fields.len); - inline for (enumInfo.fields) |enumField| { - if (@intFromEnum(value) == enumField.value) { - try writer.writeAll("."); - try writer.writeAll(@tagName(value)); - return; - } - } - - try writer.writeAll("("); - try formatType(@intFromEnum(value), actual_fmt, options, writer, max_depth); - try writer.writeAll(")"); - }, - .@"union" => |info| { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - try writer.writeAll(@typeName(T)); - if (max_depth == 0) { - return writer.writeAll("{ ... }"); - } - if (info.tag_type) |UnionTagType| { - try writer.writeAll("{ ."); - try writer.writeAll(@tagName(@as(UnionTagType, value))); - try writer.writeAll(" = "); - inline for (info.fields) |u_field| { - if (value == @field(UnionTagType, u_field.name)) { - try formatType(@field(value, u_field.name), ANY, options, writer, max_depth - 1); - } - } - try writer.writeAll(" }"); - } else { - try format(writer, "@{x}", .{@intFromPtr(&value)}); - } - }, - .@"struct" => |info| { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - if (info.is_tuple) { - // Skip the type and field names when formatting tuples. - if (max_depth == 0) { - return writer.writeAll("{ ... }"); - } - try writer.writeAll("{"); - inline for (info.fields, 0..) |f, i| { - if (i == 0) { - try writer.writeAll(" "); - } else { - try writer.writeAll(", "); - } - try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1); - } - return writer.writeAll(" }"); - } - try writer.writeAll(@typeName(T)); - if (max_depth == 0) { - return writer.writeAll("{ ... }"); - } - try writer.writeAll("{"); - inline for (info.fields, 0..) |f, i| { - if (i == 0) { - try writer.writeAll(" ."); - } else { - try writer.writeAll(", ."); - } - try writer.writeAll(f.name); - try writer.writeAll(" = "); - try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1); - } - try writer.writeAll(" }"); - }, - .pointer => |ptr_info| switch (ptr_info.size) { - .one => switch (@typeInfo(ptr_info.child)) { - .array, .@"enum", .@"union", .@"struct" => { - return formatType(value.*, actual_fmt, options, writer, max_depth); - }, - else => return format(writer, "{s}@{x}", .{ @typeName(ptr_info.child), @intFromPtr(value) }), - }, - .many, .c => { - if (actual_fmt.len == 0) - @compileError("cannot format pointer without a specifier (i.e. {s} or {*})"); - if (ptr_info.sentinel() != null) { - return formatType(mem.span(value), actual_fmt, options, writer, max_depth); - } - if (actual_fmt[0] == 's' and ptr_info.child == u8) { - return formatBuf(mem.span(value), options, writer); - } - invalidFmtError(fmt, value); - }, - .slice => { - if (actual_fmt.len == 0) - @compileError("cannot format slice without a specifier (i.e. {s} or {any})"); - if (max_depth == 0) { - return writer.writeAll("{ ... }"); - } - if (actual_fmt[0] == 's' and ptr_info.child == u8) { - return formatBuf(value, options, writer); - } - try writer.writeAll("{ "); - for (value, 0..) |elem, i| { - try formatType(elem, actual_fmt, options, writer, max_depth - 1); - if (i != value.len - 1) { - try writer.writeAll(", "); - } - } - try writer.writeAll(" }"); - }, - }, - .array => |info| { - if (actual_fmt.len == 0) - @compileError("cannot format array without a specifier (i.e. {s} or {any})"); - if (max_depth == 0) { - return writer.writeAll("{ ... }"); - } - if (actual_fmt[0] == 's' and info.child == u8) { - return formatBuf(&value, options, writer); - } - try writer.writeAll("{ "); - for (value, 0..) |elem, i| { - try formatType(elem, actual_fmt, options, writer, max_depth - 1); - if (i < value.len - 1) { - try writer.writeAll(", "); - } - } - try writer.writeAll(" }"); - }, - .vector => |info| { - if (max_depth == 0) { - return writer.writeAll("{ ... }"); - } - try writer.writeAll("{ "); - var i: usize = 0; - while (i < info.len) : (i += 1) { - try formatType(value[i], actual_fmt, options, writer, max_depth - 1); - if (i < info.len - 1) { - try writer.writeAll(", "); - } - } - try writer.writeAll(" }"); - }, - .@"fn" => @compileError("unable to format function body type, use '*const " ++ @typeName(T) ++ "' for a function pointer type"), - .type => { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return formatBuf(@typeName(value), options, writer); - }, - .enum_literal => { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - const buffer = [_]u8{'.'} ++ @tagName(value); - return formatBuf(buffer, options, writer); - }, - .null => { - if (actual_fmt.len != 0) invalidFmtError(fmt, value); - return formatBuf("null", options, writer); - }, - else => @compileError("unable to format type '" ++ @typeName(T) ++ "'"), - } -} - -fn formatValue( - value: anytype, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, -) !void { - const T = @TypeOf(value); - switch (@typeInfo(T)) { - .float, .comptime_float => return formatFloatValue(value, fmt, options, writer), - .int, .comptime_int => return formatIntValue(value, fmt, options, writer), - .bool => return formatBuf(if (value) "true" else "false", options, writer), - else => comptime unreachable, - } -} - -pub fn formatIntValue( - value: anytype, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, -) !void { - comptime var base = 10; - comptime var case: Case = .lower; - - const int_value = if (@TypeOf(value) == comptime_int) blk: { - const Int = math.IntFittingRange(value, value); - break :blk @as(Int, value); - } else value; - - if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) { - base = 10; - case = .lower; - } else if (comptime std.mem.eql(u8, fmt, "c")) { - if (@typeInfo(@TypeOf(int_value)).int.bits <= 8) { - return formatAsciiChar(@as(u8, int_value), options, writer); - } else { - @compileError("cannot print integer that is larger than 8 bits as an ASCII character"); - } - } else if (comptime std.mem.eql(u8, fmt, "u")) { - if (@typeInfo(@TypeOf(int_value)).int.bits <= 21) { - return formatUnicodeCodepoint(@as(u21, int_value), options, writer); - } else { - @compileError("cannot print integer that is larger than 21 bits as an UTF-8 sequence"); - } - } else if (comptime std.mem.eql(u8, fmt, "b")) { - base = 2; - case = .lower; - } else if (comptime std.mem.eql(u8, fmt, "x")) { - base = 16; - case = .lower; - } else if (comptime std.mem.eql(u8, fmt, "X")) { - base = 16; - case = .upper; - } else if (comptime std.mem.eql(u8, fmt, "o")) { - base = 8; - case = .lower; - } else { - invalidFmtError(fmt, value); - } - - return formatInt(int_value, base, case, options, writer); -} - -pub const format_float = @import("fmt/format_float.zig"); -pub const formatFloat = format_float.formatFloat; -pub const FormatFloatError = format_float.FormatError; - -fn formatFloatValue( - value: anytype, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, -) !void { - var buf: [format_float.bufferSize(.decimal, f64)]u8 = undefined; - - if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) { - const s = formatFloat(&buf, value, .{ .mode = .scientific, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => "(float)", - }; - return formatBuf(s, options, writer); - } else if (comptime std.mem.eql(u8, fmt, "d")) { - const s = formatFloat(&buf, value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => "(float)", - }; - return formatBuf(s, options, writer); - } else if (comptime std.mem.eql(u8, fmt, "x")) { - var buf_stream = std.io.fixedBufferStream(&buf); - formatFloatHexadecimal(value, options, buf_stream.writer()) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; - return formatBuf(buf_stream.getWritten(), options, writer); - } else { - invalidFmtError(fmt, value); - } -} - -test { - _ = &format_float; -} - pub const Case = enum { lower, upper }; -fn SliceHex(comptime case: Case) type { - const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; - - return struct { - pub fn format( - bytes: []const u8, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = fmt; - _ = options; - var buf: [2]u8 = undefined; - - for (bytes) |c| { - buf[0] = charset[c >> 4]; - buf[1] = charset[c & 15]; - try writer.writeAll(&buf); - } - } - }; -} - -const formatSliceHexLower = SliceHex(.lower).format; -const formatSliceHexUpper = SliceHex(.upper).format; - -/// Return a Formatter for a []const u8 where every byte is formatted as a pair -/// of lowercase hexadecimal digits. -pub fn fmtSliceHexLower(bytes: []const u8) std.fmt.Formatter(formatSliceHexLower) { - return .{ .data = bytes }; -} - -/// Return a Formatter for a []const u8 where every byte is formatted as pair -/// of uppercase hexadecimal digits. -pub fn fmtSliceHexUpper(bytes: []const u8) std.fmt.Formatter(formatSliceHexUpper) { - return .{ .data = bytes }; -} - -fn SliceEscape(comptime case: Case) type { - const charset = "0123456789" ++ if (case == .upper) "ABCDEF" else "abcdef"; - - return struct { - pub fn format( - bytes: []const u8, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = fmt; - _ = options; - var buf: [4]u8 = undefined; - - buf[0] = '\\'; - buf[1] = 'x'; - - for (bytes) |c| { - if (std.ascii.isPrint(c)) { - try writer.writeByte(c); - } else { - buf[2] = charset[c >> 4]; - buf[3] = charset[c & 15]; - try writer.writeAll(&buf); - } - } - } - }; -} - -const formatSliceEscapeLower = SliceEscape(.lower).format; -const formatSliceEscapeUpper = SliceEscape(.upper).format; - -/// Return a Formatter for a []const u8 where every non-printable ASCII -/// character is escaped as \xNN, where NN is the character in lowercase -/// hexadecimal notation. -pub fn fmtSliceEscapeLower(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeLower) { - return .{ .data = bytes }; -} - -/// Return a Formatter for a []const u8 where every non-printable ASCII -/// character is escaped as \xNN, where NN is the character in uppercase -/// hexadecimal notation. -pub fn fmtSliceEscapeUpper(bytes: []const u8) std.fmt.Formatter(formatSliceEscapeUpper) { - return .{ .data = bytes }; -} - -fn Size(comptime base: comptime_int) type { - return struct { - fn format( - value: u64, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, - ) !void { - _ = fmt; - if (value == 0) { - return formatBuf("0B", options, writer); - } - // The worst case in terms of space needed is 32 bytes + 3 for the suffix. - var buf: [format_float.min_buffer_size + 3]u8 = undefined; - - const mags_si = " kMGTPEZY"; - const mags_iec = " KMGTPEZY"; - - const log2 = math.log2(value); - const magnitude = switch (base) { - 1000 => @min(log2 / comptime math.log2(1000), mags_si.len - 1), - 1024 => @min(log2 / 10, mags_iec.len - 1), - else => unreachable, - }; - const new_value = lossyCast(f64, value) / math.pow(f64, lossyCast(f64, base), lossyCast(f64, magnitude)); - const suffix = switch (base) { - 1000 => mags_si[magnitude], - 1024 => mags_iec[magnitude], - else => unreachable, - }; - - const s = switch (magnitude) { - 0 => buf[0..formatIntBuf(&buf, value, 10, .lower, .{})], - else => formatFloat(&buf, new_value, .{ .mode = .decimal, .precision = options.precision }) catch |err| switch (err) { - error.BufferTooSmall => unreachable, - }, - }; - - var i: usize = s.len; - if (suffix == ' ') { - buf[i] = 'B'; - i += 1; - } else switch (base) { - 1000 => { - buf[i..][0..2].* = [_]u8{ suffix, 'B' }; - i += 2; - }, - 1024 => { - buf[i..][0..3].* = [_]u8{ suffix, 'i', 'B' }; - i += 3; - }, - else => unreachable, - } - - return formatBuf(buf[0..i], options, writer); - } - }; -} -const formatSizeDec = Size(1000).format; -const formatSizeBin = Size(1024).format; - -/// Return a Formatter for a u64 value representing a file size. -/// This formatter represents the number as multiple of 1000 and uses the SI -/// measurement units (kB, MB, GB, ...). -/// Format option `precision` is ignored when `value` is less than 1kB -pub fn fmtIntSizeDec(value: u64) std.fmt.Formatter(formatSizeDec) { - return .{ .data = value }; -} - -/// Return a Formatter for a u64 value representing a file size. -/// This formatter represents the number as multiple of 1024 and uses the IEC -/// measurement units (KiB, MiB, GiB, ...). -/// Format option `precision` is ignored when `value` is less than 1KiB -pub fn fmtIntSizeBin(value: u64) std.fmt.Formatter(formatSizeBin) { - return .{ .data = value }; -} - -fn checkTextFmt(comptime fmt: []const u8) void { - if (fmt.len != 1) - @compileError("unsupported format string '" ++ fmt ++ "' when formatting text"); - switch (fmt[0]) { - // Example of deprecation: - // '[deprecated_specifier]' => @compileError("specifier '[deprecated_specifier]' has been deprecated, wrap your argument in `std.some_function` instead"), - 'x' => @compileError("specifier 'x' has been deprecated, wrap your argument in std.fmt.fmtSliceHexLower instead"), - 'X' => @compileError("specifier 'X' has been deprecated, wrap your argument in std.fmt.fmtSliceHexUpper instead"), - else => {}, - } -} - -pub fn formatText( - bytes: []const u8, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, -) !void { - comptime checkTextFmt(fmt); - return formatBuf(bytes, options, writer); -} - -pub fn formatAsciiChar( - c: u8, - options: FormatOptions, - writer: anytype, -) !void { - return formatBuf(@as(*const [1]u8, &c), options, writer); -} - -pub fn formatUnicodeCodepoint( - c: u21, - options: FormatOptions, - writer: anytype, -) !void { - var buf: [4]u8 = undefined; - const len = unicode.utf8Encode(c, &buf) catch |err| switch (err) { - error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => { - return formatBuf(&unicode.utf8EncodeComptime(unicode.replacement_character), options, writer); - }, - }; - return formatBuf(buf[0..len], options, writer); -} - -pub fn formatBuf( - buf: []const u8, - options: FormatOptions, - writer: anytype, -) !void { - if (options.width) |min_width| { - // In case of error assume the buffer content is ASCII-encoded - const width = unicode.utf8CountCodepoints(buf) catch buf.len; - const padding = if (width < min_width) min_width - width else 0; - - if (padding == 0) - return writer.writeAll(buf); - - var fill_buffer: [4]u8 = undefined; - const fill_utf8 = if (unicode.utf8Encode(options.fill, &fill_buffer)) |len| - fill_buffer[0..len] - else |err| switch (err) { - error.Utf8CannotEncodeSurrogateHalf, - error.CodepointTooLarge, - => &unicode.utf8EncodeComptime(unicode.replacement_character), - }; - switch (options.alignment) { - .left => { - try writer.writeAll(buf); - try writer.writeBytesNTimes(fill_utf8, padding); - }, - .center => { - const left_padding = padding / 2; - const right_padding = (padding + 1) / 2; - try writer.writeBytesNTimes(fill_utf8, left_padding); - try writer.writeAll(buf); - try writer.writeBytesNTimes(fill_utf8, right_padding); - }, - .right => { - try writer.writeBytesNTimes(fill_utf8, padding); - try writer.writeAll(buf); - }, - } - } else { - // Fast path, avoid counting the number of codepoints - try writer.writeAll(buf); - } -} - -pub fn formatFloatHexadecimal( - value: anytype, - options: FormatOptions, - writer: anytype, -) !void { - if (math.signbit(value)) { - try writer.writeByte('-'); - } - if (math.isNan(value)) { - return writer.writeAll("nan"); - } - if (math.isInf(value)) { - return writer.writeAll("inf"); - } - - const T = @TypeOf(value); - const TU = std.meta.Int(.unsigned, @bitSizeOf(T)); - - const mantissa_bits = math.floatMantissaBits(T); - const fractional_bits = math.floatFractionalBits(T); - const exponent_bits = math.floatExponentBits(T); - const mantissa_mask = (1 << mantissa_bits) - 1; - const exponent_mask = (1 << exponent_bits) - 1; - const exponent_bias = (1 << (exponent_bits - 1)) - 1; - - const as_bits = @as(TU, @bitCast(value)); - var mantissa = as_bits & mantissa_mask; - var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask)); - - const is_denormal = exponent == 0 and mantissa != 0; - const is_zero = exponent == 0 and mantissa == 0; - - if (is_zero) { - // Handle this case here to simplify the logic below. - try writer.writeAll("0x0"); - if (options.precision) |precision| { - if (precision > 0) { - try writer.writeAll("."); - try writer.writeByteNTimes('0', precision); - } - } else { - try writer.writeAll(".0"); - } - try writer.writeAll("p0"); - return; - } - - if (is_denormal) { - // Adjust the exponent for printing. - exponent += 1; - } else { - if (fractional_bits == mantissa_bits) - mantissa |= 1 << fractional_bits; // Add the implicit integer bit. - } - - const mantissa_digits = (fractional_bits + 3) / 4; - // Fill in zeroes to round the fraction width to a multiple of 4. - mantissa <<= mantissa_digits * 4 - fractional_bits; - - if (options.precision) |precision| { - // Round if needed. - if (precision < mantissa_digits) { - // We always have at least 4 extra bits. - var extra_bits = (mantissa_digits - precision) * 4; - // The result LSB is the Guard bit, we need two more (Round and - // Sticky) to round the value. - while (extra_bits > 2) { - mantissa = (mantissa >> 1) | (mantissa & 1); - extra_bits -= 1; - } - // Round to nearest, tie to even. - mantissa |= @intFromBool(mantissa & 0b100 != 0); - mantissa += 1; - // Drop the excess bits. - mantissa >>= 2; - // Restore the alignment. - mantissa <<= @as(math.Log2Int(TU), @intCast((mantissa_digits - precision) * 4)); - - const overflow = mantissa & (1 << 1 + mantissa_digits * 4) != 0; - // Prefer a normalized result in case of overflow. - if (overflow) { - mantissa >>= 1; - exponent += 1; - } - } - } - - // +1 for the decimal part. - var buf: [1 + mantissa_digits]u8 = undefined; - _ = formatIntBuf(&buf, mantissa, 16, .lower, .{ .fill = '0', .width = 1 + mantissa_digits }); - - try writer.writeAll("0x"); - try writer.writeByte(buf[0]); - const trimmed = mem.trimEnd(u8, buf[1..], "0"); - if (options.precision) |precision| { - if (precision > 0) try writer.writeAll("."); - } else if (trimmed.len > 0) { - try writer.writeAll("."); - } - try writer.writeAll(trimmed); - // Add trailing zeros if explicitly requested. - if (options.precision) |precision| if (precision > 0) { - if (precision > trimmed.len) - try writer.writeByteNTimes('0', precision - trimmed.len); - }; - try writer.writeAll("p"); - try formatInt(exponent - exponent_bias, 10, .lower, .{}, writer); -} - -pub fn formatInt( - value: anytype, - base: u8, - case: Case, - options: FormatOptions, - writer: anytype, -) !void { - assert(base >= 2); - - const int_value = if (@TypeOf(value) == comptime_int) blk: { - const Int = math.IntFittingRange(value, value); - break :blk @as(Int, value); - } else value; - - const value_info = @typeInfo(@TypeOf(int_value)).int; - - // The type must have the same size as `base` or be wider in order for the - // division to work - const min_int_bits = comptime @max(value_info.bits, 8); - const MinInt = std.meta.Int(.unsigned, min_int_bits); - - const abs_value = @abs(int_value); - // The worst case in terms of space needed is base 2, plus 1 for the sign - var buf: [1 + @max(@as(comptime_int, value_info.bits), 1)]u8 = undefined; - - var a: MinInt = abs_value; - var index: usize = buf.len; - - if (base == 10) { - while (a >= 100) : (a = @divTrunc(a, 100)) { - index -= 2; - buf[index..][0..2].* = digits2(@intCast(a % 100)); - } - - if (a < 10) { - index -= 1; - buf[index] = '0' + @as(u8, @intCast(a)); - } else { - index -= 2; - buf[index..][0..2].* = digits2(@intCast(a)); - } - } else { - while (true) { - const digit = a % base; - index -= 1; - buf[index] = digitToChar(@intCast(digit), case); - a /= base; - if (a == 0) break; - } - } - - if (value_info.signedness == .signed) { - if (value < 0) { - // Negative integer - index -= 1; - buf[index] = '-'; - } else if (options.width == null or options.width.? == 0) { - // Positive integer, omit the plus sign - } else { - // Positive integer - index -= 1; - buf[index] = '+'; - } - } - - return formatBuf(buf[index..], options, writer); -} - -pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options: FormatOptions) usize { - var fbs = std.io.fixedBufferStream(out_buf); - formatInt(value, base, case, options, fbs.writer()) catch unreachable; - return fbs.pos; +/// Asserts the rendered integer value fits in `buffer`. +/// Returns the end index within `buffer`. +pub fn printInt(buffer: []u8, value: anytype, base: u8, case: Case, options: Options) usize { + var bw: Writer = .fixed(buffer); + bw.printIntOptions(value, base, case, options) catch unreachable; + return bw.end; } /// Converts values in the range [0, 100) to a base 10 string. @@ -1261,244 +422,22 @@ pub fn digits2(value: u8) [2]u8 { } } -const FormatDurationData = struct { - ns: u64, - negative: bool = false, -}; - -fn formatDuration(data: FormatDurationData, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - _ = fmt; - - // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24 - var buf: [24]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); - var buf_writer = fbs.writer(); - if (data.negative) { - buf_writer.writeByte('-') catch unreachable; - } - - var ns_remaining = data.ns; - inline for (.{ - .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' }, - .{ .ns = std.time.ns_per_week, .sep = 'w' }, - .{ .ns = std.time.ns_per_day, .sep = 'd' }, - .{ .ns = std.time.ns_per_hour, .sep = 'h' }, - .{ .ns = std.time.ns_per_min, .sep = 'm' }, - }) |unit| { - if (ns_remaining >= unit.ns) { - const units = ns_remaining / unit.ns; - formatInt(units, 10, .lower, .{}, buf_writer) catch unreachable; - buf_writer.writeByte(unit.sep) catch unreachable; - ns_remaining -= units * unit.ns; - if (ns_remaining == 0) - return formatBuf(fbs.getWritten(), options, writer); - } - } - - inline for (.{ - .{ .ns = std.time.ns_per_s, .sep = "s" }, - .{ .ns = std.time.ns_per_ms, .sep = "ms" }, - .{ .ns = std.time.ns_per_us, .sep = "us" }, - }) |unit| { - const kunits = ns_remaining * 1000 / unit.ns; - if (kunits >= 1000) { - formatInt(kunits / 1000, 10, .lower, .{}, buf_writer) catch unreachable; - const frac = kunits % 1000; - if (frac > 0) { - // Write up to 3 decimal places - var decimal_buf = [_]u8{ '.', 0, 0, 0 }; - _ = formatIntBuf(decimal_buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 3 }); - var end: usize = 4; - while (end > 1) : (end -= 1) { - if (decimal_buf[end - 1] != '0') break; - } - buf_writer.writeAll(decimal_buf[0..end]) catch unreachable; - } - buf_writer.writeAll(unit.sep) catch unreachable; - return formatBuf(fbs.getWritten(), options, writer); - } - } - - formatInt(ns_remaining, 10, .lower, .{}, buf_writer) catch unreachable; - buf_writer.writeAll("ns") catch unreachable; - return formatBuf(fbs.getWritten(), options, writer); -} - -/// Return a Formatter for number of nanoseconds according to its magnitude: -/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s -pub fn fmtDuration(ns: u64) Formatter(formatDuration) { - const data = FormatDurationData{ .ns = ns }; - return .{ .data = data }; -} - -test fmtDuration { - var buf: [24]u8 = undefined; - inline for (.{ - .{ .s = "0ns", .d = 0 }, - .{ .s = "1ns", .d = 1 }, - .{ .s = "999ns", .d = std.time.ns_per_us - 1 }, - .{ .s = "1us", .d = std.time.ns_per_us }, - .{ .s = "1.45us", .d = 1450 }, - .{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 }, - .{ .s = "14.5us", .d = 14500 }, - .{ .s = "145us", .d = 145000 }, - .{ .s = "999.999us", .d = std.time.ns_per_ms - 1 }, - .{ .s = "1ms", .d = std.time.ns_per_ms + 1 }, - .{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 }, - .{ .s = "1.11ms", .d = 1110000 }, - .{ .s = "1.111ms", .d = 1111000 }, - .{ .s = "1.111ms", .d = 1111100 }, - .{ .s = "999.999ms", .d = std.time.ns_per_s - 1 }, - .{ .s = "1s", .d = std.time.ns_per_s }, - .{ .s = "59.999s", .d = std.time.ns_per_min - 1 }, - .{ .s = "1m", .d = std.time.ns_per_min }, - .{ .s = "1h", .d = std.time.ns_per_hour }, - .{ .s = "1d", .d = std.time.ns_per_day }, - .{ .s = "1w", .d = std.time.ns_per_week }, - .{ .s = "1y", .d = 365 * std.time.ns_per_day }, - .{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d - .{ .s = "1y1h1.001s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms }, - .{ .s = "1y1h1s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us }, - .{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 }, - .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms }, - .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 }, - .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 }, - .{ .s = "584y49w23h34m33.709s", .d = math.maxInt(u64) }, - }) |tc| { - const slice = try bufPrint(&buf, "{}", .{fmtDuration(tc.d)}); - try std.testing.expectEqualStrings(tc.s, slice); - } - - inline for (.{ - .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 }, - .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 }, - .{ .s = " 999ns ", .f = "{s:^10}", .d = std.time.ns_per_us - 1 }, - }) |tc| { - const slice = try bufPrint(&buf, tc.f, .{fmtDuration(tc.d)}); - try std.testing.expectEqualStrings(tc.s, slice); - } -} - -fn formatDurationSigned(ns: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - const data = FormatDurationData{ .ns = @abs(ns), .negative = ns < 0 }; - try formatDuration(data, fmt, options, writer); -} - -/// Return a Formatter for number of nanoseconds according to its signed magnitude: -/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s -pub fn fmtDurationSigned(ns: i64) Formatter(formatDurationSigned) { - return .{ .data = ns }; -} - -test fmtDurationSigned { - var buf: [24]u8 = undefined; - inline for (.{ - .{ .s = "0ns", .d = 0 }, - .{ .s = "1ns", .d = 1 }, - .{ .s = "-1ns", .d = -(1) }, - .{ .s = "999ns", .d = std.time.ns_per_us - 1 }, - .{ .s = "-999ns", .d = -(std.time.ns_per_us - 1) }, - .{ .s = "1us", .d = std.time.ns_per_us }, - .{ .s = "-1us", .d = -(std.time.ns_per_us) }, - .{ .s = "1.45us", .d = 1450 }, - .{ .s = "-1.45us", .d = -(1450) }, - .{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 }, - .{ .s = "-1.5us", .d = -(3 * std.time.ns_per_us / 2) }, - .{ .s = "14.5us", .d = 14500 }, - .{ .s = "-14.5us", .d = -(14500) }, - .{ .s = "145us", .d = 145000 }, - .{ .s = "-145us", .d = -(145000) }, - .{ .s = "999.999us", .d = std.time.ns_per_ms - 1 }, - .{ .s = "-999.999us", .d = -(std.time.ns_per_ms - 1) }, - .{ .s = "1ms", .d = std.time.ns_per_ms + 1 }, - .{ .s = "-1ms", .d = -(std.time.ns_per_ms + 1) }, - .{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 }, - .{ .s = "-1.5ms", .d = -(3 * std.time.ns_per_ms / 2) }, - .{ .s = "1.11ms", .d = 1110000 }, - .{ .s = "-1.11ms", .d = -(1110000) }, - .{ .s = "1.111ms", .d = 1111000 }, - .{ .s = "-1.111ms", .d = -(1111000) }, - .{ .s = "1.111ms", .d = 1111100 }, - .{ .s = "-1.111ms", .d = -(1111100) }, - .{ .s = "999.999ms", .d = std.time.ns_per_s - 1 }, - .{ .s = "-999.999ms", .d = -(std.time.ns_per_s - 1) }, - .{ .s = "1s", .d = std.time.ns_per_s }, - .{ .s = "-1s", .d = -(std.time.ns_per_s) }, - .{ .s = "59.999s", .d = std.time.ns_per_min - 1 }, - .{ .s = "-59.999s", .d = -(std.time.ns_per_min - 1) }, - .{ .s = "1m", .d = std.time.ns_per_min }, - .{ .s = "-1m", .d = -(std.time.ns_per_min) }, - .{ .s = "1h", .d = std.time.ns_per_hour }, - .{ .s = "-1h", .d = -(std.time.ns_per_hour) }, - .{ .s = "1d", .d = std.time.ns_per_day }, - .{ .s = "-1d", .d = -(std.time.ns_per_day) }, - .{ .s = "1w", .d = std.time.ns_per_week }, - .{ .s = "-1w", .d = -(std.time.ns_per_week) }, - .{ .s = "1y", .d = 365 * std.time.ns_per_day }, - .{ .s = "-1y", .d = -(365 * std.time.ns_per_day) }, - .{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d - .{ .s = "-1y52w23h59m59.999s", .d = -(730 * std.time.ns_per_day - 1) }, // 365d = 52w1d - .{ .s = "1y1h1.001s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms }, - .{ .s = "-1y1h1.001s", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms) }, - .{ .s = "1y1h1s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us }, - .{ .s = "-1y1h1s", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us) }, - .{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 }, - .{ .s = "-1y1h999.999us", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1) }, - .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms }, - .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms) }, - .{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 }, - .{ .s = "-1y1h1ms", .d = -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1) }, - .{ .s = "1y1m999ns", .d = 365 * std.time.ns_per_day + std.time.ns_per_min + 999 }, - .{ .s = "-1y1m999ns", .d = -(365 * std.time.ns_per_day + std.time.ns_per_min + 999) }, - .{ .s = "292y24w3d23h47m16.854s", .d = math.maxInt(i64) }, - .{ .s = "-292y24w3d23h47m16.854s", .d = math.minInt(i64) + 1 }, - .{ .s = "-292y24w3d23h47m16.854s", .d = math.minInt(i64) }, - }) |tc| { - const slice = try bufPrint(&buf, "{}", .{fmtDurationSigned(tc.d)}); - try std.testing.expectEqualStrings(tc.s, slice); - } - - inline for (.{ - .{ .s = "=======0ns", .f = "{s:=>10}", .d = 0 }, - .{ .s = "1ns=======", .f = "{s:=<10}", .d = 1 }, - .{ .s = "-1ns======", .f = "{s:=<10}", .d = -(1) }, - .{ .s = " -999ns ", .f = "{s:^10}", .d = -(std.time.ns_per_us - 1) }, - }) |tc| { - const slice = try bufPrint(&buf, tc.f, .{fmtDurationSigned(tc.d)}); - try std.testing.expectEqualStrings(tc.s, slice); - } -} - pub const ParseIntError = error{ - /// The result cannot fit in the type specified + /// The result cannot fit in the type specified. Overflow, - - /// The input was empty or contained an invalid character + /// The input was empty or contained an invalid character. InvalidCharacter, }; -/// Creates a Formatter type from a format function. Wrapping data in Formatter(func) causes -/// the data to be formatted using the given function `func`. `func` must be of the following -/// form: -/// -/// fn formatExample( -/// data: T, -/// comptime fmt: []const u8, -/// options: std.fmt.FormatOptions, -/// writer: anytype, -/// ) !void; -/// -pub fn Formatter(comptime formatFn: anytype) type { - const Data = @typeInfo(@TypeOf(formatFn)).@"fn".params[0].type.?; +pub fn Formatter( + comptime Data: type, + comptime formatFn: fn (data: Data, writer: *Writer) Writer.Error!void, +) type { return struct { data: Data, - pub fn format( - self: @This(), - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try formatFn(self.data, fmt, options, writer); + pub fn format(self: @This(), writer: *Writer, comptime fmt: []const u8) Writer.Error!void { + comptime assert(fmt.len == 0); + try formatFn(self.data, writer); } }; } @@ -1793,15 +732,13 @@ pub const BufPrintError = error{ NoSpaceLeft, }; -/// Print a Formatter string into `buf`. Actually just a thin wrapper around `format` and `fixedBufferStream`. -/// Returns a slice of the bytes printed to. +/// Print a Formatter string into `buf`. Returns a slice of the bytes printed. pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 { - var fbs = std.io.fixedBufferStream(buf); - format(fbs.writer().any(), fmt, args) catch |err| switch (err) { - error.NoSpaceLeft => return error.NoSpaceLeft, - else => unreachable, + var w: Writer = .fixed(buf); + w.print(fmt, args) catch |err| switch (err) { + error.WriteFailed => return error.NoSpaceLeft, }; - return fbs.getWritten(); + return w.buffered(); } pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![:0]u8 { @@ -1809,51 +746,37 @@ pub fn bufPrintZ(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintErr return result[0 .. result.len - 1 :0]; } -/// Count the characters needed for format. Useful for preallocating memory -pub fn count(comptime fmt: []const u8, args: anytype) u64 { - var counting_writer = std.io.countingWriter(std.io.null_writer); - format(counting_writer.writer().any(), fmt, args) catch unreachable; - return counting_writer.bytes_written; -} - -pub const AllocPrintError = error{OutOfMemory}; - -pub fn allocPrint(allocator: mem.Allocator, comptime fmt: []const u8, args: anytype) AllocPrintError![]u8 { - const size = math.cast(usize, count(fmt, args)) orelse return error.OutOfMemory; - const buf = try allocator.alloc(u8, size); - return bufPrint(buf, fmt, args) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, // we just counted the size above +/// Count the characters needed for format. +pub fn count(comptime fmt: []const u8, args: anytype) usize { + var trash_buffer: [64]u8 = undefined; + var w: Writer = .discarding(&trash_buffer); + w.print(fmt, args) catch |err| switch (err) { + error.WriteFailed => unreachable, }; + return w.count; } -pub fn allocPrintZ(allocator: mem.Allocator, comptime fmt: []const u8, args: anytype) AllocPrintError![:0]u8 { - const result = try allocPrint(allocator, fmt ++ "\x00", args); - return result[0 .. result.len - 1 :0]; +pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 { + var aw = try Writer.Allocating.initCapacity(gpa, fmt.len); + defer aw.deinit(); + aw.interface.print(fmt, args) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return aw.toOwnedSlice(); } -test bufPrintIntToSlice { - var buffer: [100]u8 = undefined; - const buf = buffer[0..]; - - try std.testing.expectEqualSlices(u8, "-1", bufPrintIntToSlice(buf, @as(i1, -1), 10, .lower, FormatOptions{})); - - try std.testing.expectEqualSlices(u8, "-101111000110000101001110", bufPrintIntToSlice(buf, @as(i32, -12345678), 2, .lower, FormatOptions{})); - try std.testing.expectEqualSlices(u8, "-12345678", bufPrintIntToSlice(buf, @as(i32, -12345678), 10, .lower, FormatOptions{})); - try std.testing.expectEqualSlices(u8, "-bc614e", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, .lower, FormatOptions{})); - try std.testing.expectEqualSlices(u8, "-BC614E", bufPrintIntToSlice(buf, @as(i32, -12345678), 16, .upper, FormatOptions{})); - - try std.testing.expectEqualSlices(u8, "12345678", bufPrintIntToSlice(buf, @as(u32, 12345678), 10, .upper, FormatOptions{})); - - try std.testing.expectEqualSlices(u8, " 666", bufPrintIntToSlice(buf, @as(u32, 666), 10, .lower, FormatOptions{ .width = 6 })); - try std.testing.expectEqualSlices(u8, " 1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, .lower, FormatOptions{ .width = 6 })); - try std.testing.expectEqualSlices(u8, "1234", bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, .lower, FormatOptions{ .width = 1 })); - - try std.testing.expectEqualSlices(u8, "+42", bufPrintIntToSlice(buf, @as(i32, 42), 10, .lower, FormatOptions{ .width = 3 })); - try std.testing.expectEqualSlices(u8, "-42", bufPrintIntToSlice(buf, @as(i32, -42), 10, .lower, FormatOptions{ .width = 3 })); -} - -pub fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, case: Case, options: FormatOptions) []u8 { - return buf[0..formatIntBuf(buf, value, base, case, options)]; +pub fn allocPrintSentinel( + gpa: Allocator, + comptime fmt: []const u8, + args: anytype, + comptime sentinel: u8, +) Allocator.Error![:sentinel]u8 { + var aw = try Writer.Allocating.initCapacity(gpa, fmt.len); + defer aw.deinit(); + aw.interface.print(fmt, args) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return aw.toOwnedSliceSentinel(sentinel); } pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 { @@ -1984,26 +907,22 @@ test "int.padded" { try expectFmt("i16: '-12345'", "i16: '{:4}'", .{@as(i16, -12345)}); try expectFmt("i16: '+12345'", "i16: '{:4}'", .{@as(i16, 12345)}); try expectFmt("u16: '12345'", "u16: '{:4}'", .{@as(u16, 12345)}); - - try expectFmt("UTF-8: 'ü '", "UTF-8: '{u:<4}'", .{'ü'}); - try expectFmt("UTF-8: ' ü'", "UTF-8: '{u:>4}'", .{'ü'}); - try expectFmt("UTF-8: ' ü '", "UTF-8: '{u:^4}'", .{'ü'}); } test "buffer" { { var buf1: [32]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf1); - try formatType(1234, "", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth); - try std.testing.expectEqualStrings("1234", fbs.getWritten()); + var w: Writer = .fixed(&buf1); + try w.printValue("", .{}, 1234, std.options.fmt_max_depth); + try std.testing.expectEqualStrings("1234", w.buffered()); - fbs.reset(); - try formatType('a', "c", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth); - try std.testing.expectEqualStrings("a", fbs.getWritten()); + w = .fixed(&buf1); + try w.printValue("c", .{}, 'a', std.options.fmt_max_depth); + try std.testing.expectEqualStrings("a", w.buffered()); - fbs.reset(); - try formatType(0b1100, "b", FormatOptions{}, fbs.writer(), std.options.fmt_max_depth); - try std.testing.expectEqualStrings("1100", fbs.getWritten()); + w = .fixed(&buf1); + try w.printValue("b", .{}, 0b1100, std.options.fmt_max_depth); + try std.testing.expectEqualStrings("1100", w.buffered()); } } @@ -2021,7 +940,7 @@ test "array" { const value: [3]u8 = "abc".*; try expectArrayFmt("array: abc\n", "array: {s}\n", value); try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {d}\n", value); - try expectArrayFmt("array: { 61, 62, 63 }\n", "array: {x}\n", value); + try expectArrayFmt("array: 616263\n", "array: {x}\n", value); try expectArrayFmt("array: { 97, 98, 99 }\n", "array: {any}\n", value); var buf: [100]u8 = undefined; @@ -2037,7 +956,7 @@ test "array" { try expectArrayFmt("array: { abc, def }\n", "array: {s}\n", value); try expectArrayFmt("array: { { 97, 98, 99 }, { 100, 101, 102 } }\n", "array: {d}\n", value); - try expectArrayFmt("array: { { 61, 62, 63 }, { 64, 65, 66 } }\n", "array: {x}\n", value); + try expectArrayFmt("array: { 616263, 646566 }\n", "array: {x}\n", value); } } @@ -2046,7 +965,7 @@ test "slice" { const value: []const u8 = "abc"; try expectFmt("slice: abc\n", "slice: {s}\n", .{value}); try expectFmt("slice: { 97, 98, 99 }\n", "slice: {d}\n", .{value}); - try expectFmt("slice: { 61, 62, 63 }\n", "slice: {x}\n", .{value}); + try expectFmt("slice: 616263\n", "slice: {x}\n", .{value}); try expectFmt("slice: { 97, 98, 99 }\n", "slice: {any}\n", .{value}); } { @@ -2083,22 +1002,15 @@ test "slice" { const S2 = struct { x: u8, - pub fn format(s: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(s: @This(), writer: *Writer, comptime _: []const u8) Writer.Error!void { try writer.print("S2({})", .{s.x}); } }; const struct_slice: []const S2 = &[_]S2{ S2{ .x = 8 }, S2{ .x = 42 } }; - try expectFmt("slice: { S2(8), S2(42) }", "slice: {any}", .{struct_slice}); + try expectFmt("slice: { fmt.test.slice.S2{ .x = 8 }, fmt.test.slice.S2{ .x = 42 } }", "slice: {any}", .{struct_slice}); } } -test "escape non-printable" { - try expectFmt("abc 123", "{s}", .{fmtSliceEscapeLower("abc 123")}); - try expectFmt("ab\\xffc", "{s}", .{fmtSliceEscapeLower("ab\xffc")}); - try expectFmt("abc 123", "{s}", .{fmtSliceEscapeUpper("abc 123")}); - try expectFmt("ab\\xFFc", "{s}", .{fmtSliceEscapeUpper("ab\xffc")}); -} - test "pointer" { { const value = @as(*align(1) i32, @ptrFromInt(0xdeadbeef)); @@ -2129,21 +1041,6 @@ test "cstr" { ); } -test "filesize" { - try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeDec(42)}); - try expectFmt("file size: 42B\n", "file size: {}\n", .{fmtIntSizeBin(42)}); - try expectFmt("file size: 63MB\n", "file size: {}\n", .{fmtIntSizeDec(63 * 1000 * 1000)}); - try expectFmt("file size: 63MiB\n", "file size: {}\n", .{fmtIntSizeBin(63 * 1024 * 1024)}); - try expectFmt("file size: 42B\n", "file size: {:.2}\n", .{fmtIntSizeDec(42)}); - try expectFmt("file size: 42B\n", "file size: {:>9.2}\n", .{fmtIntSizeDec(42)}); - try expectFmt("file size: 66.06MB\n", "file size: {:.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)}); - try expectFmt("file size: 60.08MiB\n", "file size: {:.2}\n", .{fmtIntSizeBin(63 * 1000 * 1000)}); - try expectFmt("file size: =66.06MB=\n", "file size: {:=^9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)}); - try expectFmt("file size: 66.06MB\n", "file size: {: >9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)}); - try expectFmt("file size: 66.06MB \n", "file size: {: <9.2}\n", .{fmtIntSizeDec(63 * 1024 * 1024)}); - try expectFmt("file size: 0.01844674407370955ZB\n", "file size: {}\n", .{fmtIntSizeDec(math.maxInt(u64))}); -} - test "struct" { { const Struct = struct { @@ -2176,7 +1073,7 @@ test "struct" { // Tuples try expectFmt("{ }", "{}", .{.{}}); try expectFmt("{ -1 }", "{}", .{.{-1}}); - try expectFmt("{ -1, 42, 2.5e4 }", "{}", .{.{ -1, 42, 0.25e5 }}); + try expectFmt("{ -1, 42, 25000 }", "{}", .{.{ -1, 42, 0.25e5 }}); } test "enum" { @@ -2216,10 +1113,14 @@ test "non-exhaustive enum" { try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.One\n", "enum: {}\n", .{Enum.One}); try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {}\n", .{Enum.Two}); try expectFmt("enum: fmt.test.non-exhaustive enum.Enum(4660)\n", "enum: {}\n", .{@as(Enum, @enumFromInt(0x1234))}); - try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.One\n", "enum: {x}\n", .{Enum.One}); - try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {x}\n", .{Enum.Two}); - try expectFmt("enum: fmt.test.non-exhaustive enum.Enum.Two\n", "enum: {X}\n", .{Enum.Two}); - try expectFmt("enum: fmt.test.non-exhaustive enum.Enum(1234)\n", "enum: {x}\n", .{@as(Enum, @enumFromInt(0x1234))}); + try expectFmt("enum: f\n", "enum: {x}\n", .{Enum.One}); + try expectFmt("enum: beef\n", "enum: {x}\n", .{Enum.Two}); + try expectFmt("enum: BEEF\n", "enum: {X}\n", .{Enum.Two}); + try expectFmt("enum: 1234\n", "enum: {x}\n", .{@as(Enum, @enumFromInt(0x1234))}); + + try expectFmt("enum: 15\n", "enum: {d}\n", .{Enum.One}); + try expectFmt("enum: 48879\n", "enum: {d}\n", .{Enum.Two}); + try expectFmt("enum: 4660\n", "enum: {d}\n", .{@as(Enum, @enumFromInt(0x1234))}); } test "float.scientific" { @@ -2351,13 +1252,7 @@ test "custom" { x: f32, y: f32, - pub fn format( - self: SelfType, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, - ) !void { - _ = options; + pub fn format(self: SelfType, writer: *Writer, comptime fmt: []const u8) Writer.Error!void { if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) { return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y }); } else if (comptime std.mem.eql(u8, fmt, "d")) { @@ -2368,16 +1263,16 @@ test "custom" { } }; - var value = Vec2{ + var value: Vec2 = .{ .x = 10.2, .y = 2.22, }; - try expectFmt("point: (10.200,2.220)\n", "point: {}\n", .{&value}); - try expectFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{&value}); + try expectFmt("point: (10.200,2.220)\n", "point: {f}\n", .{&value}); + try expectFmt("dim: 10.200x2.220\n", "dim: {fd}\n", .{&value}); // same thing but not passing a pointer - try expectFmt("point: (10.200,2.220)\n", "point: {}\n", .{value}); - try expectFmt("dim: 10.200x2.220\n", "dim: {d}\n", .{value}); + try expectFmt("point: (10.200,2.220)\n", "point: {f}\n", .{value}); + try expectFmt("dim: 10.200x2.220\n", "dim: {fd}\n", .{value}); } test "union" { @@ -2439,17 +1334,6 @@ test "struct.zero-size" { try expectFmt("fmt.test.struct.zero-size.B{ .a = fmt.test.struct.zero-size.A{ }, .c = 0 }", "{}", .{b}); } -test "bytes.hex" { - const some_bytes = "\xCA\xFE\xBA\xBE"; - try expectFmt("lowercase: cafebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes)}); - try expectFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes)}); - //Test Slices - try expectFmt("uppercase: CAFE\n", "uppercase: {X}\n", .{fmtSliceHexUpper(some_bytes[0..2])}); - try expectFmt("lowercase: babe\n", "lowercase: {x}\n", .{fmtSliceHexLower(some_bytes[2..])}); - const bytes_with_zeros = "\x00\x0E\xBA\xBE"; - try expectFmt("lowercase: 000ebabe\n", "lowercase: {x}\n", .{fmtSliceHexLower(bytes_with_zeros)}); -} - /// Encodes a sequence of bytes as hexadecimal digits. /// Returns an array containing the encoded bytes. pub fn bytesToHex(input: anytype, case: Case) [input.len * 2]u8 { @@ -2494,110 +1378,14 @@ test bytesToHex { test hexToBytes { var buf: [32]u8 = undefined; - try expectFmt("90" ** 32, "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "90" ** 32))}); - try expectFmt("ABCD", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, "ABCD"))}); - try expectFmt("", "{s}", .{fmtSliceHexUpper(try hexToBytes(&buf, ""))}); + try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)}); + try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")}); + try expectFmt("", "{X}", .{try hexToBytes(&buf, "")}); try std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z")); try std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA")); try std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB")); } -test "formatIntValue with comptime_int" { - const value: comptime_int = 123456789123456789; - - var buf: [20]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); - try formatIntValue(value, "", FormatOptions{}, fbs.writer()); - try std.testing.expectEqualStrings("123456789123456789", fbs.getWritten()); -} - -test "formatFloatValue with comptime_float" { - const value: comptime_float = 1.0; - - var buf: [20]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); - try formatFloatValue(value, "", FormatOptions{}, fbs.writer()); - try std.testing.expectEqualStrings(fbs.getWritten(), "1e0"); - - try expectFmt("1e0", "{}", .{value}); - try expectFmt("1e0", "{}", .{1.0}); -} - -test "formatType max_depth" { - const Vec2 = struct { - const SelfType = @This(); - x: f32, - y: f32, - - pub fn format( - self: SelfType, - comptime fmt: []const u8, - options: FormatOptions, - writer: anytype, - ) !void { - _ = options; - if (fmt.len == 0) { - return std.fmt.format(writer, "({d:.3},{d:.3})", .{ self.x, self.y }); - } else { - @compileError("unknown format string: '" ++ fmt ++ "'"); - } - } - }; - const E = enum { - One, - Two, - Three, - }; - const TU = union(enum) { - const SelfType = @This(); - float: f32, - int: u32, - ptr: ?*SelfType, - }; - const S = struct { - const SelfType = @This(); - a: ?*SelfType, - tu: TU, - e: E, - vec: Vec2, - }; - - var inst = S{ - .a = null, - .tu = TU{ .ptr = null }, - .e = E.Two, - .vec = Vec2{ .x = 10.2, .y = 2.22 }, - }; - inst.a = &inst; - inst.tu.ptr = &inst.tu; - - var buf: [1000]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); - try formatType(inst, "", FormatOptions{}, fbs.writer(), 0); - try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ ... }", fbs.getWritten()); - - fbs.reset(); - try formatType(inst, "", FormatOptions{}, fbs.writer(), 1); - try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }", fbs.getWritten()); - - fbs.reset(); - try formatType(inst, "", FormatOptions{}, fbs.writer(), 2); - try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }", fbs.getWritten()); - - fbs.reset(); - try formatType(inst, "", FormatOptions{}, fbs.writer(), 3); - try std.testing.expectEqualStrings("fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ .a = fmt.test.formatType max_depth.S{ ... }, .tu = fmt.test.formatType max_depth.TU{ ... }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }, .tu = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ .ptr = fmt.test.formatType max_depth.TU{ ... } } }, .e = fmt.test.formatType max_depth.E.Two, .vec = (10.200,2.220) }", fbs.getWritten()); - - const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 }; - fbs.reset(); - try formatType(vec, "", FormatOptions{}, fbs.writer(), 0); - try std.testing.expectEqualStrings("{ ... }", fbs.getWritten()); - - fbs.reset(); - try formatType(vec, "", FormatOptions{}, fbs.writer(), 1); - try std.testing.expectEqualStrings("{ 1, 2, 3, 4 }", fbs.getWritten()); -} - test "positional" { try expectFmt("2 1 0", "{2} {1} {0}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) }); try expectFmt("2 1 0", "{2} {1} {}", .{ @as(usize, 0), @as(usize, 1), @as(usize, 2) }); @@ -2664,23 +1452,11 @@ test "padding" { try expectFmt("==================Filled", "{s:=>24}", .{"Filled"}); try expectFmt(" Centered ", "{s:^24}", .{"Centered"}); try expectFmt("-", "{s:-^1}", .{""}); - try expectFmt("==crêpe===", "{s:=^10}", .{"crêpe"}); - try expectFmt("=====crêpe", "{s:=>10}", .{"crêpe"}); - try expectFmt("crêpe=====", "{s:=<10}", .{"crêpe"}); try expectFmt("====a", "{c:=>5}", .{'a'}); try expectFmt("==a==", "{c:=^5}", .{'a'}); try expectFmt("a====", "{c:=<5}", .{'a'}); } -test "padding fill char utf" { - try expectFmt("──crêpe───", "{s:─^10}", .{"crêpe"}); - try expectFmt("─────crêpe", "{s:─>10}", .{"crêpe"}); - try expectFmt("crêpe─────", "{s:─<10}", .{"crêpe"}); - try expectFmt("────a", "{c:─>5}", .{'a'}); - try expectFmt("──a──", "{c:─^5}", .{'a'}); - try expectFmt("a────", "{c:─<5}", .{'a'}); -} - test "decimal float padding" { const number: f32 = 3.1415; try expectFmt("left-pad: **3.142\n", "left-pad: {d:*>7.3}\n", .{number}); @@ -2742,16 +1518,16 @@ test "recursive format function" { Leaf: i32, Branch: struct { left: *const R, right: *const R }, - pub fn format(self: R, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(self: R, writer: *Writer, comptime _: []const u8) Writer.Error!void { return switch (self) { .Leaf => |n| std.fmt.format(writer, "Leaf({})", .{n}), - .Branch => |b| std.fmt.format(writer, "Branch({}, {})", .{ b.left, b.right }), + .Branch => |b| std.fmt.format(writer, "Branch({f}, {f})", .{ b.left, b.right }), }; } }; - var r = R{ .Leaf = 1 }; - try expectFmt("Leaf(1)\n", "{}\n", .{&r}); + var r: R = .{ .Leaf = 1 }; + try expectFmt("Leaf(1)\n", "{f}\n", .{&r}); } pub const hex_charset = "0123456789abcdef"; @@ -2785,54 +1561,39 @@ test hex { test "parser until" { { // return substring till ':' - var parser: Parser = .{ - .iter = .{ .bytes = "abc:1234", .i = 0 }, - }; + var parser: Parser = .{ .bytes = "abc:1234", .i = 0 }; try testing.expectEqualStrings("abc", parser.until(':')); } { // return the entire string - `ch` not found - var parser: Parser = .{ - .iter = .{ .bytes = "abc1234", .i = 0 }, - }; + var parser: Parser = .{ .bytes = "abc1234", .i = 0 }; try testing.expectEqualStrings("abc1234", parser.until(':')); } { // substring is empty - `ch` is the only character - var parser: Parser = .{ - .iter = .{ .bytes = ":", .i = 0 }, - }; + var parser: Parser = .{ .bytes = ":", .i = 0 }; try testing.expectEqualStrings("", parser.until(':')); } { // empty string and `ch` not found - var parser: Parser = .{ - .iter = .{ .bytes = "", .i = 0 }, - }; + var parser: Parser = .{ .bytes = "", .i = 0 }; try testing.expectEqualStrings("", parser.until(':')); } { // substring starts at index 2 and goes upto `ch` - var parser: Parser = .{ - .iter = .{ .bytes = "abc:1234", .i = 2 }, - }; + var parser: Parser = .{ .bytes = "abc:1234", .i = 2 }; try testing.expectEqualStrings("c", parser.until(':')); } { // substring starts at index 4 and goes upto the end - `ch` not found - var parser: Parser = .{ - .iter = .{ .bytes = "abc1234", .i = 4 }, - }; + var parser: Parser = .{ .bytes = "abc1234", .i = 4 }; try testing.expectEqualStrings("234", parser.until(':')); } } test "parser peek" { { // start iteration from the first index - var parser: Parser = .{ - .iter = .{ .bytes = "hello world", .i = 0 }, - }; - + var parser: Parser = .{ .bytes = "hello world", .i = 0 }; try testing.expectEqual('h', parser.peek(0)); try testing.expectEqual('e', parser.peek(1)); try testing.expectEqual(' ', parser.peek(5)); @@ -2841,9 +1602,7 @@ test "parser peek" { } { // start iteration from the second last index - var parser: Parser = .{ - .iter = .{ .bytes = "hello world!", .i = 10 }, - }; + var parser: Parser = .{ .bytes = "hello world!", .i = 10 }; try testing.expectEqual('d', parser.peek(0)); try testing.expectEqual('!', parser.peek(1)); @@ -2851,18 +1610,14 @@ test "parser peek" { } { // start iteration beyond the length of the string - var parser: Parser = .{ - .iter = .{ .bytes = "hello", .i = 5 }, - }; + var parser: Parser = .{ .bytes = "hello", .i = 5 }; try testing.expectEqual(null, parser.peek(0)); try testing.expectEqual(null, parser.peek(1)); } { // empty string - var parser: Parser = .{ - .iter = .{ .bytes = "", .i = 0 }, - }; + var parser: Parser = .{ .bytes = "", .i = 0 }; try testing.expectEqual(null, parser.peek(0)); try testing.expectEqual(null, parser.peek(2)); @@ -2871,78 +1626,78 @@ test "parser peek" { test "parser char" { // character exists - iterator at 0 - var parser: Parser = .{ .iter = .{ .bytes = "~~hello", .i = 0 } }; + var parser: Parser = .{ .bytes = "~~hello", .i = 0 }; try testing.expectEqual('~', parser.char()); // character exists - iterator in the middle - parser = .{ .iter = .{ .bytes = "~~hello", .i = 3 } }; + parser = .{ .bytes = "~~hello", .i = 3 }; try testing.expectEqual('e', parser.char()); // character exists - iterator at the end - parser = .{ .iter = .{ .bytes = "~~hello", .i = 6 } }; + parser = .{ .bytes = "~~hello", .i = 6 }; try testing.expectEqual('o', parser.char()); // character doesn't exist - iterator beyond the length of the string - parser = .{ .iter = .{ .bytes = "~~hello", .i = 7 } }; + parser = .{ .bytes = "~~hello", .i = 7 }; try testing.expectEqual(null, parser.char()); } test "parser maybe" { // character exists - iterator at 0 - var parser: Parser = .{ .iter = .{ .bytes = "hello world", .i = 0 } }; + var parser: Parser = .{ .bytes = "hello world", .i = 0 }; try testing.expect(parser.maybe('h')); // character exists - iterator at space - parser = .{ .iter = .{ .bytes = "hello world", .i = 5 } }; + parser = .{ .bytes = "hello world", .i = 5 }; try testing.expect(parser.maybe(' ')); // character exists - iterator at the end - parser = .{ .iter = .{ .bytes = "hello world", .i = 10 } }; + parser = .{ .bytes = "hello world", .i = 10 }; try testing.expect(parser.maybe('d')); // character doesn't exist - iterator beyond the length of the string - parser = .{ .iter = .{ .bytes = "hello world", .i = 11 } }; + parser = .{ .bytes = "hello world", .i = 11 }; try testing.expect(!parser.maybe('e')); } test "parser number" { // input is a single digit natural number - iterator at 0 - var parser: Parser = .{ .iter = .{ .bytes = "7", .i = 0 } }; + var parser: Parser = .{ .bytes = "7", .i = 0 }; try testing.expect(7 == parser.number()); // input is a two digit natural number - iterator at 1 - parser = .{ .iter = .{ .bytes = "29", .i = 1 } }; + parser = .{ .bytes = "29", .i = 1 }; try testing.expect(9 == parser.number()); // input is a two digit natural number - iterator beyond the length of the string - parser = .{ .iter = .{ .bytes = "32", .i = 2 } }; + parser = .{ .bytes = "32", .i = 2 }; try testing.expectEqual(null, parser.number()); // input is an integer - parser = .{ .iter = .{ .bytes = "0", .i = 0 } }; + parser = .{ .bytes = "0", .i = 0 }; try testing.expect(0 == parser.number()); // input is a negative integer - parser = .{ .iter = .{ .bytes = "-2", .i = 0 } }; + parser = .{ .bytes = "-2", .i = 0 }; try testing.expectEqual(null, parser.number()); // input is a string - parser = .{ .iter = .{ .bytes = "no_number", .i = 2 } }; + parser = .{ .bytes = "no_number", .i = 2 }; try testing.expectEqual(null, parser.number()); // input is a single character string - parser = .{ .iter = .{ .bytes = "n", .i = 0 } }; + parser = .{ .bytes = "n", .i = 0 }; try testing.expectEqual(null, parser.number()); // input is an empty string - parser = .{ .iter = .{ .bytes = "", .i = 0 } }; + parser = .{ .bytes = "", .i = 0 }; try testing.expectEqual(null, parser.number()); } test "parser specifier" { { // input string is a digit; iterator at 0 const expected: Specifier = Specifier{ .number = 1 }; - var parser: Parser = .{ .iter = .{ .bytes = "1", .i = 0 } }; + var parser: Parser = .{ .bytes = "1", .i = 0 }; const result = try parser.specifier(); try testing.expect(expected.number == result.number); @@ -2950,7 +1705,7 @@ test "parser specifier" { { // input string is a two digit number; iterator at 0 const digit: Specifier = Specifier{ .number = 42 }; - var parser: Parser = .{ .iter = .{ .bytes = "42", .i = 0 } }; + var parser: Parser = .{ .bytes = "42", .i = 0 }; const result = try parser.specifier(); try testing.expect(digit.number == result.number); @@ -2958,7 +1713,7 @@ test "parser specifier" { { // input string is a two digit number digit; iterator at 1 const digit: Specifier = Specifier{ .number = 8 }; - var parser: Parser = .{ .iter = .{ .bytes = "28", .i = 1 } }; + var parser: Parser = .{ .bytes = "28", .i = 1 }; const result = try parser.specifier(); try testing.expect(digit.number == result.number); @@ -2966,7 +1721,7 @@ test "parser specifier" { { // input string is a two digit number with square brackets; iterator at 0 const digit: Specifier = Specifier{ .named = "15" }; - var parser: Parser = .{ .iter = .{ .bytes = "[15]", .i = 0 } }; + var parser: Parser = .{ .bytes = "[15]", .i = 0 }; const result = try parser.specifier(); try testing.expectEqualStrings(digit.named, result.named); @@ -2974,21 +1729,21 @@ test "parser specifier" { { // input string is not a number and contains square brackets; iterator at 0 const digit: Specifier = Specifier{ .named = "hello" }; - var parser: Parser = .{ .iter = .{ .bytes = "[hello]", .i = 0 } }; + var parser: Parser = .{ .bytes = "[hello]", .i = 0 }; const result = try parser.specifier(); try testing.expectEqualStrings(digit.named, result.named); } { // input string is not a number and doesn't contain closing square bracket; iterator at 0 - var parser: Parser = .{ .iter = .{ .bytes = "[hello", .i = 0 } }; + var parser: Parser = .{ .bytes = "[hello", .i = 0 }; const result = parser.specifier(); try testing.expectError(@field(anyerror, "Expected closing ]"), result); } { // input string is not a number and doesn't contain closing square bracket; iterator at 2 - var parser: Parser = .{ .iter = .{ .bytes = "[[[[hello", .i = 2 } }; + var parser: Parser = .{ .bytes = "[[[[hello", .i = 2 }; const result = parser.specifier(); try testing.expectError(@field(anyerror, "Expected closing ]"), result); @@ -2996,7 +1751,7 @@ test "parser specifier" { { // input string is not a number and contains unbalanced square brackets; iterator at 0 const digit: Specifier = Specifier{ .named = "[[hello" }; - var parser: Parser = .{ .iter = .{ .bytes = "[[[hello]", .i = 0 } }; + var parser: Parser = .{ .bytes = "[[[hello]", .i = 0 }; const result = try parser.specifier(); try testing.expectEqualStrings(digit.named, result.named); @@ -3004,7 +1759,7 @@ test "parser specifier" { { // input string is not a number and contains unbalanced square brackets; iterator at 1 const digit: Specifier = Specifier{ .named = "[[hello" }; - var parser: Parser = .{ .iter = .{ .bytes = "[[[[hello]]]]]", .i = 1 } }; + var parser: Parser = .{ .bytes = "[[[[hello]]]]]", .i = 1 }; const result = try parser.specifier(); try testing.expectEqualStrings(digit.named, result.named); @@ -3012,9 +1767,13 @@ test "parser specifier" { { // input string is neither a digit nor a named argument const char: Specifier = Specifier{ .none = {} }; - var parser: Parser = .{ .iter = .{ .bytes = "hello", .i = 0 } }; + var parser: Parser = .{ .bytes = "hello", .i = 0 }; const result = try parser.specifier(); try testing.expectEqual(char.none, result.none); } } + +test { + _ = float; +} diff --git a/lib/std/fmt/format_float.zig b/lib/std/fmt/float.zig similarity index 99% rename from lib/std/fmt/format_float.zig rename to lib/std/fmt/float.zig index 4c4c1a2922..16df95ad28 100644 --- a/lib/std/fmt/format_float.zig +++ b/lib/std/fmt/float.zig @@ -11,7 +11,7 @@ const special_exponent = 0x7fffffff; pub const min_buffer_size = 53; /// Returns the minimum buffer size needed to print every float of a specific type and format. -pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int { +pub fn bufferSize(comptime mode: Mode, comptime T: type) comptime_int { comptime std.debug.assert(@typeInfo(T) == .float); return switch (mode) { .scientific => 53, @@ -27,17 +27,17 @@ pub fn bufferSize(comptime mode: Format, comptime T: type) comptime_int { }; } -pub const FormatError = error{ +pub const Error = error{ BufferTooSmall, }; -pub const Format = enum { +pub const Mode = enum { scientific, decimal, }; -pub const FormatOptions = struct { - mode: Format = .scientific, +pub const Options = struct { + mode: Mode = .scientific, precision: ?usize = null, }; @@ -52,11 +52,11 @@ pub const FormatOptions = struct { /// /// When printing full precision decimals, use `bufferSize` to get the required space. It is /// recommended to bound decimal output with a fixed precision to reduce the required buffer size. -pub fn formatFloat(buf: []u8, v_: anytype, options: FormatOptions) FormatError![]const u8 { - const v = switch (@TypeOf(v_)) { +pub fn render(buf: []u8, value: anytype, options: Options) Error![]const u8 { + const v = switch (@TypeOf(value)) { // comptime_float internally is a f128; this preserves precision. - comptime_float => @as(f128, v_), - else => v_, + comptime_float => @as(f128, value), + else => value, }; const T = @TypeOf(v); @@ -192,7 +192,7 @@ fn round(comptime T: type, f: FloatDecimal(T), mode: RoundMode, precision: usize /// will not fit. /// /// It is recommended to bound decimal formatting with an exact precision. -pub fn formatScientific(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) FormatError![]const u8 { +pub fn formatScientific(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) Error![]const u8 { std.debug.assert(buf.len >= min_buffer_size); var f = f_; @@ -263,7 +263,7 @@ pub fn formatScientific(comptime T: type, buf: []u8, f_: FloatDecimal(T), precis /// The buffer provided must be greater than `min_buffer_size` bytes in length. If no precision is /// specified, this may still return an error. If precision is specified, `2 + precision` bytes will /// always be written. -pub fn formatDecimal(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) FormatError![]const u8 { +pub fn formatDecimal(comptime T: type, buf: []u8, f_: FloatDecimal(T), precision: ?usize) Error![]const u8 { std.debug.assert(buf.len >= min_buffer_size); var f = f_; @@ -1520,7 +1520,7 @@ fn check(comptime T: type, value: T, comptime expected: []const u8) !void { var buf: [6000]u8 = undefined; const value_bits: I = @bitCast(value); - const s = try formatFloat(&buf, value, .{}); + const s = try render(&buf, value, .{}); try std.testing.expectEqualStrings(expected, s); if (T == f80 and builtin.target.os.tag == .windows and builtin.target.cpu.arch == .x86_64) return; diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig index 35b84769e4..2453370c91 100644 --- a/lib/std/fs/File.zig +++ b/lib/std/fs/File.zig @@ -1,3 +1,20 @@ +const builtin = @import("builtin"); +const Os = std.builtin.Os; +const native_os = builtin.os.tag; +const is_windows = native_os == .windows; + +const File = @This(); +const std = @import("../std.zig"); +const Allocator = std.mem.Allocator; +const posix = std.posix; +const io = std.io; +const math = std.math; +const assert = std.debug.assert; +const linux = std.os.linux; +const windows = std.os.windows; +const maxInt = std.math.maxInt; +const Alignment = std.mem.Alignment; + /// The OS-specific file descriptor or file handle. handle: Handle, @@ -168,6 +185,18 @@ pub const CreateFlags = struct { mode: Mode = default_mode, }; +pub fn stdout() File { + return .{ .handle = if (is_windows) windows.peb().ProcessParameters.hStdOutput else posix.STDOUT_FILENO }; +} + +pub fn stderr() File { + return .{ .handle = if (is_windows) windows.peb().ProcessParameters.hStdError else posix.STDERR_FILENO }; +} + +pub fn stdin() File { + return .{ .handle = if (is_windows) windows.peb().ProcessParameters.hStdInput else posix.STDIN_FILENO }; +} + /// Upon success, the stream is in an uninitialized state. To continue using it, /// you must use the open() function. pub fn close(self: File) void { @@ -351,8 +380,10 @@ pub fn getPos(self: File) GetSeekPosError!u64 { return posix.lseek_CUR_get(self.handle); } +pub const GetEndPosError = std.os.windows.GetFileSizeError || StatError; + /// TODO: integrate with async I/O -pub fn getEndPos(self: File) GetSeekPosError!u64 { +pub fn getEndPos(self: File) GetEndPosError!u64 { if (builtin.os.tag == .windows) { return windows.GetFileSizeEx(self.handle); } @@ -477,7 +508,6 @@ pub const Stat = struct { pub const StatError = posix.FStatError; /// Returns `Stat` containing basic information about the `File`. -/// Use `metadata` to retrieve more detailed information (e.g. creation time, permissions). /// TODO: integrate with async I/O pub fn stat(self: File) StatError!Stat { if (builtin.os.tag == .windows) { @@ -743,361 +773,6 @@ pub fn setPermissions(self: File, permissions: Permissions) SetPermissionsError! } } -/// Cross-platform representation of file metadata. -/// Platform-specific functionality is available through the `inner` field. -pub const Metadata = struct { - /// Exposes platform-specific functionality. - inner: switch (builtin.os.tag) { - .windows => MetadataWindows, - .linux => MetadataLinux, - .wasi => MetadataWasi, - else => MetadataUnix, - }, - - const Self = @This(); - - /// Returns the size of the file - pub fn size(self: Self) u64 { - return self.inner.size(); - } - - /// Returns a `Permissions` struct, representing the permissions on the file - pub fn permissions(self: Self) Permissions { - return self.inner.permissions(); - } - - /// Returns the `Kind` of file. - /// On Windows, can only return: `.file`, `.directory`, `.sym_link` or `.unknown` - pub fn kind(self: Self) Kind { - return self.inner.kind(); - } - - /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01 - pub fn accessed(self: Self) i128 { - return self.inner.accessed(); - } - - /// Returns the time the file was modified in nanoseconds since UTC 1970-01-01 - pub fn modified(self: Self) i128 { - return self.inner.modified(); - } - - /// Returns the time the file was created in nanoseconds since UTC 1970-01-01 - /// On Windows, this cannot return null - /// On Linux, this returns null if the filesystem does not support creation times - /// On Unices, this returns null if the filesystem or OS does not support creation times - /// On MacOS, this returns the ctime if the filesystem does not support creation times; this is insanity, and yet another reason to hate on Apple - pub fn created(self: Self) ?i128 { - return self.inner.created(); - } -}; - -pub const MetadataUnix = struct { - stat: posix.Stat, - - const Self = @This(); - - /// Returns the size of the file - pub fn size(self: Self) u64 { - return @intCast(self.stat.size); - } - - /// Returns a `Permissions` struct, representing the permissions on the file - pub fn permissions(self: Self) Permissions { - return .{ .inner = .{ .mode = self.stat.mode } }; - } - - /// Returns the `Kind` of the file - pub fn kind(self: Self) Kind { - if (builtin.os.tag == .wasi and !builtin.link_libc) return switch (self.stat.filetype) { - .BLOCK_DEVICE => .block_device, - .CHARACTER_DEVICE => .character_device, - .DIRECTORY => .directory, - .SYMBOLIC_LINK => .sym_link, - .REGULAR_FILE => .file, - .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket, - else => .unknown, - }; - - const m = self.stat.mode & posix.S.IFMT; - - switch (m) { - posix.S.IFBLK => return .block_device, - posix.S.IFCHR => return .character_device, - posix.S.IFDIR => return .directory, - posix.S.IFIFO => return .named_pipe, - posix.S.IFLNK => return .sym_link, - posix.S.IFREG => return .file, - posix.S.IFSOCK => return .unix_domain_socket, - else => {}, - } - - if (builtin.os.tag.isSolarish()) switch (m) { - posix.S.IFDOOR => return .door, - posix.S.IFPORT => return .event_port, - else => {}, - }; - - return .unknown; - } - - /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01 - pub fn accessed(self: Self) i128 { - const atime = self.stat.atime(); - return @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec; - } - - /// Returns the last time the file was modified in nanoseconds since UTC 1970-01-01 - pub fn modified(self: Self) i128 { - const mtime = self.stat.mtime(); - return @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec; - } - - /// Returns the time the file was created in nanoseconds since UTC 1970-01-01. - /// Returns null if this is not supported by the OS or filesystem - pub fn created(self: Self) ?i128 { - if (!@hasDecl(@TypeOf(self.stat), "birthtime")) return null; - const birthtime = self.stat.birthtime(); - - // If the filesystem doesn't support this the value *should* be: - // On FreeBSD: nsec = 0, sec = -1 - // On NetBSD and OpenBSD: nsec = 0, sec = 0 - // On MacOS, it is set to ctime -- we cannot detect this!! - switch (builtin.os.tag) { - .freebsd => if (birthtime.sec == -1 and birthtime.nsec == 0) return null, - .netbsd, .openbsd => if (birthtime.sec == 0 and birthtime.nsec == 0) return null, - .macos => {}, - else => @compileError("Creation time detection not implemented for OS"), - } - - return @as(i128, birthtime.sec) * std.time.ns_per_s + birthtime.nsec; - } -}; - -/// `MetadataUnix`, but using Linux's `statx` syscall. -pub const MetadataLinux = struct { - statx: std.os.linux.Statx, - - const Self = @This(); - - /// Returns the size of the file - pub fn size(self: Self) u64 { - return self.statx.size; - } - - /// Returns a `Permissions` struct, representing the permissions on the file - pub fn permissions(self: Self) Permissions { - return Permissions{ .inner = PermissionsUnix{ .mode = self.statx.mode } }; - } - - /// Returns the `Kind` of the file - pub fn kind(self: Self) Kind { - const m = self.statx.mode & posix.S.IFMT; - - switch (m) { - posix.S.IFBLK => return .block_device, - posix.S.IFCHR => return .character_device, - posix.S.IFDIR => return .directory, - posix.S.IFIFO => return .named_pipe, - posix.S.IFLNK => return .sym_link, - posix.S.IFREG => return .file, - posix.S.IFSOCK => return .unix_domain_socket, - else => {}, - } - - return .unknown; - } - - /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01 - pub fn accessed(self: Self) i128 { - return @as(i128, self.statx.atime.sec) * std.time.ns_per_s + self.statx.atime.nsec; - } - - /// Returns the last time the file was modified in nanoseconds since UTC 1970-01-01 - pub fn modified(self: Self) i128 { - return @as(i128, self.statx.mtime.sec) * std.time.ns_per_s + self.statx.mtime.nsec; - } - - /// Returns the time the file was created in nanoseconds since UTC 1970-01-01. - /// Returns null if this is not supported by the filesystem, or on kernels before than version 4.11 - pub fn created(self: Self) ?i128 { - if (self.statx.mask & std.os.linux.STATX_BTIME == 0) return null; - return @as(i128, self.statx.btime.sec) * std.time.ns_per_s + self.statx.btime.nsec; - } -}; - -pub const MetadataWasi = struct { - stat: std.os.wasi.filestat_t, - - pub fn size(self: @This()) u64 { - return self.stat.size; - } - - pub fn permissions(self: @This()) Permissions { - return .{ .inner = .{ .mode = self.stat.mode } }; - } - - pub fn kind(self: @This()) Kind { - return switch (self.stat.filetype) { - .BLOCK_DEVICE => .block_device, - .CHARACTER_DEVICE => .character_device, - .DIRECTORY => .directory, - .SYMBOLIC_LINK => .sym_link, - .REGULAR_FILE => .file, - .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket, - else => .unknown, - }; - } - - pub fn accessed(self: @This()) i128 { - return self.stat.atim; - } - - pub fn modified(self: @This()) i128 { - return self.stat.mtim; - } - - pub fn created(self: @This()) ?i128 { - return self.stat.ctim; - } -}; - -pub const MetadataWindows = struct { - attributes: windows.DWORD, - reparse_tag: windows.DWORD, - _size: u64, - access_time: i128, - modified_time: i128, - creation_time: i128, - - const Self = @This(); - - /// Returns the size of the file - pub fn size(self: Self) u64 { - return self._size; - } - - /// Returns a `Permissions` struct, representing the permissions on the file - pub fn permissions(self: Self) Permissions { - return .{ .inner = .{ .attributes = self.attributes } }; - } - - /// Returns the `Kind` of the file. - /// Can only return: `.file`, `.directory`, `.sym_link` or `.unknown` - pub fn kind(self: Self) Kind { - if (self.attributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) { - if (self.reparse_tag & windows.reparse_tag_name_surrogate_bit != 0) { - return .sym_link; - } - } else if (self.attributes & windows.FILE_ATTRIBUTE_DIRECTORY != 0) { - return .directory; - } else { - return .file; - } - return .unknown; - } - - /// Returns the last time the file was accessed in nanoseconds since UTC 1970-01-01 - pub fn accessed(self: Self) i128 { - return self.access_time; - } - - /// Returns the time the file was modified in nanoseconds since UTC 1970-01-01 - pub fn modified(self: Self) i128 { - return self.modified_time; - } - - /// Returns the time the file was created in nanoseconds since UTC 1970-01-01. - /// This never returns null, only returning an optional for compatibility with other OSes - pub fn created(self: Self) ?i128 { - return self.creation_time; - } -}; - -pub const MetadataError = posix.FStatError; - -pub fn metadata(self: File) MetadataError!Metadata { - return .{ - .inner = switch (builtin.os.tag) { - .windows => blk: { - var io_status_block: windows.IO_STATUS_BLOCK = undefined; - var info: windows.FILE_ALL_INFORMATION = undefined; - - const rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &info, @sizeOf(windows.FILE_ALL_INFORMATION), .FileAllInformation); - switch (rc) { - .SUCCESS => {}, - // Buffer overflow here indicates that there is more information available than was able to be stored in the buffer - // size provided. This is treated as success because the type of variable-length information that this would be relevant for - // (name, volume name, etc) we don't care about. - .BUFFER_OVERFLOW => {}, - .INVALID_PARAMETER => unreachable, - .ACCESS_DENIED => return error.AccessDenied, - else => return windows.unexpectedStatus(rc), - } - - const reparse_tag: windows.DWORD = reparse_blk: { - if (info.BasicInformation.FileAttributes & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) { - var tag_info: windows.FILE_ATTRIBUTE_TAG_INFO = undefined; - const tag_rc = windows.ntdll.NtQueryInformationFile(self.handle, &io_status_block, &tag_info, @sizeOf(windows.FILE_ATTRIBUTE_TAG_INFO), .FileAttributeTagInformation); - switch (tag_rc) { - .SUCCESS => {}, - // INFO_LENGTH_MISMATCH and ACCESS_DENIED are the only documented possible errors - // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/d295752f-ce89-4b98-8553-266d37c84f0e - .INFO_LENGTH_MISMATCH => unreachable, - .ACCESS_DENIED => return error.AccessDenied, - else => return windows.unexpectedStatus(rc), - } - break :reparse_blk tag_info.ReparseTag; - } - break :reparse_blk 0; - }; - - break :blk .{ - .attributes = info.BasicInformation.FileAttributes, - .reparse_tag = reparse_tag, - ._size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)), - .access_time = windows.fromSysTime(info.BasicInformation.LastAccessTime), - .modified_time = windows.fromSysTime(info.BasicInformation.LastWriteTime), - .creation_time = windows.fromSysTime(info.BasicInformation.CreationTime), - }; - }, - .linux => blk: { - var stx = std.mem.zeroes(linux.Statx); - - // We are gathering information for Metadata, which is meant to contain all the - // native OS information about the file, so use all known flags. - const rc = linux.statx( - self.handle, - "", - linux.AT.EMPTY_PATH, - linux.STATX_BASIC_STATS | linux.STATX_BTIME, - &stx, - ); - - switch (linux.E.init(rc)) { - .SUCCESS => {}, - .ACCES => unreachable, - .BADF => unreachable, - .FAULT => unreachable, - .INVAL => unreachable, - .LOOP => unreachable, - .NAMETOOLONG => unreachable, - .NOENT => unreachable, - .NOMEM => return error.SystemResources, - .NOTDIR => unreachable, - else => |err| return posix.unexpectedErrno(err), - } - - break :blk .{ - .statx = stx, - }; - }, - .wasi => .{ .stat = try std.os.fstat_wasi(self.handle) }, - else => .{ .stat = try posix.fstat(self.handle) }, - }, - }; -} - pub const UpdateTimesError = posix.FutimensError || windows.SetFileTimeError; /// The underlying file system may have a different granularity than nanoseconds, @@ -1130,19 +805,12 @@ pub fn updateTimes( try posix.futimens(self.handle, ×); } -/// Reads all the bytes from the current position to the end of the file. -/// On success, caller owns returned buffer. -/// If the file is larger than `max_bytes`, returns `error.FileTooBig`. +/// Deprecated in favor of `Reader`. pub fn readToEndAlloc(self: File, allocator: Allocator, max_bytes: usize) ![]u8 { return self.readToEndAllocOptions(allocator, max_bytes, null, .of(u8), null); } -/// Reads all the bytes from the current position to the end of the file. -/// On success, caller owns returned buffer. -/// If the file is larger than `max_bytes`, returns `error.FileTooBig`. -/// If `size_hint` is specified the initial buffer size is calculated using -/// that value, otherwise an arbitrary value is used instead. -/// Allows specifying alignment and a sentinel value. +/// Deprecated in favor of `Reader`. pub fn readToEndAllocOptions( self: File, allocator: Allocator, @@ -1161,7 +829,7 @@ pub fn readToEndAllocOptions( var array_list = try std.ArrayListAligned(u8, alignment).initCapacity(allocator, initial_cap); defer array_list.deinit(); - self.reader().readAllArrayListAligned(alignment, &array_list, max_bytes) catch |err| switch (err) { + self.deprecatedReader().readAllArrayListAligned(alignment, &array_list, max_bytes) catch |err| switch (err) { error.StreamTooLong => return error.FileTooBig, else => |e| return e, }; @@ -1184,8 +852,7 @@ pub fn read(self: File, buffer: []u8) ReadError!usize { return posix.read(self.handle, buffer); } -/// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it -/// means the file reached the end. Reaching the end of a file is not an error condition. +/// Deprecated in favor of `Reader`. pub fn readAll(self: File, buffer: []u8) ReadError!usize { var index: usize = 0; while (index != buffer.len) { @@ -1206,10 +873,7 @@ pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize { return posix.pread(self.handle, buffer, offset); } -/// Returns the number of bytes read. If the number read is smaller than `buffer.len`, it -/// means the file reached the end. Reaching the end of a file is not an error condition. -/// On Windows, this function currently does alter the file pointer. -/// https://github.com/ziglang/zig/issues/12783 +/// Deprecated in favor of `Reader`. pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!usize { var index: usize = 0; while (index != buffer.len) { @@ -1223,8 +887,7 @@ pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!usize { /// See https://github.com/ziglang/zig/issues/7699 pub fn readv(self: File, iovecs: []const posix.iovec) ReadError!usize { if (is_windows) { - // TODO improve this to use ReadFileScatter - if (iovecs.len == 0) return @as(usize, 0); + if (iovecs.len == 0) return 0; const first = iovecs[0]; return windows.ReadFile(self.handle, first.base[0..first.len], null); } @@ -1232,19 +895,7 @@ pub fn readv(self: File, iovecs: []const posix.iovec) ReadError!usize { return posix.readv(self.handle, iovecs); } -/// Returns the number of bytes read. If the number read is smaller than the total bytes -/// from all the buffers, it means the file reached the end. Reaching the end of a file -/// is not an error condition. -/// -/// The `iovecs` parameter is mutable because: -/// * This function needs to mutate the fields in order to handle partial -/// reads from the underlying OS layer. -/// * The OS layer expects pointer addresses to be inside the application's address space -/// even if the length is zero. Meanwhile, in Zig, slices may have undefined pointer -/// addresses when the length is zero. So this function modifies the base fields -/// when the length is zero. -/// -/// Related open issue: https://github.com/ziglang/zig/issues/7699 +/// Deprecated in favor of `Reader`. pub fn readvAll(self: File, iovecs: []posix.iovec) ReadError!usize { if (iovecs.len == 0) return 0; @@ -1279,8 +930,7 @@ pub fn readvAll(self: File, iovecs: []posix.iovec) ReadError!usize { /// https://github.com/ziglang/zig/issues/12783 pub fn preadv(self: File, iovecs: []const posix.iovec, offset: u64) PReadError!usize { if (is_windows) { - // TODO improve this to use ReadFileScatter - if (iovecs.len == 0) return @as(usize, 0); + if (iovecs.len == 0) return 0; const first = iovecs[0]; return windows.ReadFile(self.handle, first.base[0..first.len], offset); } @@ -1288,14 +938,7 @@ pub fn preadv(self: File, iovecs: []const posix.iovec, offset: u64) PReadError!u return posix.preadv(self.handle, iovecs, offset); } -/// Returns the number of bytes read. If the number read is smaller than the total bytes -/// from all the buffers, it means the file reached the end. Reaching the end of a file -/// is not an error condition. -/// The `iovecs` parameter is mutable because this function needs to mutate the fields in -/// order to handle partial reads from the underlying OS layer. -/// See https://github.com/ziglang/zig/issues/7699 -/// On Windows, this function currently does alter the file pointer. -/// https://github.com/ziglang/zig/issues/12783 +/// Deprecated in favor of `Reader`. pub fn preadvAll(self: File, iovecs: []posix.iovec, offset: u64) PReadError!usize { if (iovecs.len == 0) return 0; @@ -1328,6 +971,7 @@ pub fn write(self: File, bytes: []const u8) WriteError!usize { return posix.write(self.handle, bytes); } +/// Deprecated in favor of `Writer`. pub fn writeAll(self: File, bytes: []const u8) WriteError!void { var index: usize = 0; while (index < bytes.len) { @@ -1345,8 +989,7 @@ pub fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize { return posix.pwrite(self.handle, bytes, offset); } -/// On Windows, this function currently does alter the file pointer. -/// https://github.com/ziglang/zig/issues/12783 +/// Deprecated in favor of `Writer`. pub fn pwriteAll(self: File, bytes: []const u8, offset: u64) PWriteError!void { var index: usize = 0; while (index < bytes.len) { @@ -1355,11 +998,10 @@ pub fn pwriteAll(self: File, bytes: []const u8, offset: u64) PWriteError!void { } /// See https://github.com/ziglang/zig/issues/7699 -/// See equivalent function: `std.net.Stream.writev`. pub fn writev(self: File, iovecs: []const posix.iovec_const) WriteError!usize { if (is_windows) { // TODO improve this to use WriteFileScatter - if (iovecs.len == 0) return @as(usize, 0); + if (iovecs.len == 0) return 0; const first = iovecs[0]; return windows.WriteFile(self.handle, first.base[0..first.len], null); } @@ -1367,15 +1009,7 @@ pub fn writev(self: File, iovecs: []const posix.iovec_const) WriteError!usize { return posix.writev(self.handle, iovecs); } -/// The `iovecs` parameter is mutable because: -/// * This function needs to mutate the fields in order to handle partial -/// writes from the underlying OS layer. -/// * The OS layer expects pointer addresses to be inside the application's address space -/// even if the length is zero. Meanwhile, in Zig, slices may have undefined pointer -/// addresses when the length is zero. So this function modifies the base fields -/// when the length is zero. -/// See https://github.com/ziglang/zig/issues/7699 -/// See equivalent function: `std.net.Stream.writevAll`. +/// Deprecated in favor of `Writer`. pub fn writevAll(self: File, iovecs: []posix.iovec_const) WriteError!void { if (iovecs.len == 0) return; @@ -1405,8 +1039,7 @@ pub fn writevAll(self: File, iovecs: []posix.iovec_const) WriteError!void { /// https://github.com/ziglang/zig/issues/12783 pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError!usize { if (is_windows) { - // TODO improve this to use WriteFileScatter - if (iovecs.len == 0) return @as(usize, 0); + if (iovecs.len == 0) return 0; const first = iovecs[0]; return windows.WriteFile(self.handle, first.base[0..first.len], offset); } @@ -1414,14 +1047,9 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError return posix.pwritev(self.handle, iovecs, offset); } -/// The `iovecs` parameter is mutable because this function needs to mutate the fields in -/// order to handle partial writes from the underlying OS layer. -/// See https://github.com/ziglang/zig/issues/7699 -/// On Windows, this function currently does alter the file pointer. -/// https://github.com/ziglang/zig/issues/12783 +/// Deprecated in favor of `Writer`. pub fn pwritevAll(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError!void { if (iovecs.len == 0) return; - var i: usize = 0; var off: u64 = 0; while (true) { @@ -1439,14 +1067,14 @@ pub fn pwritevAll(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteEr pub const CopyRangeError = posix.CopyFileRangeError; +/// Deprecated in favor of `Writer`. pub fn copyRange(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 { const adjusted_len = math.cast(usize, len) orelse maxInt(usize); const result = try posix.copy_file_range(in.handle, in_offset, out.handle, out_offset, adjusted_len, 0); return result; } -/// Returns the number of bytes copied. If the number read is smaller than `buffer.len`, it -/// means the in file reached the end. Reaching the end of a file is not an error condition. +/// Deprecated in favor of `Writer`. pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 { var total_bytes_copied: u64 = 0; var in_off = in_offset; @@ -1461,24 +1089,18 @@ pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u return total_bytes_copied; } +/// Deprecated in favor of `Writer`. pub const WriteFileOptions = struct { in_offset: u64 = 0, - - /// `null` means the entire file. `0` means no bytes from the file. - /// When this is `null`, trailers must be sent in a separate writev() call - /// due to a flaw in the BSD sendfile API. Other operating systems, such as - /// Linux, already do this anyway due to API limitations. - /// If the size of the source file is known, passing the size here will save one syscall. in_len: ?u64 = null, - headers_and_trailers: []posix.iovec_const = &[0]posix.iovec_const{}, - - /// The trailer count is inferred from `headers_and_trailers.len - header_count` header_count: usize = 0, }; +/// Deprecated in favor of `Writer`. pub const WriteFileError = ReadError || error{EndOfStream} || WriteError; +/// Deprecated in favor of `Writer`. pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) { error.Unseekable, @@ -1488,35 +1110,27 @@ pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFile error.NetworkUnreachable, error.NetworkSubsystemFailed, => return self.writeFileAllUnseekable(in_file, args), - else => |e| return e, }; } -/// Does not try seeking in either of the File parameters. -/// See `writeFileAll` as an alternative to calling this. +/// Deprecated in favor of `Writer`. pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { const headers = args.headers_and_trailers[0..args.header_count]; const trailers = args.headers_and_trailers[args.header_count..]; - try self.writevAll(headers); - - try in_file.reader().skipBytes(args.in_offset, .{ .buf_size = 4096 }); - + try in_file.deprecatedReader().skipBytes(args.in_offset, .{ .buf_size = 4096 }); var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); if (args.in_len) |len| { - var stream = std.io.limitedReader(in_file.reader(), len); - try fifo.pump(stream.reader(), self.writer()); + var stream = std.io.limitedReader(in_file.deprecatedReader(), len); + try fifo.pump(stream.reader(), self.deprecatedWriter()); } else { - try fifo.pump(in_file.reader(), self.writer()); + try fifo.pump(in_file.deprecatedReader(), self.deprecatedWriter()); } - try self.writevAll(trailers); } -/// Low level function which can fail for OS-specific reasons. -/// See `writeFileAll` as an alternative to calling this. -/// TODO integrate with async I/O +/// Deprecated in favor of `Writer`. fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix.SendFileError!void { const count = blk: { if (args.in_len) |l| { @@ -1581,18 +1195,23 @@ fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix } } -pub const Reader = io.GenericReader(File, ReadError, read); +/// Deprecated in favor of `Reader`. +pub const DeprecatedReader = io.GenericReader(File, ReadError, read); -pub fn reader(file: File) Reader { +/// Deprecated in favor of `Reader`. +pub fn deprecatedReader(file: File) DeprecatedReader { return .{ .context = file }; } -pub const Writer = io.GenericWriter(File, WriteError, write); +/// Deprecated in favor of `Writer`. +pub const DeprecatedWriter = io.GenericWriter(File, WriteError, write); -pub fn writer(file: File) Writer { +/// Deprecated in favor of `Writer`. +pub fn deprecatedWriter(file: File) DeprecatedWriter { return .{ .context = file }; } +/// Deprecated in favor of `Reader` and `Writer`. pub const SeekableStream = io.SeekableStream( File, SeekError, @@ -1603,10 +1222,715 @@ pub const SeekableStream = io.SeekableStream( getEndPos, ); +/// Deprecated in favor of `Reader` and `Writer`. pub fn seekableStream(file: File) SeekableStream { return .{ .context = file }; } +/// Memoizes key information about a file handle such as: +/// * The size from calling stat, or the error that occurred therein. +/// * The current seek position. +/// * The error that occurred when trying to seek. +/// * Whether reading should be done positionally or streaming. +/// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`) +/// versus plain variants (e.g. `read`). +/// +/// Fulfills the `std.io.Reader` interface. +pub const Reader = struct { + file: File, + err: ?ReadError = null, + mode: Reader.Mode = .positional, + pos: u64 = 0, + size: ?u64 = null, + size_err: ?GetEndPosError = null, + seek_err: ?Reader.SeekError = null, + interface: std.io.Reader, + + pub const SeekError = File.SeekError || error{ + /// Seeking fell back to reading, and reached the end before the requested seek position. + /// `pos` remains at the end of the file. + EndOfStream, + /// Seeking fell back to reading, which failed. + ReadFailed, + }; + + pub const Mode = enum { + streaming, + positional, + /// Avoid syscalls other than `read` and `readv`. + streaming_reading, + /// Avoid syscalls other than `pread` and `preadv`. + positional_reading, + /// Indicates reading cannot continue because of a seek failure. + failure, + + pub fn toStreaming(m: @This()) @This() { + return switch (m) { + .positional, .streaming => .streaming, + .positional_reading, .streaming_reading => .streaming_reading, + .failure => .failure, + }; + } + + pub fn toReading(m: @This()) @This() { + return switch (m) { + .positional, .positional_reading => .positional_reading, + .streaming, .streaming_reading => .streaming_reading, + .failure => .failure, + }; + } + }; + + pub fn initInterface(buffer: []u8) std.io.Reader { + return .{ + .vtable = &.{ + .stream = Reader.stream, + .discard = Reader.discard, + }, + .buffer = buffer, + .seek = 0, + .end = 0, + }; + } + + pub fn init(file: File, buffer: []u8) Reader { + return .{ + .file = file, + .interface = initInterface(buffer), + }; + } + + pub fn initSize(file: File, buffer: []u8, size: ?u64) Reader { + return .{ + .file = file, + .interface = initInterface(buffer), + .size = size, + }; + } + + pub fn initMode(file: File, buffer: []u8, init_mode: Reader.Mode) Reader { + return .{ + .file = file, + .interface = initInterface(buffer), + .mode = init_mode, + }; + } + + pub fn getSize(r: *Reader) GetEndPosError!u64 { + return r.size orelse { + if (r.size_err) |err| return err; + if (r.file.getEndPos()) |size| { + r.size = size; + return size; + } else |err| { + r.size_err = err; + return err; + } + }; + } + + pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void { + switch (r.mode) { + .positional, .positional_reading => { + // TODO: make += operator allow any integer types + r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); + }, + .streaming, .streaming_reading => { + const seek_err = r.seek_err orelse e: { + if (posix.lseek_CUR(r.file.handle, offset)) |_| { + // TODO: make += operator allow any integer types + r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); + return; + } else |err| { + r.seek_err = err; + break :e err; + } + }; + var remaining = std.math.cast(u64, offset) orelse return seek_err; + while (remaining > 0) { + const n = discard(&r.interface, .limited(remaining)) catch |err| { + r.seek_err = err; + return err; + }; + r.pos += n; + remaining -= n; + } + }, + .failure => return r.seek_err.?, + } + } + + pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void { + switch (r.mode) { + .positional, .positional_reading => { + r.pos = offset; + }, + .streaming, .streaming_reading => { + if (offset >= r.pos) return Reader.seekBy(r, offset - r.pos); + if (r.seek_err) |err| return err; + posix.lseek_SET(r.file.handle, offset) catch |err| { + r.seek_err = err; + return err; + }; + r.pos = offset; + }, + .failure => return r.seek_err.?, + } + } + + /// Number of slices to store on the stack, when trying to send as many byte + /// vectors through the underlying read calls as possible. + const max_buffers_len = 16; + + fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { + const r: *Reader = @fieldParentPtr("interface", io_reader); + switch (r.mode) { + .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) { + error.Unimplemented => { + r.mode = r.mode.toReading(); + return 0; + }, + else => |e| return e, + }, + .positional_reading => { + if (is_windows) { + // Unfortunately, `ReadFileScatter` cannot be used since it + // requires page alignment. + const dest = limit.slice(try w.writableSliceGreedy(1)); + const n = try readPositional(r, dest); + w.advance(n); + return n; + } + var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; + const dest = try w.writableVectorPosix(&iovecs_buffer, limit); + assert(dest[0].len > 0); + const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) { + error.Unseekable => { + r.mode = r.mode.toStreaming(); + if (r.pos != 0) r.seekBy(@intCast(r.pos)) catch { + r.mode = .failure; + return error.ReadFailed; + }; + return 0; + }, + else => |e| { + r.err = e; + return error.ReadFailed; + }, + }; + if (n == 0) { + r.size = r.pos; + return error.EndOfStream; + } + r.pos += n; + return n; + }, + .streaming_reading => { + if (is_windows) { + // Unfortunately, `ReadFileScatter` cannot be used since it + // requires page alignment. + const dest = limit.slice(try w.writableSliceGreedy(1)); + const n = try readStreaming(r, dest); + w.advance(n); + return n; + } + var iovecs_buffer: [max_buffers_len]posix.iovec = undefined; + const dest = try w.writableVectorPosix(&iovecs_buffer, limit); + assert(dest[0].len > 0); + const n = posix.readv(r.file.handle, dest) catch |err| { + r.err = err; + return error.ReadFailed; + }; + if (n == 0) { + r.size = r.pos; + return error.EndOfStream; + } + r.pos += n; + return n; + }, + .failure => return error.ReadFailed, + } + } + + fn discard(io_reader: *std.io.Reader, limit: std.io.Limit) std.io.Reader.Error!usize { + const r: *Reader = @fieldParentPtr("interface", io_reader); + const file = r.file; + const pos = r.pos; + switch (r.mode) { + .positional, .positional_reading => { + const size = r.size orelse { + if (file.getEndPos()) |size| { + r.size = size; + } else |err| { + r.size_err = err; + r.mode = r.mode.toStreaming(); + } + return 0; + }; + const delta = @min(@intFromEnum(limit), size - pos); + r.pos = pos + delta; + return delta; + }, + .streaming, .streaming_reading => { + // Unfortunately we can't seek forward without knowing the + // size because the seek syscalls provided to us will not + // return the true end position if a seek would exceed the + // end. + fallback: { + if (r.size_err == null and r.seek_err == null) break :fallback; + var trash_buffer: [128]u8 = undefined; + const trash = &trash_buffer; + if (is_windows) { + const n = windows.ReadFile(file.handle, trash, null) catch |err| { + r.err = err; + return error.ReadFailed; + }; + if (n == 0) { + r.size = pos; + return error.EndOfStream; + } + r.pos = pos + n; + return n; + } + var iovecs: [max_buffers_len]std.posix.iovec = undefined; + var iovecs_i: usize = 0; + var remaining = @intFromEnum(limit); + while (remaining > 0 and iovecs_i < iovecs.len) { + iovecs[iovecs_i] = .{ .base = trash, .len = @min(trash.len, remaining) }; + remaining -= iovecs[iovecs_i].len; + iovecs_i += 1; + } + const n = posix.readv(file.handle, iovecs[0..iovecs_i]) catch |err| { + r.err = err; + return error.ReadFailed; + }; + if (n == 0) { + r.size = pos; + return error.EndOfStream; + } + r.pos = pos + n; + return n; + } + const size = r.size orelse { + if (file.getEndPos()) |size| { + r.size = size; + } else |err| { + r.size_err = err; + } + return 0; + }; + const n = @min(size - pos, std.math.maxInt(i64), @intFromEnum(limit)); + file.seekBy(n) catch |err| { + r.seek_err = err; + return 0; + }; + r.pos = pos + n; + return n; + }, + .failure => return error.ReadFailed, + } + } + + pub fn readPositional(r: *Reader, dest: []u8) std.io.Reader.Error!usize { + const n = r.file.pread(dest, r.pos) catch |err| switch (err) { + error.Unseekable => { + r.mode = r.mode.toStreaming(); + if (r.pos != 0) r.seekBy(@intCast(r.pos)) catch { + r.mode = .failure; + return error.ReadFailed; + }; + return 0; + }, + else => |e| { + r.err = e; + return error.ReadFailed; + }, + }; + if (n == 0) { + r.size = r.pos; + return error.EndOfStream; + } + r.pos += n; + return n; + } + + pub fn readStreaming(r: *Reader, dest: []u8) std.io.Reader.Error!usize { + const n = r.file.read(dest) catch |err| { + r.err = err; + return error.ReadFailed; + }; + if (n == 0) { + r.size = r.pos; + return error.EndOfStream; + } + r.pos += n; + return n; + } + + pub fn read(r: *Reader, dest: []u8) std.io.Reader.Error!usize { + switch (r.mode) { + .positional, .positional_reading => return readPositional(r, dest), + .streaming, .streaming_reading => return readStreaming(r, dest), + .failure => return error.ReadFailed, + } + } + + pub fn atEnd(r: *Reader) bool { + // Even if stat fails, size is set when end is encountered. + const size = r.size orelse return false; + return size - r.pos == 0; + } +}; + +pub const Writer = struct { + file: File, + err: ?WriteError = null, + mode: Writer.Mode = .positional, + pos: u64 = 0, + sendfile_err: ?SendfileError = null, + copy_file_range_err: ?CopyFileRangeError = null, + fcopyfile_err: ?FcopyfileError = null, + seek_err: ?SeekError = null, + interface: std.io.Writer, + + pub const Mode = Reader.Mode; + + pub const SendfileError = error{ + UnsupportedOperation, + SystemResources, + InputOutput, + BrokenPipe, + WouldBlock, + Unexpected, + }; + + pub const CopyFileRangeError = std.os.freebsd.CopyFileRangeError || std.os.linux.wrapped.CopyFileRangeError; + + pub const FcopyfileError = error{ + OperationNotSupported, + OutOfMemory, + Unexpected, + }; + + /// Number of slices to store on the stack, when trying to send as many byte + /// vectors through the underlying write calls as possible. + const max_buffers_len = 16; + + pub fn init(file: File, buffer: []u8) Writer { + return initMode(file, buffer, .positional); + } + + pub fn initMode(file: File, buffer: []u8, init_mode: Writer.Mode) Writer { + return .{ + .file = file, + .interface = initInterface(buffer), + .mode = init_mode, + }; + } + + pub fn initInterface(buffer: []u8) std.io.Writer { + return .{ + .vtable = &.{ + .drain = drain, + .sendFile = sendFile, + }, + .buffer = buffer, + }; + } + + pub fn moveToReader(w: *Writer) Reader { + defer w.* = undefined; + return .{ + .file = w.file, + .mode = w.mode, + .pos = w.pos, + .seek_err = w.seek_err, + }; + } + + pub fn drain(io_writer: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { + const w: *Writer = @fieldParentPtr("interface", io_writer); + const handle = w.file.handle; + const buffered = io_writer.buffered(); + var splat_buffer: [256]u8 = undefined; + if (is_windows) { + var i: usize = 0; + while (i < buffered.len) { + const n = windows.WriteFile(handle, buffered[i..], null) catch |err| { + w.err = err; + w.pos += i; + _ = io_writer.consume(i); + return error.WriteFailed; + }; + i += n; + if (data.len > 0 and buffered.len - i < n) { + w.pos += i; + return io_writer.consume(i); + } + } + if (i != 0 or data.len == 0 or (data.len == 1 and splat == 0)) { + w.pos += i; + return io_writer.consume(i); + } + const n = windows.WriteFile(handle, data[0], null) catch |err| { + w.err = err; + return 0; + }; + w.pos += n; + return n; + } + if (data.len == 0) { + var i: usize = 0; + while (i < buffered.len) { + i += std.posix.write(handle, buffered) catch |err| { + w.err = err; + w.pos += i; + _ = io_writer.consume(i); + return error.WriteFailed; + }; + } + w.pos += i; + return io_writer.consumeAll(); + } + var iovecs: [max_buffers_len]std.posix.iovec_const = undefined; + var len: usize = 0; + if (buffered.len > 0) { + iovecs[len] = .{ .base = buffered.ptr, .len = buffered.len }; + len += 1; + } + for (data) |d| { + if (d.len == 0) continue; + if (iovecs.len - len == 0) break; + iovecs[len] = .{ .base = d.ptr, .len = d.len }; + len += 1; + } + switch (splat) { + 0 => if (data[data.len - 1].len != 0) { + len -= 1; + }, + 1 => {}, + else => switch (data[data.len - 1].len) { + 0 => {}, + 1 => { + const memset_len = @min(splat_buffer.len, splat); + const buf = splat_buffer[0..memset_len]; + @memset(buf, data[data.len - 1][0]); + iovecs[len - 1] = .{ .base = buf.ptr, .len = buf.len }; + var remaining_splat = splat - buf.len; + while (remaining_splat > splat_buffer.len and len < iovecs.len) { + iovecs[len] = .{ .base = &splat_buffer, .len = splat_buffer.len }; + remaining_splat -= splat_buffer.len; + len += 1; + } + if (remaining_splat > 0 and len < iovecs.len) { + iovecs[len] = .{ .base = &splat_buffer, .len = remaining_splat }; + len += 1; + } + return std.posix.writev(handle, iovecs[0..len]) catch |err| { + w.err = err; + return error.WriteFailed; + }; + }, + else => for (0..splat - 1) |_| { + if (iovecs.len - len == 0) break; + iovecs[len] = .{ .base = data[data.len - 1].ptr, .len = data[data.len - 1].len }; + len += 1; + }, + }, + } + const n = std.posix.writev(handle, iovecs[0..len]) catch |err| { + w.err = err; + return error.WriteFailed; + }; + w.pos += n; + return io_writer.consume(n); + } + + pub fn sendFile( + io_writer: *std.io.Writer, + file_reader: *Reader, + limit: std.io.Limit, + ) std.io.Writer.FileError!usize { + const w: *Writer = @fieldParentPtr("interface", io_writer); + const out_fd = w.file.handle; + const in_fd = file_reader.file.handle; + // TODO try using copy_file_range on FreeBSD + // TODO try using sendfile on macOS + // TODO try using sendfile on FreeBSD + if (native_os == .linux and w.mode == .streaming) sf: { + // Try using sendfile on Linux. + if (w.sendfile_err != null) break :sf; + // Linux sendfile does not support headers. + const buffered = limit.slice(file_reader.interface.buffer); + if (io_writer.end != 0 or buffered.len != 0) return drain(io_writer, &.{buffered}, 1); + const max_count = 0x7ffff000; // Avoid EINVAL. + var off: std.os.linux.off_t = undefined; + const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) { + .positional => o: { + const size = file_reader.size orelse { + if (file_reader.file.getEndPos()) |size| { + file_reader.size = size; + } else |err| { + file_reader.size_err = err; + file_reader.mode = .streaming; + } + return 0; + }; + off = std.math.cast(std.os.linux.off_t, file_reader.pos) orelse return error.ReadFailed; + break :o .{ &off, @min(@intFromEnum(limit), size - file_reader.pos, max_count) }; + }, + .streaming => .{ null, limit.minInt(max_count) }, + .streaming_reading, .positional_reading => break :sf, + .failure => return error.ReadFailed, + }; + const n = std.os.linux.wrapped.sendfile(out_fd, in_fd, off_ptr, count) catch |err| switch (err) { + error.Unseekable => { + file_reader.mode = file_reader.mode.toStreaming(); + if (file_reader.pos != 0) file_reader.seekBy(@intCast(file_reader.pos)) catch { + file_reader.mode = .failure; + return error.ReadFailed; + }; + return 0; + }, + else => |e| { + w.sendfile_err = e; + return 0; + }, + }; + if (n == 0) { + file_reader.size = file_reader.pos; + return error.EndOfStream; + } + file_reader.pos += n; + w.pos += n; + return n; + } + const copy_file_range_fn = switch (native_os) { + .freebsd => std.os.freebsd.copy_file_range, + .linux => if (std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 })) std.os.linux.wrapped.copy_file_range else null, + else => null, + }; + if (copy_file_range_fn) |copy_file_range| cfr: { + if (w.copy_file_range_err != null) break :cfr; + const buffered = limit.slice(file_reader.interface.buffer); + if (io_writer.end != 0 or buffered.len != 0) return drain(io_writer, &.{buffered}, 1); + var off_in: i64 = undefined; + var off_out: i64 = undefined; + const off_in_ptr: ?*i64 = switch (file_reader.mode) { + .positional_reading, .streaming_reading => return error.Unimplemented, + .positional => p: { + off_in = file_reader.pos; + break :p &off_in; + }, + .streaming => null, + .failure => return error.WriteFailed, + }; + const off_out_ptr: ?*i64 = switch (w.mode) { + .positional_reading, .streaming_reading => return error.Unimplemented, + .positional => p: { + off_out = w.pos; + break :p &off_out; + }, + .streaming => null, + .failure => return error.WriteFailed, + }; + const n = copy_file_range(in_fd, off_in_ptr, out_fd, off_out_ptr, @intFromEnum(limit), 0) catch |err| { + w.copy_file_range_err = err; + return 0; + }; + if (n == 0) { + file_reader.size = file_reader.pos; + return error.EndOfStream; + } + file_reader.pos += n; + w.pos += n; + return n; + } + + if (builtin.os.tag.isDarwin()) fcf: { + if (w.fcopyfile_err != null) break :fcf; + if (file_reader.pos != 0) break :fcf; + if (w.pos != 0) break :fcf; + if (limit != .unlimited) break :fcf; + const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true }); + switch (posix.errno(rc)) { + .SUCCESS => {}, + .INVAL => if (builtin.mode == .Debug) @panic("invalid API usage") else { + w.fcopyfile_err = error.Unexpected; + return 0; + }, + .NOMEM => { + w.fcopyfile_err = error.OutOfMemory; + return 0; + }, + .OPNOTSUPP => { + w.fcopyfile_err = error.OperationNotSupported; + return 0; + }, + else => |err| { + w.fcopyfile_err = posix.unexpectedErrno(err); + return 0; + }, + } + const n = if (file_reader.size) |size| size else @panic("TODO figure out how much copied"); + file_reader.pos = n; + w.pos = n; + return n; + } + + return error.Unimplemented; + } + + pub fn seekTo(w: *Writer, offset: u64) SeekError!void { + if (w.seek_err) |err| return err; + switch (w.mode) { + .positional, .positional_reading => { + w.pos = offset; + }, + .streaming, .streaming_reading => { + posix.lseek_SET(w.file.handle, offset) catch |err| { + w.seek_err = err; + return err; + }; + }, + } + } +}; + +/// Defaults to positional reading; falls back to streaming. +/// +/// Positional is more threadsafe, since the global seek position is not +/// affected. +pub fn reader(file: File, buffer: []u8) Reader { + return .init(file, buffer); +} + +/// Positional is more threadsafe, since the global seek position is not +/// affected, but when such syscalls are not available, preemptively choosing +/// `Reader.Mode.streaming` will skip a failed syscall. +pub fn readerStreaming(file: File) Reader { + return .{ + .file = file, + .mode = .streaming, + .seek_err = error.Unseekable, + }; +} + +/// Defaults to positional reading; falls back to streaming. +/// +/// Positional is more threadsafe, since the global seek position is not +/// affected. +pub fn writer(file: File, buffer: []u8) Writer { + return .init(file, buffer); +} + +/// Positional is more threadsafe, since the global seek position is not +/// affected, but when such syscalls are not available, preemptively choosing +/// `Writer.Mode.streaming` will skip a failed syscall. +pub fn writerStreaming(file: File, buffer: []u8) Writer { + return .initMode(file, buffer, .streaming); +} + const range_off: windows.LARGE_INTEGER = 0; const range_len: windows.LARGE_INTEGER = 1; @@ -1769,18 +2093,3 @@ pub fn downgradeLock(file: File) LockError!void { }; } } - -const File = @This(); -const std = @import("../std.zig"); -const builtin = @import("builtin"); -const Allocator = std.mem.Allocator; -const posix = std.posix; -const io = std.io; -const math = std.math; -const assert = std.debug.assert; -const linux = std.os.linux; -const windows = std.os.windows; -const Os = std.builtin.Os; -const maxInt = std.math.maxInt; -const is_windows = builtin.os.tag == .windows; -const Alignment = std.mem.Alignment; diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 159eb02564..1cf4dc3c64 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -146,14 +146,11 @@ pub fn joinZ(allocator: Allocator, paths: []const []const u8) ![:0]u8 { return out[0 .. out.len - 1 :0]; } -pub fn fmtJoin(paths: []const []const u8) std.fmt.Formatter(formatJoin) { +pub fn fmtJoin(paths: []const []const u8) std.fmt.Formatter([]const []const u8, formatJoin) { return .{ .data = paths }; } -fn formatJoin(paths: []const []const u8, comptime fmt: []const u8, options: std.fmt.FormatOptions, w: anytype) !void { - _ = fmt; - _ = options; - +fn formatJoin(paths: []const []const u8, w: *std.io.Writer) std.io.Writer.Error!void { const first_path_idx = for (paths, 0..) |p, idx| { if (p.len != 0) break idx; } else return; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 99b6dd3920..ece7f79a74 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -1798,11 +1798,11 @@ test "walker" { var num_walked: usize = 0; while (try walker.next()) |entry| { testing.expect(expected_basenames.has(entry.basename)) catch |err| { - std.debug.print("found unexpected basename: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.basename)}); + std.debug.print("found unexpected basename: {f}\n", .{std.ascii.hexEscape(entry.basename, .lower)}); return err; }; testing.expect(expected_paths.has(entry.path)) catch |err| { - std.debug.print("found unexpected path: {s}\n", .{std.fmt.fmtSliceEscapeLower(entry.path)}); + std.debug.print("found unexpected path: {f}\n", .{std.ascii.hexEscape(entry.path, .lower)}); return err; }; // make sure that the entry.dir is the containing dir @@ -1953,113 +1953,6 @@ test "chown" { try dir.chown(null, null); } -test "File.Metadata" { - var tmp = tmpDir(.{}); - defer tmp.cleanup(); - - const file = try tmp.dir.createFile("test_file", .{ .read = true }); - defer file.close(); - - const metadata = try file.metadata(); - try testing.expectEqual(File.Kind.file, metadata.kind()); - try testing.expectEqual(@as(u64, 0), metadata.size()); - _ = metadata.accessed(); - _ = metadata.modified(); - _ = metadata.created(); -} - -test "File.Permissions" { - if (native_os == .wasi) - return error.SkipZigTest; - - var tmp = tmpDir(.{}); - defer tmp.cleanup(); - - const file = try tmp.dir.createFile("test_file", .{ .read = true }); - defer file.close(); - - const metadata = try file.metadata(); - var permissions = metadata.permissions(); - - try testing.expect(!permissions.readOnly()); - permissions.setReadOnly(true); - try testing.expect(permissions.readOnly()); - - try file.setPermissions(permissions); - const new_permissions = (try file.metadata()).permissions(); - try testing.expect(new_permissions.readOnly()); - - // Must be set to non-read-only to delete - permissions.setReadOnly(false); - try file.setPermissions(permissions); -} - -test "File.PermissionsUnix" { - if (native_os == .windows or native_os == .wasi) - return error.SkipZigTest; - - var tmp = tmpDir(.{}); - defer tmp.cleanup(); - - const file = try tmp.dir.createFile("test_file", .{ .mode = 0o666, .read = true }); - defer file.close(); - - const metadata = try file.metadata(); - var permissions = metadata.permissions(); - - permissions.setReadOnly(true); - try testing.expect(permissions.readOnly()); - try testing.expect(!permissions.inner.unixHas(.user, .write)); - permissions.inner.unixSet(.user, .{ .write = true }); - try testing.expect(!permissions.readOnly()); - try testing.expect(permissions.inner.unixHas(.user, .write)); - try testing.expect(permissions.inner.mode & 0o400 != 0); - - permissions.setReadOnly(true); - try file.setPermissions(permissions); - permissions = (try file.metadata()).permissions(); - try testing.expect(permissions.readOnly()); - - // Must be set to non-read-only to delete - permissions.setReadOnly(false); - try file.setPermissions(permissions); - - const permissions_unix = File.PermissionsUnix.unixNew(0o754); - try testing.expect(permissions_unix.unixHas(.user, .execute)); - try testing.expect(!permissions_unix.unixHas(.other, .execute)); -} - -test "delete a read-only file on windows" { - if (native_os != .windows) - return error.SkipZigTest; - - var tmp = testing.tmpDir(.{}); - defer tmp.cleanup(); - - const file = try tmp.dir.createFile("test_file", .{ .read = true }); - defer file.close(); - // Create a file and make it read-only - const metadata = try file.metadata(); - var permissions = metadata.permissions(); - permissions.setReadOnly(true); - try file.setPermissions(permissions); - - // If the OS and filesystem support it, POSIX_SEMANTICS and IGNORE_READONLY_ATTRIBUTE - // is used meaning that the deletion of a read-only file will succeed. - // Otherwise, this delete will fail and the read-only flag must be unset before it's - // able to be deleted. - const delete_result = tmp.dir.deleteFile("test_file"); - if (delete_result) { - try testing.expectError(error.FileNotFound, tmp.dir.deleteFile("test_file")); - } else |err| { - try testing.expectEqual(@as(anyerror, error.AccessDenied), err); - // Now make the file not read-only - permissions.setReadOnly(false); - try file.setPermissions(permissions); - try tmp.dir.deleteFile("test_file"); - } -} - test "delete a setAsCwd directory on Windows" { if (native_os != .windows) return error.SkipZigTest; diff --git a/lib/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig index 50839c335c..980b41b8ae 100644 --- a/lib/std/hash/benchmark.zig +++ b/lib/std/hash/benchmark.zig @@ -346,7 +346,7 @@ fn mode(comptime x: comptime_int) comptime_int { } pub fn main() !void { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); var buffer: [1024]u8 = undefined; var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index e8778fc9c1..df4bb76f0f 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -436,7 +436,7 @@ pub fn DebugAllocator(comptime config: Config) type { const stack_trace = bucketStackTrace(bucket, slot_count, slot_index, .alloc); const page_addr = @intFromPtr(bucket) & ~(page_size - 1); const addr = page_addr + slot_index * size_class; - log.err("memory address 0x{x} leaked: {}", .{ addr, stack_trace }); + log.err("memory address 0x{x} leaked: {f}", .{ addr, stack_trace }); leaks = true; } } @@ -463,7 +463,7 @@ pub fn DebugAllocator(comptime config: Config) type { while (it.next()) |large_alloc| { if (config.retain_metadata and large_alloc.freed) continue; const stack_trace = large_alloc.getStackTrace(.alloc); - log.err("memory address 0x{x} leaked: {}", .{ + log.err("memory address 0x{x} leaked: {f}", .{ @intFromPtr(large_alloc.bytes.ptr), stack_trace, }); leaks = true; @@ -522,7 +522,7 @@ pub fn DebugAllocator(comptime config: Config) type { .index = 0, }; std.debug.captureStackTrace(ret_addr, &second_free_stack_trace); - log.err("Double free detected. Allocation: {} First free: {} Second free: {}", .{ + log.err("Double free detected. Allocation: {f} First free: {f} Second free: {f}", .{ alloc_stack_trace, free_stack_trace, second_free_stack_trace, }); } @@ -568,7 +568,7 @@ pub fn DebugAllocator(comptime config: Config) type { .index = 0, }; std.debug.captureStackTrace(ret_addr, &free_stack_trace); - log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{ + log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ entry.value_ptr.bytes.len, old_mem.len, entry.value_ptr.getStackTrace(.alloc), @@ -678,7 +678,7 @@ pub fn DebugAllocator(comptime config: Config) type { .index = 0, }; std.debug.captureStackTrace(ret_addr, &free_stack_trace); - log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{ + log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ entry.value_ptr.bytes.len, old_mem.len, entry.value_ptr.getStackTrace(.alloc), @@ -907,7 +907,7 @@ pub fn DebugAllocator(comptime config: Config) type { }; std.debug.captureStackTrace(return_address, &free_stack_trace); if (old_memory.len != requested_size) { - log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{ + log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ requested_size, old_memory.len, bucketStackTrace(bucket, slot_count, slot_index, .alloc), @@ -915,7 +915,7 @@ pub fn DebugAllocator(comptime config: Config) type { }); } if (alignment != slot_alignment) { - log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {} Free: {}", .{ + log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ slot_alignment.toByteUnits(), alignment.toByteUnits(), bucketStackTrace(bucket, slot_count, slot_index, .alloc), @@ -1006,7 +1006,7 @@ pub fn DebugAllocator(comptime config: Config) type { }; std.debug.captureStackTrace(return_address, &free_stack_trace); if (memory.len != requested_size) { - log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {} Free: {}", .{ + log.err("Allocation size {d} bytes does not match free size {d}. Allocation: {f} Free: {f}", .{ requested_size, memory.len, bucketStackTrace(bucket, slot_count, slot_index, .alloc), @@ -1014,7 +1014,7 @@ pub fn DebugAllocator(comptime config: Config) type { }); } if (alignment != slot_alignment) { - log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {} Free: {}", .{ + log.err("Allocation alignment {d} does not match free alignment {d}. Allocation: {f} Free: {f}", .{ slot_alignment.toByteUnits(), alignment.toByteUnits(), bucketStackTrace(bucket, slot_count, slot_index, .alloc), @@ -1054,7 +1054,7 @@ const TraceKind = enum { free, }; -const test_config = Config{}; +const test_config: Config = .{}; test "small allocations - free in same order" { var gpa = DebugAllocator(test_config){}; diff --git a/lib/std/http.zig b/lib/std/http.zig index d5d5583299..67abe36aa1 100644 --- a/lib/std/http.zig +++ b/lib/std/http.zig @@ -1,3 +1,7 @@ +const builtin = @import("builtin"); +const std = @import("std.zig"); +const assert = std.debug.assert; + pub const Client = @import("http/Client.zig"); pub const Server = @import("http/Server.zig"); pub const protocol = @import("http/protocol.zig"); @@ -38,8 +42,9 @@ pub const Method = enum(u64) { return x; } - pub fn write(self: Method, w: anytype) !void { - const bytes = std.mem.asBytes(&@intFromEnum(self)); + pub fn format(self: Method, w: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { + comptime assert(f.len == 0); + const bytes: []const u8 = @ptrCast(&@intFromEnum(self)); const str = std.mem.sliceTo(bytes, 0); try w.writeAll(str); } @@ -77,7 +82,9 @@ pub const Method = enum(u64) { }; } - /// An HTTP method is idempotent if an identical request can be made once or several times in a row with the same effect while leaving the server in the same state. + /// An HTTP method is idempotent if an identical request can be made once + /// or several times in a row with the same effect while leaving the server + /// in the same state. /// /// https://developer.mozilla.org/en-US/docs/Glossary/Idempotent /// @@ -90,7 +97,8 @@ pub const Method = enum(u64) { }; } - /// A cacheable response is an HTTP response that can be cached, that is stored to be retrieved and used later, saving a new request to the server. + /// A cacheable response can be stored to be retrieved and used later, + /// saving a new request to the server. /// /// https://developer.mozilla.org/en-US/docs/Glossary/cacheable /// @@ -282,10 +290,10 @@ pub const Status = enum(u10) { } }; +/// compression is intentionally omitted here since it is handled in `ContentEncoding`. pub const TransferEncoding = enum { chunked, none, - // compression is intentionally omitted here, as std.http.Client stores it as content-encoding }; pub const ContentEncoding = enum { @@ -308,9 +316,6 @@ pub const Header = struct { value: []const u8, }; -const builtin = @import("builtin"); -const std = @import("std.zig"); - test { if (builtin.os.tag != .wasi) { _ = Client; diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig index 4dea4415a4..8f4dfe308e 100644 --- a/lib/std/http/Client.zig +++ b/lib/std/http/Client.zig @@ -823,21 +823,28 @@ pub const Request = struct { return error.UnsupportedTransferEncoding; const connection = req.connection.?; - const w = connection.writer(); + var connection_writer_adapter = connection.writer().adaptToNewApi(); + const w = &connection_writer_adapter.new_interface; + sendAdapted(req, connection, w) catch |err| switch (err) { + error.WriteFailed => return connection_writer_adapter.err.?, + else => |e| return e, + }; + } - try req.method.write(w); + fn sendAdapted(req: *Request, connection: *Connection, w: *std.io.Writer) !void { + try req.method.format(w, ""); try w.writeByte(' '); if (req.method == .CONNECT) { - try req.uri.writeToStream(.{ .authority = true }, w); + try req.uri.writeToStream(w, .{ .authority = true }); } else { - try req.uri.writeToStream(.{ + try req.uri.writeToStream(w, .{ .scheme = connection.proxied, .authentication = connection.proxied, .authority = connection.proxied, .path = true, .query = true, - }, w); + }); } try w.writeByte(' '); try w.writeAll(@tagName(req.version)); @@ -845,7 +852,7 @@ pub const Request = struct { if (try emitOverridableHeader("host: ", req.headers.host, w)) { try w.writeAll("host: "); - try req.uri.writeToStream(.{ .authority = true }, w); + try req.uri.writeToStream(w, .{ .authority = true }); try w.writeAll("\r\n"); } @@ -1284,10 +1291,10 @@ pub const basic_authorization = struct { pub fn valueLengthFromUri(uri: Uri) usize { var stream = std.io.countingWriter(std.io.null_writer); - try stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty}); + try stream.writer().print("{fuser}", .{uri.user orelse Uri.Component.empty}); const user_len = stream.bytes_written; stream.bytes_written = 0; - try stream.writer().print("{password}", .{uri.password orelse Uri.Component.empty}); + try stream.writer().print("{fpassword}", .{uri.password orelse Uri.Component.empty}); const password_len = stream.bytes_written; return valueLength(@intCast(user_len), @intCast(password_len)); } @@ -1295,10 +1302,10 @@ pub const basic_authorization = struct { pub fn value(uri: Uri, out: []u8) []u8 { var buf: [max_user_len + ":".len + max_password_len]u8 = undefined; var stream = std.io.fixedBufferStream(&buf); - stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty}) catch + stream.writer().print("{fuser}", .{uri.user orelse Uri.Component.empty}) catch unreachable; assert(stream.pos <= max_user_len); - stream.writer().print(":{password}", .{uri.password orelse Uri.Component.empty}) catch + stream.writer().print(":{fpassword}", .{uri.password orelse Uri.Component.empty}) catch unreachable; @memcpy(out[0..prefix.len], prefix); diff --git a/lib/std/http/test.zig b/lib/std/http/test.zig index dc944fbabb..fdbed8eaf8 100644 --- a/lib/std/http/test.zig +++ b/lib/std/http/test.zig @@ -385,10 +385,8 @@ test "general client/server API coverage" { fn handleRequest(request: *http.Server.Request, listen_port: u16) !void { const log = std.log.scoped(.server); - log.info("{} {s} {s}", .{ - request.head.method, - @tagName(request.head.version), - request.head.target, + log.info("{f} {s} {s}", .{ + request.head.method, @tagName(request.head.version), request.head.target, }); const gpa = std.testing.allocator; diff --git a/lib/std/io.zig b/lib/std/io.zig index 288e31b6ca..0aa56470e4 100644 --- a/lib/std/io.zig +++ b/lib/std/io.zig @@ -364,6 +364,32 @@ pub fn GenericWriter( const ptr: *const Context = @alignCast(@ptrCast(context)); return writeFn(ptr.*, bytes); } + + /// Helper for bridging to the new `Writer` API while upgrading. + pub fn adaptToNewApi(self: *const Self) Adapter { + return .{ + .derp_writer = self.*, + .new_interface = .{ + .buffer = &.{}, + .vtable = &.{ .drain = Adapter.drain }, + }, + }; + } + + pub const Adapter = struct { + derp_writer: Self, + new_interface: Writer, + err: ?Error = null, + + fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { + _ = splat; + const a: *@This() = @fieldParentPtr("new_interface", w); + return a.derp_writer.write(data[0]) catch |err| { + a.err = err; + return error.WriteFailed; + }; + } + }; }; } @@ -419,7 +445,7 @@ pub const tty = @import("io/tty.zig"); /// A Writer that doesn't write to anything. pub const null_writer: NullWriter = .{ .context = {} }; -pub const NullWriter = Writer(void, error{}, dummyWrite); +pub const NullWriter = GenericWriter(void, error{}, dummyWrite); fn dummyWrite(context: void, data: []const u8) error{}!usize { _ = context; return data.len; diff --git a/lib/std/io/DeprecatedWriter.zig b/lib/std/io/DeprecatedWriter.zig index 26d4f88def..34d72c7efe 100644 --- a/lib/std/io/DeprecatedWriter.zig +++ b/lib/std/io/DeprecatedWriter.zig @@ -21,7 +21,7 @@ pub fn writeAll(self: Self, bytes: []const u8) anyerror!void { } pub fn print(self: Self, comptime format: []const u8, args: anytype) anyerror!void { - return std.fmt.format(self, format, args); + return std.fmt.deprecatedFormat(self, format, args); } pub fn writeByte(self: Self, byte: u8) anyerror!void { @@ -81,3 +81,29 @@ pub fn writeFile(self: Self, file: std.fs.File) anyerror!void { if (n < buf.len) return; } } + +/// Helper for bridging to the new `Writer` API while upgrading. +pub fn adaptToNewApi(self: *const Self) Adapter { + return .{ + .derp_writer = self.*, + .new_interface = .{ + .buffer = &.{}, + .vtable = &.{ .drain = Adapter.drain }, + }, + }; +} + +pub const Adapter = struct { + derp_writer: Self, + new_interface: std.io.Writer, + err: ?Error = null, + + fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { + _ = splat; + const a: *@This() = @fieldParentPtr("new_interface", w); + return a.derp_writer.write(data[0]) catch |err| { + a.err = err; + return error.WriteFailed; + }; + } +}; diff --git a/lib/std/io/Reader.zig b/lib/std/io/Reader.zig index d26c18955b..a3e1974049 100644 --- a/lib/std/io/Reader.zig +++ b/lib/std/io/Reader.zig @@ -26,7 +26,8 @@ pub const VTable = struct { /// Returns the number of bytes written, which will be at minimum `0` and /// at most `limit`. The number returned, including zero, does not indicate /// end of stream. `limit` is guaranteed to be at least as large as the - /// buffer capacity of `w`. + /// buffer capacity of `w`, a value whose minimum size is determined by the + /// stream implementation. /// /// The reader's internal logical seek position moves forward in accordance /// with the number of bytes returned from this function. @@ -1243,10 +1244,10 @@ test peekArray { test discardAll { var r: Reader = .fixed("foobar"); - try r.discard(3); + try r.discardAll(3); try testing.expectEqualStrings("bar", try r.take(3)); - try r.discard(0); - try testing.expectError(error.EndOfStream, r.discard(1)); + try r.discardAll(0); + try testing.expectError(error.EndOfStream, r.discardAll(1)); } test discardRemaining { @@ -1355,9 +1356,11 @@ test readVec { test "expected error.EndOfStream" { // Unit test inspired by https://github.com/ziglang/zig/issues/17733 - var r: std.io.Reader = .fixed(""); - try std.testing.expectError(error.EndOfStream, r.readEnum(enum(u8) { a, b }, .little)); - try std.testing.expectError(error.EndOfStream, r.isBytes("foo")); + var buffer: [3]u8 = undefined; + var r: std.io.Reader = .fixed(&buffer); + r.end = 0; // capacity 3, but empty + try std.testing.expectError(error.EndOfStream, r.takeEnum(enum(u8) { a, b }, .little)); + try std.testing.expectError(error.EndOfStream, r.take(3)); } fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { @@ -1389,21 +1392,30 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize { test "readAlloc when the backing reader provides one byte at a time" { const OneByteReader = struct { str: []const u8, - curr: usize, + i: usize, + reader: Reader, - fn read(self: *@This(), dest: []u8) usize { - if (self.str.len <= self.curr or dest.len == 0) - return 0; - - dest[0] = self.str[self.curr]; - self.curr += 1; + fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { + assert(@intFromEnum(limit) >= 1); + const self: *@This() = @fieldParentPtr("reader", r); + if (self.str.len - self.i == 0) return error.EndOfStream; + try w.writeByte(self.str[self.i]); + self.i += 1; return 1; } }; - const str = "This is a test"; - var one_byte_stream: OneByteReader = .init(str); - const res = try one_byte_stream.reader().streamReadAlloc(std.testing.allocator, str.len + 1); + var one_byte_stream: OneByteReader = .{ + .str = str, + .i = 0, + .reader = .{ + .buffer = &.{}, + .vtable = &.{ .stream = OneByteReader.stream }, + .seek = 0, + .end = 0, + }, + }; + const res = try one_byte_stream.reader.allocRemaining(std.testing.allocator, .unlimited); defer std.testing.allocator.free(res); try std.testing.expectEqualStrings(str, res); } diff --git a/lib/std/io/Writer.zig b/lib/std/io/Writer.zig index c1371d3434..1602c1559c 100644 --- a/lib/std/io/Writer.zig +++ b/lib/std/io/Writer.zig @@ -37,6 +37,10 @@ pub const VTable = struct { /// The last element of `data` is repeated as necessary so that it is /// written `splat` number of times, which may be zero. /// + /// This function may not be called if the data to be written could have + /// been stored in `buffer` instead, including when the amount of data to + /// be written is zero and the buffer capacity is zero. + /// /// Number of bytes consumed from `data` is returned, excluding bytes from /// `buffer`. /// @@ -800,18 +804,13 @@ pub fn printValue( ) Error!void { const T = @TypeOf(value); - if (comptime std.mem.eql(u8, fmt, "*")) { - return w.printAddress(value); - } + if (comptime std.mem.eql(u8, fmt, "*")) return w.printAddress(value); + if (fmt.len > 0 and fmt[0] == 'f') return value.format(w, fmt[1..]); const is_any = comptime std.mem.eql(u8, fmt, ANY); - if (!is_any and std.meta.hasMethod(T, "format")) { - if (fmt.len > 0 and fmt[0] == 'f') { - return value.format(w, fmt[1..]); - } else if (fmt.len == 0) { - // after 0.15.0 is tagged, delete the hasMethod condition and this compile error - @compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it"); - } + if (!is_any and std.meta.hasMethod(T, "format") and fmt.len == 0) { + // after 0.15.0 is tagged, delete this compile error and its condition + @compileError("ambiguous format string; specify {f} to call format method, or {any} to skip it"); } switch (@typeInfo(T)) { @@ -952,9 +951,8 @@ pub fn printValue( }, .pointer => |ptr_info| switch (ptr_info.size) { .one => switch (@typeInfo(ptr_info.child)) { - .array, .@"enum", .@"union", .@"struct" => { - return w.printValue(fmt, options, value.*, max_depth); - }, + .array => |array_info| return w.printValue(fmt, options, @as([]const array_info.child, value), max_depth), + .@"enum", .@"union", .@"struct" => return w.printValue(fmt, options, value.*, max_depth), else => { var buffers: [2][]const u8 = .{ @typeName(ptr_info.child), "@" }; try w.writeVecAll(&buffers); @@ -1120,7 +1118,12 @@ pub fn printAscii(w: *Writer, bytes: []const u8, options: std.fmt.Options) Error pub fn printUnicodeCodepoint(w: *Writer, c: u21, options: std.fmt.Options) Error!void { var buf: [4]u8 = undefined; - const len = try std.unicode.utf8Encode(c, &buf); + const len = std.unicode.utf8Encode(c, &buf) catch |err| switch (err) { + error.Utf8CannotEncodeSurrogateHalf, error.CodepointTooLarge => l: { + buf[0..3].* = std.unicode.replacement_character_utf8; + break :l 3; + }, + }; return w.alignBufferOptions(buf[0..len], options); } @@ -1553,13 +1556,7 @@ test "formatValue max_depth" { x: f32, y: f32, - pub fn format( - self: SelfType, - comptime fmt: []const u8, - options: std.fmt.Options, - w: *Writer, - ) Error!void { - _ = options; + pub fn format(self: SelfType, w: *Writer, comptime fmt: []const u8) Error!void { if (fmt.len == 0) { return w.print("({d:.3},{d:.3})", .{ self.x, self.y }); } else { @@ -1600,131 +1597,131 @@ test "formatValue max_depth" { try w.printValue("", .{}, inst, 0); try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ ... }", w.buffered()); - w.reset(); + w = .fixed(&buf); try w.printValue("", .{}, inst, 1); try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered()); - w.reset(); + w = .fixed(&buf); try w.printValue("", .{}, inst, 2); try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered()); - w.reset(); + w = .fixed(&buf); try w.printValue("", .{}, inst, 3); try testing.expectEqualStrings("io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ .a = io.Writer.test.printValue max_depth.S{ ... }, .tu = io.Writer.test.printValue max_depth.TU{ ... }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }, .tu = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ .ptr = io.Writer.test.printValue max_depth.TU{ ... } } }, .e = io.Writer.test.printValue max_depth.E.Two, .vec = (10.200,2.220) }", w.buffered()); const vec: @Vector(4, i32) = .{ 1, 2, 3, 4 }; - w.reset(); + w = .fixed(&buf); try w.printValue("", .{}, vec, 0); try testing.expectEqualStrings("{ ... }", w.buffered()); - w.reset(); + w = .fixed(&buf); try w.printValue("", .{}, vec, 1); try testing.expectEqualStrings("{ 1, 2, 3, 4 }", w.buffered()); } test printDuration { - testDurationCase("0ns", 0); - testDurationCase("1ns", 1); - testDurationCase("999ns", std.time.ns_per_us - 1); - testDurationCase("1us", std.time.ns_per_us); - testDurationCase("1.45us", 1450); - testDurationCase("1.5us", 3 * std.time.ns_per_us / 2); - testDurationCase("14.5us", 14500); - testDurationCase("145us", 145000); - testDurationCase("999.999us", std.time.ns_per_ms - 1); - testDurationCase("1ms", std.time.ns_per_ms + 1); - testDurationCase("1.5ms", 3 * std.time.ns_per_ms / 2); - testDurationCase("1.11ms", 1110000); - testDurationCase("1.111ms", 1111000); - testDurationCase("1.111ms", 1111100); - testDurationCase("999.999ms", std.time.ns_per_s - 1); - testDurationCase("1s", std.time.ns_per_s); - testDurationCase("59.999s", std.time.ns_per_min - 1); - testDurationCase("1m", std.time.ns_per_min); - testDurationCase("1h", std.time.ns_per_hour); - testDurationCase("1d", std.time.ns_per_day); - testDurationCase("1w", std.time.ns_per_week); - testDurationCase("1y", 365 * std.time.ns_per_day); - testDurationCase("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1 - testDurationCase("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); - testDurationCase("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); - testDurationCase("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); - testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); - testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); - testDurationCase("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); - testDurationCase("584y49w23h34m33.709s", std.math.maxInt(u64)); + try testDurationCase("0ns", 0); + try testDurationCase("1ns", 1); + try testDurationCase("999ns", std.time.ns_per_us - 1); + try testDurationCase("1us", std.time.ns_per_us); + try testDurationCase("1.45us", 1450); + try testDurationCase("1.5us", 3 * std.time.ns_per_us / 2); + try testDurationCase("14.5us", 14500); + try testDurationCase("145us", 145000); + try testDurationCase("999.999us", std.time.ns_per_ms - 1); + try testDurationCase("1ms", std.time.ns_per_ms + 1); + try testDurationCase("1.5ms", 3 * std.time.ns_per_ms / 2); + try testDurationCase("1.11ms", 1110000); + try testDurationCase("1.111ms", 1111000); + try testDurationCase("1.111ms", 1111100); + try testDurationCase("999.999ms", std.time.ns_per_s - 1); + try testDurationCase("1s", std.time.ns_per_s); + try testDurationCase("59.999s", std.time.ns_per_min - 1); + try testDurationCase("1m", std.time.ns_per_min); + try testDurationCase("1h", std.time.ns_per_hour); + try testDurationCase("1d", std.time.ns_per_day); + try testDurationCase("1w", std.time.ns_per_week); + try testDurationCase("1y", 365 * std.time.ns_per_day); + try testDurationCase("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1 + try testDurationCase("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); + try testDurationCase("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); + try testDurationCase("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); + try testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); + try testDurationCase("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); + try testDurationCase("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); + try testDurationCase("584y49w23h34m33.709s", std.math.maxInt(u64)); - testing.expectFmt("=======0ns", "{D:=>10}", .{0}); - testing.expectFmt("1ns=======", "{D:=<10}", .{1}); - testing.expectFmt(" 999ns ", "{D:^10}", .{std.time.ns_per_us - 1}); + try testing.expectFmt("=======0ns", "{D:=>10}", .{0}); + try testing.expectFmt("1ns=======", "{D:=<10}", .{1}); + try testing.expectFmt(" 999ns ", "{D:^10}", .{std.time.ns_per_us - 1}); } test printDurationSigned { - testDurationCaseSigned("0ns", 0); - testDurationCaseSigned("1ns", 1); - testDurationCaseSigned("-1ns", -(1)); - testDurationCaseSigned("999ns", std.time.ns_per_us - 1); - testDurationCaseSigned("-999ns", -(std.time.ns_per_us - 1)); - testDurationCaseSigned("1us", std.time.ns_per_us); - testDurationCaseSigned("-1us", -(std.time.ns_per_us)); - testDurationCaseSigned("1.45us", 1450); - testDurationCaseSigned("-1.45us", -(1450)); - testDurationCaseSigned("1.5us", 3 * std.time.ns_per_us / 2); - testDurationCaseSigned("-1.5us", -(3 * std.time.ns_per_us / 2)); - testDurationCaseSigned("14.5us", 14500); - testDurationCaseSigned("-14.5us", -(14500)); - testDurationCaseSigned("145us", 145000); - testDurationCaseSigned("-145us", -(145000)); - testDurationCaseSigned("999.999us", std.time.ns_per_ms - 1); - testDurationCaseSigned("-999.999us", -(std.time.ns_per_ms - 1)); - testDurationCaseSigned("1ms", std.time.ns_per_ms + 1); - testDurationCaseSigned("-1ms", -(std.time.ns_per_ms + 1)); - testDurationCaseSigned("1.5ms", 3 * std.time.ns_per_ms / 2); - testDurationCaseSigned("-1.5ms", -(3 * std.time.ns_per_ms / 2)); - testDurationCaseSigned("1.11ms", 1110000); - testDurationCaseSigned("-1.11ms", -(1110000)); - testDurationCaseSigned("1.111ms", 1111000); - testDurationCaseSigned("-1.111ms", -(1111000)); - testDurationCaseSigned("1.111ms", 1111100); - testDurationCaseSigned("-1.111ms", -(1111100)); - testDurationCaseSigned("999.999ms", std.time.ns_per_s - 1); - testDurationCaseSigned("-999.999ms", -(std.time.ns_per_s - 1)); - testDurationCaseSigned("1s", std.time.ns_per_s); - testDurationCaseSigned("-1s", -(std.time.ns_per_s)); - testDurationCaseSigned("59.999s", std.time.ns_per_min - 1); - testDurationCaseSigned("-59.999s", -(std.time.ns_per_min - 1)); - testDurationCaseSigned("1m", std.time.ns_per_min); - testDurationCaseSigned("-1m", -(std.time.ns_per_min)); - testDurationCaseSigned("1h", std.time.ns_per_hour); - testDurationCaseSigned("-1h", -(std.time.ns_per_hour)); - testDurationCaseSigned("1d", std.time.ns_per_day); - testDurationCaseSigned("-1d", -(std.time.ns_per_day)); - testDurationCaseSigned("1w", std.time.ns_per_week); - testDurationCaseSigned("-1w", -(std.time.ns_per_week)); - testDurationCaseSigned("1y", 365 * std.time.ns_per_day); - testDurationCaseSigned("-1y", -(365 * std.time.ns_per_day)); - testDurationCaseSigned("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1d - testDurationCaseSigned("-1y52w23h59m59.999s", -(730 * std.time.ns_per_day - 1)); // 365d = 52w1d - testDurationCaseSigned("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); - testDurationCaseSigned("-1y1h1.001s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms)); - testDurationCaseSigned("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); - testDurationCaseSigned("-1y1h1s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us)); - testDurationCaseSigned("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); - testDurationCaseSigned("-1y1h999.999us", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1)); - testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); - testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms)); - testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); - testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1)); - testDurationCaseSigned("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); - testDurationCaseSigned("-1y1m999ns", -(365 * std.time.ns_per_day + std.time.ns_per_min + 999)); - testDurationCaseSigned("292y24w3d23h47m16.854s", std.math.maxInt(i64)); - testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64) + 1); - testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64)); + try testDurationCaseSigned("0ns", 0); + try testDurationCaseSigned("1ns", 1); + try testDurationCaseSigned("-1ns", -(1)); + try testDurationCaseSigned("999ns", std.time.ns_per_us - 1); + try testDurationCaseSigned("-999ns", -(std.time.ns_per_us - 1)); + try testDurationCaseSigned("1us", std.time.ns_per_us); + try testDurationCaseSigned("-1us", -(std.time.ns_per_us)); + try testDurationCaseSigned("1.45us", 1450); + try testDurationCaseSigned("-1.45us", -(1450)); + try testDurationCaseSigned("1.5us", 3 * std.time.ns_per_us / 2); + try testDurationCaseSigned("-1.5us", -(3 * std.time.ns_per_us / 2)); + try testDurationCaseSigned("14.5us", 14500); + try testDurationCaseSigned("-14.5us", -(14500)); + try testDurationCaseSigned("145us", 145000); + try testDurationCaseSigned("-145us", -(145000)); + try testDurationCaseSigned("999.999us", std.time.ns_per_ms - 1); + try testDurationCaseSigned("-999.999us", -(std.time.ns_per_ms - 1)); + try testDurationCaseSigned("1ms", std.time.ns_per_ms + 1); + try testDurationCaseSigned("-1ms", -(std.time.ns_per_ms + 1)); + try testDurationCaseSigned("1.5ms", 3 * std.time.ns_per_ms / 2); + try testDurationCaseSigned("-1.5ms", -(3 * std.time.ns_per_ms / 2)); + try testDurationCaseSigned("1.11ms", 1110000); + try testDurationCaseSigned("-1.11ms", -(1110000)); + try testDurationCaseSigned("1.111ms", 1111000); + try testDurationCaseSigned("-1.111ms", -(1111000)); + try testDurationCaseSigned("1.111ms", 1111100); + try testDurationCaseSigned("-1.111ms", -(1111100)); + try testDurationCaseSigned("999.999ms", std.time.ns_per_s - 1); + try testDurationCaseSigned("-999.999ms", -(std.time.ns_per_s - 1)); + try testDurationCaseSigned("1s", std.time.ns_per_s); + try testDurationCaseSigned("-1s", -(std.time.ns_per_s)); + try testDurationCaseSigned("59.999s", std.time.ns_per_min - 1); + try testDurationCaseSigned("-59.999s", -(std.time.ns_per_min - 1)); + try testDurationCaseSigned("1m", std.time.ns_per_min); + try testDurationCaseSigned("-1m", -(std.time.ns_per_min)); + try testDurationCaseSigned("1h", std.time.ns_per_hour); + try testDurationCaseSigned("-1h", -(std.time.ns_per_hour)); + try testDurationCaseSigned("1d", std.time.ns_per_day); + try testDurationCaseSigned("-1d", -(std.time.ns_per_day)); + try testDurationCaseSigned("1w", std.time.ns_per_week); + try testDurationCaseSigned("-1w", -(std.time.ns_per_week)); + try testDurationCaseSigned("1y", 365 * std.time.ns_per_day); + try testDurationCaseSigned("-1y", -(365 * std.time.ns_per_day)); + try testDurationCaseSigned("1y52w23h59m59.999s", 730 * std.time.ns_per_day - 1); // 365d = 52w1d + try testDurationCaseSigned("-1y52w23h59m59.999s", -(730 * std.time.ns_per_day - 1)); // 365d = 52w1d + try testDurationCaseSigned("1y1h1.001s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms); + try testDurationCaseSigned("-1y1h1.001s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms)); + try testDurationCaseSigned("1y1h1s", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us); + try testDurationCaseSigned("-1y1h1s", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us)); + try testDurationCaseSigned("1y1h999.999us", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1); + try testDurationCaseSigned("-1y1h999.999us", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1)); + try testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms); + try testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms)); + try testDurationCaseSigned("1y1h1ms", 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1); + try testDurationCaseSigned("-1y1h1ms", -(365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1)); + try testDurationCaseSigned("1y1m999ns", 365 * std.time.ns_per_day + std.time.ns_per_min + 999); + try testDurationCaseSigned("-1y1m999ns", -(365 * std.time.ns_per_day + std.time.ns_per_min + 999)); + try testDurationCaseSigned("292y24w3d23h47m16.854s", std.math.maxInt(i64)); + try testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64) + 1); + try testDurationCaseSigned("-292y24w3d23h47m16.854s", std.math.minInt(i64)); - testing.expectFmt("=======0ns", "{s:=>10}", .{0}); - testing.expectFmt("1ns=======", "{s:=<10}", .{1}); - testing.expectFmt("-1ns======", "{s:=<10}", .{-(1)}); - testing.expectFmt(" -999ns ", "{s:^10}", .{-(std.time.ns_per_us - 1)}); + try testing.expectFmt("=======0ns", "{D:=>10}", .{0}); + try testing.expectFmt("1ns=======", "{D:=<10}", .{1}); + try testing.expectFmt("-1ns======", "{D:=<10}", .{-(1)}); + try testing.expectFmt(" -999ns ", "{D:^10}", .{-(std.time.ns_per_us - 1)}); } fn testDurationCase(expected: []const u8, input: u64) !void { @@ -1762,7 +1759,7 @@ test printIntOptions { test "printInt with comptime_int" { var buf: [20]u8 = undefined; var w: Writer = .fixed(&buf); - try w.printInt(@as(comptime_int, 123456789123456789), "", .{}); + try w.printInt("", .{}, @as(comptime_int, 123456789123456789)); try std.testing.expectEqualStrings("123456789123456789", w.buffered()); } @@ -1777,7 +1774,7 @@ test "printFloat with comptime_float" { fn testPrintIntCase(expected: []const u8, value: anytype, base: u8, case: std.fmt.Case, options: std.fmt.Options) !void { var buffer: [100]u8 = undefined; var w: Writer = .fixed(&buffer); - w.printIntOptions(value, base, case, options); + try w.printIntOptions(value, base, case, options); try testing.expectEqualStrings(expected, w.buffered()); } @@ -1832,17 +1829,15 @@ test "fixed output" { try w.writeAll("world"); try testing.expect(std.mem.eql(u8, w.buffered(), "Helloworld")); - try testing.expectError(error.WriteStreamEnd, w.writeAll("!")); + try testing.expectError(error.WriteFailed, w.writeAll("!")); try testing.expect(std.mem.eql(u8, w.buffered(), "Helloworld")); - w.reset(); + w = .fixed(&buffer); + try testing.expect(w.buffered().len == 0); - try testing.expectError(error.WriteStreamEnd, w.writeAll("Hello world!")); + try testing.expectError(error.WriteFailed, w.writeAll("Hello world!")); try testing.expect(std.mem.eql(u8, w.buffered(), "Hello worl")); - - try w.seekTo((try w.getEndPos()) + 1); - try testing.expectError(error.WriteStreamEnd, w.writeAll("H")); } pub fn failingDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize { diff --git a/lib/std/io/buffered_atomic_file.zig b/lib/std/io/buffered_atomic_file.zig index 59f3767ebd..48510bde52 100644 --- a/lib/std/io/buffered_atomic_file.zig +++ b/lib/std/io/buffered_atomic_file.zig @@ -33,7 +33,7 @@ pub const BufferedAtomicFile = struct { self.atomic_file = try dir.atomicFile(dest_path, atomic_file_options); errdefer self.atomic_file.deinit(); - self.file_writer = self.atomic_file.file.writer(); + self.file_writer = self.atomic_file.file.deprecatedWriter(); self.buffered_writer = .{ .unbuffered_writer = self.file_writer }; return self; } diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig index 523b25c9c8..bf14f0c24c 100644 --- a/lib/std/io/test.zig +++ b/lib/std/io/test.zig @@ -24,7 +24,7 @@ test "write a file, read it, then delete it" { var file = try tmp.dir.createFile(tmp_file_name, .{}); defer file.close(); - var buf_stream = io.bufferedWriter(file.writer()); + var buf_stream = io.bufferedWriter(file.deprecatedWriter()); const st = buf_stream.writer(); try st.print("begin", .{}); try st.writeAll(data[0..]); @@ -45,7 +45,7 @@ test "write a file, read it, then delete it" { const expected_file_size: u64 = "begin".len + data.len + "end".len; try expectEqual(expected_file_size, file_size); - var buf_stream = io.bufferedReader(file.reader()); + var buf_stream = io.bufferedReader(file.deprecatedReader()); const st = buf_stream.reader(); const contents = try st.readAllAlloc(std.testing.allocator, 2 * 1024); defer std.testing.allocator.free(contents); @@ -66,7 +66,7 @@ test "BitStreams with File Stream" { var file = try tmp.dir.createFile(tmp_file_name, .{}); defer file.close(); - var bit_stream = io.bitWriter(native_endian, file.writer()); + var bit_stream = io.bitWriter(native_endian, file.deprecatedWriter()); try bit_stream.writeBits(@as(u2, 1), 1); try bit_stream.writeBits(@as(u5, 2), 2); @@ -80,7 +80,7 @@ test "BitStreams with File Stream" { var file = try tmp.dir.openFile(tmp_file_name, .{}); defer file.close(); - var bit_stream = io.bitReader(native_endian, file.reader()); + var bit_stream = io.bitReader(native_endian, file.deprecatedReader()); var out_bits: u16 = undefined; diff --git a/lib/std/json/dynamic.zig b/lib/std/json/dynamic.zig index ab79f19d9a..4d24444390 100644 --- a/lib/std/json/dynamic.zig +++ b/lib/std/json/dynamic.zig @@ -56,7 +56,7 @@ pub const Value = union(enum) { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); stringify(self, .{}, stderr) catch return; } diff --git a/lib/std/json/fmt.zig b/lib/std/json/fmt.zig index 09f58b3be6..dc1a6b43e8 100644 --- a/lib/std/json/fmt.zig +++ b/lib/std/json/fmt.zig @@ -1,4 +1,5 @@ -const std = @import("std"); +const std = @import("../std.zig"); +const assert = std.debug.assert; const stringify = @import("stringify.zig").stringify; const StringifyOptions = @import("stringify.zig").StringifyOptions; @@ -14,14 +15,8 @@ pub fn Formatter(comptime T: type) type { value: T, options: StringifyOptions, - pub fn format( - self: @This(), - comptime fmt_spec: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = fmt_spec; - _ = options; + pub fn format(self: @This(), writer: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { + comptime assert(f.len == 0); try stringify(self.value, self.options, writer); } }; diff --git a/lib/std/json/stringify.zig b/lib/std/json/stringify.zig index d5add74124..0b575fc587 100644 --- a/lib/std/json/stringify.zig +++ b/lib/std/json/stringify.zig @@ -689,7 +689,8 @@ fn outputUnicodeEscape(codepoint: u21, out_stream: anytype) !void { // then it may be represented as a six-character sequence: a reverse solidus, followed // by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point. try out_stream.writeAll("\\u"); - try std.fmt.formatIntValue(codepoint, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream); + //try w.printInt("x", .{ .width = 4, .fill = '0' }, codepoint); + try std.fmt.deprecatedFormat(out_stream, "{x:0>4}", .{codepoint}); } else { assert(codepoint <= 0x10FFFF); // To escape an extended character that is not in the Basic Multilingual Plane, @@ -697,9 +698,11 @@ fn outputUnicodeEscape(codepoint: u21, out_stream: anytype) !void { const high = @as(u16, @intCast((codepoint - 0x10000) >> 10)) + 0xD800; const low = @as(u16, @intCast(codepoint & 0x3FF)) + 0xDC00; try out_stream.writeAll("\\u"); - try std.fmt.formatIntValue(high, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream); + //try w.printInt("x", .{ .width = 4, .fill = '0' }, high); + try std.fmt.deprecatedFormat(out_stream, "{x:0>4}", .{high}); try out_stream.writeAll("\\u"); - try std.fmt.formatIntValue(low, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, out_stream); + //try w.printInt("x", .{ .width = 4, .fill = '0' }, low); + try std.fmt.deprecatedFormat(out_stream, "{x:0>4}", .{low}); } } diff --git a/lib/std/log.zig b/lib/std/log.zig index 8a39035dfe..4cbb73e6a4 100644 --- a/lib/std/log.zig +++ b/lib/std/log.zig @@ -47,7 +47,7 @@ //! // Print the message to stderr, silently ignoring any errors //! std.debug.lockStdErr(); //! defer std.debug.unlockStdErr(); -//! const stderr = std.fs.File.stderr().writer(); +//! const stderr = std.fs.File.stderr().deprecatedWriter(); //! nosuspend stderr.print(prefix ++ format ++ "\n", args) catch return; //! } //! @@ -148,7 +148,7 @@ pub fn defaultLog( ) void { const level_txt = comptime message_level.asText(); const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): "; - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); var bw = std.io.bufferedWriter(stderr); const writer = bw.writer(); diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 552ded4d51..3e6d66321f 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -2322,13 +2322,7 @@ pub const Const = struct { /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. - pub fn format( - self: Const, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - _ = options; + pub fn format(self: Const, w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { comptime var base = 10; comptime var case: std.fmt.Case = .lower; @@ -2350,7 +2344,7 @@ pub const Const = struct { const available_len = 64; if (self.limbs.len > available_len) - return out_stream.writeAll("(BigInt)"); + return w.writeAll("(BigInt)"); var limbs: [calcToStringLimbsBufferLen(available_len, base)]Limb = undefined; @@ -2360,7 +2354,7 @@ pub const Const = struct { }; var buf: [biggest.sizeInBaseUpperBound(base)]u8 = undefined; const len = self.toString(&buf, base, case, &limbs); - return out_stream.writeAll(buf[0..len]); + return w.writeAll(buf[0..len]); } /// Converts self to a string in the requested base. @@ -2934,13 +2928,8 @@ pub const Managed = struct { /// this function will fail to print the string, printing "(BigInt)" instead of a number. /// This is because the rendering algorithm requires reversing a string, which requires O(N) memory. /// See `toString` and `toStringAlloc` for a way to print big integers without failure. - pub fn format( - self: Managed, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - return self.toConst().format(fmt, options, out_stream); + pub fn format(self: Managed, w: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { + return self.toConst().format(w, f); } /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| == diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 5a0fda52b2..0f688b359d 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -3813,10 +3813,10 @@ test "(BigInt) positive" { try a.pow(&a, 64 * @sizeOf(Limb) * 8); try b.sub(&a, &c); - const a_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{a}); + const a_fmt = try std.fmt.allocPrintSentinel(testing.allocator, "{fd}", .{a}, 0); defer testing.allocator.free(a_fmt); - const b_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{b}); + const b_fmt = try std.fmt.allocPrintSentinel(testing.allocator, "{fd}", .{b}, 0); defer testing.allocator.free(b_fmt); try testing.expect(mem.eql(u8, a_fmt, "(BigInt)")); @@ -3838,10 +3838,10 @@ test "(BigInt) negative" { a.negate(); try b.add(&a, &c); - const a_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{a}); + const a_fmt = try std.fmt.allocPrintSentinel(testing.allocator, "{fd}", .{a}, 0); defer testing.allocator.free(a_fmt); - const b_fmt = try std.fmt.allocPrintZ(testing.allocator, "{d}", .{b}); + const b_fmt = try std.fmt.allocPrintSentinel(testing.allocator, "{fd}", .{b}, 0); defer testing.allocator.free(b_fmt); try testing.expect(mem.eql(u8, a_fmt, "(BigInt)")); diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index 279a150799..160a9f2fba 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -991,6 +991,7 @@ test "0 sized struct" { test "struct with many fields" { const ManyFields = struct { fn Type(count: comptime_int) type { + @setEvalBranchQuota(50000); var fields: [count]std.builtin.Type.StructField = undefined; for (0..count) |i| { fields[i] = .{ diff --git a/lib/std/net.zig b/lib/std/net.zig index a2b5fff70a..cfaad090ab 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -161,22 +161,14 @@ pub const Address = extern union { } } - pub fn format( - self: Address, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); + pub fn format(self: Address, w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); switch (self.any.family) { - posix.AF.INET => try self.in.format(fmt, options, out_stream), - posix.AF.INET6 => try self.in6.format(fmt, options, out_stream), + posix.AF.INET => try self.in.format(w, fmt), + posix.AF.INET6 => try self.in6.format(w, fmt), posix.AF.UNIX => { - if (!has_unix_sockets) { - unreachable; - } - - try std.fmt.format(out_stream, "{s}", .{std.mem.sliceTo(&self.un.path, 0)}); + if (!has_unix_sockets) unreachable; + try w.writeAll(std.mem.sliceTo(&self.un.path, 0)); }, else => unreachable, } @@ -349,22 +341,10 @@ pub const Ip4Address = extern struct { self.sa.port = mem.nativeToBig(u16, port); } - pub fn format( - self: Ip4Address, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); - _ = options; - const bytes = @as(*const [4]u8, @ptrCast(&self.sa.addr)); - try std.fmt.format(out_stream, "{}.{}.{}.{}:{}", .{ - bytes[0], - bytes[1], - bytes[2], - bytes[3], - self.getPort(), - }); + pub fn format(self: Ip4Address, w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); + const bytes: *const [4]u8 = @ptrCast(&self.sa.addr); + try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], self.getPort() }); } pub fn getOsSockLen(self: Ip4Address) posix.socklen_t { @@ -653,17 +633,11 @@ pub const Ip6Address = extern struct { self.sa.port = mem.nativeToBig(u16, port); } - pub fn format( - self: Ip6Address, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - out_stream: anytype, - ) !void { - if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self); - _ = options; + pub fn format(self: Ip6Address, w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); const port = mem.bigToNative(u16, self.sa.port); if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) { - try std.fmt.format(out_stream, "[::ffff:{}.{}.{}.{}]:{}", .{ + try w.print("[::ffff:{d}.{d}.{d}.{d}]:{d}", .{ self.sa.addr[12], self.sa.addr[13], self.sa.addr[14], @@ -711,14 +685,14 @@ pub const Ip6Address = extern struct { longest_len = 0; } - try out_stream.writeAll("["); + try w.writeAll("["); var i: usize = 0; var abbrv = false; while (i < native_endian_parts.len) : (i += 1) { if (i == longest_start) { // Emit "::" for the longest zero run if (!abbrv) { - try out_stream.writeAll(if (i == 0) "::" else ":"); + try w.writeAll(if (i == 0) "::" else ":"); abbrv = true; } i += longest_len - 1; // Skip the compressed range @@ -727,12 +701,12 @@ pub const Ip6Address = extern struct { if (abbrv) { abbrv = false; } - try std.fmt.format(out_stream, "{x}", .{native_endian_parts[i]}); + try w.print("{x}", .{native_endian_parts[i]}); if (i != native_endian_parts.len - 1) { - try out_stream.writeAll(":"); + try w.writeAll(":"); } } - try std.fmt.format(out_stream, "]:{}", .{port}); + try w.print("]:{}", .{port}); } pub fn getOsSockLen(self: Ip6Address) posix.socklen_t { @@ -894,7 +868,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get const name_c = try allocator.dupeZ(u8, name); defer allocator.free(name_c); - const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port}); + const port_c = try std.fmt.allocPrintSentinel(allocator, "{}", .{port}, 0); defer allocator.free(port_c); const ws2_32 = windows.ws2_32; @@ -966,7 +940,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get const name_c = try allocator.dupeZ(u8, name); defer allocator.free(name_c); - const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port}); + const port_c = try std.fmt.allocPrintSentinel(allocator, "{}", .{port}, 0); defer allocator.free(port_c); const hints: posix.addrinfo = .{ @@ -1356,7 +1330,7 @@ fn linuxLookupNameFromHosts( }; defer file.close(); - var buffered_reader = std.io.bufferedReader(file.reader()); + var buffered_reader = std.io.bufferedReader(file.deprecatedReader()); const reader = buffered_reader.reader(); var line_buf: [512]u8 = undefined; while (reader.readUntilDelimiterOrEof(&line_buf, '\n') catch |err| switch (err) { @@ -1557,7 +1531,7 @@ fn getResolvConf(allocator: mem.Allocator, rc: *ResolvConf) !void { }; defer file.close(); - var buf_reader = std.io.bufferedReader(file.reader()); + var buf_reader = std.io.bufferedReader(file.deprecatedReader()); const stream = buf_reader.reader(); var line_buf: [512]u8 = undefined; while (stream.readUntilDelimiterOrEof(&line_buf, '\n') catch |err| switch (err) { diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig index 88a18094ac..413f95ae15 100644 --- a/lib/std/net/test.zig +++ b/lib/std/net/test.zig @@ -7,18 +7,12 @@ const testing = std.testing; test "parse and render IP addresses at comptime" { if (builtin.os.tag == .wasi) return error.SkipZigTest; comptime { - var ipAddrBuffer: [16]u8 = undefined; - // Parses IPv6 at comptime const ipv6addr = net.Address.parseIp("::1", 0) catch unreachable; - var ipv6 = std.fmt.bufPrint(ipAddrBuffer[0..], "{}", .{ipv6addr}) catch unreachable; - try std.testing.expect(std.mem.eql(u8, "::1", ipv6[1 .. ipv6.len - 3])); + try std.testing.expectFmt("[::1]:0", "{f}", .{ipv6addr}); - // Parses IPv4 at comptime const ipv4addr = net.Address.parseIp("127.0.0.1", 0) catch unreachable; - var ipv4 = std.fmt.bufPrint(ipAddrBuffer[0..], "{}", .{ipv4addr}) catch unreachable; - try std.testing.expect(std.mem.eql(u8, "127.0.0.1", ipv4[0 .. ipv4.len - 2])); + try std.testing.expectFmt("127.0.0.1:0", "{f}", .{ipv4addr}); - // Returns error for invalid IP addresses at comptime try testing.expectError(error.InvalidIPAddressFormat, net.Address.parseIp("::123.123.123.123", 0)); try testing.expectError(error.InvalidIPAddressFormat, net.Address.parseIp("127.01.0.1", 0)); try testing.expectError(error.InvalidIPAddressFormat, net.Address.resolveIp("::123.123.123.123", 0)); @@ -28,13 +22,8 @@ test "parse and render IP addresses at comptime" { test "format IPv6 address with no zero runs" { if (builtin.os.tag == .wasi) return error.SkipZigTest; - const addr = try std.net.Address.parseIp6("2001:db8:1:2:3:4:5:6", 0); - - var buffer: [50]u8 = undefined; - const result = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable; - - try std.testing.expectEqualStrings("[2001:db8:1:2:3:4:5:6]:0", result); + try std.testing.expectFmt("[2001:db8:1:2:3:4:5:6]:0", "{f}", .{addr}); } test "parse IPv6 addresses and check compressed form" { @@ -111,12 +100,12 @@ test "parse and render IPv6 addresses" { }; for (ips, 0..) |ip, i| { const addr = net.Address.parseIp6(ip, 0) catch unreachable; - var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable; + var newIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr}) catch unreachable; try std.testing.expect(std.mem.eql(u8, printed[i], newIp[1 .. newIp.len - 3])); if (builtin.os.tag == .linux) { const addr_via_resolve = net.Address.resolveIp6(ip, 0) catch unreachable; - var newResolvedIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr_via_resolve}) catch unreachable; + var newResolvedIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr_via_resolve}) catch unreachable; try std.testing.expect(std.mem.eql(u8, printed[i], newResolvedIp[1 .. newResolvedIp.len - 3])); } } @@ -159,7 +148,7 @@ test "parse and render IPv4 addresses" { "127.0.0.1", }) |ip| { const addr = net.Address.parseIp4(ip, 0) catch unreachable; - var newIp = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable; + var newIp = std.fmt.bufPrint(buffer[0..], "{f}", .{addr}) catch unreachable; try std.testing.expect(std.mem.eql(u8, ip, newIp[0 .. newIp.len - 2])); } @@ -175,10 +164,8 @@ test "parse and render UNIX addresses" { if (builtin.os.tag == .wasi) return error.SkipZigTest; if (!net.has_unix_sockets) return error.SkipZigTest; - var buffer: [14]u8 = undefined; const addr = net.Address.initUnix("/tmp/testpath") catch unreachable; - const fmt_addr = std.fmt.bufPrint(buffer[0..], "{}", .{addr}) catch unreachable; - try std.testing.expectEqualSlices(u8, "/tmp/testpath", fmt_addr); + try std.testing.expectFmt("/tmp/testpath", "{f}", .{addr}); const too_long = [_]u8{'a'} ** 200; try testing.expectError(error.NameTooLong, net.Address.initUnix(too_long[0..])); diff --git a/lib/std/os.zig b/lib/std/os.zig index 3cf0c745cc..7de672191a 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -31,6 +31,7 @@ pub const uefi = @import("os/uefi.zig"); pub const wasi = @import("os/wasi.zig"); pub const emscripten = @import("os/emscripten.zig"); pub const windows = @import("os/windows.zig"); +pub const freebsd = @import("os/freebsd.zig"); test { _ = linux; diff --git a/lib/std/os/freebsd.zig b/lib/std/os/freebsd.zig new file mode 100644 index 0000000000..cdc1973e04 --- /dev/null +++ b/lib/std/os/freebsd.zig @@ -0,0 +1,49 @@ +const std = @import("../std.zig"); +const fd_t = std.c.fd_t; +const off_t = std.c.off_t; +const unexpectedErrno = std.posix.unexpectedErrno; +const errno = std.posix.errno; + +pub const CopyFileRangeError = error{ + /// If infd is not open for reading or outfd is not open for writing, or + /// opened for writing with O_APPEND, or if infd and outfd refer to the + /// same file. + BadFileFlags, + /// If the copy exceeds the process's file size limit or the maximum + /// file size for the file system outfd re- sides on. + FileTooBig, + /// A signal interrupted the system call before it could be completed. + /// This may happen for files on some NFS mounts. When this happens, + /// the values pointed to by inoffp and outoffp are reset to the + /// initial values for the system call. + Interrupted, + /// One of: + /// * infd and outfd refer to the same file and the byte ranges overlap. + /// * The flags argument is not zero. + /// * Either infd or outfd refers to a file object that is not a regular file. + InvalidArguments, + /// An I/O error occurred while reading/writing the files. + InputOutput, + /// Corrupted data was detected while reading from a file system. + CorruptedData, + /// Either infd or outfd refers to a directory. + IsDir, + /// File system that stores outfd is full. + NoSpaceLeft, +}; + +pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, len: usize, flags: u32) CopyFileRangeError!usize { + const rc = std.c.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); + switch (errno(rc)) { + .SUCCESS => return @intCast(rc), + .BADF => return error.BadFileFlags, + .FBIG => return error.FileTooBig, + .INTR => return error.Interrupted, + .INVAL => return error.InvalidArguments, + .IO => return error.InputOutput, + .INTEGRITY => return error.CorruptedData, + .ISDIR => return error.IsDir, + .NOSPC => return error.NoSpaceLeft, + else => |err| return unexpectedErrno(err), + } +} diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 3b2f51464e..75494145b9 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -9420,4 +9420,132 @@ pub const msghdr_const = extern struct { control: ?*const anyopaque, controllen: usize, flags: u32, -}; \ No newline at end of file +}; + +/// The syscalls, but with Zig error sets, going through libc if linking libc, +/// and with some footguns eliminated. +pub const wrapped = struct { + pub const lfs64_abi = builtin.link_libc and (builtin.abi.isGnu() or builtin.abi.isAndroid()); + const system = if (builtin.link_libc) std.c else std.os.linux; + + pub const SendfileError = std.posix.UnexpectedError || error{ + /// `out_fd` is an unconnected socket, or out_fd closed its read end. + BrokenPipe, + /// Descriptor is not valid or locked, or an mmap(2)-like operation is not available for in_fd. + UnsupportedOperation, + /// Nonblocking I/O has been selected but the write would block. + WouldBlock, + /// Unspecified error while reading from in_fd. + InputOutput, + /// Insufficient kernel memory to read from in_fd. + SystemResources, + /// `offset` is not `null` but the input file is not seekable. + Unseekable, + }; + + pub fn sendfile( + out_fd: fd_t, + in_fd: fd_t, + in_offset: ?*off_t, + in_len: usize, + ) SendfileError!usize { + const adjusted_len = @min(in_len, 0x7ffff000); // Prevents EOVERFLOW. + const sendfileSymbol = if (lfs64_abi) system.sendfile64 else system.sendfile; + const rc = sendfileSymbol(out_fd, in_fd, in_offset, adjusted_len); + switch (errno(rc)) { + .SUCCESS => return @intCast(rc), + .BADF => return invalidApiUsage(), // Always a race condition. + .FAULT => return invalidApiUsage(), // Segmentation fault. + .OVERFLOW => return unexpectedErrno(.OVERFLOW), // We avoid passing too large of a `count`. + .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket + .INVAL => return error.UnsupportedOperation, + .AGAIN => return error.WouldBlock, + .IO => return error.InputOutput, + .PIPE => return error.BrokenPipe, + .NOMEM => return error.SystemResources, + .NXIO => return error.Unseekable, + .SPIPE => return error.Unseekable, + else => |err| return unexpectedErrno(err), + } + } + + pub const CopyFileRangeError = std.posix.UnexpectedError || error{ + /// One of: + /// * One or more file descriptors are not valid. + /// * fd_in is not open for reading; or fd_out is not open for writing. + /// * The O_APPEND flag is set for the open file description referred + /// to by the file descriptor fd_out. + BadFileFlags, + /// One of: + /// * An attempt was made to write at a position past the maximum file + /// offset the kernel supports. + /// * An attempt was made to write a range that exceeds the allowed + /// maximum file size. The maximum file size differs between + /// filesystem implementations and can be different from the maximum + /// allowed file offset. + /// * An attempt was made to write beyond the process's file size + /// resource limit. This may also result in the process receiving a + /// SIGXFSZ signal. + FileTooBig, + /// One of: + /// * either fd_in or fd_out is not a regular file + /// * flags argument is not zero + /// * fd_in and fd_out refer to the same file and the source and target ranges overlap. + InvalidArguments, + /// A low-level I/O error occurred while copying. + InputOutput, + /// Either fd_in or fd_out refers to a directory. + IsDir, + OutOfMemory, + /// There is not enough space on the target filesystem to complete the copy. + NoSpaceLeft, + /// (since Linux 5.19) the filesystem does not support this operation. + OperationNotSupported, + /// The requested source or destination range is too large to represent + /// in the specified data types. + Overflow, + /// fd_out refers to an immutable file. + PermissionDenied, + /// Either fd_in or fd_out refers to an active swap file. + SwapFile, + /// The files referred to by fd_in and fd_out are not on the same + /// filesystem, and the source and target filesystems are not of the + /// same type, or do not support cross-filesystem copy. + NotSameFileSystem, + }; + + pub fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, len: usize, flags: u32) CopyFileRangeError!usize { + const rc = system.copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); + switch (errno(rc)) { + .SUCCESS => return @intCast(rc), + .BADF => return error.BadFileFlags, + .FBIG => return error.FileTooBig, + .INVAL => return error.InvalidArguments, + .IO => return error.InputOutput, + .ISDIR => return error.IsDir, + .NOMEM => return error.OutOfMemory, + .NOSPC => return error.NoSpaceLeft, + .OPNOTSUPP => return error.OperationNotSupported, + .OVERFLOW => return error.Overflow, + .PERM => return error.PermissionDenied, + .TXTBSY => return error.SwapFile, + .XDEV => return error.NotSameFileSystem, + else => |err| return unexpectedErrno(err), + } + } + + const unexpectedErrno = std.posix.unexpectedErrno; + + fn invalidApiUsage() error{Unexpected} { + if (builtin.mode == .Debug) @panic("invalid API usage"); + return error.Unexpected; + } + + fn errno(rc: anytype) E { + if (builtin.link_libc) { + return if (rc == -1) @enumFromInt(std.c._errno().*) else .SUCCESS; + } else { + return errnoFromSyscall(rc); + } + } +}; diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig index c362f707c6..33822e0070 100644 --- a/lib/std/os/uefi.zig +++ b/lib/std/os/uefi.zig @@ -1,4 +1,5 @@ const std = @import("../std.zig"); +const assert = std.debug.assert; /// A protocol is an interface identified by a GUID. pub const protocol = @import("uefi/protocol.zig"); @@ -59,31 +60,21 @@ pub const Guid = extern struct { node: [6]u8, /// Format GUID into hexadecimal lowercase xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format - pub fn format( - self: @This(), - comptime f: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; - if (f.len == 0) { - const fmt = std.fmt.fmtSliceHexLower; + pub fn format(self: @This(), writer: *std.io.Writer, comptime f: []const u8) std.io.Writer.Error!void { + comptime assert(f.len == 0); - const time_low = @byteSwap(self.time_low); - const time_mid = @byteSwap(self.time_mid); - const time_high_and_version = @byteSwap(self.time_high_and_version); + const time_low = @byteSwap(self.time_low); + const time_mid = @byteSwap(self.time_mid); + const time_high_and_version = @byteSwap(self.time_high_and_version); - return std.fmt.format(writer, "{:0>8}-{:0>4}-{:0>4}-{:0>2}{:0>2}-{:0>12}", .{ - fmt(std.mem.asBytes(&time_low)), - fmt(std.mem.asBytes(&time_mid)), - fmt(std.mem.asBytes(&time_high_and_version)), - fmt(std.mem.asBytes(&self.clock_seq_high_and_reserved)), - fmt(std.mem.asBytes(&self.clock_seq_low)), - fmt(std.mem.asBytes(&self.node)), - }); - } else { - std.fmt.invalidFmtError(f, self); - } + return std.fmt.format(writer, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{ + std.mem.asBytes(&time_low), + std.mem.asBytes(&time_mid), + std.mem.asBytes(&time_high_and_version), + std.mem.asBytes(&self.clock_seq_high_and_reserved), + std.mem.asBytes(&self.clock_seq_low), + std.mem.asBytes(&self.node), + }); } pub fn eql(a: std.os.uefi.Guid, b: std.os.uefi.Guid) bool { diff --git a/lib/std/os/uefi/protocol/file.zig b/lib/std/os/uefi/protocol/file.zig index 88ac361862..f8802fa64f 100644 --- a/lib/std/os/uefi/protocol/file.zig +++ b/lib/std/os/uefi/protocol/file.zig @@ -79,30 +79,6 @@ pub const File = extern struct { VolumeFull, }; - pub const SeekableStream = io.SeekableStream( - *File, - SeekError, - SeekError, - setPosition, - seekBy, - getPosition, - getEndPos, - ); - pub const Reader = io.GenericReader(*File, ReadError, read); - pub const Writer = io.GenericWriter(*File, WriteError, write); - - pub fn seekableStream(self: *File) SeekableStream { - return .{ .context = self }; - } - - pub fn reader(self: *File) Reader { - return .{ .context = self }; - } - - pub fn writer(self: *File) Writer { - return .{ .context = self }; - } - pub fn open( self: *const File, file_name: [*:0]const u16, diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 3aaff1d60a..33c2e7a548 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -1690,40 +1690,6 @@ pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so return ws2_32.getpeername(s, name, @as(*i32, @ptrCast(namelen))); } -pub fn sendmsg( - s: ws2_32.SOCKET, - msg: *ws2_32.WSAMSG_const, - flags: u32, -) i32 { - var bytes_send: DWORD = undefined; - if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) { - return ws2_32.SOCKET_ERROR; - } else { - return @as(i32, @as(u31, @intCast(bytes_send))); - } -} - -pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 { - var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = @constCast(buf) }; - var bytes_send: DWORD = undefined; - if (ws2_32.WSASendTo(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_send, flags, to, @as(i32, @intCast(to_len)), null, null) == ws2_32.SOCKET_ERROR) { - return ws2_32.SOCKET_ERROR; - } else { - return @as(i32, @as(u31, @intCast(bytes_send))); - } -} - -pub fn recvfrom(s: ws2_32.SOCKET, buf: [*]u8, len: usize, flags: u32, from: ?*ws2_32.sockaddr, from_len: ?*ws2_32.socklen_t) i32 { - var buffer = ws2_32.WSABUF{ .len = @as(u31, @truncate(len)), .buf = buf }; - var bytes_received: DWORD = undefined; - var flags_inout = flags; - if (ws2_32.WSARecvFrom(s, @as([*]ws2_32.WSABUF, @ptrCast(&buffer)), 1, &bytes_received, &flags_inout, from, @as(?*i32, @ptrCast(from_len)), null, null) == ws2_32.SOCKET_ERROR) { - return ws2_32.SOCKET_ERROR; - } else { - return @as(i32, @as(u31, @intCast(bytes_received))); - } -} - pub fn poll(fds: [*]ws2_32.pollfd, n: c_ulong, timeout: i32) i32 { return ws2_32.WSAPoll(fds, n, timeout); } diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig index e8375dc2c1..83194425fa 100644 --- a/lib/std/os/windows/ws2_32.zig +++ b/lib/std/os/windows/ws2_32.zig @@ -1829,7 +1829,7 @@ pub extern "ws2_32" fn sendto( buf: [*]const u8, len: i32, flags: i32, - to: *const sockaddr, + to: ?*const sockaddr, tolen: i32, ) callconv(.winapi) i32; @@ -2116,14 +2116,6 @@ pub extern "ws2_32" fn WSASendMsg( lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, ) callconv(.winapi) i32; -pub extern "ws2_32" fn WSARecvMsg( - s: SOCKET, - lpMsg: *WSAMSG, - lpdwNumberOfBytesRecv: ?*u32, - lpOverlapped: ?*OVERLAPPED, - lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE, -) callconv(.winapi) i32; - pub extern "ws2_32" fn WSASendDisconnect( s: SOCKET, lpOutboundDisconnectData: ?*WSABUF, diff --git a/lib/std/posix.zig b/lib/std/posix.zig index ae638226a1..c42ddd84b7 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -651,7 +651,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void { } const file: fs.File = .{ .handle = fd }; - const stream = file.reader(); + const stream = file.deprecatedReader(); stream.readNoEof(buf) catch return error.Unexpected; } diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index 776fe615b3..993b8e28cd 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -667,7 +667,7 @@ test "mmap" { const file = try tmp.dir.createFile(test_out_file, .{}); defer file.close(); - const stream = file.writer(); + const stream = file.deprecatedWriter(); var i: u32 = 0; while (i < alloc_size / @sizeOf(u32)) : (i += 1) { diff --git a/lib/std/process.zig b/lib/std/process.zig index 072cbeefdb..58d16eef1d 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -1553,7 +1553,7 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { const file = try std.fs.openFileAbsolute("/etc/passwd", .{}); defer file.close(); - const reader = file.reader(); + const reader = file.deprecatedReader(); const State = enum { Start, @@ -1895,7 +1895,7 @@ pub fn createEnvironFromMap( var i: usize = 0; if (zig_progress_action == .add) { - envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}); + envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}, 0); i += 1; } @@ -1906,16 +1906,16 @@ pub fn createEnvironFromMap( .add => unreachable, .delete => continue, .edit => { - envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={d}", .{ + envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "{s}={d}", .{ pair.key_ptr.*, options.zig_progress_fd.?, - }); + }, 0); i += 1; continue; }, .nothing => {}, }; - envp_buf[i] = try std.fmt.allocPrintZ(arena, "{s}={s}", .{ pair.key_ptr.*, pair.value_ptr.* }); + envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "{s}={s}", .{ pair.key_ptr.*, pair.value_ptr.* }, 0); i += 1; } } @@ -1965,7 +1965,7 @@ pub fn createEnvironFromExisting( var existing_index: usize = 0; if (zig_progress_action == .add) { - envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}); + envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}, 0); i += 1; } @@ -1974,7 +1974,7 @@ pub fn createEnvironFromExisting( .add => unreachable, .delete => continue, .edit => { - envp_buf[i] = try std.fmt.allocPrintZ(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}); + envp_buf[i] = try std.fmt.allocPrintSentinel(arena, "ZIG_PROGRESS={d}", .{options.zig_progress_fd.?}, 0); i += 1; continue; }, diff --git a/lib/std/process/Child.zig b/lib/std/process/Child.zig index f9dc28aaaf..c2effb523a 100644 --- a/lib/std/process/Child.zig +++ b/lib/std/process/Child.zig @@ -1004,12 +1004,12 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { fn writeIntFd(fd: i32, value: ErrInt) !void { const file: File = .{ .handle = fd }; - file.writer().writeInt(u64, @intCast(value), .little) catch return error.SystemResources; + file.deprecatedWriter().writeInt(u64, @intCast(value), .little) catch return error.SystemResources; } fn readIntFd(fd: i32) !ErrInt { const file: File = .{ .handle = fd }; - return @intCast(file.reader().readInt(u64, .little) catch return error.SystemResources); + return @intCast(file.deprecatedReader().readInt(u64, .little) catch return error.SystemResources); } const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8); diff --git a/lib/std/testing.zig b/lib/std/testing.zig index b7e1c6333c..0e601765d1 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -105,7 +105,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { .error_set, => { if (actual != expected) { - print("expected {}, found {}\n", .{ expected, actual }); + print("expected {any}, found {any}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -267,9 +267,13 @@ test "expectEqual null" { /// This function is intended to be used only in tests. When the formatted result of the template /// and its arguments does not equal the expected text, it prints diagnostics to stderr to show how -/// they are not equal, then returns an error. It depends on `expectEqualStrings()` for printing +/// they are not equal, then returns an error. It depends on `expectEqualStrings` for printing /// diagnostics. pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anytype) !void { + if (@inComptime()) { + var buffer: [std.fmt.count(template, args)]u8 = undefined; + return expectEqualStrings(expected, try std.fmt.bufPrint(&buffer, template, args)); + } const actual = try std.fmt.allocPrint(allocator, template, args); defer allocator.free(actual); return expectEqualStrings(expected, actual); @@ -415,7 +419,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const print("... truncated ...\n", .{}); } } - differ.write(stderr.writer()) catch {}; + differ.write(stderr.deprecatedWriter()) catch {}; if (expected_truncated) { const end_offset = window_start + expected_window.len; const num_missing_items = expected.len - (window_start + expected_window.len); @@ -437,7 +441,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const print("... truncated ...\n", .{}); } } - differ.write(stderr.writer()) catch {}; + differ.write(stderr.deprecatedWriter()) catch {}; if (actual_truncated) { const end_offset = window_start + actual_window.len; const num_missing_items = actual.len - (window_start + actual_window.len); @@ -637,6 +641,11 @@ pub fn tmpDir(opts: std.fs.Dir.OpenOptions) TmpDir { pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { if (std.mem.indexOfDiff(u8, actual, expected)) |diff_index| { + if (@inComptime()) { + @compileError(std.fmt.comptimePrint("\nexpected:\n{s}\nfound:\n{s}\ndifference starts at index {d}", .{ + expected, actual, diff_index, + })); + } print("\n====== expected this output: =========\n", .{}); printWithVisibleNewlines(expected); print("\n======== instead found this: =========\n", .{}); @@ -1108,7 +1117,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime const arg_i_str = comptime str: { var str_buf: [100]u8 = undefined; const args_i = i + 1; - const str_len = std.fmt.formatIntBuf(&str_buf, args_i, 10, .lower, .{}); + const str_len = std.fmt.printInt(&str_buf, args_i, 10, .lower, .{}); break :str str_buf[0..str_len]; }; @field(args, arg_i_str) = @field(extra_args, field.name); @@ -1138,7 +1147,7 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime error.OutOfMemory => { if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) { print( - "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {}", + "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}", .{ fail_index, needed_alloc_count, diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 4c6ec1294b..ef694f33ba 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -9,6 +9,7 @@ const native_endian = builtin.cpu.arch.endian(); /// /// See also: https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character pub const replacement_character: u21 = 0xFFFD; +pub const replacement_character_utf8: [3]u8 = utf8EncodeComptime(replacement_character); /// Returns how many bytes the UTF-8 representation would require /// for the given codepoint. @@ -802,14 +803,7 @@ fn testDecode(bytes: []const u8) !u21 { /// Ill-formed UTF-8 byte sequences are replaced by the replacement character (U+FFFD) /// according to "U+FFFD Substitution of Maximal Subparts" from Chapter 3 of /// the Unicode standard, and as specified by https://encoding.spec.whatwg.org/#utf-8-decoder -fn formatUtf8( - utf8: []const u8, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = fmt; - _ = options; +fn formatUtf8(utf8: []const u8, writer: *std.io.Writer) std.io.Writer.Error!void { var buf: [300]u8 = undefined; // just an arbitrary size var u8len: usize = 0; @@ -898,27 +892,27 @@ fn formatUtf8( /// Ill-formed UTF-8 byte sequences are replaced by the replacement character (U+FFFD) /// according to "U+FFFD Substitution of Maximal Subparts" from Chapter 3 of /// the Unicode standard, and as specified by https://encoding.spec.whatwg.org/#utf-8-decoder -pub fn fmtUtf8(utf8: []const u8) std.fmt.Formatter(formatUtf8) { +pub fn fmtUtf8(utf8: []const u8) std.fmt.Formatter([]const u8, formatUtf8) { return .{ .data = utf8 }; } test fmtUtf8 { const expectFmt = testing.expectFmt; - try expectFmt("", "{}", .{fmtUtf8("")}); - try expectFmt("foo", "{}", .{fmtUtf8("foo")}); - try expectFmt("𐐷", "{}", .{fmtUtf8("𐐷")}); + try expectFmt("", "{f}", .{fmtUtf8("")}); + try expectFmt("foo", "{f}", .{fmtUtf8("foo")}); + try expectFmt("𐐷", "{f}", .{fmtUtf8("𐐷")}); // Table 3-8. U+FFFD for Non-Shortest Form Sequences - try expectFmt("��������A", "{}", .{fmtUtf8("\xC0\xAF\xE0\x80\xBF\xF0\x81\x82A")}); + try expectFmt("��������A", "{f}", .{fmtUtf8("\xC0\xAF\xE0\x80\xBF\xF0\x81\x82A")}); // Table 3-9. U+FFFD for Ill-Formed Sequences for Surrogates - try expectFmt("��������A", "{}", .{fmtUtf8("\xED\xA0\x80\xED\xBF\xBF\xED\xAFA")}); + try expectFmt("��������A", "{f}", .{fmtUtf8("\xED\xA0\x80\xED\xBF\xBF\xED\xAFA")}); // Table 3-10. U+FFFD for Other Ill-Formed Sequences - try expectFmt("�����A��B", "{}", .{fmtUtf8("\xF4\x91\x92\x93\xFFA\x80\xBFB")}); + try expectFmt("�����A��B", "{f}", .{fmtUtf8("\xF4\x91\x92\x93\xFFA\x80\xBFB")}); // Table 3-11. U+FFFD for Truncated Sequences - try expectFmt("����A", "{}", .{fmtUtf8("\xE1\x80\xE2\xF0\x91\x92\xF1\xBFA")}); + try expectFmt("����A", "{f}", .{fmtUtf8("\xE1\x80\xE2\xF0\x91\x92\xF1\xBFA")}); } fn utf16LeToUtf8ArrayListImpl( @@ -1477,14 +1471,7 @@ test calcWtf16LeLen { /// Print the given `utf16le` string, encoded as UTF-8 bytes. /// Unpaired surrogates are replaced by the replacement character (U+FFFD). -fn formatUtf16Le( - utf16le: []const u16, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = fmt; - _ = options; +fn formatUtf16Le(utf16le: []const u16, writer: *std.io.Writer) std.io.Writer.Error!void { var buf: [300]u8 = undefined; // just an arbitrary size var it = Utf16LeIterator.init(utf16le); var u8len: usize = 0; @@ -1505,23 +1492,23 @@ pub const fmtUtf16le = @compileError("deprecated; renamed to fmtUtf16Le"); /// Return a Formatter for a (potentially ill-formed) UTF-16 LE string, /// which will be converted to UTF-8 during formatting. /// Unpaired surrogates are replaced by the replacement character (U+FFFD). -pub fn fmtUtf16Le(utf16le: []const u16) std.fmt.Formatter(formatUtf16Le) { +pub fn fmtUtf16Le(utf16le: []const u16) std.fmt.Formatter([]const u16, formatUtf16Le) { return .{ .data = utf16le }; } test fmtUtf16Le { const expectFmt = testing.expectFmt; - try expectFmt("", "{}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral(""))}); - try expectFmt("", "{}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral(""))}); - try expectFmt("foo", "{}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral("foo"))}); - try expectFmt("foo", "{}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("foo"))}); - try expectFmt("𐐷", "{}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("𐐷"))}); - try expectFmt("퟿", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xd7", native_endian)})}); - try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xd8", native_endian)})}); - try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdb", native_endian)})}); - try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xdc", native_endian)})}); - try expectFmt("�", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdf", native_endian)})}); - try expectFmt("", "{}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xe0", native_endian)})}); + try expectFmt("", "{f}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral(""))}); + try expectFmt("", "{f}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral(""))}); + try expectFmt("foo", "{f}", .{fmtUtf16Le(utf8ToUtf16LeStringLiteral("foo"))}); + try expectFmt("foo", "{f}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("foo"))}); + try expectFmt("𐐷", "{f}", .{fmtUtf16Le(wtf8ToWtf16LeStringLiteral("𐐷"))}); + try expectFmt("퟿", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xd7", native_endian)})}); + try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xd8", native_endian)})}); + try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdb", native_endian)})}); + try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xdc", native_endian)})}); + try expectFmt("�", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\xff\xdf", native_endian)})}); + try expectFmt("", "{f}", .{fmtUtf16Le(&[_]u16{mem.readInt(u16, "\x00\xe0", native_endian)})}); } fn testUtf8ToUtf16LeStringLiteral(utf8ToUtf16LeStringLiteral_: anytype) !void { diff --git a/lib/std/unicode/throughput_test.zig b/lib/std/unicode/throughput_test.zig index d98b59c2d6..c13a38b101 100644 --- a/lib/std/unicode/throughput_test.zig +++ b/lib/std/unicode/throughput_test.zig @@ -39,7 +39,7 @@ fn benchmarkCodepointCount(buf: []const u8) !ResultCount { } pub fn main() !void { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.print("short ASCII strings\n", .{}); { diff --git a/lib/std/zig.zig b/lib/std/zig.zig index da4973b109..5d7f16a2a0 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -363,149 +363,136 @@ const Allocator = std.mem.Allocator; /// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed. /// -/// - An empty `{}` format specifier escapes invalid identifiers, identifiers that shadow primitives -/// and the reserved `_` identifier. -/// - Add `p` to the specifier to render identifiers that shadow primitives unescaped. -/// - Add `_` to the specifier to render the reserved `_` identifier unescaped. -/// - `p` and `_` can be combined, e.g. `{p_}`. +/// See also `fmtIdFlags`. +pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) { + return .{ .data = .{ .bytes = bytes, .flags = .{} } }; +} + +/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed. /// -pub fn fmtId(bytes: []const u8) std.fmt.Formatter(formatId) { - return .{ .data = bytes }; +/// See also `fmtId`. +pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) { + return .{ .data = .{ .bytes = bytes, .flags = flags } }; +} + +pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) { + return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } }; +} + +pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) { + return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } }; } test fmtId { const expectFmt = std.testing.expectFmt; - try expectFmt("@\"while\"", "{}", .{fmtId("while")}); - try expectFmt("@\"while\"", "{p}", .{fmtId("while")}); - try expectFmt("@\"while\"", "{_}", .{fmtId("while")}); - try expectFmt("@\"while\"", "{p_}", .{fmtId("while")}); - try expectFmt("@\"while\"", "{_p}", .{fmtId("while")}); + try expectFmt("@\"while\"", "{f}", .{fmtId("while")}); + try expectFmt("@\"while\"", "{f}", .{fmtIdFlags("while", .{ .allow_primitive = true })}); + try expectFmt("@\"while\"", "{f}", .{fmtIdFlags("while", .{ .allow_underscore = true })}); + try expectFmt("@\"while\"", "{f}", .{fmtIdFlags("while", .{ .allow_primitive = true, .allow_underscore = true })}); - try expectFmt("hello", "{}", .{fmtId("hello")}); - try expectFmt("hello", "{p}", .{fmtId("hello")}); - try expectFmt("hello", "{_}", .{fmtId("hello")}); - try expectFmt("hello", "{p_}", .{fmtId("hello")}); - try expectFmt("hello", "{_p}", .{fmtId("hello")}); + try expectFmt("hello", "{f}", .{fmtId("hello")}); + try expectFmt("hello", "{f}", .{fmtIdFlags("hello", .{ .allow_primitive = true })}); + try expectFmt("hello", "{f}", .{fmtIdFlags("hello", .{ .allow_underscore = true })}); + try expectFmt("hello", "{f}", .{fmtIdFlags("hello", .{ .allow_primitive = true, .allow_underscore = true })}); - try expectFmt("@\"type\"", "{}", .{fmtId("type")}); - try expectFmt("type", "{p}", .{fmtId("type")}); - try expectFmt("@\"type\"", "{_}", .{fmtId("type")}); - try expectFmt("type", "{p_}", .{fmtId("type")}); - try expectFmt("type", "{_p}", .{fmtId("type")}); + try expectFmt("@\"type\"", "{f}", .{fmtId("type")}); + try expectFmt("type", "{f}", .{fmtIdFlags("type", .{ .allow_primitive = true })}); + try expectFmt("@\"type\"", "{f}", .{fmtIdFlags("type", .{ .allow_underscore = true })}); + try expectFmt("type", "{f}", .{fmtIdFlags("type", .{ .allow_primitive = true, .allow_underscore = true })}); - try expectFmt("@\"_\"", "{}", .{fmtId("_")}); - try expectFmt("@\"_\"", "{p}", .{fmtId("_")}); - try expectFmt("_", "{_}", .{fmtId("_")}); - try expectFmt("_", "{p_}", .{fmtId("_")}); - try expectFmt("_", "{_p}", .{fmtId("_")}); + try expectFmt("@\"_\"", "{f}", .{fmtId("_")}); + try expectFmt("@\"_\"", "{f}", .{fmtIdFlags("_", .{ .allow_primitive = true })}); + try expectFmt("_", "{f}", .{fmtIdFlags("_", .{ .allow_underscore = true })}); + try expectFmt("_", "{f}", .{fmtIdFlags("_", .{ .allow_primitive = true, .allow_underscore = true })}); - try expectFmt("@\"i123\"", "{}", .{fmtId("i123")}); - try expectFmt("i123", "{p}", .{fmtId("i123")}); - try expectFmt("@\"4four\"", "{}", .{fmtId("4four")}); - try expectFmt("_underscore", "{}", .{fmtId("_underscore")}); - try expectFmt("@\"11\\\"23\"", "{}", .{fmtId("11\"23")}); - try expectFmt("@\"11\\x0f23\"", "{}", .{fmtId("11\x0F23")}); + try expectFmt("@\"i123\"", "{f}", .{fmtId("i123")}); + try expectFmt("i123", "{f}", .{fmtIdFlags("i123", .{ .allow_primitive = true })}); + try expectFmt("@\"4four\"", "{f}", .{fmtId("4four")}); + try expectFmt("_underscore", "{f}", .{fmtId("_underscore")}); + try expectFmt("@\"11\\\"23\"", "{f}", .{fmtId("11\"23")}); + try expectFmt("@\"11\\x0f23\"", "{f}", .{fmtId("11\x0F23")}); // These are technically not currently legal in Zig. - try expectFmt("@\"\"", "{}", .{fmtId("")}); - try expectFmt("@\"\\x00\"", "{}", .{fmtId("\x00")}); + try expectFmt("@\"\"", "{f}", .{fmtId("")}); + try expectFmt("@\"\\x00\"", "{f}", .{fmtId("\x00")}); } -/// Print the string as a Zig identifier, escaping it with `@""` syntax if needed. -fn formatId( +pub const FormatId = struct { bytes: []const u8, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - const allow_primitive, const allow_underscore = comptime parse_fmt: { - var allow_primitive = false; - var allow_underscore = false; - for (fmt) |char| { - switch (char) { - 'p' => if (!allow_primitive) { - allow_primitive = true; - continue; - }, - '_' => if (!allow_underscore) { - allow_underscore = true; - continue; - }, - else => {}, - } - @compileError("expected {}, {p}, {_}, {p_} or {_p}, found {" ++ fmt ++ "}"); - } - break :parse_fmt .{ allow_primitive, allow_underscore }; + flags: Flags, + pub const Flags = struct { + allow_primitive: bool = false, + allow_underscore: bool = false, }; - if (isValidId(bytes) and - (allow_primitive or !std.zig.isPrimitive(bytes)) and - (allow_underscore or !isUnderscore(bytes))) - { - return writer.writeAll(bytes); + /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed. + fn render(ctx: FormatId, writer: *std.io.Writer) std.io.Writer.Error!void { + const bytes = ctx.bytes; + if (isValidId(bytes) and + (ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and + (ctx.flags.allow_underscore or !isUnderscore(bytes))) + { + return writer.writeAll(bytes); + } + try writer.writeAll("@\""); + try stringEscape(bytes, writer); + try writer.writeByte('"'); } - try writer.writeAll("@\""); - try stringEscape(bytes, "", options, writer); - try writer.writeByte('"'); -} +}; -/// Return a Formatter for Zig Escapes of a double quoted string. -/// The format specifier must be one of: -/// * `{}` treats contents as a double-quoted string. -/// * `{'}` treats contents as a single-quoted string. -pub fn fmtEscapes(bytes: []const u8) std.fmt.Formatter(stringEscape) { +/// Return a formatter for escaping a double quoted Zig string. +pub fn fmtString(bytes: []const u8) std.fmt.Formatter([]const u8, stringEscape) { return .{ .data = bytes }; } -test fmtEscapes { - const expectFmt = std.testing.expectFmt; - try expectFmt("\\x0f", "{}", .{fmtEscapes("\x0f")}); - try expectFmt( - \\" \\ hi \x07 \x11 " derp \'" - , "\"{'}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); - try expectFmt( - \\" \\ hi \x07 \x11 \" derp '" - , "\"{}\"", .{fmtEscapes(" \\ hi \x07 \x11 \" derp '")}); +/// Return a formatter for escaping a single quoted Zig string. +pub fn fmtChar(bytes: []const u8) std.fmt.Formatter([]const u8, charEscape) { + return .{ .data = bytes }; } -/// Print the string as escaped contents of a double quoted or single-quoted string. -/// Format `{}` treats contents as a double-quoted string. -/// Format `{'}` treats contents as a single-quoted string. -pub fn stringEscape( - bytes: []const u8, - comptime f: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, -) !void { - _ = options; +test fmtString { + try std.testing.expectFmt("\\x0f", "{f}", .{fmtString("\x0f")}); + try std.testing.expectFmt( + \\" \\ hi \x07 \x11 \" derp '" + , "\"{f}\"", .{fmtString(" \\ hi \x07 \x11 \" derp '")}); +} + +test fmtChar { + try std.testing.expectFmt( + \\" \\ hi \x07 \x11 " derp \'" + , "\"{f}\"", .{fmtChar(" \\ hi \x07 \x11 \" derp '")}); +} + +/// Print the string as escaped contents of a double quoted string. +pub fn stringEscape(bytes: []const u8, w: *std.io.Writer) std.io.Writer.Error!void { for (bytes) |byte| switch (byte) { - '\n' => try writer.writeAll("\\n"), - '\r' => try writer.writeAll("\\r"), - '\t' => try writer.writeAll("\\t"), - '\\' => try writer.writeAll("\\\\"), - '"' => { - if (f.len == 1 and f[0] == '\'') { - try writer.writeByte('"'); - } else if (f.len == 0) { - try writer.writeAll("\\\""); - } else { - @compileError("expected {} or {'}, found {" ++ f ++ "}"); - } - }, - '\'' => { - if (f.len == 1 and f[0] == '\'') { - try writer.writeAll("\\'"); - } else if (f.len == 0) { - try writer.writeByte('\''); - } else { - @compileError("expected {} or {'}, found {" ++ f ++ "}"); - } - }, - ' ', '!', '#'...'&', '('...'[', ']'...'~' => try writer.writeByte(byte), - // Use hex escapes for rest any unprintable characters. + '\n' => try w.writeAll("\\n"), + '\r' => try w.writeAll("\\r"), + '\t' => try w.writeAll("\\t"), + '\\' => try w.writeAll("\\\\"), + '"' => try w.writeAll("\\\""), + '\'' => try w.writeByte('\''), + ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte), else => { - try writer.writeAll("\\x"); - try std.fmt.formatInt(byte, 16, .lower, .{ .width = 2, .fill = '0' }, writer); + try w.writeAll("\\x"); + try w.printIntOptions(byte, 16, .lower, .{ .width = 2, .fill = '0' }); + }, + }; +} + +/// Print the string as escaped contents of a single-quoted string. +pub fn charEscape(bytes: []const u8, w: *std.io.Writer) std.io.Writer.Error!void { + for (bytes) |byte| switch (byte) { + '\n' => try w.writeAll("\\n"), + '\r' => try w.writeAll("\\r"), + '\t' => try w.writeAll("\\t"), + '\\' => try w.writeAll("\\\\"), + '"' => try w.writeByte('"'), + '\'' => try w.writeAll("\\'"), + ' ', '!', '#'...'&', '('...'[', ']'...'~' => try w.writeByte(byte), + else => { + try w.writeAll("\\x"); + try w.printIntOptions(byte, 16, .lower, .{ .width = 2, .fill = '0' }); }, }; } diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 6c4c0ff602..ecdc7a8a4e 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -565,14 +565,14 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { .invalid_byte => { const tok_slice = tree.source[tree.tokens.items(.start)[parse_error.token]..]; - return stream.print("{s} contains invalid byte: '{'}'", .{ + return stream.print("{s} contains invalid byte: '{f}'", .{ switch (tok_slice[0]) { '\'' => "character literal", '"', '\\' => "string literal", '/' => "comment", else => unreachable, }, - std.zig.fmtEscapes(tok_slice[parse_error.extra.offset..][0..1]), + std.zig.fmtChar(tok_slice[parse_error.extra.offset..][0..1]), }); }, diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig index af2dc2fd0f..48a4e9966a 100644 --- a/lib/std/zig/ErrorBundle.zig +++ b/lib/std/zig/ErrorBundle.zig @@ -165,7 +165,7 @@ pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); const stderr: std.fs.File = .stderr(); - return renderToWriter(eb, options, stderr.writer()) catch return; + return renderToWriter(eb, options, stderr.deprecatedWriter()) catch return; } pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void { diff --git a/lib/std/zig/ZonGen.zig b/lib/std/zig/ZonGen.zig index a43663a609..ccc09a82ce 100644 --- a/lib/std/zig/ZonGen.zig +++ b/lib/std/zig/ZonGen.zig @@ -756,13 +756,7 @@ fn lowerStrLitError( raw_string: []const u8, offset: u32, ) Allocator.Error!void { - return ZonGen.addErrorTokOff( - zg, - token, - @intCast(offset + err.offset()), - "{}", - .{err.fmt(raw_string)}, - ); + return ZonGen.addErrorTokOff(zg, token, @intCast(offset + err.offset()), "{f}", .{err.fmt(raw_string)}); } fn lowerNumberError(zg: *ZonGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) Allocator.Error!void { diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index ada07ebbc6..9443e7f92b 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -1,3 +1,14 @@ +const std = @import("../../std.zig"); +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; +const bitcode_writer = @import("bitcode_writer.zig"); +const Builder = @This(); +const builtin = @import("builtin"); +const DW = std.dwarf; +const ir = @import("ir.zig"); +const log = std.log.scoped(.llvm); +const Writer = std.io.Writer; + gpa: Allocator, strip: bool, @@ -90,31 +101,25 @@ pub const String = enum(u32) { const FormatData = struct { string: String, builder: *const Builder, + quote_behavior: ?QuoteBehavior, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_| - @compileError("invalid format string: '" ++ fmt_str ++ "'"); + fn format(data: FormatData, w: *Writer) Writer.Error!void { assert(data.string != .none); const string_slice = data.string.slice(data.builder) orelse - return writer.print("{d}", .{@intFromEnum(data.string)}); - if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_| - return writer.writeAll(string_slice); - try printEscapedString( - string_slice, - if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_| - .always_quote - else - .quote_unless_valid_identifier, - writer, - ); + return w.print("{d}", .{@intFromEnum(data.string)}); + const quote_behavior = data.quote_behavior orelse return w.writeAll(string_slice); + return printEscapedString(string_slice, quote_behavior, w); } - pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) { - return .{ .data = .{ .string = self, .builder = builder } }; + pub fn fmt( + self: String, + builder: *const Builder, + quote_behavior: ?QuoteBehavior, + ) std.fmt.Formatter(FormatData, format) { + return .{ .data = .{ + .string = self, + .builder = builder, + .quote_behavior = quote_behavior, + } }; } fn fromIndex(index: ?usize) String { @@ -228,7 +233,7 @@ pub const Type = enum(u32) { _, pub const ptr_amdgpu_constant = - @field(Type, std.fmt.comptimePrint("ptr{ }", .{AddrSpace.amdgpu.constant})); + @field(Type, std.fmt.comptimePrint("ptr{f }", .{AddrSpace.amdgpu.constant})); pub const Tag = enum(u4) { simple, @@ -653,18 +658,16 @@ pub const Type = enum(u32) { const FormatData = struct { type: Type, builder: *const Builder, + mode: Mode, + + const Mode = enum { default, m, lt, gt, percent }; }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, w: *Writer) Writer.Error!void { assert(data.type != .none); - if (comptime std.mem.eql(u8, fmt_str, "m")) { + if (data.mode == .m) { const item = data.builder.type_items.items[@intFromEnum(data.type)]; switch (item.tag) { - .simple => try writer.writeAll(switch (@as(Simple, @enumFromInt(item.data))) { + .simple => try w.writeAll(switch (@as(Simple, @enumFromInt(item.data))) { .void => "isVoid", .half => "f16", .bfloat => "bf16", @@ -681,29 +684,29 @@ pub const Type = enum(u32) { .function, .vararg_function => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Function, item.data); const params = extra.trail.next(extra.data.params_len, Type, data.builder); - try writer.print("f_{m}", .{extra.data.ret.fmt(data.builder)}); - for (params) |param| try writer.print("{m}", .{param.fmt(data.builder)}); + try w.print("f_{fm}", .{extra.data.ret.fmt(data.builder)}); + for (params) |param| try w.print("{fm}", .{param.fmt(data.builder)}); switch (kind) { .function => {}, - .vararg_function => try writer.writeAll("vararg"), + .vararg_function => try w.writeAll("vararg"), else => unreachable, } - try writer.writeByte('f'); + try w.writeByte('f'); }, - .integer => try writer.print("i{d}", .{item.data}), - .pointer => try writer.print("p{d}", .{item.data}), + .integer => try w.print("i{d}", .{item.data}), + .pointer => try w.print("p{d}", .{item.data}), .target => { var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); const types = extra.trail.next(extra.data.types_len, Type, data.builder); const ints = extra.trail.next(extra.data.ints_len, u32, data.builder); - try writer.print("t{s}", .{extra.data.name.slice(data.builder).?}); - for (types) |ty| try writer.print("_{m}", .{ty.fmt(data.builder)}); - for (ints) |int| try writer.print("_{d}", .{int}); - try writer.writeByte('t'); + try w.print("t{s}", .{extra.data.name.slice(data.builder).?}); + for (types) |ty| try w.print("_{fm}", .{ty.fmt(data.builder)}); + for (ints) |int| try w.print("_{d}", .{int}); + try w.writeByte('t'); }, .vector, .scalable_vector => |kind| { const extra = data.builder.typeExtraData(Type.Vector, item.data); - try writer.print("{s}v{d}{m}", .{ + try w.print("{s}v{d}{fm}", .{ switch (kind) { .vector => "", .scalable_vector => "nx", @@ -719,65 +722,65 @@ pub const Type = enum(u32) { .array => Type.Array, else => unreachable, }, item.data); - try writer.print("a{d}{m}", .{ extra.length(), extra.child.fmt(data.builder) }); + try w.print("a{d}{fm}", .{ extra.length(), extra.child.fmt(data.builder) }); }, .structure, .packed_structure => { var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, data.builder); - try writer.writeAll("sl_"); - for (fields) |field| try writer.print("{m}", .{field.fmt(data.builder)}); - try writer.writeByte('s'); + try w.writeAll("sl_"); + for (fields) |field| try w.print("{fm}", .{field.fmt(data.builder)}); + try w.writeByte('s'); }, .named_structure => { const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); - try writer.writeAll("s_"); - if (extra.id.slice(data.builder)) |id| try writer.writeAll(id); + try w.writeAll("s_"); + if (extra.id.slice(data.builder)) |id| try w.writeAll(id); }, } return; } - if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name); + if (std.enums.tagName(Type, data.type)) |name| return w.writeAll(name); const item = data.builder.type_items.items[@intFromEnum(data.type)]; switch (item.tag) { .simple => unreachable, .function, .vararg_function => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Function, item.data); const params = extra.trail.next(extra.data.params_len, Type, data.builder); - if (!comptime std.mem.eql(u8, fmt_str, ">")) - try writer.print("{%} ", .{extra.data.ret.fmt(data.builder)}); - if (!comptime std.mem.eql(u8, fmt_str, "<")) { - try writer.writeByte('('); + if (data.mode != .gt) + try w.print("{f%} ", .{extra.data.ret.fmt(data.builder)}); + if (data.mode != .lt) { + try w.writeByte('('); for (params, 0..) |param, index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{param.fmt(data.builder)}); + if (index > 0) try w.writeAll(", "); + try w.print("{f%}", .{param.fmt(data.builder)}); } switch (kind) { .function => {}, .vararg_function => { - if (params.len > 0) try writer.writeAll(", "); - try writer.writeAll("..."); + if (params.len > 0) try w.writeAll(", "); + try w.writeAll("..."); }, else => unreachable, } - try writer.writeByte(')'); + try w.writeByte(')'); } }, - .integer => try writer.print("i{d}", .{item.data}), - .pointer => try writer.print("ptr{ }", .{@as(AddrSpace, @enumFromInt(item.data))}), + .integer => try w.print("i{d}", .{item.data}), + .pointer => try w.print("ptr{f }", .{@as(AddrSpace, @enumFromInt(item.data))}), .target => { var extra = data.builder.typeExtraDataTrail(Type.Target, item.data); const types = extra.trail.next(extra.data.types_len, Type, data.builder); const ints = extra.trail.next(extra.data.ints_len, u32, data.builder); - try writer.print( - \\target({"} + try w.print( + \\target({f"} , .{extra.data.name.fmt(data.builder)}); - for (types) |ty| try writer.print(", {%}", .{ty.fmt(data.builder)}); - for (ints) |int| try writer.print(", {d}", .{int}); - try writer.writeByte(')'); + for (types) |ty| try w.print(", {f%}", .{ty.fmt(data.builder)}); + for (ints) |int| try w.print(", {d}", .{int}); + try w.writeByte(')'); }, .vector, .scalable_vector => |kind| { const extra = data.builder.typeExtraData(Type.Vector, item.data); - try writer.print("<{s}{d} x {%}>", .{ + try w.print("<{s}{d} x {f%}>", .{ switch (kind) { .vector => "", .scalable_vector => "vscale x ", @@ -793,44 +796,45 @@ pub const Type = enum(u32) { .array => Type.Array, else => unreachable, }, item.data); - try writer.print("[{d} x {%}]", .{ extra.length(), extra.child.fmt(data.builder) }); + try w.print("[{d} x {f%}]", .{ extra.length(), extra.child.fmt(data.builder) }); }, .structure, .packed_structure => |kind| { var extra = data.builder.typeExtraDataTrail(Type.Structure, item.data); const fields = extra.trail.next(extra.data.fields_len, Type, data.builder); switch (kind) { .structure => {}, - .packed_structure => try writer.writeByte('<'), + .packed_structure => try w.writeByte('<'), else => unreachable, } - try writer.writeAll("{ "); + try w.writeAll("{ "); for (fields, 0..) |field, index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{field.fmt(data.builder)}); + if (index > 0) try w.writeAll(", "); + try w.print("{f%}", .{field.fmt(data.builder)}); } - try writer.writeAll(" }"); + try w.writeAll(" }"); switch (kind) { .structure => {}, - .packed_structure => try writer.writeByte('>'), + .packed_structure => try w.writeByte('>'), else => unreachable, } }, .named_structure => { const extra = data.builder.typeExtraData(Type.NamedStructure, item.data); - if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{ + if (data.mode == .percent) try w.print("%{f}", .{ extra.id.fmt(data.builder), }) else switch (extra.body) { - .none => try writer.writeAll("opaque"), + .none => try w.writeAll("opaque"), else => try format(.{ .type = extra.body, .builder = data.builder, - }, fmt_str, fmt_opts, writer), + .mode = data.mode, + }, w), } }, } } - pub fn fmt(self: Type, builder: *const Builder) std.fmt.Formatter(format) { - return .{ .data = .{ .type = self, .builder = builder } }; + pub fn fmt(self: Type, builder: *const Builder, mode: FormatData.Mode) std.fmt.Formatter(FormatData, format) { + return .{ .data = .{ .type = self, .builder = builder, .mode = mode } }; } const IsSizedVisited = std.AutoHashMapUnmanaged(Type, void); @@ -1138,15 +1142,10 @@ pub const Attribute = union(Kind) { const FormatData = struct { attribute_index: Index, builder: *const Builder, + mode: Mode, + const Mode = enum { default, quote, pound }; }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (comptime std.mem.indexOfNone(u8, fmt_str, "\"#")) |_| - @compileError("invalid format string: '" ++ fmt_str ++ "'"); + fn format(data: FormatData, w: *Writer) Writer.Error!void { const attribute = data.attribute_index.toAttribute(data.builder); switch (attribute) { .zeroext, @@ -1219,97 +1218,94 @@ pub const Attribute = union(Kind) { .no_sanitize_address, .no_sanitize_hwaddress, .sanitize_address_dyninit, - => try writer.print(" {s}", .{@tagName(attribute)}), + => try w.print(" {s}", .{@tagName(attribute)}), .byval, .byref, .preallocated, .inalloca, .sret, .elementtype, - => |ty| try writer.print(" {s}({%})", .{ @tagName(attribute), ty.fmt(data.builder) }), - .@"align" => |alignment| try writer.print("{ }", .{alignment}), + => |ty| try w.print(" {s}({f%})", .{ @tagName(attribute), ty.fmt(data.builder) }), + .@"align" => |alignment| try w.print("{f }", .{alignment}), .dereferenceable, .dereferenceable_or_null, - => |size| try writer.print(" {s}({d})", .{ @tagName(attribute), size }), + => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }), .nofpclass => |fpclass| { const Int = @typeInfo(FpClass).@"struct".backing_integer.?; - try writer.print(" {s}(", .{@tagName(attribute)}); + try w.print(" {s}(", .{@tagName(attribute)}); var any = false; var remaining: Int = @bitCast(fpclass); inline for (@typeInfo(FpClass).@"struct".decls) |decl| { const pattern: Int = @bitCast(@field(FpClass, decl.name)); if (remaining & pattern == pattern) { if (!any) { - try writer.writeByte(' '); + try w.writeByte(' '); any = true; } - try writer.writeAll(decl.name); + try w.writeAll(decl.name); remaining &= ~pattern; } } - try writer.writeByte(')'); + try w.writeByte(')'); }, - .alignstack => |alignment| try writer.print( - if (comptime std.mem.indexOfScalar(u8, fmt_str, '#') != null) - " {s}={d}" - else - " {s}({d})", + .alignstack => |alignment| try w.print( + if (data.mode == .pound) " {s}={d}" else " {s}({d})", .{ @tagName(attribute), alignment.toByteUnits() orelse return }, ), .allockind => |allockind| { - try writer.print(" {s}(\"", .{@tagName(attribute)}); + try w.print(" {s}(\"", .{@tagName(attribute)}); var any = false; inline for (@typeInfo(AllocKind).@"struct".fields) |field| { if (comptime std.mem.eql(u8, field.name, "_")) continue; if (@field(allockind, field.name)) { if (!any) { - try writer.writeByte(','); + try w.writeByte(','); any = true; } - try writer.writeAll(field.name); + try w.writeAll(field.name); } } - try writer.writeAll("\")"); + try w.writeAll("\")"); }, .allocsize => |allocsize| { - try writer.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size }); + try w.print(" {s}({d}", .{ @tagName(attribute), allocsize.elem_size }); if (allocsize.num_elems != AllocSize.none) - try writer.print(",{d}", .{allocsize.num_elems}); - try writer.writeByte(')'); + try w.print(",{d}", .{allocsize.num_elems}); + try w.writeByte(')'); }, .memory => |memory| { - try writer.print(" {s}(", .{@tagName(attribute)}); + try w.print(" {s}(", .{@tagName(attribute)}); var any = memory.other != .none or (memory.argmem == .none and memory.inaccessiblemem == .none); - if (any) try writer.writeAll(@tagName(memory.other)); + if (any) try w.writeAll(@tagName(memory.other)); inline for (.{ "argmem", "inaccessiblemem" }) |kind| { if (@field(memory, kind) != memory.other) { - if (any) try writer.writeAll(", "); - try writer.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) }); + if (any) try w.writeAll(", "); + try w.print("{s}: {s}", .{ kind, @tagName(@field(memory, kind)) }); any = true; } } - try writer.writeByte(')'); + try w.writeByte(')'); }, .uwtable => |uwtable| if (uwtable != .none) { - try writer.print(" {s}", .{@tagName(attribute)}); - if (uwtable != UwTable.default) try writer.print("({s})", .{@tagName(uwtable)}); + try w.print(" {s}", .{@tagName(attribute)}); + if (uwtable != UwTable.default) try w.print("({s})", .{@tagName(uwtable)}); }, - .vscale_range => |vscale_range| try writer.print(" {s}({d},{d})", .{ + .vscale_range => |vscale_range| try w.print(" {s}({d},{d})", .{ @tagName(attribute), vscale_range.min.toByteUnits().?, vscale_range.max.toByteUnits() orelse 0, }), - .string => |string_attr| if (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) { - try writer.print(" {\"}", .{string_attr.kind.fmt(data.builder)}); + .string => |string_attr| if (data.mode == .quote) { + try w.print(" {f\"}", .{string_attr.kind.fmt(data.builder)}); if (string_attr.value != .empty) - try writer.print("={\"}", .{string_attr.value.fmt(data.builder)}); + try w.print("={f\"}", .{string_attr.value.fmt(data.builder)}); }, .none => unreachable, } } - pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) { - return .{ .data = .{ .attribute_index = self, .builder = builder } }; + pub fn fmt(self: Index, builder: *const Builder, mode: FormatData.mode) std.fmt.Formatter(FormatData, format) { + return .{ .data = .{ .attribute_index = self, .builder = builder, .mode = mode } }; } fn toStorage(self: Index, builder: *const Builder) Storage { @@ -1583,18 +1579,13 @@ pub const Attributes = enum(u32) { attributes: Attributes, builder: *const Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, w: *Writer) Writer.Error!void { for (data.attributes.slice(data.builder)) |attribute_index| try Attribute.Index.format(.{ .attribute_index = attribute_index, .builder = data.builder, - }, fmt_str, fmt_opts, writer); + }, w); } - pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(format) { + pub fn fmt(self: Attributes, builder: *const Builder) std.fmt.Formatter(FormatData, format) { return .{ .data = .{ .attributes = self, .builder = builder } }; } }; @@ -1781,24 +1772,15 @@ pub const Linkage = enum(u4) { extern_weak = 7, external = 0, - pub fn format( - self: Linkage, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .external) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: Linkage, w: *Writer, comptime f: []const u8) Writer.Error!void { + comptime assert(f.len == 0); + if (self != .external) try w.print(" {s}", .{@tagName(self)}); } - fn formatOptional( - data: ?Linkage, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (data) |linkage| try writer.print(" {s}", .{@tagName(linkage)}); + fn formatOptional(data: ?Linkage, w: *Writer) Writer.Error!void { + if (data) |linkage| try w.print(" {s}", .{@tagName(linkage)}); } - pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(formatOptional) { + pub fn fmtOptional(self: ?Linkage) std.fmt.Formatter(?Linkage, formatOptional) { return .{ .data = self }; } }; @@ -1808,13 +1790,8 @@ pub const Preemption = enum { dso_local, implicit_dso_local, - pub fn format( - self: Preemption, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: Preemption, w: *Writer, comptime _: []const u8) Writer.Error!void { + if (self == .dso_local) try w.print(" {s}", .{@tagName(self)}); } }; @@ -1831,12 +1808,8 @@ pub const Visibility = enum(u2) { }; } - pub fn format( - self: Visibility, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: Visibility, comptime format_string: []const u8, writer: *Writer) Writer.Error!void { + comptime assert(format_string.len == 0); if (self != .default) try writer.print(" {s}", .{@tagName(self)}); } }; @@ -1846,13 +1819,8 @@ pub const DllStorageClass = enum(u2) { dllimport = 1, dllexport = 2, - pub fn format( - self: DllStorageClass, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .default) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: DllStorageClass, w: *Writer, comptime _: []const u8) Writer.Error!void { + if (self != .default) try w.print(" {s}", .{@tagName(self)}); } }; @@ -1863,15 +1831,10 @@ pub const ThreadLocal = enum(u3) { initialexec = 3, localexec = 4, - pub fn format( - self: ThreadLocal, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: ThreadLocal, w: *Writer, comptime prefix: []const u8) Writer.Error!void { if (self == .default) return; - try writer.print("{s}thread_local", .{prefix}); - if (self != .generaldynamic) try writer.print("({s})", .{@tagName(self)}); + try w.print("{s}thread_local", .{prefix}); + if (self != .generaldynamic) try w.print("({s})", .{@tagName(self)}); } }; @@ -1882,13 +1845,8 @@ pub const UnnamedAddr = enum(u2) { unnamed_addr = 1, local_unnamed_addr = 2, - pub fn format( - self: UnnamedAddr, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .default) try writer.print(" {s}", .{@tagName(self)}); + pub fn format(self: UnnamedAddr, w: *Writer, comptime _: []const u8) Writer.Error!void { + if (self != .default) try w.print(" {s}", .{@tagName(self)}); } }; @@ -1981,13 +1939,8 @@ pub const AddrSpace = enum(u24) { pub const funcref: AddrSpace = @enumFromInt(20); }; - pub fn format( - self: AddrSpace, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .default) try writer.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) }); + pub fn format(self: AddrSpace, w: *Writer, comptime prefix: []const u8) Writer.Error!void { + if (self != .default) try w.print("{s}addrspace({d})", .{ prefix, @intFromEnum(self) }); } }; @@ -1995,15 +1948,8 @@ pub const ExternallyInitialized = enum { default, externally_initialized, - pub fn format( - self: ExternallyInitialized, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self == .default) return; - try writer.writeByte(' '); - try writer.writeAll(@tagName(self)); + pub fn format(self: ExternallyInitialized, w: *Writer, comptime _: []const u8) Writer.Error!void { + if (self != .default) try w.print(" {s}", .{@tagName(self)}); } }; @@ -2026,13 +1972,8 @@ pub const Alignment = enum(u6) { return if (self == .default) 0 else (@intFromEnum(self) + 1); } - pub fn format( - self: Alignment, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return }); + pub fn format(self: Alignment, w: *Writer, comptime prefix: []const u8) Writer.Error!void { + try w.print("{s}align {d}", .{ prefix, self.toByteUnits() orelse return }); } }; @@ -2105,12 +2046,7 @@ pub const CallConv = enum(u10) { pub const default = CallConv.ccc; - pub fn format( - self: CallConv, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: CallConv, w: *Writer, comptime _: []const u8) Writer.Error!void { switch (self) { default => {}, .fastcc, @@ -2164,8 +2100,8 @@ pub const CallConv = enum(u10) { .aarch64_sme_preservemost_from_x2, .m68k_rtdcc, .riscv_vectorcallcc, - => try writer.print(" {s}", .{@tagName(self)}), - _ => try writer.print(" cc{d}", .{@intFromEnum(self)}), + => try w.print(" {s}", .{@tagName(self)}), + _ => try w.print(" cc{d}", .{@intFromEnum(self)}), } } }; @@ -2190,31 +2126,25 @@ pub const StrtabString = enum(u32) { const FormatData = struct { string: StrtabString, builder: *const Builder, + quote_behavior: ?QuoteBehavior, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (comptime std.mem.indexOfNone(u8, fmt_str, "\"r")) |_| - @compileError("invalid format string: '" ++ fmt_str ++ "'"); + fn format(data: FormatData, w: *Writer) Writer.Error!void { assert(data.string != .none); const string_slice = data.string.slice(data.builder) orelse - return writer.print("{d}", .{@intFromEnum(data.string)}); - if (comptime std.mem.indexOfScalar(u8, fmt_str, 'r')) |_| - return writer.writeAll(string_slice); - try printEscapedString( - string_slice, - if (comptime std.mem.indexOfScalar(u8, fmt_str, '"')) |_| - .always_quote - else - .quote_unless_valid_identifier, - writer, - ); + return w.print("{d}", .{@intFromEnum(data.string)}); + const quote_behavior = data.quote_behavior orelse return w.writeAll(string_slice); + return printEscapedString(string_slice, quote_behavior, w); } - pub fn fmt(self: StrtabString, builder: *const Builder) std.fmt.Formatter(format) { - return .{ .data = .{ .string = self, .builder = builder } }; + pub fn fmt( + self: StrtabString, + builder: *const Builder, + quote_behavior: ?QuoteBehavior, + ) std.fmt.Formatter(FormatData, format) { + return .{ .data = .{ + .string = self, + .builder = builder, + .quote_behavior = quote_behavior, + } }; } fn fromIndex(index: ?usize) StrtabString { @@ -2264,7 +2194,7 @@ pub fn strtabStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: a } pub fn strtabStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) StrtabString { - self.strtab_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable; + self.strtab_string_bytes.printAssumeCapacity(fmt_str, fmt_args); return self.trailingStrtabStringAssumeCapacity(); } @@ -2383,17 +2313,12 @@ pub const Global = struct { global: Index, builder: *const Builder, }; - fn format( - data: FormatData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try writer.print("@{}", .{ + fn format(data: FormatData, w: *Writer) Writer.Error!void { + try w.print("@{f}", .{ data.global.unwrap(data.builder).name(data.builder).fmt(data.builder), }); } - pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) { + pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(FormatData, format) { return .{ .data = .{ .global = self, .builder = builder } }; } @@ -4833,29 +4758,28 @@ pub const Function = struct { instruction: Instruction.Index, function: Function.Index, builder: *Builder, + flags: Flags, + const Flags = struct { + comma: bool = false, + space: bool = false, + percent: bool = false, + }; }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_| - @compileError("invalid format string: '" ++ fmt_str ++ "'"); - if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) { + fn format(data: FormatData, w: *Writer) Writer.Error!void { + if (data.flags.comma) { if (data.instruction == .none) return; - try writer.writeByte(','); + try w.writeByte(','); } - if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) { + if (data.flags.space) { if (data.instruction == .none) return; - try writer.writeByte(' '); + try w.writeByte(' '); } - if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print( - "{%} ", + if (data.flags.percent) try w.print( + "{f%} ", .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)}, ); assert(data.instruction != .none); - try writer.print("%{}", .{ + try w.print("%{f}", .{ data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder), }); } @@ -4863,8 +4787,14 @@ pub const Function = struct { self: Instruction.Index, function: Function.Index, builder: *Builder, - ) std.fmt.Formatter(format) { - return .{ .data = .{ .instruction = self, .function = function, .builder = builder } }; + flags: FormatData.Flags, + ) std.fmt.Formatter(FormatData, format) { + return .{ .data = .{ + .instruction = self, + .function = function, + .builder = builder, + .flags = flags, + } }; } }; @@ -6361,7 +6291,7 @@ pub const WipFunction = struct { while (true) { gop.value_ptr.* = @enumFromInt(@intFromEnum(gop.value_ptr.*) + 1); - const unique_name = try wip_name.builder.fmt("{r}{s}{r}", .{ + const unique_name = try wip_name.builder.fmt("{fr}{s}{fr}", .{ name.fmt(wip_name.builder), sep, gop.value_ptr.fmt(wip_name.builder), @@ -7031,13 +6961,8 @@ pub const MemoryAccessKind = enum(u1) { normal, @"volatile", - pub fn format( - self: MemoryAccessKind, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .normal) try writer.print("{s}{s}", .{ prefix, @tagName(self) }); + pub fn format(self: MemoryAccessKind, w: *Writer, comptime prefix: []const u8) Writer.Error!void { + if (self != .normal) try w.print("{s}{s}", .{ prefix, @tagName(self) }); } }; @@ -7045,13 +6970,8 @@ pub const SyncScope = enum(u1) { singlethread, system, - pub fn format( - self: SyncScope, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .system) try writer.print( + pub fn format(self: SyncScope, w: *Writer, comptime prefix: []const u8) Writer.Error!void { + if (self != .system) try w.print( \\{s}syncscope("{s}") , .{ prefix, @tagName(self) }); } @@ -7066,13 +6986,8 @@ pub const AtomicOrdering = enum(u3) { acq_rel = 5, seq_cst = 6, - pub fn format( - self: AtomicOrdering, - comptime prefix: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (self != .none) try writer.print("{s}{s}", .{ prefix, @tagName(self) }); + pub fn format(self: AtomicOrdering, w: *Writer, comptime prefix: []const u8) Writer.Error!void { + if (self != .none) try w.print("{s}{s}", .{ prefix, @tagName(self) }); } }; @@ -7486,27 +7401,26 @@ pub const Constant = enum(u32) { const FormatData = struct { constant: Constant, builder: *Builder, + flags: Flags, + const Flags = struct { + comma: bool = false, + space: bool = false, + percent: bool = false, + }; }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_| - @compileError("invalid format string: '" ++ fmt_str ++ "'"); - if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) { + fn format(data: FormatData, w: *Writer) Writer.Error!void { + if (data.flags.comma) { if (data.constant == .no_init) return; - try writer.writeByte(','); + try w.writeByte(','); } - if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) { + if (data.flags.space) { if (data.constant == .no_init) return; - try writer.writeByte(' '); + try w.writeByte(' '); } - if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) - try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)}); + if (data.flags.percent) + try w.print("{f%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)}); assert(data.constant != .no_init); - if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name); + if (std.enums.tagName(Constant, data.constant)) |name| return w.writeAll(name); switch (data.constant.unwrap()) { .constant => |constant| { const item = data.builder.constant_items.get(constant); @@ -7545,11 +7459,11 @@ pub const Constant = enum(u32) { const allocator = stack.get(); const str = try bigint.toStringAlloc(allocator, 10, undefined); defer allocator.free(str); - try writer.writeAll(str); + try w.writeAll(str); }, .half, .bfloat, - => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) { + => |tag| try w.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) { .half => 'H', .bfloat => 'R', else => unreachable, @@ -7580,7 +7494,7 @@ pub const Constant = enum(u32) { ) + 1, else => 0, }; - try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){ + try w.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){ .mantissa = std.math.shl( Mantissa64, repr.mantissa, @@ -7602,13 +7516,13 @@ pub const Constant = enum(u32) { }, .double => { const extra = data.builder.constantExtraData(Double, item.data); - try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo }); + try w.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo }); }, .fp128, .ppc_fp128, => |tag| { const extra = data.builder.constantExtraData(Fp128, item.data); - try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{ + try w.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{ @as(u8, switch (tag) { .fp128 => 'L', .ppc_fp128 => 'M', @@ -7622,7 +7536,7 @@ pub const Constant = enum(u32) { }, .x86_fp80 => { const extra = data.builder.constantExtraData(Fp80, item.data); - try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{ + try w.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{ extra.hi, extra.lo_hi, extra.lo_lo, }); }, @@ -7631,7 +7545,7 @@ pub const Constant = enum(u32) { .zeroinitializer, .undef, .poison, - => |tag| try writer.writeAll(@tagName(tag)), + => |tag| try w.writeAll(@tagName(tag)), .structure, .packed_structure, .array, @@ -7640,7 +7554,7 @@ pub const Constant = enum(u32) { var extra = data.builder.constantExtraDataTrail(Aggregate, item.data); const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder)); const vals = extra.trail.next(len, Constant, data.builder); - try writer.writeAll(switch (tag) { + try w.writeAll(switch (tag) { .structure => "{ ", .packed_structure => "<{ ", .array => "[", @@ -7648,10 +7562,10 @@ pub const Constant = enum(u32) { else => unreachable, }); for (vals, 0..) |val, index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{val.fmt(data.builder)}); + if (index > 0) try w.writeAll(", "); + try w.print("{f%}", .{val.fmt(data.builder)}); } - try writer.writeAll(switch (tag) { + try w.writeAll(switch (tag) { .structure => " }", .packed_structure => " }>", .array => "]", @@ -7662,20 +7576,20 @@ pub const Constant = enum(u32) { .splat => { const extra = data.builder.constantExtraData(Splat, item.data); const len = extra.type.vectorLen(data.builder); - try writer.writeByte('<'); + try w.writeByte('<'); for (0..len) |index| { - if (index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{extra.value.fmt(data.builder)}); + if (index > 0) try w.writeAll(", "); + try w.print("{f%}", .{extra.value.fmt(data.builder)}); } - try writer.writeByte('>'); + try w.writeByte('>'); }, - .string => try writer.print("c{\"}", .{ + .string => try w.print("c{f\"}", .{ @as(String, @enumFromInt(item.data)).fmt(data.builder), }), .blockaddress => |tag| { const extra = data.builder.constantExtraData(BlockAddress, item.data); const function = extra.function.ptrConst(data.builder); - try writer.print("{s}({}, {})", .{ + try w.print("{s}({f}, {f})", .{ @tagName(tag), function.global.fmt(data.builder), extra.block.toInst(function).fmt(extra.function, data.builder), @@ -7685,7 +7599,7 @@ pub const Constant = enum(u32) { .no_cfi, => |tag| { const function: Function.Index = @enumFromInt(item.data); - try writer.print("{s} {}", .{ + try w.print("{s} {f}", .{ @tagName(tag), function.ptrConst(data.builder).global.fmt(data.builder), }); @@ -7697,7 +7611,7 @@ pub const Constant = enum(u32) { .addrspacecast, => |tag| { const extra = data.builder.constantExtraData(Cast, item.data); - try writer.print("{s} ({%} to {%})", .{ + try w.print("{s} ({f%} to {f%})", .{ @tagName(tag), extra.val.fmt(data.builder), extra.type.fmt(data.builder), @@ -7709,13 +7623,13 @@ pub const Constant = enum(u32) { var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data); const indices = extra.trail.next(extra.data.info.indices_len, Constant, data.builder); - try writer.print("{s} ({%}, {%}", .{ + try w.print("{s} ({f%}, {f%}", .{ @tagName(tag), extra.data.type.fmt(data.builder), extra.data.base.fmt(data.builder), }); - for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)}); - try writer.writeByte(')'); + for (indices) |index| try w.print(", {f%}", .{index.fmt(data.builder)}); + try w.writeByte(')'); }, .add, .@"add nsw", @@ -7727,7 +7641,7 @@ pub const Constant = enum(u32) { .xor, => |tag| { const extra = data.builder.constantExtraData(Binary, item.data); - try writer.print("{s} ({%}, {%})", .{ + try w.print("{s} ({f%}, {f%})", .{ @tagName(tag), extra.lhs.fmt(data.builder), extra.rhs.fmt(data.builder), @@ -7751,7 +7665,7 @@ pub const Constant = enum(u32) { .@"asm sideeffect alignstack inteldialect unwind", => |tag| { const extra = data.builder.constantExtraData(Assembly, item.data); - try writer.print("{s} {\"}, {\"}", .{ + try w.print("{s} {f\"}, {f\"}", .{ @tagName(tag), extra.assembly.fmt(data.builder), extra.constraints.fmt(data.builder), @@ -7759,11 +7673,15 @@ pub const Constant = enum(u32) { }, } }, - .global => |global| try writer.print("{}", .{global.fmt(data.builder)}), + .global => |global| try w.print("{f}", .{global.fmt(data.builder)}), } } - pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) { - return .{ .data = .{ .constant = self, .builder = builder } }; + pub fn fmt(self: Constant, builder: *Builder, flags: FormatData.Flags) std.fmt.Formatter(FormatData, format) { + return .{ .data = .{ + .constant = self, + .builder = builder, + .flags = flags, + } }; } }; @@ -7819,26 +7737,21 @@ pub const Value = enum(u32) { function: Function.Index, builder: *Builder, }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, w: *Writer) Writer.Error!void { switch (data.value.unwrap()) { .instruction => |instruction| try Function.Instruction.Index.format(.{ .instruction = instruction, .function = data.function, .builder = data.builder, - }, fmt_str, fmt_opts, writer), + }, w), .constant => |constant| try Constant.format(.{ .constant = constant, .builder = data.builder, - }, fmt_str, fmt_opts, writer), + }, w), .metadata => unreachable, } } - pub fn fmt(self: Value, function: Function.Index, builder: *Builder) std.fmt.Formatter(format) { + pub fn fmt(self: Value, function: Function.Index, builder: *Builder) std.fmt.Formatter(FormatData, format) { return .{ .data = .{ .value = self, .function = function, .builder = builder } }; } }; @@ -7869,15 +7782,10 @@ pub const MetadataString = enum(u32) { metadata_string: MetadataString, builder: *const Builder, }; - fn format( - data: FormatData, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { - try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, writer); + fn format(data: FormatData, w: *Writer) Writer.Error!void { + try printEscapedString(data.metadata_string.slice(data.builder), .always_quote, w); } - fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(format) { + fn fmt(self: MetadataString, builder: *const Builder) std.fmt.Formatter(FormatData, format) { return .{ .data = .{ .metadata_string = self, .builder = builder } }; } }; @@ -8039,29 +7947,24 @@ pub const Metadata = enum(u32) { AllCallsDescribed: bool = false, Unused: u2 = 0, - pub fn format( - self: DIFlags, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: DIFlags, w: *Writer, comptime _: []const u8) Writer.Error!void { var need_pipe = false; inline for (@typeInfo(DIFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { .bool => if (@field(self, field.name)) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DIFlag{s}", .{field.name}); + if (need_pipe) try w.writeAll(" | ") else need_pipe = true; + try w.print("DIFlag{s}", .{field.name}); }, .@"enum" => if (@field(self, field.name) != .Zero) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DIFlag{s}", .{@tagName(@field(self, field.name))}); + if (need_pipe) try w.writeAll(" | ") else need_pipe = true; + try w.print("DIFlag{s}", .{@tagName(@field(self, field.name))}); }, .int => assert(@field(self, field.name) == 0), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), } } - if (!need_pipe) try writer.writeByte('0'); + if (!need_pipe) try w.writeByte('0'); } }; @@ -8101,29 +8004,24 @@ pub const Metadata = enum(u32) { ObjCDirect: bool = false, Unused: u20 = 0, - pub fn format( - self: DISPFlags, - comptime _: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + pub fn format(self: DISPFlags, w: *Writer, comptime _: []const u8) Writer.Error!void { var need_pipe = false; inline for (@typeInfo(DISPFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { .bool => if (@field(self, field.name)) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DISPFlag{s}", .{field.name}); + if (need_pipe) try w.writeAll(" | ") else need_pipe = true; + try w.print("DISPFlag{s}", .{field.name}); }, .@"enum" => if (@field(self, field.name) != .Zero) { - if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; - try writer.print("DISPFlag{s}", .{@tagName(@field(self, field.name))}); + if (need_pipe) try w.writeAll(" | ") else need_pipe = true; + try w.print("DISPFlag{s}", .{@tagName(@field(self, field.name))}); }, .int => assert(@field(self, field.name) == 0), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), } } - if (!need_pipe) try writer.writeByte('0'); + if (!need_pipe) try w.writeByte('0'); } }; @@ -8298,6 +8196,9 @@ pub const Metadata = enum(u32) { formatter: *Formatter, prefix: []const u8 = "", node: Node, + specialized: ?TODO, + + const TODO = opaque {}; const Node = union(enum) { none, @@ -8323,20 +8224,15 @@ pub const Metadata = enum(u32) { }; }; }; - fn format( - data: FormatData, - comptime fmt_str: []const u8, - fmt_opts: std.fmt.FormatOptions, - writer: anytype, - ) @TypeOf(writer).Error!void { + fn format(data: FormatData, w: *Writer) Writer.Error!void { if (data.node == .none) return; - const is_specialized = fmt_str.len > 0 and fmt_str[0] == 'S'; - const recurse_fmt_str = if (is_specialized) fmt_str[1..] else fmt_str; + const is_specialized = data.specialized != null; + const recurse_fmt_str = data.specialized orelse {}; - if (data.formatter.need_comma) try writer.writeAll(", "); + if (data.formatter.need_comma) try w.writeAll(", "); defer data.formatter.need_comma = true; - try writer.writeAll(data.prefix); + try w.writeAll(data.prefix); const builder = data.formatter.builder; switch (data.node) { @@ -8351,54 +8247,50 @@ pub const Metadata = enum(u32) { .expression => { var extra = builder.metadataExtraDataTrail(Expression, item.data); const elements = extra.trail.next(extra.data.elements_len, u32, builder); - try writer.writeAll("!DIExpression("); + try w.writeAll("!DIExpression("); for (elements) |element| try format(.{ .formatter = data.formatter, .node = .{ .u64 = element }, - }, "%", fmt_opts, writer); - try writer.writeByte(')'); + }, w, "%"); + try w.writeByte(')'); }, .constant => try Constant.format(.{ .constant = @enumFromInt(item.data), .builder = builder, - }, recurse_fmt_str, fmt_opts, writer), + }, w, recurse_fmt_str), else => unreachable, } }, - .index => |node| try writer.print("!{d}", .{node}), + .index => |node| try w.print("!{d}", .{node}), inline .local_value, .local_metadata => |node, tag| try Value.format(.{ .value = node.value, .function = node.function, .builder = builder, - }, switch (tag) { + }, w, switch (tag) { .local_value => recurse_fmt_str, .local_metadata => "%", else => unreachable, - }, fmt_opts, writer), + }), inline .local_inline, .local_index => |node, tag| { if (comptime std.mem.eql(u8, recurse_fmt_str, "%")) - try writer.print("{%} ", .{Type.metadata.fmt(builder)}); + try w.print("{f%} ", .{Type.metadata.fmt(builder)}); try format(.{ .formatter = data.formatter, .node = @unionInit(FormatData.Node, @tagName(tag)["local_".len..], node), - }, "%", fmt_opts, writer); + }, w, "%"); }, - .string => |node| try writer.print((if (is_specialized) "" else "!") ++ "{}", .{ + .string => |node| try w.print((if (is_specialized) "" else "!") ++ "{f}", .{ node.fmt(builder), }), - inline .bool, - .u32, - .u64, - .di_flags, - .sp_flags, - => |node| try writer.print("{}", .{node}), - .raw => |node| try writer.writeAll(node), + inline .bool, .u32, .u64 => |node| try w.print("{}", .{node}), + inline .di_flags, .sp_flags => |node| try w.print("{f}", .{node}), + .raw => |node| try w.writeAll(node), } } inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype) switch (@TypeOf(node)) { Metadata => Allocator.Error, else => error{}, - }!std.fmt.Formatter(format) { + }!std.fmt.Formatter(FormatData, format) { const Node = @TypeOf(node); const MaybeNode = switch (@typeInfo(Node)) { .optional => Node, @@ -8442,7 +8334,7 @@ pub const Metadata = enum(u32) { prefix: []const u8, value: Value, function: Function.Index, - ) Allocator.Error!std.fmt.Formatter(format) { + ) Allocator.Error!std.fmt.Formatter(FormatData, format) { return .{ .data = .{ .formatter = formatter, .prefix = prefix, @@ -8506,7 +8398,7 @@ pub const Metadata = enum(u32) { DIGlobalVariableExpression, }, nodes: anytype, - writer: anytype, + w: *Writer, ) !void { comptime var fmt_str: []const u8 = ""; const names = comptime std.meta.fieldNames(@TypeOf(nodes)); @@ -8523,10 +8415,10 @@ pub const Metadata = enum(u32) { } fmt_str = fmt_str ++ "("; inline for (fields[2..], names) |*field, name| { - fmt_str = fmt_str ++ "{[" ++ name ++ "]S}"; + fmt_str = fmt_str ++ "{[" ++ name ++ "]fS}"; field.* = .{ .name = name, - .type = std.fmt.Formatter(format), + .type = std.fmt.Formatter(FormatData, format), .default_value_ptr = null, .is_comptime = false, .alignment = 0, @@ -8546,7 +8438,7 @@ pub const Metadata = enum(u32) { name ++ ": ", @field(nodes, name), ); - try writer.print(fmt_str, fmt_args); + try w.print(fmt_str, fmt_args); } }; }; @@ -8636,7 +8528,7 @@ pub fn init(options: Options) Allocator.Error!Builder { inline for (.{ 0, 4 }) |addr_space_index| { const addr_space: AddrSpace = @enumFromInt(addr_space_index); assert(self.ptrTypeAssumeCapacity(addr_space) == - @field(Type, std.fmt.comptimePrint("ptr{ }", .{addr_space}))); + @field(Type, std.fmt.comptimePrint("ptr{f }", .{addr_space}))); } } @@ -8759,16 +8651,8 @@ pub fn deinit(self: *Builder) void { self.* = undefined; } -pub fn setModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { - self.module_asm.clearRetainingCapacity(); - return self.appendModuleAsm(); -} - -pub fn appendModuleAsm(self: *Builder) std.ArrayListUnmanaged(u8).Writer { - return self.module_asm.writer(self.gpa); -} - -pub fn finishModuleAsm(self: *Builder) Allocator.Error!void { +pub fn finishModuleAsm(self: *Builder, aw: *Writer.Allocating) Allocator.Error!void { + self.module_asm = aw.toArrayList(); if (self.module_asm.getLastOrNull()) |last| if (last != '\n') try self.module_asm.append(self.gpa, '\n'); } @@ -8804,7 +8688,7 @@ pub fn fmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) Allo } pub fn fmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) String { - self.string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable; + self.string_bytes.printAssumeCapacity(fmt_str, fmt_args); return self.trailingStringAssumeCapacity(); } @@ -9076,9 +8960,13 @@ pub fn getIntrinsic( const allocator = stack.get(); const name = name: { - const writer = self.strtab_string_bytes.writer(self.gpa); - try writer.print("llvm.{s}", .{@tagName(id)}); - for (overload) |ty| try writer.print(".{m}", .{ty.fmt(self)}); + { + var aw: Writer.Allocating = .fromArrayList(self.gpa, &self.strtab_string_bytes); + const w = &aw.interface; + defer self.strtab_string_bytes = aw.toArrayList(); + w.print("llvm.{s}", .{@tagName(id)}) catch return error.OutOfMemory; + for (overload) |ty| w.print(".{fm}", .{ty.fmt(self)}) catch return error.OutOfMemory; + } break :name try self.trailingStrtabString(); }; if (self.getGlobal(name)) |global| return global.ptrConst(self).kind.function; @@ -9492,110 +9380,74 @@ pub fn asmValue( return (try self.asmConst(ty, info, assembly, constraints)).toValue(); } -pub fn dump(self: *Builder) void { +pub fn dump(b: *Builder) void { + var buffer: [4000]u8 = undefined; const stderr: std.fs.File = .stderr(); - self.print(stderr.writer()) catch {}; + b.printToFile(stderr, &buffer) catch {}; } -pub fn printToFile(self: *Builder, path: []const u8) Allocator.Error!bool { - var file = std.fs.cwd().createFile(path, .{}) catch |err| { - log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) }); - return false; - }; +pub fn printToFilePath(b: *Builder, dir: std.fs.Dir, path: []const u8) !void { + var buffer: [4000]u8 = undefined; + const file = try dir.createFile(path, .{}); defer file.close(); - self.print(file.writer()) catch |err| { - log.err("failed printing LLVM module to \"{s}\": {s}", .{ path, @errorName(err) }); - return false; - }; - return true; + try b.printToFile(file, &buffer); } -pub fn print(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void { - var bw = std.io.bufferedWriter(writer); - try self.printUnbuffered(bw.writer()); - try bw.flush(); +pub fn printToFile(b: *Builder, file: std.fs.File, buffer: []u8) !void { + var fw = file.writer(buffer); + try print(b, &fw.interface); + try fw.interface.flush(); } -fn WriterWithErrors(comptime BackingWriter: type, comptime ExtraErrors: type) type { - return struct { - backing_writer: BackingWriter, - - pub const Error = BackingWriter.Error || ExtraErrors; - pub const Writer = std.io.GenericWriter(*const Self, Error, write); - - const Self = @This(); - - pub fn writer(self: *const Self) Writer { - return .{ .context = self }; - } - - pub fn write(self: *const Self, bytes: []const u8) Error!usize { - return self.backing_writer.write(bytes); - } - }; -} -fn writerWithErrors( - backing_writer: anytype, - comptime ExtraErrors: type, -) WriterWithErrors(@TypeOf(backing_writer), ExtraErrors) { - return .{ .backing_writer = backing_writer }; -} - -pub fn printUnbuffered( - self: *Builder, - backing_writer: anytype, -) (@TypeOf(backing_writer).Error || Allocator.Error)!void { - const writer_with_errors = writerWithErrors(backing_writer, Allocator.Error); - const writer = writer_with_errors.writer(); - +pub fn print(self: *Builder, w: *Writer) Writer.Error!void { var need_newline = false; var metadata_formatter: Metadata.Formatter = .{ .builder = self, .need_comma = undefined }; defer metadata_formatter.map.deinit(self.gpa); if (self.source_filename != .none or self.data_layout != .none or self.target_triple != .none) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; - if (self.source_filename != .none) try writer.print( + if (need_newline) try w.writeByte('\n') else need_newline = true; + if (self.source_filename != .none) try w.print( \\; ModuleID = '{s}' - \\source_filename = {"} + \\source_filename = {f"} \\ , .{ self.source_filename.slice(self).?, self.source_filename.fmt(self) }); - if (self.data_layout != .none) try writer.print( - \\target datalayout = {"} + if (self.data_layout != .none) try w.print( + \\target datalayout = {f"} \\ , .{self.data_layout.fmt(self)}); - if (self.target_triple != .none) try writer.print( - \\target triple = {"} + if (self.target_triple != .none) try w.print( + \\target triple = {f"} \\ , .{self.target_triple.fmt(self)}); } if (self.module_asm.items.len > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try w.writeByte('\n') else need_newline = true; var line_it = std.mem.tokenizeScalar(u8, self.module_asm.items, '\n'); while (line_it.next()) |line| { - try writer.writeAll("module asm "); - try printEscapedString(line, .always_quote, writer); - try writer.writeByte('\n'); + try w.writeAll("module asm "); + try printEscapedString(line, .always_quote, w); + try w.writeByte('\n'); } } if (self.types.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; - for (self.types.keys(), self.types.values()) |id, ty| try writer.print( - \\%{} = type {} + if (need_newline) try w.writeByte('\n') else need_newline = true; + for (self.types.keys(), self.types.values()) |id, ty| try w.print( + \\%{f} = type {f} \\ , .{ id.fmt(self), ty.fmt(self) }); } if (self.variables.items.len > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try w.writeByte('\n') else need_newline = true; for (self.variables.items) |variable| { if (variable.global.getReplacement(self) != .none) continue; const global = variable.global.ptrConst(self); metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; - try writer.print( - \\{} ={}{}{}{}{ }{}{ }{} {s} {%}{ }{, }{} + try w.print( + \\{f} ={f}{f}{f}{f}{f }{f}{f }{f} {s} {f%}{f }{f, }{f} \\ , .{ variable.global.fmt(self), @@ -9618,14 +9470,14 @@ pub fn printUnbuffered( } if (self.aliases.items.len > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try w.writeByte('\n') else need_newline = true; for (self.aliases.items) |alias| { if (alias.global.getReplacement(self) != .none) continue; const global = alias.global.ptrConst(self); metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; - try writer.print( - \\{} ={}{}{}{}{ }{} alias {%}, {%}{} + try w.print( + \\{f} ={f}{f}{f}{f}{f }{f} alias {f%}, {f%}{f} \\ , .{ alias.global.fmt(self), @@ -9647,17 +9499,17 @@ pub fn printUnbuffered( for (0.., self.functions.items) |function_i, function| { if (function.global.getReplacement(self) != .none) continue; - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try w.writeByte('\n') else need_newline = true; const function_index: Function.Index = @enumFromInt(function_i); const global = function.global.ptrConst(self); const params_len = global.type.functionParameters(self).len; const function_attributes = function.attributes.func(self); - if (function_attributes != .none) try writer.print( - \\; Function Attrs:{} + if (function_attributes != .none) try w.print( + \\; Function Attrs:{f} \\ , .{function_attributes.fmt(self)}); - try writer.print( - \\{s}{}{}{}{}{}{"} {%} {}( + try w.print( + \\{s}{f}{f}{f}{f}{f}{f"} {f%} {f}( , .{ if (function.instructions.len > 0) "define" else "declare", global.linkage, @@ -9670,40 +9522,40 @@ pub fn printUnbuffered( function.global.fmt(self), }); for (0..params_len) |arg| { - if (arg > 0) try writer.writeAll(", "); - try writer.print( - \\{%}{"} + if (arg > 0) try w.writeAll(", "); + try w.print( + \\{f%}{f"} , .{ global.type.functionParameters(self)[arg].fmt(self), function.attributes.param(arg, self).fmt(self), }); if (function.instructions.len > 0) - try writer.print(" {}", .{function.arg(@intCast(arg)).fmt(function_index, self)}) + try w.print(" {f}", .{function.arg(@intCast(arg)).fmt(function_index, self)}) else - try writer.print(" %{d}", .{arg}); + try w.print(" %{d}", .{arg}); } switch (global.type.functionKind(self)) { .normal => {}, .vararg => { - if (params_len > 0) try writer.writeAll(", "); - try writer.writeAll("..."); + if (params_len > 0) try w.writeAll(", "); + try w.writeAll("..."); }, } - try writer.print("){}{ }", .{ global.unnamed_addr, global.addr_space }); - if (function_attributes != .none) try writer.print(" #{d}", .{ + try w.print("){f}{f }", .{ global.unnamed_addr, global.addr_space }); + if (function_attributes != .none) try w.print(" #{d}", .{ (try attribute_groups.getOrPutValue(self.gpa, function_attributes, {})).index, }); { metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; - try writer.print("{ }{}", .{ + try w.print("{f }{f}", .{ function.alignment, try metadata_formatter.fmt(" !dbg ", global.dbg), }); } if (function.instructions.len > 0) { var block_incoming_len: u32 = undefined; - try writer.writeAll(" {\n"); + try w.writeAll(" {\n"); var maybe_dbg_index: ?u32 = null; for (params_len..function.instructions.len) |instruction_i| { const instruction_index: Function.Instruction.Index = @enumFromInt(instruction_i); @@ -9801,7 +9653,7 @@ pub fn printUnbuffered( .xor, => |tag| { const extra = function.extraData(Function.Instruction.Binary, instruction.data); - try writer.print(" %{} = {s} {%}, {}", .{ + try w.print(" %{f} = {s} {f%}, {f}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.lhs.fmt(function_index, self), @@ -9823,7 +9675,7 @@ pub fn printUnbuffered( .zext, => |tag| { const extra = function.extraData(Function.Instruction.Cast, instruction.data); - try writer.print(" %{} = {s} {%} to {%}", .{ + try w.print(" %{f} = {s} {f%} to {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.val.fmt(function_index, self), @@ -9834,7 +9686,7 @@ pub fn printUnbuffered( .@"alloca inalloca", => |tag| { const extra = function.extraData(Function.Instruction.Alloca, instruction.data); - try writer.print(" %{} = {s} {%}{,%}{, }{, }", .{ + try w.print(" %{f} = {s} {f%}{f,%}{f, }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.type.fmt(self), @@ -9850,7 +9702,7 @@ pub fn printUnbuffered( .atomicrmw => |tag| { const extra = function.extraData(Function.Instruction.AtomicRmw, instruction.data); - try writer.print(" %{} = {s}{ } {s} {%}, {%}{ }{ }{, }", .{ + try w.print(" %{f} = {s}{f } {s} {f%}, {f%}{f }{f }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.info.access_kind, @@ -9866,19 +9718,19 @@ pub fn printUnbuffered( block_incoming_len = instruction.data; const name = instruction_index.name(&function); if (@intFromEnum(instruction_index) > params_len) - try writer.writeByte('\n'); - try writer.print("{}:\n", .{name.fmt(self)}); + try w.writeByte('\n'); + try w.print("{f}:\n", .{name.fmt(self)}); continue; }, .br => |tag| { const target: Function.Block.Index = @enumFromInt(instruction.data); - try writer.print(" {s} {%}", .{ + try w.print(" {s} {f%}", .{ @tagName(tag), target.toInst(&function).fmt(function_index, self), }); }, .br_cond => { const extra = function.extraData(Function.Instruction.BrCond, instruction.data); - try writer.print(" br {%}, {%}, {%}", .{ + try w.print(" br {f%}, {f%}, {f%}", .{ extra.cond.fmt(function_index, self), extra.then.toInst(&function).fmt(function_index, self), extra.@"else".toInst(&function).fmt(function_index, self), @@ -9887,8 +9739,8 @@ pub fn printUnbuffered( defer metadata_formatter.need_comma = undefined; switch (extra.weights) { .none => {}, - .unpredictable => try writer.writeAll("!unpredictable !{}"), - _ => try writer.print("{}", .{ + .unpredictable => try w.writeAll("!unpredictable !{}"), + _ => try w.print("{f}", .{ try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.weights)))), }), } @@ -9905,16 +9757,16 @@ pub fn printUnbuffered( var extra = function.extraDataTrail(Function.Instruction.Call, instruction.data); const args = extra.trail.next(extra.data.args_len, Value, &function); - try writer.writeAll(" "); + try w.writeAll(" "); const ret_ty = extra.data.ty.functionReturn(self); switch (ret_ty) { .void => {}, - else => try writer.print("%{} = ", .{ + else => try w.print("%{f} = ", .{ instruction_index.name(&function).fmt(self), }), .none => unreachable, } - try writer.print("{s}{}{}{} {%} {}(", .{ + try w.print("{s}{f}{f}{f} {f%} {f}(", .{ @tagName(tag), extra.data.info.call_conv, extra.data.attributes.ret(self).fmt(self), @@ -9926,21 +9778,21 @@ pub fn printUnbuffered( extra.data.callee.fmt(function_index, self), }); for (0.., args) |arg_index, arg| { - if (arg_index > 0) try writer.writeAll(", "); + if (arg_index > 0) try w.writeAll(", "); metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; - try writer.print("{%}{}{}", .{ + try w.print("{f%}{f}{f}", .{ arg.typeOf(function_index, self).fmt(self), extra.data.attributes.param(arg_index, self).fmt(self), try metadata_formatter.fmtLocal(" ", arg, function_index), }); } - try writer.writeByte(')'); + try w.writeByte(')'); if (extra.data.info.has_op_bundle_cold) { - try writer.writeAll(" [ \"cold\"() ]"); + try w.writeAll(" [ \"cold\"() ]"); } const call_function_attributes = extra.data.attributes.func(self); - if (call_function_attributes != .none) try writer.print(" #{d}", .{ + if (call_function_attributes != .none) try w.print(" #{d}", .{ (try attribute_groups.getOrPutValue( self.gpa, call_function_attributes, @@ -9953,7 +9805,7 @@ pub fn printUnbuffered( => |tag| { const extra = function.extraData(Function.Instruction.CmpXchg, instruction.data); - try writer.print(" %{} = {s}{ } {%}, {%}, {%}{ }{ }{ }{, }", .{ + try w.print(" %{f} = {s}{f } {f%}, {f%}, {f%}{f }{f }{f }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.info.access_kind, @@ -9969,7 +9821,7 @@ pub fn printUnbuffered( .extractelement => |tag| { const extra = function.extraData(Function.Instruction.ExtractElement, instruction.data); - try writer.print(" %{} = {s} {%}, {%}", .{ + try w.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.val.fmt(function_index, self), @@ -9982,16 +9834,16 @@ pub fn printUnbuffered( instruction.data, ); const indices = extra.trail.next(extra.data.indices_len, u32, &function); - try writer.print(" %{} = {s} {%}", .{ + try w.print(" %{f} = {s} {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.data.val.fmt(function_index, self), }); - for (indices) |index| try writer.print(", {d}", .{index}); + for (indices) |index| try w.print(", {d}", .{index}); }, .fence => |tag| { const info: MemoryAccessInfo = @bitCast(instruction.data); - try writer.print(" {s}{ }{ }", .{ + try w.print(" {s}{f }{f }", .{ @tagName(tag), info.sync_scope, info.success_ordering, @@ -10001,7 +9853,7 @@ pub fn printUnbuffered( .@"fneg fast", => |tag| { const val: Value = @enumFromInt(instruction.data); - try writer.print(" %{} = {s} {%}", .{ + try w.print(" %{f} = {s} {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), val.fmt(function_index, self), @@ -10015,13 +9867,13 @@ pub fn printUnbuffered( instruction.data, ); const indices = extra.trail.next(extra.data.indices_len, Value, &function); - try writer.print(" %{} = {s} {%}, {%}", .{ + try w.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.data.type.fmt(self), extra.data.base.fmt(function_index, self), }); - for (indices) |index| try writer.print(", {%}", .{ + for (indices) |index| try w.print(", {f%}", .{ index.fmt(function_index, self), }); }, @@ -10030,22 +9882,22 @@ pub fn printUnbuffered( function.extraDataTrail(Function.Instruction.IndirectBr, instruction.data); const targets = extra.trail.next(extra.data.targets_len, Function.Block.Index, &function); - try writer.print(" {s} {%}, [", .{ + try w.print(" {s} {f%}, [", .{ @tagName(tag), extra.data.addr.fmt(function_index, self), }); for (0.., targets) |target_index, target| { - if (target_index > 0) try writer.writeAll(", "); - try writer.print("{%}", .{ + if (target_index > 0) try w.writeAll(", "); + try w.print("{f%}", .{ target.toInst(&function).fmt(function_index, self), }); } - try writer.writeByte(']'); + try w.writeByte(']'); }, .insertelement => |tag| { const extra = function.extraData(Function.Instruction.InsertElement, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}", .{ + try w.print(" %{f} = {s} {f%}, {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.val.fmt(function_index, self), @@ -10057,19 +9909,19 @@ pub fn printUnbuffered( var extra = function.extraDataTrail(Function.Instruction.InsertValue, instruction.data); const indices = extra.trail.next(extra.data.indices_len, u32, &function); - try writer.print(" %{} = {s} {%}, {%}", .{ + try w.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.data.val.fmt(function_index, self), extra.data.elem.fmt(function_index, self), }); - for (indices) |index| try writer.print(", {d}", .{index}); + for (indices) |index| try w.print(", {d}", .{index}); }, .load, .@"load atomic", => |tag| { const extra = function.extraData(Function.Instruction.Load, instruction.data); - try writer.print(" %{} = {s}{ } {%}, {%}{ }{ }{, }", .{ + try w.print(" %{f} = {s}{f } {f%}, {f%}{f }{f }{f, }", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.info.access_kind, @@ -10087,14 +9939,14 @@ pub fn printUnbuffered( const vals = extra.trail.next(block_incoming_len, Value, &function); const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &function); - try writer.print(" %{} = {s} {%} ", .{ + try w.print(" %{f} = {s} {f%} ", .{ instruction_index.name(&function).fmt(self), @tagName(tag), vals[0].typeOf(function_index, self).fmt(self), }); for (0.., vals, blocks) |incoming_index, incoming_val, incoming_block| { - if (incoming_index > 0) try writer.writeAll(", "); - try writer.print("[ {}, {} ]", .{ + if (incoming_index > 0) try w.writeAll(", "); + try w.print("[ {f}, {f} ]", .{ incoming_val.fmt(function_index, self), incoming_block.toInst(&function).fmt(function_index, self), }); @@ -10102,19 +9954,19 @@ pub fn printUnbuffered( }, .ret => |tag| { const val: Value = @enumFromInt(instruction.data); - try writer.print(" {s} {%}", .{ + try w.print(" {s} {f%}", .{ @tagName(tag), val.fmt(function_index, self), }); }, .@"ret void", .@"unreachable", - => |tag| try writer.print(" {s}", .{@tagName(tag)}), + => |tag| try w.print(" {s}", .{@tagName(tag)}), .select, .@"select fast", => |tag| { const extra = function.extraData(Function.Instruction.Select, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}", .{ + try w.print(" %{f} = {s} {f%}, {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.cond.fmt(function_index, self), @@ -10125,7 +9977,7 @@ pub fn printUnbuffered( .shufflevector => |tag| { const extra = function.extraData(Function.Instruction.ShuffleVector, instruction.data); - try writer.print(" %{} = {s} {%}, {%}, {%}", .{ + try w.print(" %{f} = {s} {f%}, {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.lhs.fmt(function_index, self), @@ -10137,7 +9989,7 @@ pub fn printUnbuffered( .@"store atomic", => |tag| { const extra = function.extraData(Function.Instruction.Store, instruction.data); - try writer.print(" {s}{ } {%}, {%}{ }{ }{, }", .{ + try w.print(" {s}{f } {f%}, {f%}{f }{f }{f, }", .{ @tagName(tag), extra.info.access_kind, extra.val.fmt(function_index, self), @@ -10153,32 +10005,32 @@ pub fn printUnbuffered( const vals = extra.trail.next(extra.data.cases_len, Constant, &function); const blocks = extra.trail.next(extra.data.cases_len, Function.Block.Index, &function); - try writer.print(" {s} {%}, {%} [\n", .{ + try w.print(" {s} {f%}, {f%} [\n", .{ @tagName(tag), extra.data.val.fmt(function_index, self), extra.data.default.toInst(&function).fmt(function_index, self), }); - for (vals, blocks) |case_val, case_block| try writer.print( - " {%}, {%}\n", + for (vals, blocks) |case_val, case_block| try w.print( + " {f%}, {f%}\n", .{ case_val.fmt(self), case_block.toInst(&function).fmt(function_index, self), }, ); - try writer.writeAll(" ]"); + try w.writeAll(" ]"); metadata_formatter.need_comma = true; defer metadata_formatter.need_comma = undefined; switch (extra.data.weights) { .none => {}, - .unpredictable => try writer.writeAll("!unpredictable !{}"), - _ => try writer.print("{}", .{ + .unpredictable => try w.writeAll("!unpredictable !{}"), + _ => try w.print("{f}", .{ try metadata_formatter.fmt("!prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.data.weights)))), }), } }, .va_arg => |tag| { const extra = function.extraData(Function.Instruction.VaArg, instruction.data); - try writer.print(" %{} = {s} {%}, {%}", .{ + try w.print(" %{f} = {s} {f%}, {f%}", .{ instruction_index.name(&function).fmt(self), @tagName(tag), extra.list.fmt(function_index, self), @@ -10188,45 +10040,45 @@ pub fn printUnbuffered( } if (maybe_dbg_index) |dbg_index| { - try writer.print(", !dbg !{}", .{dbg_index}); + try w.print(", !dbg !{d}", .{dbg_index}); } - try writer.writeByte('\n'); + try w.writeByte('\n'); } - try writer.writeByte('}'); + try w.writeByte('}'); } - try writer.writeByte('\n'); + try w.writeByte('\n'); } if (attribute_groups.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try w.writeByte('\n') else need_newline = true; for (0.., attribute_groups.keys()) |attribute_group_index, attribute_group| - try writer.print( - \\attributes #{d} = {{{#"} }} + try w.print( + \\attributes #{d} = {{{f#"} }} \\ , .{ attribute_group_index, attribute_group.fmt(self) }); } if (self.metadata_named.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try w.writeByte('\n') else need_newline = true; for (self.metadata_named.keys(), self.metadata_named.values()) |name, data| { const elements: []const Metadata = @ptrCast(self.metadata_extra.items[data.index..][0..data.len]); - try writer.writeByte('!'); - try printEscapedString(name.slice(self), .quote_unless_valid_identifier, writer); - try writer.writeAll(" = !{"); + try w.writeByte('!'); + try printEscapedString(name.slice(self), .quote_unless_valid_identifier, w); + try w.writeAll(" = !{"); metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; - for (elements) |element| try writer.print("{}", .{try metadata_formatter.fmt("", element)}); - try writer.writeAll("}\n"); + for (elements) |element| try w.print("{f}", .{try metadata_formatter.fmt("", element)}); + try w.writeAll("}\n"); } } if (metadata_formatter.map.count() > 0) { - if (need_newline) try writer.writeByte('\n') else need_newline = true; + if (need_newline) try w.writeByte('\n') else need_newline = true; var metadata_index: usize = 0; while (metadata_index < metadata_formatter.map.count()) : (metadata_index += 1) { @setEvalBranchQuota(10_000); - try writer.print("!{} = ", .{metadata_index}); + try w.print("!{d} = ", .{metadata_index}); metadata_formatter.need_comma = false; defer metadata_formatter.need_comma = undefined; @@ -10239,7 +10091,7 @@ pub fn printUnbuffered( .scope = location.scope, .inlinedAt = location.inlined_at, .isImplicitCode = false, - }, writer); + }, w); continue; }, .metadata => |metadata| self.metadata_items.get(@intFromEnum(metadata)), @@ -10255,7 +10107,7 @@ pub fn printUnbuffered( .checksumkind = null, .checksum = null, .source = null, - }, writer); + }, w); }, .compile_unit, .@"compile_unit optimized", @@ -10286,7 +10138,7 @@ pub fn printUnbuffered( .rangesBaseAddress = null, .sysroot = null, .sdk = null, - }, writer); + }, w); }, .subprogram, .@"subprogram local", @@ -10320,7 +10172,7 @@ pub fn printUnbuffered( .thrownTypes = null, .annotations = null, .targetFuncName = null, - }, writer); + }, w); }, .lexical_block => { const extra = self.metadataExtraData(Metadata.LexicalBlock, metadata_item.data); @@ -10329,7 +10181,7 @@ pub fn printUnbuffered( .file = extra.file, .line = extra.line, .column = extra.column, - }, writer); + }, w); }, .location => { const extra = self.metadataExtraData(Metadata.Location, metadata_item.data); @@ -10339,7 +10191,7 @@ pub fn printUnbuffered( .scope = extra.scope, .inlinedAt = extra.inlined_at, .isImplicitCode = false, - }, writer); + }, w); }, .basic_bool_type, .basic_unsigned_type, @@ -10368,7 +10220,7 @@ pub fn printUnbuffered( else => unreachable, }), .flags = null, - }, writer); + }, w); }, .composite_struct_type, .composite_union_type, @@ -10413,7 +10265,7 @@ pub fn printUnbuffered( .allocated = null, .rank = null, .annotations = null, - }, writer); + }, w); }, .derived_pointer_type, .derived_member_type, @@ -10446,7 +10298,7 @@ pub fn printUnbuffered( .extraData = null, .dwarfAddressSpace = null, .annotations = null, - }, writer); + }, w); }, .subroutine_type => { const extra = self.metadataExtraData(Metadata.SubroutineType, metadata_item.data); @@ -10454,7 +10306,7 @@ pub fn printUnbuffered( .flags = null, .cc = null, .types = extra.types_tuple, - }, writer); + }, w); }, .enumerator_unsigned, .enumerator_signed_positive, @@ -10504,7 +10356,7 @@ pub fn printUnbuffered( => false, else => unreachable, }, - }, writer); + }, w); }, .subrange => { const extra = self.metadataExtraData(Metadata.Subrange, metadata_item.data); @@ -10513,31 +10365,31 @@ pub fn printUnbuffered( .lowerBound = extra.lower_bound, .upperBound = null, .stride = null, - }, writer); + }, w); }, .tuple => { var extra = self.metadataExtraDataTrail(Metadata.Tuple, metadata_item.data); const elements = extra.trail.next(extra.data.elements_len, Metadata, self); - try writer.writeAll("!{"); - for (elements) |element| try writer.print("{[element]%}", .{ + try w.writeAll("!{"); + for (elements) |element| try w.print("{[element]f%}", .{ .element = try metadata_formatter.fmt("", element), }); - try writer.writeAll("}\n"); + try w.writeAll("}\n"); }, .str_tuple => { var extra = self.metadataExtraDataTrail(Metadata.StrTuple, metadata_item.data); const elements = extra.trail.next(extra.data.elements_len, Metadata, self); - try writer.print("!{{{[str]%}", .{ + try w.print("!{{{[str]f%}", .{ .str = try metadata_formatter.fmt("", extra.data.str), }); - for (elements) |element| try writer.print("{[element]%}", .{ + for (elements) |element| try w.print("{[element]f%}", .{ .element = try metadata_formatter.fmt("", element), }); - try writer.writeAll("}\n"); + try w.writeAll("}\n"); }, .module_flag => { const extra = self.metadataExtraData(Metadata.ModuleFlag, metadata_item.data); - try writer.print("!{{{[behavior]%}{[name]%}{[constant]%}}}\n", .{ + try w.print("!{{{[behavior]f%}{[name]f%}{[constant]f%}}}\n", .{ .behavior = try metadata_formatter.fmt("", extra.behavior), .name = try metadata_formatter.fmt("", extra.name), .constant = try metadata_formatter.fmt("", extra.constant), @@ -10555,7 +10407,7 @@ pub fn printUnbuffered( .flags = null, .@"align" = null, .annotations = null, - }, writer); + }, w); }, .parameter => { const extra = self.metadataExtraData(Metadata.Parameter, metadata_item.data); @@ -10569,7 +10421,7 @@ pub fn printUnbuffered( .flags = null, .@"align" = null, .annotations = null, - }, writer); + }, w); }, .global_var, .@"global_var local", @@ -10592,7 +10444,7 @@ pub fn printUnbuffered( .templateParams = null, .@"align" = null, .annotations = null, - }, writer); + }, w); }, .global_var_expression => { const extra = @@ -10600,7 +10452,7 @@ pub fn printUnbuffered( try metadata_formatter.specialized(.@"!", .DIGlobalVariableExpression, .{ .@"var" = extra.variable, .expr = extra.expression, - }, writer); + }, w); }, } } @@ -10619,22 +10471,18 @@ fn isValidIdentifier(id: []const u8) bool { } const QuoteBehavior = enum { always_quote, quote_unless_valid_identifier }; -fn printEscapedString( - slice: []const u8, - quotes: QuoteBehavior, - writer: anytype, -) @TypeOf(writer).Error!void { +fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, w: *Writer) Writer.Error!void { const need_quotes = switch (quotes) { .always_quote => true, .quote_unless_valid_identifier => !isValidIdentifier(slice), }; - if (need_quotes) try writer.writeByte('"'); + if (need_quotes) try w.writeByte('"'); for (slice) |byte| switch (byte) { - '\\' => try writer.writeAll("\\\\"), - ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(byte), - else => try writer.print("\\{X:0>2}", .{byte}), + '\\' => try w.writeAll("\\\\"), + ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try w.writeByte(byte), + else => try w.print("\\{X:0>2}", .{byte}), }; - if (need_quotes) try writer.writeByte('"'); + if (need_quotes) try w.writeByte('"'); } fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void { @@ -12019,7 +11867,7 @@ pub fn metadataStringFmt(self: *Builder, comptime fmt_str: []const u8, fmt_args: } pub fn metadataStringFmtAssumeCapacity(self: *Builder, comptime fmt_str: []const u8, fmt_args: anytype) MetadataString { - self.metadata_string_bytes.writer(undefined).print(fmt_str, fmt_args) catch unreachable; + self.metadata_string_bytes.printAssumeCapacity(fmt_str, fmt_args); return self.trailingMetadataStringAssumeCapacity(); } @@ -15261,13 +15109,3 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco return bitcode.toOwnedSlice(); } - -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; -const bitcode_writer = @import("bitcode_writer.zig"); -const Builder = @This(); -const builtin = @import("builtin"); -const DW = std.dwarf; -const ir = @import("ir.zig"); -const log = std.log.scoped(.llvm); -const std = @import("../../std.zig"); diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 0a3aba275d..596befcb3e 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -6324,7 +6324,7 @@ test "ampersand" { var fixed_buffer_mem: [100 * 1024]u8 = undefined; fn testParse(source: [:0]const u8, allocator: mem.Allocator, anything_changed: *bool) ![]u8 { - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); var tree = try std.zig.Ast.parse(allocator, source, .zig); defer tree.deinit(allocator); diff --git a/lib/std/zig/perf_test.zig b/lib/std/zig/perf_test.zig index d0a6c41a74..087b081475 100644 --- a/lib/std/zig/perf_test.zig +++ b/lib/std/zig/perf_test.zig @@ -23,7 +23,7 @@ pub fn main() !void { const bytes_per_sec = @as(u64, @intFromFloat(@floor(bytes_per_sec_float))); var stdout_file: std.fs.File = .stdout(); - const stdout = stdout_file.writer(); + const stdout = stdout_file.deprecatedWriter(); try stdout.print("parsing speed: {:.2}/s, {:.2} used \n", .{ fmtIntSizeBin(bytes_per_sec), fmtIntSizeBin(memory_used), diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 6ec8cde18d..597820df25 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1564,7 +1564,7 @@ fn renderBuiltinCall( defer r.gpa.free(new_string); try renderToken(r, builtin_token + 1, .none); // ( - try ais.writer().print("\"{}\"", .{std.zig.fmtEscapes(new_string)}); + try ais.writer().print("\"{f}\"", .{std.zig.fmtString(new_string)}); return renderToken(r, str_lit_token + 1, space); // ) } } @@ -2872,7 +2872,7 @@ fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void { .success => |codepoint| { if (codepoint <= 0x7f) { const buf = [1]u8{@as(u8, @intCast(codepoint))}; - try std.fmt.format(writer, "{}", .{std.zig.fmtEscapes(&buf)}); + try std.fmt.deprecatedFormat(writer, "{f}", .{std.zig.fmtString(&buf)}); } else { try writer.writeAll(escape_sequence); } @@ -2884,7 +2884,7 @@ fn renderIdentifierContents(writer: anytype, bytes: []const u8) !void { }, 0x00...('\\' - 1), ('\\' + 1)...0x7f => { const buf = [1]u8{byte}; - try std.fmt.format(writer, "{}", .{std.zig.fmtEscapes(&buf)}); + try std.fmt.deprecatedFormat(writer, "{f}", .{std.zig.fmtString(&buf)}); pos += 1; }, 0x80...0xff => { diff --git a/lib/std/zig/string_literal.zig b/lib/std/zig/string_literal.zig index 58187d0f26..99b060eceb 100644 --- a/lib/std/zig/string_literal.zig +++ b/lib/std/zig/string_literal.zig @@ -44,14 +44,7 @@ pub const Error = union(enum) { raw_string: []const u8, }; - fn formatMessage( - self: FormatMessage, - comptime f: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = f; - _ = options; + fn formatMessage(self: FormatMessage, writer: *std.io.Writer) std.io.Writer.Error!void { switch (self.err) { .invalid_escape_character => |bad_index| try writer.print( "invalid escape character: '{c}'", @@ -93,7 +86,7 @@ pub const Error = union(enum) { } } - pub fn fmt(self: @This(), raw_string: []const u8) std.fmt.Formatter(formatMessage) { + pub fn fmt(self: @This(), raw_string: []const u8) std.fmt.Formatter(FormatMessage, formatMessage) { return .{ .data = .{ .err = self, .raw_string = raw_string, diff --git a/lib/std/zip.zig b/lib/std/zip.zig index 3a1ce9bb95..706a737ab0 100644 --- a/lib/std/zip.zig +++ b/lib/std/zip.zig @@ -557,7 +557,7 @@ pub fn Iterator(comptime SeekableStream: type) type { self.compression_method, self.uncompressed_size, limited_reader.reader(), - out_file.writer(), + out_file.deprecatedWriter(), ); if (limited_reader.bytes_left != 0) return error.ZipDecompressTruncated; diff --git a/lib/std/zip/test.zig b/lib/std/zip/test.zig index aba49e7af2..27f12cf2a6 100644 --- a/lib/std/zip/test.zig +++ b/lib/std/zip/test.zig @@ -33,7 +33,7 @@ pub fn expectFiles( var file = try dir.openFile(normalized_sub_path, .{}); defer file.close(); var content_buf: [4096]u8 = undefined; - const n = try file.reader().readAll(&content_buf); + const n = try file.deprecatedReader().readAll(&content_buf); try testing.expectEqualStrings(test_file.content, content_buf[0..n]); } } diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index 8340048805..cc54f682de 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -64,22 +64,14 @@ pub const Error = union(enum) { } }; - fn formatMessage( - self: []const u8, - comptime f: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = f; - _ = options; - + fn formatMessage(self: []const u8, w: *std.io.Writer) std.io.Writer.Error!void { // Just writes the string for now, but we're keeping this behind a formatter so we have // the option to extend it in the future to print more advanced messages (like `Error` // does) without breaking the API. - try writer.writeAll(self); + try w.writeAll(self); } - pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Formatter(Note.formatMessage) { + pub fn fmtMessage(self: Note, diag: *const Diagnostics) std.fmt.Formatter([]const u8, Note.formatMessage) { return .{ .data = switch (self) { .zoir => |note| note.msg.get(diag.zoir), .type_check => |note| note.msg, @@ -155,21 +147,14 @@ pub const Error = union(enum) { diag: *const Diagnostics, }; - fn formatMessage( - self: FormatMessage, - comptime f: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = f; - _ = options; + fn formatMessage(self: FormatMessage, w: *std.io.Writer) std.io.Writer.Error!void { switch (self.err) { - .zoir => |err| try writer.writeAll(err.msg.get(self.diag.zoir)), - .type_check => |tc| try writer.writeAll(tc.message), + .zoir => |err| try w.writeAll(err.msg.get(self.diag.zoir)), + .type_check => |tc| try w.writeAll(tc.message), } } - pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Formatter(formatMessage) { + pub fn fmtMessage(self: @This(), diag: *const Diagnostics) std.fmt.Formatter(FormatMessage, formatMessage) { return .{ .data = .{ .err = self, .diag = diag, @@ -241,25 +226,19 @@ pub const Diagnostics = struct { return .{ .diag = self }; } - pub fn format( - self: *const @This(), - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = fmt; - _ = options; + pub fn format(self: *const @This(), w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); var errors = self.iterateErrors(); while (errors.next()) |err| { const loc = err.getLocation(self); const msg = err.fmtMessage(self); - try writer.print("{}:{}: error: {}\n", .{ loc.line + 1, loc.column + 1, msg }); + try w.print("{d}:{d}: error: {f}\n", .{ loc.line + 1, loc.column + 1, msg }); var notes = err.iterateNotes(self); while (notes.next()) |note| { const note_loc = note.getLocation(self); const note_msg = note.fmtMessage(self); - try writer.print("{}:{}: note: {s}\n", .{ + try w.print("{d}:{d}: note: {f}\n", .{ note_loc.line + 1, note_loc.column + 1, note_msg, @@ -646,7 +625,7 @@ const Parser = struct { .failure => |err| { const token = self.ast.nodeMainToken(ast_node); const raw_string = self.ast.tokenSlice(token); - return self.failTokenFmt(token, @intCast(err.offset()), "{s}", .{err.fmt(raw_string)}); + return self.failTokenFmt(token, @intCast(err.offset()), "{f}", .{err.fmt(raw_string)}); }, } @@ -1087,7 +1066,10 @@ const Parser = struct { try writer.writeAll(msg); inline for (info.fields, 0..) |field_info, i| { if (i != 0) try writer.writeAll(", "); - try writer.print("'{p_}'", .{std.zig.fmtId(field_info.name)}); + try writer.print("'{f}'", .{std.zig.fmtIdFlags(field_info.name, .{ + .allow_primitive = true, + .allow_underscore = true, + })}); } break :b .{ .token = token, @@ -1298,7 +1280,7 @@ test "std.zon ast errors" { error.ParseZon, fromSlice(struct {}, gpa, ".{.x = 1 .y = 2}", &diag, .{}), ); - try std.testing.expectFmt("1:13: error: expected ',' after initializer\n", "{}", .{diag}); + try std.testing.expectFmt("1:13: error: expected ',' after initializer\n", "{f}", .{diag}); } test "std.zon comments" { @@ -1320,7 +1302,7 @@ test "std.zon comments" { , &diag, .{})); try std.testing.expectFmt( "1:1: error: expected expression, found 'a document comment'\n", - "{}", + "{f}", .{diag}, ); } @@ -1341,7 +1323,7 @@ test "std.zon failure/oom formatting" { &diag, .{}, )); - try std.testing.expectFmt("", "{}", .{diag}); + try std.testing.expectFmt("", "{f}", .{diag}); } test "std.zon fromSlice syntax error" { @@ -1421,7 +1403,7 @@ test "std.zon unions" { \\1:4: note: supported: 'x', 'y' \\ , - "{}", + "{f}", .{diag}, ); } @@ -1435,7 +1417,7 @@ test "std.zon unions" { error.ParseZon, fromSlice(Union, gpa, ".{.x=1}", &diag, .{}), ); - try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{}", .{diag}); + try std.testing.expectFmt("1:6: error: expected type 'void'\n", "{f}", .{diag}); } // Extra field @@ -1447,7 +1429,7 @@ test "std.zon unions" { error.ParseZon, fromSlice(Union, gpa, ".{.x = 1.5, .y = true}", &diag, .{}), ); - try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag}); + try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag}); } // No fields @@ -1459,7 +1441,7 @@ test "std.zon unions" { error.ParseZon, fromSlice(Union, gpa, ".{}", &diag, .{}), ); - try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag}); + try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag}); } // Enum literals cannot coerce into untagged unions @@ -1468,7 +1450,7 @@ test "std.zon unions" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(Union, gpa, ".x", &diag, .{})); - try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag}); + try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag}); } // Unknown field for enum literal coercion @@ -1482,7 +1464,7 @@ test "std.zon unions" { \\1:2: note: supported: 'x' \\ , - "{}", + "{f}", .{diag}, ); } @@ -1493,7 +1475,7 @@ test "std.zon unions" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(Union, gpa, ".x", &diag, .{})); - try std.testing.expectFmt("1:2: error: expected union\n", "{}", .{diag}); + try std.testing.expectFmt("1:2: error: expected union\n", "{f}", .{diag}); } } @@ -1549,7 +1531,7 @@ test "std.zon structs" { \\1:12: note: supported: 'x', 'y' \\ , - "{}", + "{f}", .{diag}, ); } @@ -1567,7 +1549,7 @@ test "std.zon structs" { \\1:4: error: duplicate struct field name \\1:12: note: duplicate name here \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Ignore unknown fields @@ -1592,7 +1574,7 @@ test "std.zon structs" { \\1:4: error: unexpected field 'x' \\1:4: note: none expected \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Missing field @@ -1604,7 +1586,7 @@ test "std.zon structs" { error.ParseZon, fromSlice(Vec2, gpa, ".{.x=1.5}", &diag, .{}), ); - try std.testing.expectFmt("1:2: error: missing required field y\n", "{}", .{diag}); + try std.testing.expectFmt("1:2: error: missing required field y\n", "{f}", .{diag}); } // Default field @@ -1631,7 +1613,7 @@ test "std.zon structs" { try std.testing.expectFmt( \\1:18: error: cannot initialize comptime field \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Enum field (regression test, we were previously getting the field name in an @@ -1661,7 +1643,7 @@ test "std.zon structs" { \\1:1: error: types are not available in ZON \\1:1: note: replace the type with '.' \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Arrays @@ -1674,7 +1656,7 @@ test "std.zon structs" { \\1:1: error: types are not available in ZON \\1:1: note: replace the type with '.' \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Slices @@ -1687,7 +1669,7 @@ test "std.zon structs" { \\1:1: error: types are not available in ZON \\1:1: note: replace the type with '.' \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Tuples @@ -1706,7 +1688,7 @@ test "std.zon structs" { \\1:1: error: types are not available in ZON \\1:1: note: replace the type with '.' \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Nested @@ -1719,7 +1701,7 @@ test "std.zon structs" { \\1:9: error: types are not available in ZON \\1:9: note: replace the type with '.' \\ - , "{}", .{diag}); + , "{f}", .{diag}); } } } @@ -1764,7 +1746,7 @@ test "std.zon tuples" { error.ParseZon, fromSlice(Tuple, gpa, ".{0.5, true, 123}", &diag, .{}), ); - try std.testing.expectFmt("1:14: error: index 2 outside of tuple length 2\n", "{}", .{diag}); + try std.testing.expectFmt("1:14: error: index 2 outside of tuple length 2\n", "{f}", .{diag}); } // Extra field @@ -1778,7 +1760,7 @@ test "std.zon tuples" { ); try std.testing.expectFmt( "1:2: error: missing tuple field with index 1\n", - "{}", + "{f}", .{diag}, ); } @@ -1792,7 +1774,7 @@ test "std.zon tuples" { error.ParseZon, fromSlice(Tuple, gpa, ".{.foo = 10.0}", &diag, .{}), ); - try std.testing.expectFmt("1:2: error: expected tuple\n", "{}", .{diag}); + try std.testing.expectFmt("1:2: error: expected tuple\n", "{f}", .{diag}); } // Struct with missing field names @@ -1804,7 +1786,7 @@ test "std.zon tuples" { error.ParseZon, fromSlice(Struct, gpa, ".{10.0}", &diag, .{}), ); - try std.testing.expectFmt("1:2: error: expected struct\n", "{}", .{diag}); + try std.testing.expectFmt("1:2: error: expected struct\n", "{f}", .{diag}); } // Comptime field @@ -1824,7 +1806,7 @@ test "std.zon tuples" { try std.testing.expectFmt( \\1:9: error: cannot initialize comptime field \\ - , "{}", .{diag}); + , "{f}", .{diag}); } } @@ -1936,7 +1918,7 @@ test "std.zon arrays and slices" { ); try std.testing.expectFmt( "1:3: error: index 0 outside of array of length 0\n", - "{}", + "{f}", .{diag}, ); } @@ -1951,7 +1933,7 @@ test "std.zon arrays and slices" { ); try std.testing.expectFmt( "1:8: error: index 1 outside of array of length 1\n", - "{}", + "{f}", .{diag}, ); } @@ -1966,7 +1948,7 @@ test "std.zon arrays and slices" { ); try std.testing.expectFmt( "1:2: error: expected 2 array elements; found 1\n", - "{}", + "{f}", .{diag}, ); } @@ -1981,7 +1963,7 @@ test "std.zon arrays and slices" { ); try std.testing.expectFmt( "1:2: error: expected 3 array elements; found 0\n", - "{}", + "{f}", .{diag}, ); } @@ -1996,7 +1978,7 @@ test "std.zon arrays and slices" { error.ParseZon, fromSlice([3]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}), ); - try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{}", .{diag}); + try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag}); } // Slice @@ -2007,7 +1989,7 @@ test "std.zon arrays and slices" { error.ParseZon, fromSlice([]bool, gpa, ".{'a', 'b', 'c'}", &diag, .{}), ); - try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{}", .{diag}); + try std.testing.expectFmt("1:3: error: expected type 'bool'\n", "{f}", .{diag}); } } @@ -2021,7 +2003,7 @@ test "std.zon arrays and slices" { error.ParseZon, fromSlice([3]u8, gpa, "'a'", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } // Slice @@ -2032,7 +2014,7 @@ test "std.zon arrays and slices" { error.ParseZon, fromSlice([]u8, gpa, "'a'", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } } @@ -2046,7 +2028,7 @@ test "std.zon arrays and slices" { ); try std.testing.expectFmt( "1:3: error: pointers are not available in ZON\n", - "{}", + "{f}", .{diag}, ); } @@ -2085,7 +2067,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]u8, gpa, "\"abcd\"", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } { @@ -2095,7 +2077,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]u8, gpa, "\\\\abcd", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } } @@ -2112,7 +2094,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([4:0]u8, gpa, "\"abcd\"", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } { @@ -2122,7 +2104,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([4:0]u8, gpa, "\\\\abcd", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } } @@ -2164,7 +2146,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([:1]const u8, gpa, "\"foo\"", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } { @@ -2174,7 +2156,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([:1]const u8, gpa, "\\\\foo", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } } @@ -2186,7 +2168,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]const u8, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected string\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected string\n", "{f}", .{diag}); } // Expecting string literal, getting an incompatible tuple @@ -2197,7 +2179,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]const u8, gpa, ".{false}", &diag, .{}), ); - try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:3: error: expected type 'u8'\n", "{f}", .{diag}); } // Invalid string literal @@ -2208,7 +2190,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]const i8, gpa, "\"\\a\"", &diag, .{}), ); - try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{}", .{diag}); + try std.testing.expectFmt("1:3: error: invalid escape character: 'a'\n", "{f}", .{diag}); } // Slice wrong child type @@ -2220,7 +2202,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]const i8, gpa, "\"a\"", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } { @@ -2230,7 +2212,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]const i8, gpa, "\\\\a", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } } @@ -2243,7 +2225,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]align(2) const u8, gpa, "\"abc\"", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } { @@ -2253,7 +2235,7 @@ test "std.zon string literal" { error.ParseZon, fromSlice([]align(2) const u8, gpa, "\\\\abc", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected array\n", "{f}", .{diag}); } } @@ -2327,7 +2309,7 @@ test "std.zon enum literals" { \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"' \\ , - "{}", + "{f}", .{diag}, ); } @@ -2345,7 +2327,7 @@ test "std.zon enum literals" { \\1:2: note: supported: 'foo', 'bar', 'baz', '@"ab\nc"' \\ , - "{}", + "{f}", .{diag}, ); } @@ -2358,7 +2340,7 @@ test "std.zon enum literals" { error.ParseZon, fromSlice(Enum, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected enum literal\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected enum literal\n", "{f}", .{diag}); } // Test embedded nulls in an identifier @@ -2371,7 +2353,7 @@ test "std.zon enum literals" { ); try std.testing.expectFmt( "1:2: error: identifier cannot contain null bytes\n", - "{}", + "{f}", .{diag}, ); } @@ -2397,13 +2379,13 @@ test "std.zon parse bool" { \\1:2: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan' \\1:2: note: precede identifier with '.' for an enum literal \\ - , "{}", .{diag}); + , "{f}", .{diag}); } { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(bool, gpa, "123", &diag, .{})); - try std.testing.expectFmt("1:1: error: expected type 'bool'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type 'bool'\n", "{f}", .{diag}); } } @@ -2476,7 +2458,7 @@ test "std.zon parse int" { )); try std.testing.expectFmt( "1:1: error: type 'i66' cannot represent value\n", - "{}", + "{f}", .{diag}, ); } @@ -2492,7 +2474,7 @@ test "std.zon parse int" { )); try std.testing.expectFmt( "1:1: error: type 'i66' cannot represent value\n", - "{}", + "{f}", .{diag}, ); } @@ -2581,7 +2563,7 @@ test "std.zon parse int" { try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "32a32", &diag, .{})); try std.testing.expectFmt( "1:3: error: invalid digit 'a' for decimal base\n", - "{}", + "{f}", .{diag}, ); } @@ -2591,7 +2573,7 @@ test "std.zon parse int" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "true", &diag, .{})); - try std.testing.expectFmt("1:1: error: expected type 'u8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type 'u8'\n", "{f}", .{diag}); } // Failing because an int is out of range @@ -2601,7 +2583,7 @@ test "std.zon parse int" { try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "256", &diag, .{})); try std.testing.expectFmt( "1:1: error: type 'u8' cannot represent value\n", - "{}", + "{f}", .{diag}, ); } @@ -2613,7 +2595,7 @@ test "std.zon parse int" { try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-129", &diag, .{})); try std.testing.expectFmt( "1:1: error: type 'i8' cannot represent value\n", - "{}", + "{f}", .{diag}, ); } @@ -2625,7 +2607,7 @@ test "std.zon parse int" { try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1", &diag, .{})); try std.testing.expectFmt( "1:1: error: type 'u8' cannot represent value\n", - "{}", + "{f}", .{diag}, ); } @@ -2637,7 +2619,7 @@ test "std.zon parse int" { try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "1.5", &diag, .{})); try std.testing.expectFmt( "1:1: error: type 'u8' cannot represent value\n", - "{}", + "{f}", .{diag}, ); } @@ -2649,7 +2631,7 @@ test "std.zon parse int" { try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "-1.0", &diag, .{})); try std.testing.expectFmt( "1:1: error: type 'u8' cannot represent value\n", - "{}", + "{f}", .{diag}, ); } @@ -2664,7 +2646,7 @@ test "std.zon parse int" { \\1:2: note: use '0' for an integer zero \\1:2: note: use '-0.0' for a floating-point signed zero \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Negative integer zero casted to float @@ -2677,7 +2659,7 @@ test "std.zon parse int" { \\1:2: note: use '0' for an integer zero \\1:2: note: use '-0.0' for a floating-point signed zero \\ - , "{}", .{diag}); + , "{f}", .{diag}); } // Negative float 0 is allowed @@ -2693,7 +2675,7 @@ test "std.zon parse int" { try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "--2", &diag, .{})); try std.testing.expectFmt( "1:1: error: expected number or 'inf' after '-'\n", - "{}", + "{f}", .{diag}, ); } @@ -2707,7 +2689,7 @@ test "std.zon parse int" { ); try std.testing.expectFmt( "1:1: error: expected number or 'inf' after '-'\n", - "{}", + "{f}", .{diag}, ); } @@ -2717,7 +2699,7 @@ test "std.zon parse int" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(u8, gpa, "0xg", &diag, .{})); - try std.testing.expectFmt("1:3: error: invalid digit 'g' for hex base\n", "{}", .{diag}); + try std.testing.expectFmt("1:3: error: invalid digit 'g' for hex base\n", "{f}", .{diag}); } // Notes on invalid int literal @@ -2729,7 +2711,7 @@ test "std.zon parse int" { \\1:1: error: number '0123' has leading zero \\1:1: note: use '0o' prefix for octal literals \\ - , "{}", .{diag}); + , "{f}", .{diag}); } } @@ -2742,7 +2724,7 @@ test "std.zon negative char" { try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-'a'", &diag, .{})); try std.testing.expectFmt( "1:1: error: expected number or 'inf' after '-'\n", - "{}", + "{f}", .{diag}, ); } @@ -2752,7 +2734,7 @@ test "std.zon negative char" { try std.testing.expectError(error.ParseZon, fromSlice(i16, gpa, "-'a'", &diag, .{})); try std.testing.expectFmt( "1:1: error: expected number or 'inf' after '-'\n", - "{}", + "{f}", .{diag}, ); } @@ -2839,7 +2821,7 @@ test "std.zon parse float" { try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-nan", &diag, .{})); try std.testing.expectFmt( "1:1: error: expected number or 'inf' after '-'\n", - "{}", + "{f}", .{diag}, ); } @@ -2849,7 +2831,7 @@ test "std.zon parse float" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{})); - try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag}); } // nan as int not allowed @@ -2857,7 +2839,7 @@ test "std.zon parse float" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "nan", &diag, .{})); - try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag}); } // inf as int not allowed @@ -2865,7 +2847,7 @@ test "std.zon parse float" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "inf", &diag, .{})); - try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag}); } // -inf as int not allowed @@ -2873,7 +2855,7 @@ test "std.zon parse float" { var diag: Diagnostics = .{}; defer diag.deinit(gpa); try std.testing.expectError(error.ParseZon, fromSlice(i8, gpa, "-inf", &diag, .{})); - try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type 'i8'\n", "{f}", .{diag}); } // Bad identifier as float @@ -2886,7 +2868,7 @@ test "std.zon parse float" { \\1:1: note: ZON allows identifiers 'true', 'false', 'null', 'inf', and 'nan' \\1:1: note: precede identifier with '.' for an enum literal \\ - , "{}", .{diag}); + , "{f}", .{diag}); } { @@ -2895,7 +2877,7 @@ test "std.zon parse float" { try std.testing.expectError(error.ParseZon, fromSlice(f32, gpa, "-foo", &diag, .{})); try std.testing.expectFmt( "1:1: error: expected number or 'inf' after '-'\n", - "{}", + "{f}", .{diag}, ); } @@ -2908,7 +2890,7 @@ test "std.zon parse float" { error.ParseZon, fromSlice(f32, gpa, "\"foo\"", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected type 'f32'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type 'f32'\n", "{f}", .{diag}); } } @@ -3152,7 +3134,7 @@ test "std.zon vector" { ); try std.testing.expectFmt( "1:2: error: expected 2 vector elements; found 1\n", - "{}", + "{f}", .{diag}, ); } @@ -3167,7 +3149,7 @@ test "std.zon vector" { ); try std.testing.expectFmt( "1:2: error: expected 2 vector elements; found 3\n", - "{}", + "{f}", .{diag}, ); } @@ -3182,7 +3164,7 @@ test "std.zon vector" { ); try std.testing.expectFmt( "1:8: error: expected type 'f32'\n", - "{}", + "{f}", .{diag}, ); } @@ -3195,7 +3177,7 @@ test "std.zon vector" { error.ParseZon, fromSlice(@Vector(3, u8), gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected type '@Vector(3, u8)'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type '@Vector(3, u8)'\n", "{f}", .{diag}); } // Elements should get freed on error @@ -3206,7 +3188,7 @@ test "std.zon vector" { error.ParseZon, fromSlice(@Vector(3, *u8), gpa, ".{1, true, 3}", &diag, .{}), ); - try std.testing.expectFmt("1:6: error: expected type 'u8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:6: error: expected type 'u8'\n", "{f}", .{diag}); } } @@ -3330,7 +3312,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const u8, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type '?u8'\n", "{f}", .{diag}); } { @@ -3340,7 +3322,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const f32, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type '?f32'\n", "{f}", .{diag}); } { @@ -3350,7 +3332,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const @Vector(3, u8), gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected type '?@Vector(3, u8)'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type '?@Vector(3, u8)'\n", "{f}", .{diag}); } { @@ -3360,7 +3342,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const bool, gpa, "10", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected type '?bool'\n", "{f}", .{diag}); } { @@ -3370,7 +3352,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const struct { a: i32 }, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional struct\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional struct\n", "{f}", .{diag}); } { @@ -3380,7 +3362,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const struct { i32 }, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional tuple\n", "{f}", .{diag}); } { @@ -3390,7 +3372,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const union { x: void }, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional union\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional union\n", "{f}", .{diag}); } { @@ -3400,7 +3382,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const [3]u8, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); } { @@ -3410,7 +3392,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(?[3]u8, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); } { @@ -3420,7 +3402,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const []u8, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); } { @@ -3430,7 +3412,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(?[]u8, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional array\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional array\n", "{f}", .{diag}); } { @@ -3440,7 +3422,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const []const u8, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional string\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional string\n", "{f}", .{diag}); } { @@ -3450,7 +3432,7 @@ test "std.zon add pointers" { error.ParseZon, fromSlice(*const ?*const enum { foo }, gpa, "true", &diag, .{}), ); - try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{}", .{diag}); + try std.testing.expectFmt("1:1: error: expected optional enum literal\n", "{f}", .{diag}); } } diff --git a/lib/std/zon/stringify.zig b/lib/std/zon/stringify.zig index 8682fdc5f4..c25bf733e3 100644 --- a/lib/std/zon/stringify.zig +++ b/lib/std/zon/stringify.zig @@ -501,7 +501,7 @@ pub fn Serializer(Writer: type) type { try self.int(val); }, .float, .comptime_float => try self.float(val), - .bool, .null => try std.fmt.format(self.writer, "{}", .{val}), + .bool, .null => try std.fmt.deprecatedFormat(self.writer, "{}", .{val}), .enum_literal => try self.ident(@tagName(val)), .@"enum" => try self.ident(@tagName(val)), .pointer => |pointer| { @@ -615,7 +615,8 @@ pub fn Serializer(Writer: type) type { /// Serialize an integer. pub fn int(self: *Self, val: anytype) Writer.Error!void { - try std.fmt.formatInt(val, 10, .lower, .{}, self.writer); + //try self.writer.printIntOptions(val, 10, .lower, .{}); + try std.fmt.deprecatedFormat(self.writer, "{d}", .{val}); } /// Serialize a float. @@ -630,12 +631,12 @@ pub fn Serializer(Writer: type) type { } else if (std.math.isNegativeZero(val)) { return self.writer.writeAll("-0.0"); } else { - try std.fmt.format(self.writer, "{d}", .{val}); + try std.fmt.deprecatedFormat(self.writer, "{d}", .{val}); }, .comptime_float => if (val == 0) { return self.writer.writeAll("0"); } else { - try std.fmt.format(self.writer, "{d}", .{val}); + try std.fmt.deprecatedFormat(self.writer, "{d}", .{val}); }, else => comptime unreachable, } @@ -645,7 +646,7 @@ pub fn Serializer(Writer: type) type { /// /// Escapes the identifier if necessary. pub fn ident(self: *Self, name: []const u8) Writer.Error!void { - try self.writer.print(".{p_}", .{std.zig.fmtId(name)}); + try self.writer.print(".{f}", .{std.zig.fmtIdPU(name)}); } /// Serialize `val` as a Unicode codepoint. @@ -658,7 +659,7 @@ pub fn Serializer(Writer: type) type { var buf: [8]u8 = undefined; const len = std.unicode.utf8Encode(val, &buf) catch return error.InvalidCodepoint; const str = buf[0..len]; - try std.fmt.format(self.writer, "'{'}'", .{std.zig.fmtEscapes(str)}); + try std.fmt.deprecatedFormat(self.writer, "'{f}'", .{std.zig.fmtChar(str)}); } /// Like `value`, but always serializes `val` as a tuple. @@ -716,7 +717,7 @@ pub fn Serializer(Writer: type) type { /// Like `value`, but always serializes `val` as a string. pub fn string(self: *Self, val: []const u8) Writer.Error!void { - try std.fmt.format(self.writer, "\"{}\"", .{std.zig.fmtEscapes(val)}); + try std.fmt.deprecatedFormat(self.writer, "\"{f}\"", .{std.zig.fmtString(val)}); } /// Options for formatting multiline strings. diff --git a/lib/ubsan_rt.zig b/lib/ubsan_rt.zig index a2e0a6c1aa..cc58e424f9 100644 --- a/lib/ubsan_rt.zig +++ b/lib/ubsan_rt.zig @@ -119,12 +119,7 @@ const Value = extern struct { } } - pub fn format( - value: Value, - comptime fmt: []const u8, - _: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(value: Value, writer: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { comptime assert(fmt.len == 0); // Work around x86_64 backend limitation. @@ -136,12 +131,12 @@ const Value = extern struct { switch (value.td.kind) { .integer => { if (value.td.isSigned()) { - try writer.print("{}", .{value.getSignedInteger()}); + try writer.print("{d}", .{value.getSignedInteger()}); } else { - try writer.print("{}", .{value.getUnsignedInteger()}); + try writer.print("{d}", .{value.getUnsignedInteger()}); } }, - .float => try writer.print("{}", .{value.getFloat()}), + .float => try writer.print("{d}", .{value.getFloat()}), .unknown => try writer.writeAll("(unknown)"), } } @@ -172,17 +167,12 @@ fn overflowHandler( ) callconv(.c) noreturn { const lhs: Value = .{ .handle = lhs_handle, .td = data.td }; const rhs: Value = .{ .handle = rhs_handle, .td = data.td }; - - const is_signed = data.td.isSigned(); - const fmt = "{s} integer overflow: " ++ "{} " ++ - operator ++ " {} cannot be represented in type {s}"; - - panic(@returnAddress(), fmt, .{ - if (is_signed) "signed" else "unsigned", - lhs, - rhs, - data.td.getName(), - }); + const signed_str = if (data.td.isSigned()) "signed" else "unsigned"; + panic( + @returnAddress(), + "{s} integer overflow: {f} " ++ operator ++ " {f} cannot be represented in type {s}", + .{ signed_str, lhs, rhs, data.td.getName() }, + ); } }; @@ -201,11 +191,9 @@ fn negationHandler( value_handle: ValueHandle, ) callconv(.c) noreturn { const value: Value = .{ .handle = value_handle, .td = data.td }; - panic( - @returnAddress(), - "negation of {} cannot be represented in type {s}", - .{ value, data.td.getName() }, - ); + panic(@returnAddress(), "negation of {f} cannot be represented in type {s}", .{ + value, data.td.getName(), + }); } fn divRemHandlerAbort( @@ -225,11 +213,9 @@ fn divRemHandler( const rhs: Value = .{ .handle = rhs_handle, .td = data.td }; if (rhs.isMinusOne()) { - panic( - @returnAddress(), - "division of {} by -1 cannot be represented in type {s}", - .{ lhs, data.td.getName() }, - ); + panic(@returnAddress(), "division of {f} by -1 cannot be represented in type {s}", .{ + lhs, data.td.getName(), + }); } else panic(@returnAddress(), "division by zero", .{}); } @@ -269,8 +255,8 @@ fn alignmentAssumptionHandler( if (maybe_offset) |offset| { panic( @returnAddress(), - "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++ - "offset address is {} aligned, misalignment offset is {} bytes", + "assumption of {f} byte alignment (with offset of {d} byte) for pointer of type {s} failed\n" ++ + "offset address is {d} aligned, misalignment offset is {d} bytes", .{ alignment, @intFromPtr(offset), @@ -282,8 +268,8 @@ fn alignmentAssumptionHandler( } else { panic( @returnAddress(), - "assumption of {} byte alignment for pointer of type {s} failed\n" ++ - "address is {} aligned, misalignment offset is {} bytes", + "assumption of {f} byte alignment for pointer of type {s} failed\n" ++ + "address is {d} aligned, misalignment offset is {d} bytes", .{ alignment, data.td.getName(), @@ -320,21 +306,21 @@ fn shiftOob( rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize()) { if (rhs.isNegative()) { - panic(@returnAddress(), "shift exponent {} is negative", .{rhs}); + panic(@returnAddress(), "shift exponent {f} is negative", .{rhs}); } else { panic( @returnAddress(), - "shift exponent {} is too large for {}-bit type {s}", + "shift exponent {f} is too large for {d}-bit type {s}", .{ rhs, data.lhs_type.getIntegerSize(), data.lhs_type.getName() }, ); } } else { if (lhs.isNegative()) { - panic(@returnAddress(), "left shift of negative value {}", .{lhs}); + panic(@returnAddress(), "left shift of negative value {f}", .{lhs}); } else { panic( @returnAddress(), - "left shift of {} by {} places cannot be represented in type {s}", + "left shift of {f} by {f} places cannot be represented in type {s}", .{ lhs, rhs, data.lhs_type.getName() }, ); } @@ -359,11 +345,10 @@ fn outOfBounds( index_handle: ValueHandle, ) callconv(.c) noreturn { const index: Value = .{ .handle = index_handle, .td = data.index_type }; - panic( - @returnAddress(), - "index {} out of bounds for type {s}", - .{ index, data.array_type.getName() }, - ); + panic(@returnAddress(), "index {f} out of bounds for type {s}", .{ + index, + data.array_type.getName(), + }); } const PointerOverflowData = extern struct { @@ -387,7 +372,7 @@ fn pointerOverflow( if (result == 0) { panic(@returnAddress(), "applying zero offset to null pointer", .{}); } else { - panic(@returnAddress(), "applying non-zero offset {} to null pointer", .{result}); + panic(@returnAddress(), "applying non-zero offset {d} to null pointer", .{result}); } } else { if (result == 0) { @@ -483,7 +468,7 @@ fn typeMismatch( } else if (!std.mem.isAligned(handle, alignment)) { panic( @returnAddress(), - "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment", + "{s} misaligned address 0x{x} for type {s}, which requires {d} byte alignment", .{ data.kind.getName(), handle, data.td.getName(), alignment }, ); } else { @@ -531,7 +516,7 @@ fn nonNullArgAbort(data: *const NonNullArgData) callconv(.c) noreturn { fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn { panic( @returnAddress(), - "null pointer passed as argument {}, which is declared to never be null", + "null pointer passed as argument {d}, which is declared to never be null", .{data.arg_index}, ); } @@ -553,11 +538,9 @@ fn loadInvalidValue( value_handle: ValueHandle, ) callconv(.c) noreturn { const value: Value = .{ .handle = value_handle, .td = data.td }; - panic( - @returnAddress(), - "load of value {}, which is not valid for type {s}", - .{ value, data.td.getName() }, - ); + panic(@returnAddress(), "load of value {f}, which is not valid for type {s}", .{ + value, data.td.getName(), + }); } const InvalidBuiltinData = extern struct { @@ -596,11 +579,7 @@ fn vlaBoundNotPositive( bound_handle: ValueHandle, ) callconv(.c) noreturn { const bound: Value = .{ .handle = bound_handle, .td = data.td }; - panic( - @returnAddress(), - "variable length array bound evaluates to non-positive value {}", - .{bound}, - ); + panic(@returnAddress(), "variable length array bound evaluates to non-positive value {f}", .{bound}); } const FloatCastOverflowData = extern struct { @@ -631,13 +610,13 @@ fn floatCastOverflow( if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) { const data: *const FloatCastOverflowData = @ptrCast(data_handle); const from_value: Value = .{ .handle = from_handle, .td = data.from }; - panic(@returnAddress(), "{} is outside the range of representable values of type {s}", .{ + panic(@returnAddress(), "{f} is outside the range of representable values of type {s}", .{ from_value, data.to.getName(), }); } else { const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle); const from_value: Value = .{ .handle = from_handle, .td = data.from }; - panic(@returnAddress(), "{} is outside the range of representable values of type {s}", .{ + panic(@returnAddress(), "{f} is outside the range of representable values of type {s}", .{ from_value, data.to.getName(), }); } diff --git a/src/Air/print.zig b/src/Air/print.zig index daeb327d3f..0e90496342 100644 --- a/src/Air/print.zig +++ b/src/Air/print.zig @@ -73,11 +73,11 @@ pub fn writeInst( } pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { - air.write(std.fs.File.stderr().writer(), pt, liveness); + air.write(std.fs.File.stderr().deprecatedWriter(), pt, liveness); } pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { - air.writeInst(std.fs.File.stderr().writer(), inst, pt, liveness); + air.writeInst(std.fs.File.stderr().deprecatedWriter(), inst, pt, liveness); } const Writer = struct { @@ -704,7 +704,7 @@ const Writer = struct { } } const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len]; - try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)}); + try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)}); } fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { @@ -716,7 +716,7 @@ const Writer = struct { const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; try w.writeOperand(s, inst, 0, pl_op.operand); const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); - try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))}); + try s.print(", \"{f}\"", .{std.zig.fmtString(name.toSlice(w.air))}); } fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { diff --git a/src/Builtin.zig b/src/Builtin.zig index d68d49c253..d67efc31fb 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -51,60 +51,60 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { const zig_backend = opts.zig_backend; @setEvalBranchQuota(4000); - try buffer.writer().print( + try buffer.print( \\const std = @import("std"); \\/// Zig version. When writing code that supports multiple versions of Zig, prefer \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. \\pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable; \\pub const zig_version_string = "{s}"; - \\pub const zig_backend = std.builtin.CompilerBackend.{p_}; + \\pub const zig_backend = std.builtin.CompilerBackend.{f}; \\ - \\pub const output_mode: std.builtin.OutputMode = .{p_}; - \\pub const link_mode: std.builtin.LinkMode = .{p_}; - \\pub const unwind_tables: std.builtin.UnwindTables = .{p_}; + \\pub const output_mode: std.builtin.OutputMode = .{f}; + \\pub const link_mode: std.builtin.LinkMode = .{f}; + \\pub const unwind_tables: std.builtin.UnwindTables = .{f}; \\pub const is_test = {}; \\pub const single_threaded = {}; - \\pub const abi: std.Target.Abi = .{p_}; + \\pub const abi: std.Target.Abi = .{f}; \\pub const cpu: std.Target.Cpu = .{{ - \\ .arch = .{p_}, - \\ .model = &std.Target.{p_}.cpu.{p_}, - \\ .features = std.Target.{p_}.featureSet(&.{{ + \\ .arch = .{f}, + \\ .model = &std.Target.{f}.cpu.{f}, + \\ .features = std.Target.{f}.featureSet(&.{{ \\ , .{ build_options.version, - std.zig.fmtId(@tagName(zig_backend)), - std.zig.fmtId(@tagName(opts.output_mode)), - std.zig.fmtId(@tagName(opts.link_mode)), - std.zig.fmtId(@tagName(opts.unwind_tables)), + std.zig.fmtIdPU(@tagName(zig_backend)), + std.zig.fmtIdPU(@tagName(opts.output_mode)), + std.zig.fmtIdPU(@tagName(opts.link_mode)), + std.zig.fmtIdPU(@tagName(opts.unwind_tables)), opts.is_test, opts.single_threaded, - std.zig.fmtId(@tagName(target.abi)), - std.zig.fmtId(@tagName(target.cpu.arch)), - std.zig.fmtId(arch_family_name), - std.zig.fmtId(target.cpu.model.name), - std.zig.fmtId(arch_family_name), + std.zig.fmtIdPU(@tagName(target.abi)), + std.zig.fmtIdPU(@tagName(target.cpu.arch)), + std.zig.fmtIdPU(arch_family_name), + std.zig.fmtIdPU(target.cpu.model.name), + std.zig.fmtIdPU(arch_family_name), }); for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| { const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); const is_enabled = target.cpu.features.isEnabled(index); if (is_enabled) { - try buffer.writer().print(" .{p_},\n", .{std.zig.fmtId(feature.name)}); + try buffer.print(" .{f},\n", .{std.zig.fmtIdPU(feature.name)}); } } - try buffer.writer().print( + try buffer.print( \\ }}), \\}}; \\pub const os: std.Target.Os = .{{ - \\ .tag = .{p_}, + \\ .tag = .{f}, \\ .version_range = .{{ , - .{std.zig.fmtId(@tagName(target.os.tag))}, + .{std.zig.fmtIdPU(@tagName(target.os.tag))}, ); switch (target.os.versionRange()) { .none => try buffer.appendSlice(" .none = {} },\n"), - .semver => |semver| try buffer.writer().print( + .semver => |semver| try buffer.print( \\ .semver = .{{ \\ .min = .{{ \\ .major = {}, @@ -127,7 +127,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { semver.max.minor, semver.max.patch, }), - .linux => |linux| try buffer.writer().print( + .linux => |linux| try buffer.print( \\ .linux = .{{ \\ .range = .{{ \\ .min = .{{ @@ -164,7 +164,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { linux.android, }), - .hurd => |hurd| try buffer.writer().print( + .hurd => |hurd| try buffer.print( \\ .hurd = .{{ \\ .range = .{{ \\ .min = .{{ @@ -198,10 +198,10 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { hurd.glibc.minor, hurd.glibc.patch, }), - .windows => |windows| try buffer.writer().print( + .windows => |windows| try buffer.print( \\ .windows = .{{ - \\ .min = {c}, - \\ .max = {c}, + \\ .min = {fc}, + \\ .max = {fc}, \\ }}}}, \\ , .{ windows.min, windows.max }), @@ -217,7 +217,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { ); if (target.dynamic_linker.get()) |dl| { - try buffer.writer().print( + try buffer.print( \\ .dynamic_linker = .init("{s}"), \\}}; \\ @@ -237,9 +237,9 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { // knows libc will provide it, and likewise c.zig will not export memcpy. const link_libc = opts.link_libc; - try buffer.writer().print( - \\pub const object_format: std.Target.ObjectFormat = .{p_}; - \\pub const mode: std.builtin.OptimizeMode = .{p_}; + try buffer.print( + \\pub const object_format: std.Target.ObjectFormat = .{f}; + \\pub const mode: std.builtin.OptimizeMode = .{f}; \\pub const link_libc = {}; \\pub const link_libcpp = {}; \\pub const have_error_return_tracing = {}; @@ -249,12 +249,12 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { \\pub const position_independent_code = {}; \\pub const position_independent_executable = {}; \\pub const strip_debug_info = {}; - \\pub const code_model: std.builtin.CodeModel = .{p_}; + \\pub const code_model: std.builtin.CodeModel = .{f}; \\pub const omit_frame_pointer = {}; \\ , .{ - std.zig.fmtId(@tagName(target.ofmt)), - std.zig.fmtId(@tagName(opts.optimize_mode)), + std.zig.fmtIdPU(@tagName(target.ofmt)), + std.zig.fmtIdPU(@tagName(opts.optimize_mode)), link_libc, opts.link_libcpp, opts.error_tracing, @@ -264,15 +264,15 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { opts.pic, opts.pie, opts.strip, - std.zig.fmtId(@tagName(opts.code_model)), + std.zig.fmtIdPU(@tagName(opts.code_model)), opts.omit_frame_pointer, }); if (target.os.tag == .wasi) { - try buffer.writer().print( - \\pub const wasi_exec_model: std.builtin.WasiExecModel = .{p_}; + try buffer.print( + \\pub const wasi_exec_model: std.builtin.WasiExecModel = .{f}; \\ - , .{std.zig.fmtId(@tagName(opts.wasi_exec_model))}); + , .{std.zig.fmtIdPU(@tagName(opts.wasi_exec_model))}); } if (opts.is_test) { @@ -317,7 +317,7 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void { if (root_dir.statFile(sub_path)) |stat| { if (stat.size != file.source.?.len) { std.log.warn( - "the cached file '{}' had the wrong size. Expected {d}, found {d}. " ++ + "the cached file '{f}{s}' had the wrong size. Expected {d}, found {d}. " ++ "Overwriting with correct file contents now", .{ file.path.fmt(comp), file.source.?.len, stat.size }, ); diff --git a/src/Compilation.zig b/src/Compilation.zig index 5a221ca579..d94c5bdeff 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1001,7 +1001,7 @@ pub const CObject = struct { var line = std.ArrayList(u8).init(eb.gpa); defer line.deinit(); - file.reader().readUntilDelimiterArrayList(&line, '\n', 1 << 10) catch break :source_line 0; + file.deprecatedReader().readUntilDelimiterArrayList(&line, '\n', 1 << 10) catch break :source_line 0; break :source_line try eb.addString(line.items); }; @@ -1069,7 +1069,7 @@ pub const CObject = struct { const file = try std.fs.cwd().openFile(path, .{}); defer file.close(); - var br = std.io.bufferedReader(file.reader()); + var br = std.io.bufferedReader(file.deprecatedReader()); const reader = br.reader(); var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = reader.any() }); defer bc.deinit(); @@ -1875,7 +1875,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); nosuspend { stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print; stderr.print(" target: {s}\n", .{try target.zigTriple(arena)}) catch break :print; @@ -3932,7 +3932,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { // This AU is referenced and has a transitive compile error, meaning it referenced something with a compile error. // However, we haven't reported any such error. // This is a compiler bug. - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); try stderr.writeAll("referenced transitive analysis errors, but none actually emitted\n"); try stderr.print("{} [transitive failure]\n", .{zcu.fmtAnalUnit(failed_unit)}); while (ref) |r| { @@ -4894,7 +4894,7 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, var walker = try mod_dir.walk(comp.gpa); defer walker.deinit(); - var archiver = std.tar.writer(tar_file.writer().any()); + var archiver = std.tar.writer(tar_file.deprecatedWriter().any()); archiver.prefix = name; while (try walker.next()) |entry| { @@ -7214,7 +7214,7 @@ pub fn lockAndSetMiscFailure( pub fn dump_argv(argv: []const []const u8) void { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); for (argv[0 .. argv.len - 1]) |arg| { nosuspend stderr.print("{s} ", .{arg}) catch return; } diff --git a/src/InternPool.zig b/src/InternPool.zig index 1cf42316dc..bfa838b5d6 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1892,7 +1892,7 @@ pub const NullTerminatedString = enum(u32) { if (comptime std.mem.eql(u8, specifier, "")) { try writer.writeAll(slice); } else if (comptime std.mem.eql(u8, specifier, "i")) { - try writer.print("{p}", .{std.zig.fmtId(slice)}); + try writer.print("{f}", .{std.zig.fmtIdP(slice)}); } else @compileError("invalid format string '" ++ specifier ++ "' for '" ++ @typeName(NullTerminatedString) ++ "'"); } @@ -11259,7 +11259,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { } fn dumpAllFallible(ip: *const InternPool) anyerror!void { - var bw = std.io.bufferedWriter(std.fs.File.stderr().writer()); + var bw = std.io.bufferedWriter(std.fs.File.stderr().deprecatedWriter()); const w = bw.writer(); for (ip.locals, 0..) |*local, tid| { const items = local.shared.items.view(); @@ -11369,7 +11369,7 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - var bw = std.io.bufferedWriter(std.fs.File.stderr().writer()); + var bw = std.io.bufferedWriter(std.fs.File.stderr().deprecatedWriter()); const w = bw.writer(); var instances: std.AutoArrayHashMapUnmanaged(Index, std.ArrayListUnmanaged(Index)) = .empty; diff --git a/src/Package.zig b/src/Package.zig index 2eb7321cee..f625dd4908 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -134,7 +134,7 @@ pub const Hash = struct { } var bin_digest: [Algo.digest_length]u8 = undefined; Algo.hash(sub_path, &bin_digest, .{}); - _ = std.fmt.bufPrint(result.bytes[i..], "{}", .{std.fmt.fmtSliceHexLower(&bin_digest)}) catch unreachable; + _ = std.fmt.bufPrint(result.bytes[i..], "{x}", .{&bin_digest}) catch unreachable; return result; } }; diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index ec59062d3e..f1fda179aa 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -201,7 +201,7 @@ pub const JobQueue = struct { const hash_slice = hash.toSlice(); try buf.writer().print( - \\ pub const {} = struct {{ + \\ pub const {f} = struct {{ \\ , .{std.zig.fmtId(hash_slice)}); @@ -233,9 +233,9 @@ pub const JobQueue = struct { if (fetch.has_build_zig) { try buf.writer().print( - \\ pub const build_zig = @import("{}"); + \\ pub const build_zig = @import("{f}"); \\ - , .{std.zig.fmtEscapes(hash_slice)}); + , .{std.zig.fmtString(hash_slice)}); } if (fetch.manifest) |*manifest| { @@ -246,8 +246,8 @@ pub const JobQueue = struct { for (manifest.dependencies.keys(), manifest.dependencies.values()) |name, dep| { const h = depDigest(fetch.package_root, jq.global_cache, dep) orelse continue; try buf.writer().print( - " .{{ \"{}\", \"{}\" }},\n", - .{ std.zig.fmtEscapes(name), std.zig.fmtEscapes(h.toSlice()) }, + " .{{ \"{f}\", \"{f}\" }},\n", + .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) }, ); } @@ -278,8 +278,8 @@ pub const JobQueue = struct { for (root_manifest.dependencies.keys(), root_manifest.dependencies.values()) |name, dep| { const h = depDigest(root_fetch.package_root, jq.global_cache, dep) orelse continue; try buf.writer().print( - " .{{ \"{}\", \"{}\" }},\n", - .{ std.zig.fmtEscapes(name), std.zig.fmtEscapes(h.toSlice()) }, + " .{{ \"{f}\", \"{f}\" }},\n", + .{ std.zig.fmtString(name), std.zig.fmtString(h.toSlice()) }, ); } try buf.appendSlice("};\n"); @@ -1321,7 +1321,7 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult { .{@errorName(err)}, )); if (len == 0) break; - zip_file.writer().writeAll(buf[0..len]) catch |err| return f.fail(f.location_tok, try eb.printString( + zip_file.deprecatedWriter().writeAll(buf[0..len]) catch |err| return f.fail(f.location_tok, try eb.printString( "write temporary zip file failed: {s}", .{@errorName(err)}, )); @@ -1374,7 +1374,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true }); defer pack_file.close(); var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); - try fifo.pump(resource.fetch_stream.reader(), pack_file.writer()); + try fifo.pump(resource.fetch_stream.reader(), pack_file.deprecatedWriter()); try pack_file.sync(); var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true }); @@ -1382,7 +1382,7 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U { const index_prog_node = f.prog_node.start("Index pack", 0); defer index_prog_node.end(); - var index_buffered_writer = std.io.bufferedWriter(index_file.writer()); + var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter()); try git.indexPack(gpa, object_format, pack_file, index_buffered_writer.writer()); try index_buffered_writer.flush(); try index_file.sync(); @@ -1655,13 +1655,13 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute fn dumpHashInfo(all_files: []const *const HashedFile) !void { const stdout: std.fs.File = .stdout(); - var bw = std.io.bufferedWriter(stdout.writer()); + var bw = std.io.bufferedWriter(stdout.deprecatedWriter()); const w = bw.writer(); for (all_files) |hashed_file| { - try w.print("{s}: {s}: {s}\n", .{ + try w.print("{s}: {x}: {s}\n", .{ @tagName(hashed_file.kind), - std.fmt.fmtSliceHexLower(&hashed_file.hash), + &hashed_file.hash, hashed_file.normalized_path, }); } @@ -2074,7 +2074,7 @@ test "zip" { { var zip_file = try tmp.dir.createFile("test.zip", .{}); defer zip_file.close(); - var bw = std.io.bufferedWriter(zip_file.writer()); + var bw = std.io.bufferedWriter(zip_file.deprecatedWriter()); var store: [test_files.len]std.zip.testutil.FileStore = undefined; try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{}); try bw.flush(); @@ -2107,7 +2107,7 @@ test "zip with one root folder" { { var zip_file = try tmp.dir.createFile("test.zip", .{}); defer zip_file.close(); - var bw = std.io.bufferedWriter(zip_file.writer()); + var bw = std.io.bufferedWriter(zip_file.deprecatedWriter()); var store: [test_files.len]std.zip.testutil.FileStore = undefined; try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{}); try bw.flush(); diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig index 0daed436ce..911175bd29 100644 --- a/src/Package/Fetch/git.zig +++ b/src/Package/Fetch/git.zig @@ -127,7 +127,7 @@ pub const Oid = union(Format) { ) @TypeOf(writer).Error!void { _ = fmt; _ = options; - try writer.print("{}", .{std.fmt.fmtSliceHexLower(oid.slice())}); + try writer.print("{x}", .{oid.slice()}); } pub fn slice(oid: *const Oid) []const u8 { @@ -353,7 +353,7 @@ const Odb = struct { fn init(allocator: Allocator, format: Oid.Format, pack_file: std.fs.File, index_file: std.fs.File) !Odb { try pack_file.seekTo(0); try index_file.seekTo(0); - const index_header = try IndexHeader.read(index_file.reader()); + const index_header = try IndexHeader.read(index_file.deprecatedReader()); return .{ .format = format, .pack_file = pack_file, @@ -377,7 +377,7 @@ const Odb = struct { const base_object = while (true) { if (odb.cache.get(base_offset)) |base_object| break base_object; - base_header = try EntryHeader.read(odb.format, odb.pack_file.reader()); + base_header = try EntryHeader.read(odb.format, odb.pack_file.deprecatedReader()); switch (base_header) { .ofs_delta => |ofs_delta| { try delta_offsets.append(odb.allocator, base_offset); @@ -390,7 +390,7 @@ const Odb = struct { base_offset = try odb.pack_file.getPos(); }, else => { - const base_data = try readObjectRaw(odb.allocator, odb.pack_file.reader(), base_header.uncompressedLength()); + const base_data = try readObjectRaw(odb.allocator, odb.pack_file.deprecatedReader(), base_header.uncompressedLength()); errdefer odb.allocator.free(base_data); const base_object: Object = .{ .type = base_header.objectType(), .data = base_data }; try odb.cache.put(odb.allocator, base_offset, base_object); @@ -420,7 +420,7 @@ const Odb = struct { const found_index = while (start_index < end_index) { const mid_index = start_index + (end_index - start_index) / 2; try odb.index_file.seekTo(IndexHeader.size + mid_index * oid_length); - const mid_oid = try Oid.readBytes(odb.format, odb.index_file.reader()); + const mid_oid = try Oid.readBytes(odb.format, odb.index_file.deprecatedReader()); switch (mem.order(u8, mid_oid.slice(), oid.slice())) { .lt => start_index = mid_index + 1, .gt => end_index = mid_index, @@ -431,12 +431,12 @@ const Odb = struct { const n_objects = odb.index_header.fan_out_table[255]; const offset_values_start = IndexHeader.size + n_objects * (oid_length + 4); try odb.index_file.seekTo(offset_values_start + found_index * 4); - const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.reader().readInt(u32, .big)); + const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.deprecatedReader().readInt(u32, .big)); const pack_offset = pack_offset: { if (l1_offset.big) { const l2_offset_values_start = offset_values_start + n_objects * 4; try odb.index_file.seekTo(l2_offset_values_start + l1_offset.value * 4); - break :pack_offset try odb.index_file.reader().readInt(u64, .big); + break :pack_offset try odb.index_file.deprecatedReader().readInt(u64, .big); } else { break :pack_offset l1_offset.value; } @@ -1561,7 +1561,7 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true }); defer index_file.close(); - try indexPack(testing.allocator, format, pack_file, index_file.writer()); + try indexPack(testing.allocator, format, pack_file, index_file.deprecatedWriter()); // Arbitrary size limit on files read while checking the repository contents // (all files in the test repo are known to be smaller than this) @@ -1678,7 +1678,7 @@ pub fn main() !void { std.debug.print("Starting index...\n", .{}); var index_file = try git_dir.createFile("idx", .{ .read = true }); defer index_file.close(); - var index_buffered_writer = std.io.bufferedWriter(index_file.writer()); + var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter()); try indexPack(allocator, format, pack_file, index_buffered_writer.writer()); try index_buffered_writer.flush(); try index_file.sync(); diff --git a/src/Package/Manifest.zig b/src/Package/Manifest.zig index 6dff300503..1d71b60fa3 100644 --- a/src/Package/Manifest.zig +++ b/src/Package/Manifest.zig @@ -401,7 +401,7 @@ const Parse = struct { return fail(p, main_token, "name must be a valid bare zig identifier (hint: switch from string to enum literal)", .{}); if (name.len > max_name_len) - return fail(p, main_token, "name '{}' exceeds max length of {d}", .{ + return fail(p, main_token, "name '{f}' exceeds max length of {d}", .{ std.zig.fmtId(name), max_name_len, }); @@ -416,7 +416,7 @@ const Parse = struct { return fail(p, main_token, "name must be a valid bare zig identifier", .{}); if (ident_name.len > max_name_len) - return fail(p, main_token, "name '{}' exceeds max length of {d}", .{ + return fail(p, main_token, "name '{f}' exceeds max length of {d}", .{ std.zig.fmtId(ident_name), max_name_len, }); diff --git a/src/Sema.zig b/src/Sema.zig index 22ac21d644..d0f50a01ab 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5,6 +5,39 @@ //! Does type checking, comptime control flow, and safety-check generation. //! This is the the heart of the Zig compiler. +const std = @import("std"); +const math = std.math; +const mem = std.mem; +const Allocator = mem.Allocator; +const assert = std.debug.assert; +const log = std.log.scoped(.sema); + +const Sema = @This(); +const Value = @import("Value.zig"); +const MutableValue = @import("mutable_value.zig").MutableValue; +const Type = @import("Type.zig"); +const Air = @import("Air.zig"); +const Zir = std.zig.Zir; +const Zcu = @import("Zcu.zig"); +const trace = @import("tracy.zig").trace; +const Namespace = Zcu.Namespace; +const CompileError = Zcu.CompileError; +const SemaError = Zcu.SemaError; +const LazySrcLoc = Zcu.LazySrcLoc; +const RangeSet = @import("RangeSet.zig"); +const target_util = @import("target.zig"); +const Package = @import("Package.zig"); +const crash_report = @import("crash_report.zig"); +const build_options = @import("build_options"); +const Compilation = @import("Compilation.zig"); +const InternPool = @import("InternPool.zig"); +const Alignment = InternPool.Alignment; +const AnalUnit = InternPool.AnalUnit; +const ComptimeAllocIndex = InternPool.ComptimeAllocIndex; +const Cache = std.Build.Cache; +const LowerZon = @import("Sema/LowerZon.zig"); +const arith = @import("Sema/arith.zig"); + pt: Zcu.PerThread, /// Alias to `zcu.gpa`. gpa: Allocator, @@ -157,39 +190,6 @@ pub fn getComptimeAlloc(sema: *Sema, idx: ComptimeAllocIndex) *ComptimeAlloc { return &sema.comptime_allocs.items[@intFromEnum(idx)]; } -const std = @import("std"); -const math = std.math; -const mem = std.mem; -const Allocator = mem.Allocator; -const assert = std.debug.assert; -const log = std.log.scoped(.sema); - -const Sema = @This(); -const Value = @import("Value.zig"); -const MutableValue = @import("mutable_value.zig").MutableValue; -const Type = @import("Type.zig"); -const Air = @import("Air.zig"); -const Zir = std.zig.Zir; -const Zcu = @import("Zcu.zig"); -const trace = @import("tracy.zig").trace; -const Namespace = Zcu.Namespace; -const CompileError = Zcu.CompileError; -const SemaError = Zcu.SemaError; -const LazySrcLoc = Zcu.LazySrcLoc; -const RangeSet = @import("RangeSet.zig"); -const target_util = @import("target.zig"); -const Package = @import("Package.zig"); -const crash_report = @import("crash_report.zig"); -const build_options = @import("build_options"); -const Compilation = @import("Compilation.zig"); -const InternPool = @import("InternPool.zig"); -const Alignment = InternPool.Alignment; -const AnalUnit = InternPool.AnalUnit; -const ComptimeAllocIndex = InternPool.ComptimeAllocIndex; -const Cache = std.Build.Cache; -const LowerZon = @import("Sema/LowerZon.zig"); -const arith = @import("Sema/arith.zig"); - pub const default_branch_quota = 1000; pub const InferredErrorSet = struct { @@ -888,7 +888,7 @@ const ComptimeReason = union(enum) { /// Evaluating at comptime because of a comptime-only type. This field is separate so that /// the type in question can be included in the error message. AstGen could never emit this /// reason, because it knows nothing of types. - /// The format string looks like "foo '{}' bar", where "{}" is the comptime-only type. + /// The format string looks like "foo '{f}' bar", where "{f}" is the comptime-only type. /// We will then explain why this type is comptime-only. comptime_only: struct { ty: Type, @@ -930,17 +930,17 @@ const ComptimeReason = union(enum) { .struct_init => .{ "initializer of comptime-only struct", "must be comptime-known" }, .tuple_init => .{ "initializer of comptime-only tuple", "must be comptime-known" }, }; - try sema.errNote(src, err_msg, "{s} '{}' {s}", .{ pre, co.ty.fmt(sema.pt), post }); + try sema.errNote(src, err_msg, "{s} '{f}' {s}", .{ pre, co.ty.fmt(sema.pt), post }); try sema.explainWhyTypeIsComptime(err_msg, src, co.ty); }, .comptime_only_param_ty => |co| { - try sema.errNote(src, err_msg, "argument to parameter with comptime-only type '{}' must be comptime-known", .{co.ty.fmt(sema.pt)}); + try sema.errNote(src, err_msg, "argument to parameter with comptime-only type '{f}' must be comptime-known", .{co.ty.fmt(sema.pt)}); try sema.errNote(co.param_ty_src, err_msg, "parameter type declared here", .{}); try sema.explainWhyTypeIsComptime(err_msg, src, co.ty); }, .comptime_only_ret_ty => |co| { const function_with: []const u8 = if (co.is_generic_inst) "generic function instantiated with" else "function with"; - try sema.errNote(src, err_msg, "call to {s} comptime-only return type '{}' is evaluated at comptime", .{ function_with, co.ty.fmt(sema.pt) }); + try sema.errNote(src, err_msg, "call to {s} comptime-only return type '{f}' is evaluated at comptime", .{ function_with, co.ty.fmt(sema.pt) }); try sema.errNote(co.ret_ty_src, err_msg, "return type declared here", .{}); try sema.explainWhyTypeIsComptime(err_msg, src, co.ty); }, @@ -1905,7 +1905,7 @@ fn analyzeBodyInner( const err_union = try sema.resolveInst(extra.data.operand); const err_union_ty = sema.typeOf(err_union); if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -2339,7 +2339,7 @@ pub fn failWithDivideByZero(sema: *Sema, block: *Block, src: LazySrcLoc) Compile fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: Type, rhs_ty: Type) CompileError { const pt = sema.pt; - return sema.fail(block, src, "remainder division with '{}' and '{}': signed integers and floats must use @rem or @mod", .{ + return sema.fail(block, src, "remainder division with '{f}' and '{f}': signed integers and floats must use @rem or @mod", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), }); } @@ -2347,7 +2347,7 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non_optional_ty: Type) CompileError { const pt = sema.pt; const msg = msg: { - const msg = try sema.errMsg(src, "expected optional type, found '{}'", .{ + const msg = try sema.errMsg(src, "expected optional type, found '{f}'", .{ non_optional_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -2363,12 +2363,12 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { const pt = sema.pt; const msg = msg: { - const msg = try sema.errMsg(src, "type '{}' does not support array initialization syntax", .{ + const msg = try sema.errMsg(src, "type '{f}' does not support array initialization syntax", .{ ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); if (ty.isSlice(pt.zcu)) { - try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(pt.zcu).fmt(pt)}); + try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.elemType2(pt.zcu).fmt(pt)}); } break :msg msg; }; @@ -2377,7 +2377,7 @@ fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty fn failWithStructInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { const pt = sema.pt; - return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{ + return sema.fail(block, src, "type '{f}' does not support struct initialization syntax", .{ ty.fmt(pt), }); } @@ -2390,7 +2390,7 @@ fn failWithErrorSetCodeMissing( src_err_set_ty: Type, ) CompileError { const pt = sema.pt; - return sema.fail(block, src, "expected type '{}', found type '{}'", .{ + return sema.fail(block, src, "expected type '{f}', found type '{f}'", .{ dest_err_set_ty.fmt(pt), src_err_set_ty.fmt(pt), }); } @@ -2398,7 +2398,7 @@ fn failWithErrorSetCodeMissing( pub fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: ?usize) CompileError { const pt = sema.pt; return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "overflow of integer type '{}' with value '{}'", .{ + const msg = try sema.errMsg(src, "overflow of integer type '{f}' with value '{f}'", .{ int_ty.fmt(pt), val.fmtValueSema(pt, sema), }); errdefer msg.destroy(sema.gpa); @@ -2448,7 +2448,7 @@ fn failWithInvalidFieldAccess( const child_ty = inner_ty.optionalChild(zcu); if (!typeSupportsFieldAccess(zcu, child_ty, field_name)) break :opt; const msg = msg: { - const msg = try sema.errMsg(src, "optional type '{}' does not support field access", .{object_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "optional type '{f}' does not support field access", .{object_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "consider using '.?', 'orelse', or 'if'", .{}); break :msg msg; @@ -2458,14 +2458,14 @@ fn failWithInvalidFieldAccess( const child_ty = inner_ty.errorUnionPayload(zcu); if (!typeSupportsFieldAccess(zcu, child_ty, field_name)) break :err; const msg = msg: { - const msg = try sema.errMsg(src, "error union type '{}' does not support field access", .{object_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "error union type '{f}' does not support field access", .{object_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); } - return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(pt)}); + return sema.fail(block, src, "type '{f}' does not support field access", .{object_ty.fmt(pt)}); } fn typeSupportsFieldAccess(zcu: *const Zcu, ty: Type, field_name: InternPool.NullTerminatedString) bool { @@ -2494,7 +2494,7 @@ fn failWithComptimeErrorRetTrace( const pt = sema.pt; const zcu = pt.zcu; const msg = msg: { - const msg = try sema.errMsg(src, "caught unexpected error '{}'", .{name.fmt(&zcu.intern_pool)}); + const msg = try sema.errMsg(src, "caught unexpected error '{f}'", .{name.fmt(&zcu.intern_pool)}); errdefer msg.destroy(sema.gpa); for (sema.comptime_err_ret_trace.items) |src_loc| { @@ -3005,7 +3005,7 @@ pub fn createTypeName( inst: ?Zir.Inst.Index, /// This is used purely to give the type a unique name in the `anon` case. type_index: InternPool.Index, -) !struct { +) CompileError!struct { name: InternPool.NullTerminatedString, nav: InternPool.Nav.Index.Optional, } { @@ -3024,11 +3024,10 @@ pub fn createTypeName( const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); const zir_tags = sema.code.instructions.items(.tag); - var buf: std.ArrayListUnmanaged(u8) = .empty; - defer buf.deinit(gpa); - - const writer = buf.writer(gpa); - try writer.print("{}(", .{block.type_name_ctx.fmt(ip)}); + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; + bw.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory; var arg_i: usize = 0; for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) { @@ -3041,18 +3040,18 @@ pub fn createTypeName( // result in a compile error. const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat - if (arg_i != 0) try writer.writeByte(','); + if (arg_i != 0) bw.writeByte(',') catch return error.OutOfMemory; // Limiting the depth here helps avoid type names getting too long, which // in turn helps to avoid unreasonably long symbol names for namespaced // symbols. Such names should ideally be human-readable, and additionally, // some tooling may not support very long symbol names. - try writer.print("{}", .{Value.fmtValueSemaFull(.{ + bw.print("{f}", .{Value.fmtValueSemaFull(.{ .val = arg_val, .pt = pt, .opt_sema = sema, .depth = 1, - })}); + })}) catch return error.OutOfMemory; arg_i += 1; continue; @@ -3060,9 +3059,9 @@ pub fn createTypeName( else => continue, }; - try writer.writeByte(')'); + try bw.writeByte(')'); return .{ - .name = try ip.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls), + .name = try ip.getOrPutString(gpa, pt.tid, aw.getWritten(), .no_embedded_nulls), .nav = .none, }; }, @@ -3074,7 +3073,7 @@ pub fn createTypeName( for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) { .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { return .{ - .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.{s}", .{ + .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}.{s}", .{ block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), }, .no_embedded_nulls), .nav = .none, @@ -3097,7 +3096,7 @@ pub fn createTypeName( // that builtin from the language, we can consider this. return .{ - .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{}__{s}_{d}", .{ + .name = try ip.getOrPutStringFmt(gpa, pt.tid, "{f}__{s}_{d}", .{ block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index), }, .no_embedded_nulls), .nav = .none, @@ -3581,7 +3580,7 @@ fn ensureResultUsed( }, else => { const msg = msg: { - const msg = try sema.errMsg(src, "value of type '{}' ignored", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "value of type '{f}' ignored", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "all non-void values must be used", .{}); try sema.errNote(src, msg, "to discard the value, assign it to '_'", .{}); @@ -3851,7 +3850,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro // The value was initialized through RLS, so we didn't detect the runtime condition earlier. // TODO: source location of runtime control flow const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node }); - return sema.fail(block, init_src, "value with comptime-only type '{}' depends on runtime control flow", .{elem_ty.fmt(pt)}); + return sema.fail(block, init_src, "value with comptime-only type '{f}' depends on runtime control flow", .{elem_ty.fmt(pt)}); } // This is a runtime value. @@ -4348,7 +4347,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com // The alloc wasn't comptime-known per the above logic, so the // type cannot be comptime-only. // TODO: source location of runtime control flow - return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(pt)}); + return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)}); } if (sema.func_is_naked and try final_elem_ty.hasRuntimeBitsSema(pt)) { const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); @@ -4445,7 +4444,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. if (!object_ty.isIndexable(zcu)) { // Instead of using checkIndexable we customize this error. const msg = msg: { - const msg = try sema.errMsg(arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(pt)}); + const msg = try sema.errMsg(arg_src, "type '{f}' is not indexable and not a range", .{object_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(arg_src, msg, "for loop operand must be a range, array, slice, tuple, or vector", .{}); @@ -4480,10 +4479,10 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .for_node_offset = inst_data.src_node, .input_index = len_idx, } }); - try sema.errNote(a_src, msg, "length {} here", .{ + try sema.errNote(a_src, msg, "length {f} here", .{ v.fmtValueSema(pt, sema), }); - try sema.errNote(arg_src, msg, "length {} here", .{ + try sema.errNote(arg_src, msg, "length {f} here", .{ arg_val.fmtValueSema(pt, sema), }); break :msg msg; @@ -4515,7 +4514,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .for_node_offset = inst_data.src_node, .input_index = i, } }); - try sema.errNote(arg_src, msg, "type '{}' has no upper bound", .{ + try sema.errNote(arg_src, msg, "type '{f}' has no upper bound", .{ object_ty.fmt(pt), }); } @@ -4591,7 +4590,7 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE switch (val_ty.zigTypeTag(zcu)) { .array, .vector => {}, else => if (!val_ty.isTuple(zcu)) { - return sema.fail(block, src, "expected array of '{}', found '{}'", .{ elem_ty.fmt(pt), val_ty.fmt(pt) }); + return sema.fail(block, src, "expected array of '{f}', found '{f}'", .{ elem_ty.fmt(pt), val_ty.fmt(pt) }); }, } const want_ty = try pt.arrayType(.{ @@ -4665,7 +4664,7 @@ fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const ty_operand = try sema.resolveTypeOrPoison(block, src, un_tok.operand) orelse return; if (ty_operand.optEuBaseType(zcu).zigTypeTag(zcu) != .pointer) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "expected type '{}', found pointer", .{ty_operand.fmt(pt)}); + const msg = try sema.errMsg(src, "expected type '{f}', found pointer", .{ty_operand.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "address-of operator always returns a pointer", .{}); break :msg msg; @@ -5074,7 +5073,7 @@ fn validateStructInit( } continue; }; - const template = "missing struct field: {}"; + const template = "missing struct field: {f}"; const args = .{field_name.fmt(ip)}; if (root_msg) |msg| { try sema.errNote(init_src, msg, template, args); @@ -5204,7 +5203,7 @@ fn validateStructInit( } continue; }; - const template = "missing struct field: {}"; + const template = "missing struct field: {f}"; const args = .{field_name.fmt(ip)}; if (root_msg) |msg| { try sema.errNote(init_src, msg, template, args); @@ -5508,11 +5507,11 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const operand_ty = sema.typeOf(operand); if (operand_ty.zigTypeTag(zcu) != .pointer) { - return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(pt)}); + return sema.fail(block, src, "cannot dereference non-pointer type '{f}'", .{operand_ty.fmt(pt)}); } else switch (operand_ty.ptrSize(zcu)) { .one, .c => {}, - .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(pt)}), - .slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(pt)}), + .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{f}'", .{operand_ty.fmt(pt)}), + .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}), } if ((try sema.typeHasOnePossibleValue(operand_ty.childType(zcu))) != null) { @@ -5529,7 +5528,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const msg = msg: { const msg = try sema.errMsg( src, - "values of type '{}' must be comptime-known, but operand value is runtime-known", + "values of type '{f}' must be comptime-known, but operand value is runtime-known", .{elem_ty.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -5561,7 +5560,7 @@ fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp if (!typeIsDestructurable(operand_ty, zcu)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "type '{}' cannot be destructured", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' cannot be destructured", .{operand_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(destructure_src, msg, "result destructured here", .{}); if (operand_ty.zigTypeTag(pt.zcu) == .error_union) { @@ -5604,12 +5603,12 @@ fn failWithBadMemberAccess( else => unreachable, }; if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) { - return sema.fail(block, field_src, "root source file struct '{}' has no member named '{}'", .{ + return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{ agg_ty.fmt(pt), field_name.fmt(ip), }); }; - return sema.fail(block, field_src, "{s} '{}' has no member named '{}'", .{ + return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{ kw_name, agg_ty.fmt(pt), field_name.fmt(ip), }); } @@ -5629,7 +5628,7 @@ fn failWithBadStructFieldAccess( const msg = msg: { const msg = try sema.errMsg( field_src, - "no field named '{}' in struct '{}'", + "no field named '{f}' in struct '{f}'", .{ field_name.fmt(ip), struct_type.name.fmt(ip) }, ); errdefer msg.destroy(sema.gpa); @@ -5655,7 +5654,7 @@ fn failWithBadUnionFieldAccess( const msg = msg: { const msg = try sema.errMsg( field_src, - "no field named '{}' in union '{}'", + "no field named '{f}' in union '{f}'", .{ field_name.fmt(ip), union_obj.name.fmt(ip) }, ); errdefer msg.destroy(gpa); @@ -5907,30 +5906,30 @@ fn zirCompileLog( const zcu = pt.zcu; const gpa = zcu.gpa; - var buf: std.ArrayListUnmanaged(u8) = .empty; - defer buf.deinit(gpa); - - const writer = buf.writer(gpa); + var aw: std.io.Writer.Allocating = .init(gpa); + defer aw.deinit(); + const bw = &aw.interface; const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); const src_node = extra.data.src_node; const args = sema.code.refSlice(extra.end, extended.small); for (args, 0..) |arg_ref, i| { - if (i != 0) try writer.print(", ", .{}); + if (i != 0) bw.writeAll(", ") catch return error.OutOfMemory; const arg = try sema.resolveInst(arg_ref); const arg_ty = sema.typeOf(arg); if (try sema.resolveValueResolveLazy(arg)) |val| { - try writer.print("@as({}, {})", .{ + bw.print("@as({f}, {f})", .{ arg_ty.fmt(pt), val.fmtValueSema(pt, sema), - }); + }) catch return error.OutOfMemory; } else { - try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(pt)}); + bw.print("@as({f}, [runtime value])", .{arg_ty.fmt(pt)}) catch return error.OutOfMemory; } } + bw.writeByte('\n') catch return error.OutOfMemory; - const line_data = try zcu.intern_pool.getOrPutString(gpa, pt.tid, buf.items, .no_embedded_nulls); + const line_data = try zcu.intern_pool.getOrPutString(gpa, pt.tid, aw.getWritten(), .no_embedded_nulls); const line_idx: Zcu.CompileLogLine.Index = if (zcu.free_compile_log_lines.pop()) |idx| idx: { zcu.compile_log_lines.items[@intFromEnum(idx)] = .{ @@ -6472,7 +6471,7 @@ fn resolveAnalyzedBlock( const type_src = src; // TODO: better source location if (try resolved_ty.comptimeOnlySema(pt)) { const msg = msg: { - const msg = try sema.errMsg(type_src, "value with comptime-only type '{}' depends on runtime control flow", .{resolved_ty.fmt(pt)}); + const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?; @@ -6588,7 +6587,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { if (ptr_ty.zigTypeTag(zcu) != .pointer) { - return sema.fail(block, ptr_src, "expected pointer type, found '{}'", .{ptr_ty.fmt(pt)}); + return sema.fail(block, ptr_src, "expected pointer type, found '{f}'", .{ptr_ty.fmt(pt)}); } const ptr_ty_info = ptr_ty.ptrInfo(zcu); if (ptr_ty_info.flags.size == .slice) { @@ -6611,7 +6610,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const export_ty = Value.fromInterned(uav.val).typeOf(zcu); if (!try sema.validateExternType(export_ty, .other)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); try sema.addDeclaredHereNote(msg, export_ty); @@ -6663,7 +6662,7 @@ pub fn analyzeExport( if (!try sema.validateExternType(export_ty, .other)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); @@ -7287,7 +7286,7 @@ fn checkCallArgumentCount( opt_child.childType(zcu).zigTypeTag(zcu) == .@"fn")) { const msg = msg: { - const msg = try sema.errMsg(func_src, "cannot call optional type '{}'", .{ + const msg = try sema.errMsg(func_src, "cannot call optional type '{f}'", .{ callee_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -7299,7 +7298,7 @@ fn checkCallArgumentCount( }, else => {}, } - return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(pt)}); + return sema.fail(block, func_src, "type '{f}' not a function", .{callee_ty.fmt(pt)}); }; const func_ty_info = zcu.typeToFunc(func_ty).?; @@ -7362,7 +7361,7 @@ fn callBuiltin( }, else => {}, } - std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(pt)}); + std.debug.panic("type '{f}' is not a function calling builtin fn", .{callee_ty.fmt(pt)}); }; const func_ty_info = zcu.typeToFunc(func_ty).?; @@ -7746,7 +7745,7 @@ fn analyzeCall( if (!param_ty.isValidParamType(zcu)) { const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{ + return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{ opaque_str, param_ty.fmt(pt), }); } @@ -7843,7 +7842,7 @@ fn analyzeCall( if (!full_ty.isValidReturnType(zcu)) { const opaque_str = if (full_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, func_ret_ty_src, "{s}return type '{}' not allowed", .{ + return sema.fail(block, func_ret_ty_src, "{s}return type '{f}' not allowed", .{ opaque_str, full_ty.fmt(pt), }); } @@ -8301,7 +8300,7 @@ fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Typ } const owner_func_ty: Type = .fromInterned(zcu.funcInfo(sema.owner.unwrap().func).ty); if (owner_func_ty.toIntern() != func_ty.toIntern()) { - return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ + return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{f}' does not match type of calling function '{f}'", .{ func_ty.fmt(pt), owner_func_ty.fmt(pt), }); } @@ -8325,9 +8324,9 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node }); const child_type = try sema.resolveType(block, operand_src, inst_data.operand); if (child_type.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(pt)}); + return sema.fail(block, operand_src, "opaque type '{f}' cannot be optional", .{child_type.fmt(pt)}); } else if (child_type.zigTypeTag(zcu) == .null) { - return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(pt)}); + return sema.fail(block, operand_src, "type '{f}' cannot be optional", .{child_type.fmt(pt)}); } const opt_type = try pt.optionalType(child_type.toIntern()); @@ -8388,7 +8387,7 @@ fn zirVecArrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const vec_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type; switch (vec_ty.zigTypeTag(zcu)) { .array, .vector => {}, - else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{}'", .{vec_ty.fmt(pt)}), + else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{f}'", .{vec_ty.fmt(pt)}), } return Air.internedToRef(vec_ty.childType(zcu).toIntern()); } @@ -8456,7 +8455,7 @@ fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: const pt = sema.pt; const zcu = pt.zcu; if (elem_type.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(pt)}); + return sema.fail(block, elem_src, "array of opaque type '{f}' not allowed", .{elem_type.fmt(pt)}); } else if (elem_type.zigTypeTag(zcu) == .noreturn) { return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{}); } @@ -8492,7 +8491,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const payload = try sema.resolveType(block, rhs_src, extra.rhs); if (error_set.zigTypeTag(zcu) != .error_set) { - return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{ + return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{ error_set.fmt(pt), }); } @@ -8505,11 +8504,11 @@ fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, p const pt = sema.pt; const zcu = pt.zcu; if (payload_ty.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{ + return sema.fail(block, payload_src, "error union with payload of opaque type '{f}' not allowed", .{ payload_ty.fmt(pt), }); } else if (payload_ty.zigTypeTag(zcu) == .error_set) { - return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{ + return sema.fail(block, payload_src, "error union with payload of error set type '{f}' not allowed", .{ payload_ty.fmt(pt), }); } @@ -8647,9 +8646,9 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); if (lhs_ty.zigTypeTag(zcu) != .error_set) - return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(pt)}); + return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)}); if (rhs_ty.zigTypeTag(zcu) != .error_set) - return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(pt)}); + return sema.fail(block, rhs_src, "expected error set type, found '{f}'", .{rhs_ty.fmt(pt)}); // Anything merged with anyerror is anyerror. if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) { @@ -8759,7 +8758,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.fail( block, operand_src, - "untagged union '{}' cannot be converted to integer", + "untagged union '{f}' cannot be converted to integer", .{operand_ty.fmt(pt)}, ); }; @@ -8767,7 +8766,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError break :blk try sema.unionToTag(block, tag_ty, operand, operand_src); }, else => { - return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{ + return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{ operand_ty.fmt(pt), }); }, @@ -8778,7 +8777,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError // TODO: use correct solution // https://github.com/ziglang/zig/issues/15909 if (enum_tag_ty.enumFieldCount(zcu) == 0 and !enum_tag_ty.isNonexhaustiveEnum(zcu)) { - return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{}'", .{ + return sema.fail(block, operand_src, "cannot use @intFromEnum on empty enum '{f}'", .{ enum_tag_ty.fmt(pt), }); } @@ -8812,7 +8811,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const operand_ty = sema.typeOf(operand); if (dest_ty.zigTypeTag(zcu) != .@"enum") { - return sema.fail(block, src, "expected enum, found '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)}); } _ = try sema.checkIntType(block, operand_src, operand_ty); @@ -8822,7 +8821,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError if (try sema.intFitsInType(int_val, int_tag_ty, null)) { return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); } - return sema.fail(block, src, "int value '{}' out of range of non-exhaustive enum '{}'", .{ + return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{ int_val.fmtValueSema(pt, sema), dest_ty.fmt(pt), }); } @@ -8830,7 +8829,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.failWithUseOfUndef(block, operand_src); } if (!(try sema.enumHasInt(dest_ty, int_val))) { - return sema.fail(block, src, "enum '{}' has no tag with value '{}'", .{ + return sema.fail(block, src, "enum '{f}' has no tag with value '{f}'", .{ dest_ty.fmt(pt), int_val.fmtValueSema(pt, sema), }); } @@ -9024,7 +9023,7 @@ fn zirErrUnionPayload( const operand_src = src; const err_union_ty = sema.typeOf(operand); if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -9092,7 +9091,7 @@ fn analyzeErrUnionPayloadPtr( assert(operand_ty.zigTypeTag(zcu) == .pointer); if (operand_ty.childType(zcu).zigTypeTag(zcu) != .error_union) { - return sema.fail(block, src, "expected error union type, found '{}'", .{ + return sema.fail(block, src, "expected error union type, found '{f}'", .{ operand_ty.childType(zcu).fmt(pt), }); } @@ -9169,7 +9168,7 @@ fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air const zcu = pt.zcu; const operand_ty = sema.typeOf(operand); if (operand_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, src, "expected error union type, found '{}'", .{ + return sema.fail(block, src, "expected error union type, found '{f}'", .{ operand_ty.fmt(pt), }); } @@ -9205,7 +9204,7 @@ fn analyzeErrUnionCodePtr(sema: *Sema, block: *Block, src: LazySrcLoc, operand: assert(operand_ty.zigTypeTag(zcu) == .pointer); if (operand_ty.childType(zcu).zigTypeTag(zcu) != .error_union) { - return sema.fail(block, src, "expected error union type, found '{}'", .{ + return sema.fail(block, src, "expected error union type, found '{f}'", .{ operand_ty.childType(zcu).fmt(pt), }); } @@ -9450,19 +9449,18 @@ fn callConvSupportsVarArgs(cc: std.builtin.CallingConvention.Tag) bool { fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: std.builtin.CallingConvention.Tag) CompileError!void { const CallingConventionsSupportingVarArgsList = struct { arch: std.Target.Cpu.Arch, - pub fn format(ctx: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - _ = fmt; - _ = options; + pub fn format(ctx: @This(), w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); var first = true; for (calling_conventions_supporting_var_args) |cc_inner| { for (std.Target.Cpu.Arch.fromCallingConvention(cc_inner)) |supported_arch| { if (supported_arch == ctx.arch) break; } else continue; // callconv not supported by this arch if (!first) { - try writer.writeAll(", "); + try w.writeAll(", "); } first = false; - try writer.print("'{s}'", .{@tagName(cc_inner)}); + try w.print("'{s}'", .{@tagName(cc_inner)}); } } }; @@ -9472,7 +9470,7 @@ fn checkCallConvSupportsVarArgs(sema: *Sema, block: *Block, src: LazySrcLoc, cc: const msg = try sema.errMsg(src, "variadic function does not support '{s}' calling convention", .{@tagName(cc)}); errdefer msg.destroy(sema.gpa); const target = sema.pt.zcu.getTarget(); - try sema.errNote(src, msg, "supported calling conventions: {}", .{CallingConventionsSupportingVarArgsList{ .arch = target.cpu.arch }}); + try sema.errNote(src, msg, "supported calling conventions: {f}", .{CallingConventionsSupportingVarArgsList{ .arch = target.cpu.arch }}); break :msg msg; }); } @@ -9520,7 +9518,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type) } return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "value with non-mergable pointer type '{}' depends on runtime control flow", .{peer_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "value with non-mergable pointer type '{f}' depends on runtime control flow", .{peer_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); const runtime_src = block.runtime_cond orelse block.runtime_loop.?; @@ -9598,13 +9596,13 @@ fn funcCommon( } if (!param_ty.isValidParamType(zcu)) { const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, param_src, "parameter of {s}type '{}' not allowed", .{ + return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{ opaque_str, param_ty.fmt(pt), }); } if (!param_ty_generic and !target_util.fnCallConvAllowsZigTypes(cc) and !try sema.validateExternType(param_ty, .param_ty)) { const msg = msg: { - const msg = try sema.errMsg(param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ + const msg = try sema.errMsg(param_src, "parameter of type '{f}' not allowed in function with calling convention '{s}'", .{ param_ty.fmt(pt), @tagName(cc), }); errdefer msg.destroy(sema.gpa); @@ -9618,7 +9616,7 @@ fn funcCommon( } if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) { const msg = msg: { - const msg = try sema.errMsg(param_src, "parameter of type '{}' must be declared comptime", .{ + const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{ param_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -9798,7 +9796,7 @@ fn finishFunc( if (!return_type.isValidReturnType(zcu)) { const opaque_str = if (return_type.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; - return sema.fail(block, ret_ty_src, "{s}return type '{}' not allowed", .{ + return sema.fail(block, ret_ty_src, "{s}return type '{f}' not allowed", .{ opaque_str, return_type.fmt(pt), }); } @@ -9806,7 +9804,7 @@ fn finishFunc( !try sema.validateExternType(return_type, .ret_ty)) { const msg = msg: { - const msg = try sema.errMsg(ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ + const msg = try sema.errMsg(ret_ty_src, "return type '{f}' not allowed in function with calling convention '{s}'", .{ return_type.fmt(pt), @tagName(cc_resolved), }); errdefer msg.destroy(gpa); @@ -9828,7 +9826,7 @@ fn finishFunc( const msg = try sema.errMsg( ret_ty_src, - "function with comptime-only return type '{}' requires all parameters to be comptime", + "function with comptime-only return type '{f}' requires all parameters to be comptime", .{return_type.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -9897,17 +9895,16 @@ fn finishFunc( .bad_arch => |allowed_archs| { const ArchListFormatter = struct { archs: []const std.Target.Cpu.Arch, - pub fn format(formatter: @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { - _ = fmt; - _ = options; + pub fn format(formatter: @This(), w: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); for (formatter.archs, 0..) |arch, i| { if (i != 0) - try writer.writeAll(", "); - try writer.print("'{s}'", .{@tagName(arch)}); + try w.writeAll(", "); + try w.print("'{s}'", .{@tagName(arch)}); } } }; - return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {}", .{ + return sema.fail(block, cc_src, "calling convention '{s}' only available on architectures {f}", .{ @tagName(cc_resolved), ArchListFormatter{ .archs = allowed_archs }, }); @@ -10008,7 +10005,7 @@ fn analyzeAs( const operand = try sema.resolveInst(zir_operand); const dest_ty = try sema.resolveTypeOrPoison(block, src, zir_dest_type) orelse return operand; switch (dest_ty.zigTypeTag(zcu)) { - .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{}'", .{dest_ty.fmt(pt)}), + .@"opaque" => return sema.fail(block, src, "cannot cast to opaque type '{f}'", .{dest_ty.fmt(pt)}), .noreturn => return sema.fail(block, src, "cannot cast to noreturn", .{}), else => {}, } @@ -10036,12 +10033,12 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! const ptr_ty = operand_ty.scalarType(zcu); const is_vector = operand_ty.zigTypeTag(zcu) == .vector; if (!ptr_ty.isPtrAtRuntime(zcu)) { - return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(pt)}); + return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}); } const pointee_ty = ptr_ty.childType(zcu); if (try ptr_ty.comptimeOnlySema(pt)) { const msg = msg: { - const msg = try sema.errMsg(ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(pt)}); + const msg = try sema.errMsg(ptr_src, "comptime-only type '{f}' has no pointer address", .{pointee_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsComptime(msg, ptr_src, pointee_ty); break :msg msg; @@ -10289,14 +10286,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .type, .undefined, .void, - => return sema.fail(block, src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)}), + => return sema.fail(block, src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}), .@"enum" => { const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (operand_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(src, msg, "use @enumFromInt to cast from '{}'", .{operand_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(src, msg, "use @enumFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}), else => {}, } @@ -10307,11 +10304,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .pointer => { const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast to '{}'", .{dest_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (operand_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{}'", .{operand_ty.fmt(pt)}), - .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}), + .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{f}'", .{operand_ty.fmt(pt)}), else => {}, } @@ -10325,7 +10322,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .@"union" => "union", else => unreachable, }; - return sema.fail(block, src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{ + return sema.fail(block, src, "cannot @bitCast to '{f}'; {s} does not have a guaranteed in-memory layout", .{ dest_ty.fmt(pt), container, }); }, @@ -10353,14 +10350,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .type, .undefined, .void, - => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)}), + => return sema.fail(block, operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}), .@"enum" => { const msg = msg: { - const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (dest_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromEnum to cast to '{}'", .{dest_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromEnum to cast to '{f}'", .{dest_ty.fmt(pt)}), else => {}, } @@ -10370,11 +10367,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air }, .pointer => { const msg = msg: { - const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (dest_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{}'", .{dest_ty.fmt(pt)}), - .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(pt)}), + .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{f}'", .{dest_ty.fmt(pt)}), + .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{f}'", .{dest_ty.fmt(pt)}), else => {}, } @@ -10388,7 +10385,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .@"union" => "union", else => unreachable, }; - return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{ + return sema.fail(block, operand_src, "cannot @bitCast from '{f}'; {s} does not have a guaranteed in-memory layout", .{ operand_ty.fmt(pt), container, }); }, @@ -10431,7 +10428,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A else => return sema.fail( block, src, - "expected float or vector type, found '{}'", + "expected float or vector type, found '{f}'", .{dest_ty.fmt(pt)}, ), }; @@ -10441,7 +10438,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A else => return sema.fail( block, operand_src, - "expected float or vector type, found '{}'", + "expected float or vector type, found '{f}'", .{operand_ty.fmt(pt)}, ), } @@ -10525,7 +10522,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (indexable_ty.zigTypeTag(zcu) != .pointer) { const capture_src = block.src(.{ .for_capture_from_input = inst_data.src_node }); const msg = msg: { - const msg = try sema.errMsg(capture_src, "pointer capture of non pointer type '{}'", .{ + const msg = try sema.errMsg(capture_src, "pointer capture of non pointer type '{f}'", .{ indexable_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -10667,7 +10664,7 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE const lhs_ptr_ty = sema.typeOf(try sema.resolveInst(inst_data.operand)); const lhs_ty = switch (lhs_ptr_ty.zigTypeTag(zcu)) { .pointer => lhs_ptr_ty.childType(zcu), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{lhs_ptr_ty.fmt(pt)}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{lhs_ptr_ty.fmt(pt)}), }; const sentinel_ty: Type = switch (lhs_ty.zigTypeTag(zcu)) { @@ -10682,7 +10679,7 @@ fn zirSliceSentinelTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE }; }, }, - else => return sema.fail(block, src, "slice of non-array type '{}'", .{lhs_ty.fmt(pt)}), + else => return sema.fail(block, src, "slice of non-array type '{f}'", .{lhs_ty.fmt(pt)}), }; return Air.internedToRef(sentinel_ty.toIntern()); @@ -10877,7 +10874,7 @@ const SwitchProngAnalysis = struct { .base_node_inst = capture_src.base_node_inst, .offset = .{ .switch_tag_capture = capture_src.offset.switch_capture }, }; - return sema.fail(block, tag_capture_src, "cannot capture tag of non-union type '{}'", .{ + return sema.fail(block, tag_capture_src, "cannot capture tag of non-union type '{f}'", .{ operand_ty.fmt(pt), }); } @@ -11309,7 +11306,7 @@ fn switchCond( .@"enum", => { if (operand_ty.isSlice(zcu)) { - return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(pt)}); + return sema.fail(block, src, "switch on type '{f}'", .{operand_ty.fmt(pt)}); } if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| { return Air.internedToRef(opv.toIntern()); @@ -11344,7 +11341,7 @@ fn switchCond( .vector, .frame, .@"anyframe", - => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(pt)}), + => return sema.fail(block, src, "switch on type '{f}'", .{operand_ty.fmt(pt)}), } } @@ -11445,7 +11442,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp operand_ty; if (operand_err_set.zigTypeTag(zcu) != .error_union) { - return sema.fail(block, switch_src, "expected error union type, found '{}'", .{ + return sema.fail(block, switch_src, "expected error union type, found '{f}'", .{ operand_ty.fmt(pt), }); } @@ -11699,7 +11696,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r // Even if the operand is comptime-known, this `switch` is runtime. if (try operand_ty.comptimeOnlySema(pt)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{}'", .{operand_ty.fmt(pt)}); + const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{}); break :msg msg; @@ -11923,14 +11920,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r cond_ty, i, msg, - "unhandled enumeration value: '{}'", + "unhandled enumeration value: '{f}'", .{field_name.fmt(&zcu.intern_pool)}, ); } try sema.errNote( cond_ty.srcLoc(zcu), msg, - "enum '{}' declared here", + "enum '{f}' declared here", .{cond_ty.fmt(pt)}, ); break :msg msg; @@ -12142,7 +12139,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r return sema.fail( block, src, - "else prong required when switching on type '{}'", + "else prong required when switching on type '{f}'", .{cond_ty.fmt(pt)}, ); } @@ -12218,7 +12215,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r .@"anyframe", .comptime_float, .float, - => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{ + => return sema.fail(block, operand_src, "invalid switch operand type '{f}'", .{ raw_operand_ty.fmt(pt), }), } @@ -12747,7 +12744,7 @@ fn analyzeSwitchRuntimeBlock( if (special.is_inline) switch (operand_ty.zigTypeTag(zcu)) { .@"enum" => { if (operand_ty.isNonexhaustiveEnum(zcu) and !union_originally) { - return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ + return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ operand_ty.fmt(pt), }); } @@ -12803,7 +12800,7 @@ fn analyzeSwitchRuntimeBlock( }, .error_set => { if (operand_ty.isAnyError(zcu)) { - return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ + return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ operand_ty.fmt(pt), }); } @@ -12964,7 +12961,7 @@ fn analyzeSwitchRuntimeBlock( cases_extra.appendSliceAssumeCapacity(@ptrCast(case_block.instructions.items)); } }, - else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ + else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{f}' for 'inline else'", .{ operand_ty.fmt(pt), }), }; @@ -13478,7 +13475,7 @@ fn validateErrSetSwitch( try sema.errNote( src, msg, - "unhandled error value: 'error.{}'", + "unhandled error value: 'error.{f}'", .{error_name.fmt(ip)}, ); } @@ -13704,7 +13701,7 @@ fn validateSwitchNoRange( const msg = msg: { const msg = try sema.errMsg( operand_src, - "ranges not allowed when switching on type '{}'", + "ranges not allowed when switching on type '{f}'", .{operand_ty.fmt(sema.pt)}, ); errdefer msg.destroy(sema.gpa); @@ -13862,7 +13859,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .array_type => break :hf field_name.eqlSlice("len", ip), else => {}, } - return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ + return sema.fail(block, ty_src, "type '{f}' does not support '@hasField'", .{ ty.fmt(pt), }); }; @@ -14050,7 +14047,7 @@ fn zirShl( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' at index '{d}' is too large for operand type '{f}'", .{ rhs_elem.fmtValueSema(pt, sema), i, scalar_ty.fmt(pt), @@ -14058,7 +14055,7 @@ fn zirShl( } } } else if (rhs_val.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' is too large for operand type '{f}'", .{ rhs_val.fmtValueSema(pt, sema), scalar_ty.fmt(pt), }); @@ -14069,14 +14066,14 @@ fn zirShl( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.lt, try pt.intValue(scalar_rhs_ty, 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}' at index '{d}'", .{ rhs_elem.fmtValueSema(pt, sema), i, }); } } } else if (rhs_val.compareHetero(.lt, try pt.intValue(rhs_ty, 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}'", .{ rhs_val.fmtValueSema(pt, sema), }); } @@ -14231,7 +14228,7 @@ fn zirShr( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' at index '{d}' is too large for operand type '{f}'", .{ rhs_elem.fmtValueSema(pt, sema), i, scalar_ty.fmt(pt), @@ -14239,7 +14236,7 @@ fn zirShr( } } } else if (rhs_val.compareHetero(.gte, bit_value, zcu)) { - return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ + return sema.fail(block, rhs_src, "shift amount '{f}' is too large for operand type '{f}'", .{ rhs_val.fmtValueSema(pt, sema), scalar_ty.fmt(pt), }); @@ -14250,14 +14247,14 @@ fn zirShr( while (i < rhs_ty.vectorLen(zcu)) : (i += 1) { const rhs_elem = try rhs_val.elemValue(pt, i); if (rhs_elem.compareHetero(.lt, try pt.intValue(rhs_ty.childType(zcu), 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}' at index '{d}'", .{ rhs_elem.fmtValueSema(pt, sema), i, }); } } } else if (rhs_val.compareHetero(.lt, try pt.intValue(rhs_ty, 0), zcu)) { - return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ + return sema.fail(block, rhs_src, "shift by negative amount '{f}'", .{ rhs_val.fmtValueSema(pt, sema), }); } @@ -14543,11 +14540,11 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: { if (lhs_is_tuple) break :lhs_info undefined; - return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(pt)}); + return sema.fail(block, lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)}); }; const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse { assert(!rhs_is_tuple); - return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(pt)}); + return sema.fail(block, rhs_src, "expected indexable; found '{f}'", .{rhs_ty.fmt(pt)}); }; const resolved_elem_ty = t: { @@ -15000,7 +14997,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // Analyze the lhs first, to catch the case that someone tried to do exponentiation const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse { const msg = msg: { - const msg = try sema.errMsg(lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(pt)}); + const msg = try sema.errMsg(lhs_src, "expected indexable; found '{f}'", .{lhs_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); switch (lhs_ty.zigTypeTag(zcu)) { .int, .float, .comptime_float, .comptime_int, .vector => { @@ -15132,7 +15129,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .int, .comptime_int, .float, .comptime_float => false, else => true, }) { - return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(pt)}); + return sema.fail(block, src, "negation of type '{f}'", .{rhs_ty.fmt(pt)}); } if (rhs_scalar_ty.isAnyFloat()) { @@ -15163,7 +15160,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! switch (rhs_scalar_ty.zigTypeTag(zcu)) { .int, .comptime_int, .float, .comptime_float => {}, - else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(pt)}), + else => return sema.fail(block, src, "negation of type '{f}'", .{rhs_ty.fmt(pt)}), } const lhs = Air.internedToRef((try sema.splat(rhs_ty, try pt.intValue(rhs_scalar_ty, 0))).toIntern()); @@ -15237,7 +15234,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins return sema.fail( block, src, - "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'", + "ambiguous coercion of division operands '{f}' and '{f}'; non-zero remainder '{f}'", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), rem.fmtValueSema(pt, sema) }, ); } @@ -15289,7 +15286,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins return sema.fail( block, src, - "division with '{}' and '{}': signed integers must use @divTrunc, @divFloor, or @divExact", + "division with '{f}' and '{f}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt) }, ); } @@ -15951,7 +15948,7 @@ fn zirOverflowArithmetic( const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src); if (dest_ty.scalarType(zcu).zigTypeTag(zcu) != .int) { - return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, src, "expected vector of integers or integer tag type, found '{f}'", .{dest_ty.fmt(pt)}); } const maybe_lhs_val = try sema.resolveValue(lhs); @@ -16157,14 +16154,14 @@ fn analyzeArithmetic( return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction"); } if (!lhs_ty.elemType2(zcu).eql(rhs_ty.elemType2(zcu), zcu)) { - return sema.fail(block, src, "incompatible pointer arithmetic operands '{}' and '{}'", .{ + return sema.fail(block, src, "incompatible pointer arithmetic operands '{f}' and '{f}'", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), }); } const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu); if (elem_size == 0) { - return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{ + return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{ lhs_ty.elemType2(zcu).fmt(pt), }); } @@ -16215,7 +16212,7 @@ fn analyzeArithmetic( }; if (!try lhs_ty.elemType2(zcu).hasRuntimeBitsSema(pt)) { - return sema.fail(block, src, "pointer arithmetic requires element type '{}' to have runtime bits", .{ + return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{ lhs_ty.elemType2(zcu).fmt(pt), }); } @@ -16619,7 +16616,7 @@ fn zirCmpEq( if (lhs_ty_tag == .null or rhs_ty_tag == .null) { const non_null_type = if (lhs_ty_tag == .null) rhs_ty else lhs_ty; - return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(pt)}); + return sema.fail(block, src, "comparison of '{f}' with null", .{non_null_type.fmt(pt)}); } if (lhs_ty_tag == .@"union" and (rhs_ty_tag == .enum_literal or rhs_ty_tag == .@"enum")) { @@ -16676,7 +16673,7 @@ fn analyzeCmpUnionTag( const msg = msg: { const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(union_ty.srcLoc(zcu), msg, "union '{}' is not a tagged union", .{union_ty.fmt(pt)}); + try sema.errNote(union_ty.srcLoc(zcu), msg, "union '{f}' is not a tagged union", .{union_ty.fmt(pt)}); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); @@ -16762,7 +16759,7 @@ fn analyzeCmp( const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); if (!resolved_type.isSelfComparable(zcu, is_equality_cmp)) { - return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{ + return sema.fail(block, src, "operator {s} not allowed for type '{f}'", .{ compareOperatorName(op), resolved_type.fmt(pt), }); } @@ -16871,7 +16868,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .undefined, .null, .@"opaque", - => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(pt)}), + => return sema.fail(block, operand_src, "no size available for type '{f}'", .{ty.fmt(pt)}), .type, .enum_literal, @@ -16912,7 +16909,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A .undefined, .null, .@"opaque", - => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(pt)}), + => return sema.fail(block, operand_src, "no size available for type '{f}'", .{operand_ty.fmt(pt)}), .type, .enum_literal, @@ -18212,7 +18209,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi return sema.fail( block, src, - "bit shifting operation expected integer type, found '{}'", + "bit shifting operation expected integer type, found '{f}'", .{operand.fmt(pt)}, ); } @@ -18451,7 +18448,7 @@ fn checkSentinelType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !voi const pt = sema.pt; const zcu = pt.zcu; if (!ty.isSelfComparable(zcu, true)) { - return sema.fail(block, src, "non-scalar sentinel type '{}'", .{ty.fmt(pt)}); + return sema.fail(block, src, "non-scalar sentinel type '{f}'", .{ty.fmt(pt)}); } } @@ -18501,7 +18498,7 @@ fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { const zcu = pt.zcu; switch (ty.zigTypeTag(zcu)) { .error_set, .error_union, .undefined => return, - else => return sema.fail(block, src, "expected error union type, found '{}'", .{ + else => return sema.fail(block, src, "expected error union type, found '{f}'", .{ ty.fmt(pt), }), } @@ -18645,7 +18642,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError! const pt = sema.pt; const zcu = pt.zcu; if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -18705,7 +18702,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr const pt = sema.pt; const zcu = pt.zcu; if (err_union_ty.zigTypeTag(zcu) != .error_union) { - return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ + return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{ err_union_ty.fmt(pt), }); } @@ -18903,7 +18900,7 @@ fn zirRetImplicit( const base_tag = sema.fn_ret_ty.baseZigTypeTag(zcu); if (base_tag == .noreturn) { const msg = msg: { - const msg = try sema.errMsg(ret_ty_src, "function declared '{}' implicitly returns", .{ + const msg = try sema.errMsg(ret_ty_src, "function declared '{f}' implicitly returns", .{ sema.fn_ret_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -18913,7 +18910,7 @@ fn zirRetImplicit( return sema.failWithOwnedErrorMsg(block, msg); } else if (base_tag != .void) { const msg = msg: { - const msg = try sema.errMsg(ret_ty_src, "function with non-void return type '{}' implicitly returns", .{ + const msg = try sema.errMsg(ret_ty_src, "function with non-void return type '{f}' implicitly returns", .{ sema.fn_ret_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -19302,13 +19299,13 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (host_size != 0) { if (bit_offset >= host_size * 8) { - return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} starts {} bits after the end of a {} byte host integer", .{ + return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {} starts {} bits after the end of a {} byte host integer", .{ elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size, }); } const elem_bit_size = try elem_ty.bitSizeSema(pt); if (elem_bit_size > host_size * 8 - bit_offset) { - return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{ + return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{ elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size, }); } @@ -19323,7 +19320,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } else if (inst_data.size == .c) { if (!try sema.validateExternType(elem_ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src, elem_ty, .other); @@ -19340,7 +19337,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (host_size != 0 and !try sema.validatePackedType(elem_ty)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{}'", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotPacked(msg, elem_ty_src, elem_ty); break :msg msg; @@ -19509,7 +19506,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; const union_ty = try sema.resolveType(block, ty_src, extra.union_type); if (union_ty.zigTypeTag(pt.zcu) != .@"union") { - return sema.fail(block, ty_src, "expected union type, found '{}'", .{union_ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected union type, found '{f}'", .{union_ty.fmt(pt)}); } const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .union_field_name }); const init = try sema.resolveInst(extra.init); @@ -19672,7 +19669,7 @@ fn zirStructInit( const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(resolved_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, resolved_ty); @@ -19791,7 +19788,7 @@ fn finishStructInit( const field_init = struct_type.fieldInit(ip, i); if (field_init == .none) { const field_name = struct_type.field_names.get(ip)[i]; - const template = "missing struct field: {}"; + const template = "missing struct field: {f}"; const args = .{field_name.fmt(ip)}; if (root_msg) |msg| { try sema.errNote(init_src, msg, template, args); @@ -20406,7 +20403,7 @@ fn fieldType( }, else => {}, } - return sema.fail(block, ty_src, "expected struct or union; found '{}'", .{ + return sema.fail(block, ty_src, "expected struct or union; found '{f}'", .{ cur_ty.fmt(pt), }); } @@ -20453,7 +20450,7 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); const ty = try sema.resolveType(block, operand_src, inst_data.operand); if (ty.isNoReturn(zcu)) { - return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.pt)}); + return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)}); } const val = try ty.lazyAbiAlignment(sema.pt); return Air.internedToRef(val.toIntern()); @@ -20531,7 +20528,7 @@ fn zirAbs( else => return sema.fail( block, operand_src, - "expected integer, float, or vector of either integers or floats, found '{}'", + "expected integer, float, or vector of either integers or floats, found '{f}'", .{operand_ty.fmt(pt)}, ), }; @@ -20600,7 +20597,7 @@ fn zirUnaryMath( else => return sema.fail( block, operand_src, - "expected vector of floats or float type, found '{}'", + "expected vector of floats or float type, found '{f}'", .{operand_ty.fmt(pt)}, ), } @@ -20629,8 +20626,8 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air }, .@"enum" => operand_ty, .@"union" => operand_ty.unionTagType(zcu) orelse - return sema.fail(block, src, "union '{}' is untagged", .{operand_ty.fmt(pt)}), - else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{ + return sema.fail(block, src, "union '{f}' is untagged", .{operand_ty.fmt(pt)}), + else => return sema.fail(block, operand_src, "expected enum or union; found '{f}'", .{ operand_ty.fmt(pt), }), }; @@ -20638,7 +20635,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air // TODO I don't think this is the correct way to handle this but // it prevents a crash. // https://github.com/ziglang/zig/issues/15909 - return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{ + return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{f}'", .{ enum_ty.fmt(pt), }); } @@ -20646,7 +20643,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { const field_index = enum_ty.enumTagFieldIndex(val, zcu) orelse { const msg = msg: { - const msg = try sema.errMsg(src, "no field with value '{}' in enum '{}'", .{ + const msg = try sema.errMsg(src, "no field with value '{f}' in enum '{f}'", .{ val.fmtValueSema(pt, sema), enum_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -20833,7 +20830,7 @@ fn zirReify( } else if (ptr_size == .c) { if (!try sema.validateExternType(elem_ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "C pointers cannot point to non-C-ABI-compatible type '{f}'", .{elem_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, elem_ty, .other); @@ -20946,7 +20943,7 @@ fn zirReify( _ = try pt.getErrorValue(name); const gop = names.getOrPutAssumeCapacity(name); if (gop.found_existing) { - return sema.fail(block, src, "duplicate error '{}'", .{ + return sema.fail(block, src, "duplicate error '{f}'", .{ name.fmt(ip), }); } @@ -21294,7 +21291,7 @@ fn reifyEnum( if (!try sema.intFitsInType(field_value_val, tag_ty, null)) { // TODO: better source location - return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{ + return sema.fail(block, src, "field '{f}' with enumeration value '{f}' is too large for backing int type '{f}'", .{ field_name.fmt(ip), field_value_val.fmtValueSema(pt, sema), tag_ty.fmt(pt), @@ -21305,14 +21302,14 @@ fn reifyEnum( if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| { return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) { .name => msg: { - const msg = try sema.errMsg(src, "duplicate enum field '{}'", .{field_name.fmt(ip)}); + const msg = try sema.errMsg(src, "duplicate enum field '{f}'", .{field_name.fmt(ip)}); errdefer msg.destroy(gpa); _ = conflict.prev_field_idx; // TODO: this note is incorrect try sema.errNote(src, msg, "other field here", .{}); break :msg msg; }, .value => msg: { - const msg = try sema.errMsg(src, "enum tag value {} already taken", .{field_value_val.fmtValueSema(pt, sema)}); + const msg = try sema.errMsg(src, "enum tag value {f} already taken", .{field_value_val.fmtValueSema(pt, sema)}); errdefer msg.destroy(gpa); _ = conflict.prev_field_idx; // TODO: this note is incorrect try sema.errNote(src, msg, "other enum tag value here", .{}); @@ -21460,13 +21457,13 @@ fn reifyUnion( const enum_index = enum_tag_ty.enumFieldIndex(field_name, zcu) orelse { // TODO: better source location - return sema.fail(block, src, "no field named '{}' in enum '{}'", .{ + return sema.fail(block, src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), enum_tag_ty.fmt(pt), }); }; if (seen_tags.isSet(enum_index)) { // TODO: better source location - return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)}); + return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)}); } seen_tags.set(enum_index); @@ -21487,7 +21484,7 @@ fn reifyUnion( var it = seen_tags.iterator(.{ .kind = .unset }); while (it.next()) |enum_index| { const field_name = enum_tag_ty.enumFieldName(enum_index, zcu); - try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{}' missing, declared here", .{ + try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{f}' missing, declared here", .{ field_name.fmt(ip), }); } @@ -21512,7 +21509,7 @@ fn reifyUnion( const gop = field_names.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { // TODO: better source location - return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)}); + return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)}); } field_ty.* = field_type_val.toIntern(); @@ -21544,7 +21541,7 @@ fn reifyUnion( } if (layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .union_field); @@ -21554,7 +21551,7 @@ fn reifyUnion( }); } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotPacked(msg, src, field_ty); @@ -21636,7 +21633,7 @@ fn reifyTuple( const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail( block, src, - "tuple cannot have non-numeric field '{}'", + "tuple cannot have non-numeric field '{f}'", .{field_name.fmt(ip)}, ); if (field_name_index != field_idx) { @@ -21814,7 +21811,7 @@ fn reifyStruct( const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined); if (struct_type.addFieldName(ip, field_name)) |prev_index| { _ = prev_index; // TODO: better source location - return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)}); + return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); } if (any_aligned_fields) { @@ -21883,7 +21880,7 @@ fn reifyStruct( } if (layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotExtern(msg, src, field_ty, .struct_field); @@ -21893,7 +21890,7 @@ fn reifyStruct( }); } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(gpa); try sema.explainWhyTypeIsNotPacked(msg, src, field_ty); @@ -21970,7 +21967,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C if (!try sema.validateExternType(arg_ty, .param_ty)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "cannot get '{}' from variadic argument", .{arg_ty.fmt(sema.pt)}); + const msg = try sema.errMsg(ty_src, "cannot get '{f}' from variadic argument", .{arg_ty.fmt(sema.pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, ty_src, arg_ty, .param_ty); @@ -22029,7 +22026,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0); const ty = try sema.resolveType(block, ty_src, inst_data.operand); - const type_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{}", .{ty.fmt(pt)}, .no_embedded_nulls); + const type_name = try ip.getOrPutStringFmt(sema.gpa, pt.tid, "{f}", .{ty.fmt(pt)}, .no_embedded_nulls); return sema.addNullTerminatedStrLit(type_name); } @@ -22157,7 +22154,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! if (ptr_ty.isSlice(zcu)) { const msg = msg: { - const msg = try sema.errMsg(src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "integer cannot be converted to slice type '{f}'", .{ptr_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "slice length cannot be inferred from address", .{}); break :msg msg; @@ -22184,7 +22181,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! } if (try ptr_ty.comptimeOnlySema(pt)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "pointer to comptime-only type '{}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "pointer to comptime-only type '{f}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsComptime(msg, src, ptr_ty); @@ -22241,7 +22238,7 @@ fn ptrFromIntVal( } const addr = try operand_val.toUnsignedIntSema(pt); if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0) - return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(pt)}); + return sema.fail(block, operand_src, "pointer type '{f}' does not allow address zero", .{ptr_ty.fmt(pt)}); if (addr != 0 and ptr_align != .none) { const masked_addr = if (ptr_ty.childType(zcu).fnPtrMaskOrNull(zcu)) |mask| addr & mask @@ -22249,7 +22246,7 @@ fn ptrFromIntVal( addr; if (!ptr_align.check(masked_addr)) { - return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(pt)}); + return sema.fail(block, operand_src, "pointer type '{f}' requires aligned address", .{ptr_ty.fmt(pt)}); } } @@ -22294,8 +22291,8 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData errdefer msg.destroy(sema.gpa); const dest_payload_ty = dest_ty.errorUnionPayload(zcu); const operand_payload_ty = operand_ty.errorUnionPayload(zcu); - try sema.errNote(src, msg, "destination payload is '{}'", .{dest_payload_ty.fmt(pt)}); - try sema.errNote(src, msg, "operand payload is '{}'", .{operand_payload_ty.fmt(pt)}); + try sema.errNote(src, msg, "destination payload is '{f}'", .{dest_payload_ty.fmt(pt)}); + try sema.errNote(src, msg, "operand payload is '{f}'", .{operand_payload_ty.fmt(pt)}); try addDeclaredHereNote(sema, msg, dest_ty); try addDeclaredHereNote(sema, msg, operand_ty); break :msg msg; @@ -22340,7 +22337,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData break :disjoint true; }; if (disjoint and !(operand_tag == .error_union and dest_tag == .error_union)) { - return sema.fail(block, src, "error sets '{}' and '{}' have no common errors", .{ + return sema.fail(block, src, "error sets '{f}' and '{f}' have no common errors", .{ operand_err_ty.fmt(pt), dest_err_ty.fmt(pt), }); } @@ -22360,7 +22357,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData }; if (!dest_err_ty.isAnyError(zcu) and !Type.errorSetHasFieldIp(ip, dest_err_ty.toIntern(), err_name)) { - return sema.fail(block, src, "'error.{}' not a member of error set '{}'", .{ + return sema.fail(block, src, "'error.{f}' not a member of error set '{f}'", .{ err_name.fmt(ip), dest_err_ty.fmt(pt), }); } @@ -22520,13 +22517,15 @@ fn ptrCastFull( const src_elem_size = src_elem_ty.abiSize(zcu); const dest_elem_size = dest_elem_ty.abiSize(zcu); if (dest_elem_size == 0) { - return sema.fail(block, src, "cannot infer length of slice of zero-bit '{}' from '{}'", .{ dest_elem_ty.fmt(pt), operand_ty.fmt(pt) }); + return sema.fail(block, src, "cannot infer length of slice of zero-bit '{f}' from '{f}'", .{ + dest_elem_ty.fmt(pt), operand_ty.fmt(pt), + }); } if (opt_src_len) |src_len| { const bytes = src_len * src_elem_size; const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) { .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}), - .one => return sema.fail(block, src, "type '{}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), + .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), else => unreachable, }; break :len .{ .constant = dest_len }; @@ -22544,7 +22543,9 @@ fn ptrCastFull( // The source value has `src_len * src_base_per_elem` values of type `src_base_ty`. // The result value will have `dest_len * dest_base_per_elem` values of type `dest_base_ty`. if (dest_base_ty.toIntern() != src_base_ty.toIntern()) { - return sema.fail(block, src, "cannot infer length of comptime-only '{}' from incompatible '{}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }); + return sema.fail(block, src, "cannot infer length of comptime-only '{f}' from incompatible '{f}'", .{ + dest_ty.fmt(pt), operand_ty.fmt(pt), + }); } // `src_base_ty` is comptime-only, so `src_elem_ty` is comptime-only, so `operand_ty` is // comptime-only, so `operand` is comptime-known, so `opt_src_len` is non-`null`. @@ -22552,7 +22553,7 @@ fn ptrCastFull( const base_len = src_len * src_base_per_elem; const dest_len = std.math.divExact(u64, base_len, dest_base_per_elem) catch switch (src_info.flags.size) { .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}), - .one => return sema.fail(block, src, "type '{}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), + .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), else => unreachable, }; break :len .{ .constant = dest_len }; @@ -22613,7 +22614,7 @@ fn ptrCastFull( ); if (imc_res == .ok) break :check_child; return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "pointer element type '{}' cannot coerce into element type '{}'", .{ + const msg = try sema.errMsg(src, "pointer element type '{f}' cannot coerce into element type '{f}'", .{ src_child.fmt(pt), dest_child.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -22640,11 +22641,11 @@ fn ptrCastFull( } return sema.failWithOwnedErrorMsg(block, msg: { const msg = if (src_info.sentinel == .none) blk: { - break :blk try sema.errMsg(src, "destination pointer requires '{}' sentinel", .{ + break :blk try sema.errMsg(src, "destination pointer requires '{f}' sentinel", .{ Value.fromInterned(dest_info.sentinel).fmtValueSema(pt, sema), }); } else blk: { - break :blk try sema.errMsg(src, "pointer sentinel '{}' cannot coerce into pointer sentinel '{}'", .{ + break :blk try sema.errMsg(src, "pointer sentinel '{f}' cannot coerce into pointer sentinel '{f}'", .{ Value.fromInterned(src_info.sentinel).fmtValueSema(pt, sema), Value.fromInterned(dest_info.sentinel).fmtValueSema(pt, sema), }); @@ -22686,7 +22687,7 @@ fn ptrCastFull( if (dest_allows_zero) break :check_allowzero; return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "'{}' could have null values which are illegal in type '{}'", .{ + const msg = try sema.errMsg(src, "'{f}' could have null values which are illegal in type '{f}'", .{ operand_ty.fmt(pt), dest_ty.fmt(pt), }); @@ -22714,10 +22715,10 @@ fn ptrCastFull( return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "{s} increases pointer alignment", .{operation}); errdefer msg.destroy(sema.gpa); - try sema.errNote(operand_src, msg, "'{}' has alignment '{d}'", .{ + try sema.errNote(operand_src, msg, "'{f}' has alignment '{d}'", .{ operand_ty.fmt(pt), src_align.toByteUnits() orelse 0, }); - try sema.errNote(src, msg, "'{}' has alignment '{d}'", .{ + try sema.errNote(src, msg, "'{f}' has alignment '{d}'", .{ dest_ty.fmt(pt), dest_align.toByteUnits() orelse 0, }); try sema.errNote(src, msg, "use @alignCast to assert pointer alignment", .{}); @@ -22731,10 +22732,10 @@ fn ptrCastFull( return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "{s} changes pointer address space", .{operation}); errdefer msg.destroy(sema.gpa); - try sema.errNote(operand_src, msg, "'{}' has address space '{s}'", .{ + try sema.errNote(operand_src, msg, "'{f}' has address space '{s}'", .{ operand_ty.fmt(pt), @tagName(src_info.flags.address_space), }); - try sema.errNote(src, msg, "'{}' has address space '{s}'", .{ + try sema.errNote(src, msg, "'{f}' has address space '{s}'", .{ dest_ty.fmt(pt), @tagName(dest_info.flags.address_space), }); try sema.errNote(src, msg, "use @addrSpaceCast to cast pointer address space", .{}); @@ -22801,7 +22802,7 @@ fn ptrCastFull( if (operand_val.isNull(zcu)) { if (!dest_ty.ptrAllowsZero(zcu)) { - return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, operand_src, "null pointer casted to type '{f}'", .{dest_ty.fmt(pt)}); } if (dest_ty.zigTypeTag(zcu) == .optional) { return Air.internedToRef((try pt.nullValue(dest_ty)).toIntern()); @@ -23092,7 +23093,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const operand_is_vector = operand_ty.zigTypeTag(zcu) == .vector; const dest_is_vector = dest_ty.zigTypeTag(zcu) == .vector; if (operand_is_vector != dest_is_vector) { - return sema.fail(block, operand_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }); + return sema.fail(block, operand_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }); } if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_int) { @@ -23112,7 +23113,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } if (operand_info.signedness != dest_info.signedness) { - return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{ + return sema.fail(block, operand_src, "expected {s} integer type, found '{f}'", .{ @tagName(dest_info.signedness), operand_ty.fmt(pt), }); } @@ -23121,7 +23122,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const msg = msg: { const msg = try sema.errMsg( src, - "destination type '{}' has more bits than source type '{}'", + "destination type '{f}' has more bits than source type '{f}'", .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }, ); errdefer msg.destroy(sema.gpa); @@ -23239,7 +23240,7 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai return sema.fail( block, operand_src, - "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits", + "@byteSwap requires the number of bits to be evenly divisible by 8, but {f} has {} bits", .{ scalar_ty.fmt(pt), bits }, ); } @@ -23359,7 +23360,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 try ty.resolveLayout(pt); switch (ty.zigTypeTag(zcu)) { .@"struct" => {}, - else => return sema.fail(block, ty_src, "expected struct type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, ty_src, "expected struct type, found '{f}'", .{ty.fmt(pt)}), } const field_index = if (ty.isTuple(zcu)) blk: { @@ -23394,7 +23395,7 @@ fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Com const zcu = pt.zcu; switch (ty.zigTypeTag(zcu)) { .@"struct", .@"enum", .@"union", .@"opaque" => return, - else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{f}'", .{ty.fmt(pt)}), } } @@ -23405,7 +23406,7 @@ fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileEr switch (ty.zigTypeTag(zcu)) { .comptime_int => return true, .int => return false, - else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, src, "expected integer type, found '{f}'", .{ty.fmt(pt)}), } } @@ -23459,7 +23460,7 @@ fn checkPtrOperand( const msg = msg: { const msg = try sema.errMsg( ty_src, - "expected pointer, found '{}'", + "expected pointer, found '{f}'", .{ty.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -23473,7 +23474,7 @@ fn checkPtrOperand( .optional => if (ty.childType(zcu).zigTypeTag(zcu) == .pointer) return, else => {}, } - return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected pointer type, found '{f}'", .{ty.fmt(pt)}); } fn checkPtrType( @@ -23491,7 +23492,7 @@ fn checkPtrType( const msg = msg: { const msg = try sema.errMsg( ty_src, - "expected pointer type, found '{}'", + "expected pointer type, found '{f}'", .{ty.fmt(pt)}, ); errdefer msg.destroy(sema.gpa); @@ -23505,7 +23506,7 @@ fn checkPtrType( .optional => if (ty.childType(zcu).zigTypeTag(zcu) == .pointer) return, else => {}, } - return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected pointer type, found '{f}'", .{ty.fmt(pt)}); } fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { @@ -23516,7 +23517,7 @@ fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ const as = ty.ptrAddressSpace(zcu); if (target_util.arePointersLogical(target, as)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{}'", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{f}'", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote( src, @@ -23547,7 +23548,7 @@ fn checkVectorElemType( .optional, .pointer => if (ty.isPtrAtRuntime(zcu)) return, else => {}, } - return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{f}'", .{ty.fmt(pt)}); } fn checkFloatType( @@ -23560,7 +23561,7 @@ fn checkFloatType( const zcu = pt.zcu; switch (ty.zigTypeTag(zcu)) { .comptime_int, .comptime_float, .float => {}, - else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, ty_src, "expected float type, found '{f}'", .{ty.fmt(pt)}), } } @@ -23578,7 +23579,7 @@ fn checkNumericType( .comptime_float, .float, .comptime_int, .int => {}, else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}), }, - else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, ty_src, "expected number, found '{f}'", .{ty.fmt(pt)}), } } @@ -23612,7 +23613,7 @@ fn checkAtomicPtrOperand( error.BadType => return sema.fail( block, elem_ty_src, - "expected bool, integer, float, enum, packed struct, or pointer type; found '{}'", + "expected bool, integer, float, enum, packed struct, or pointer type; found '{f}'", .{elem_ty.fmt(pt)}, ), }; @@ -23673,12 +23674,12 @@ fn checkIntOrVector( const elem_ty = operand_ty.childType(zcu); switch (elem_ty.zigTypeTag(zcu)) { .int => return elem_ty, - else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ + else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{f}'", .{ elem_ty.fmt(pt), }), } }, - else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ + else => return sema.fail(block, operand_src, "expected integer or vector, found '{f}'", .{ operand_ty.fmt(pt), }), } @@ -23698,12 +23699,12 @@ fn checkIntOrVectorAllowComptime( const elem_ty = operand_ty.childType(zcu); switch (elem_ty.zigTypeTag(zcu)) { .int, .comptime_int => return elem_ty, - else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ + else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{f}'", .{ elem_ty.fmt(pt), }), } }, - else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ + else => return sema.fail(block, operand_src, "expected integer or vector, found '{f}'", .{ operand_ty.fmt(pt), }), } @@ -23794,7 +23795,7 @@ fn checkVectorizableBinaryOperands( } } else { const msg = msg: { - const msg = try sema.errMsg(src, "mixed scalar and vector operands: '{}' and '{}'", .{ + const msg = try sema.errMsg(src, "mixed scalar and vector operands: '{f}' and '{f}'", .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -23928,7 +23929,7 @@ fn zirCmpxchg( return sema.fail( block, elem_ty_src, - "expected bool, integer, enum, packed struct, or pointer type; found '{}'", + "expected bool, integer, enum, packed struct, or pointer type; found '{f}'", .{elem_ty.fmt(pt)}, ); } @@ -24012,7 +24013,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I switch (dest_ty.zigTypeTag(zcu)) { .array, .vector => {}, - else => return sema.fail(block, src, "expected array or vector type, found '{}'", .{dest_ty.fmt(pt)}), + else => return sema.fail(block, src, "expected array or vector type, found '{f}'", .{dest_ty.fmt(pt)}), } const operand = try sema.resolveInst(extra.rhs); @@ -24088,7 +24089,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. const zcu = pt.zcu; if (operand_ty.zigTypeTag(zcu) != .vector) { - return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(pt)}); + return sema.fail(block, operand_src, "expected vector, found '{f}'", .{operand_ty.fmt(pt)}); } const scalar_ty = operand_ty.childType(zcu); @@ -24097,13 +24098,13 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. switch (operation) { .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(zcu)) { .int, .bool => {}, - else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{ + else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{f}'", .{ @tagName(operation), operand_ty.fmt(pt), }), }, .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag(zcu)) { .int, .float => {}, - else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{ + else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{f}'", .{ @tagName(operation), operand_ty.fmt(pt), }), }, @@ -24157,7 +24158,7 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const mask_len = switch (sema.typeOf(mask).zigTypeTag(zcu)) { .array, .vector => sema.typeOf(mask).arrayLen(zcu), - else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(pt)}), + else => return sema.fail(block, mask_src, "expected vector or array, found '{f}'", .{sema.typeOf(mask).fmt(pt)}), }; mask_ty = try pt.vectorType(.{ .len = @intCast(mask_len), @@ -24184,11 +24185,14 @@ fn analyzeShuffle( const b_src = block.builtinCallArgSrc(src_node, 2); const mask_src = block.builtinCallArgSrc(src_node, 3); - // If the type of `a` is `@Type(.undefined)`, i.e. the argument is untyped, this is 0, because it is an error to index into this vector. + // If the type of `a` is `@Type(.undefined)`, i.e. the argument is untyped, + // this is 0, because it is an error to index into this vector. const a_len: u32 = switch (sema.typeOf(a_uncoerced).zigTypeTag(zcu)) { .array, .vector => @intCast(sema.typeOf(a_uncoerced).arrayLen(zcu)), .undefined => 0, - else => return sema.fail(block, a_src, "expected vector of '{}', found '{}'", .{ elem_ty.fmt(pt), sema.typeOf(a_uncoerced).fmt(pt) }), + else => return sema.fail(block, a_src, "expected vector of '{f}', found '{f}'", .{ + elem_ty.fmt(pt), sema.typeOf(a_uncoerced).fmt(pt), + }), }; const a_ty = try pt.vectorType(.{ .len = a_len, .child = elem_ty.toIntern() }); const a_coerced = try sema.coerce(block, a_ty, a_uncoerced, a_src); @@ -24197,7 +24201,9 @@ fn analyzeShuffle( const b_len: u32 = switch (sema.typeOf(b_uncoerced).zigTypeTag(zcu)) { .array, .vector => @intCast(sema.typeOf(b_uncoerced).arrayLen(zcu)), .undefined => 0, - else => return sema.fail(block, b_src, "expected vector of '{}', found '{}'", .{ elem_ty.fmt(pt), sema.typeOf(b_uncoerced).fmt(pt) }), + else => return sema.fail(block, b_src, "expected vector of '{f}', found '{f}'", .{ + elem_ty.fmt(pt), sema.typeOf(b_uncoerced).fmt(pt), + }), }; const b_ty = try pt.vectorType(.{ .len = b_len, .child = elem_ty.toIntern() }); const b_coerced = try sema.coerce(block, b_ty, b_uncoerced, b_src); @@ -24235,7 +24241,7 @@ fn analyzeShuffle( if (idx >= a_len) return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(mask_src, "mask element at index '{d}' selects out-of-bounds index", .{mask_idx}); errdefer msg.destroy(sema.gpa); - try sema.errNote(a_src, msg, "index '{d}' exceeds bounds of '{}' given here", .{ idx, a_ty.fmt(pt) }); + try sema.errNote(a_src, msg, "index '{d}' exceeds bounds of '{f}' given here", .{ idx, a_ty.fmt(pt) }); if (idx < b_len) { try sema.errNote(b_src, msg, "use '~@as(u32, {d})' to index into second vector given here", .{idx}); } @@ -24351,7 +24357,7 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C const vec_len_u64 = switch (pred_ty.zigTypeTag(zcu)) { .vector, .array => pred_ty.arrayLen(zcu), - else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(pt)}), + else => return sema.fail(block, pred_src, "expected vector or array, found '{f}'", .{pred_ty.fmt(pt)}), }; const vec_len: u32 = @intCast(try sema.usizeCast(block, pred_src, vec_len_u64)); @@ -24611,7 +24617,7 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. switch (ty.scalarType(zcu).zigTypeTag(zcu)) { .comptime_float, .float => {}, - else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(pt)}), + else => return sema.fail(block, src, "expected vector of floats or float type, found '{f}'", .{ty.fmt(pt)}), } const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { @@ -24712,7 +24718,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const args_ty = sema.typeOf(args); if (!args_ty.isTuple(zcu)) { - return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(pt)}); + return sema.fail(block, args_src, "expected a tuple, found '{f}'", .{args_ty.fmt(pt)}); } const resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(zcu)); @@ -24757,12 +24763,12 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins try sema.checkPtrType(block, inst_src, parent_ptr_ty, true); const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu); if (parent_ptr_info.flags.size != .one) { - return sema.fail(block, inst_src, "expected single pointer type, found '{}'", .{parent_ptr_ty.fmt(pt)}); + return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)}); } const parent_ty: Type = .fromInterned(parent_ptr_info.child); switch (parent_ty.zigTypeTag(zcu)) { .@"struct", .@"union" => {}, - else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(pt)}), + else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}), } try parent_ty.resolveLayout(pt); @@ -24912,7 +24918,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins } if (field.index != field_index) { - return sema.fail(block, inst_src, "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{ + return sema.fail(block, inst_src, "field '{f}' has index '{d}' but pointer value is index '{d}' of struct '{f}'", .{ field_name.fmt(ip), field_index, field.index, parent_ty.fmt(pt), }); } @@ -25371,10 +25377,10 @@ fn zirMemcpy( const msg = msg: { const msg = try sema.errMsg(src, "unknown copy length", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(dest_src, msg, "destination type '{}' provides no length", .{ + try sema.errNote(dest_src, msg, "destination type '{f}' provides no length", .{ dest_ty.fmt(pt), }); - try sema.errNote(src_src, msg, "source type '{}' provides no length", .{ + try sema.errNote(src_src, msg, "source type '{f}' provides no length", .{ src_ty.fmt(pt), }); break :msg msg; @@ -25398,7 +25404,7 @@ fn zirMemcpy( if (imc != .ok) return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg( src, - "pointer element type '{}' cannot coerce into element type '{}'", + "pointer element type '{f}' cannot coerce into element type '{f}'", .{ src_elem_ty.fmt(pt), dest_elem_ty.fmt(pt) }, ); errdefer msg.destroy(sema.gpa); @@ -25417,10 +25423,10 @@ fn zirMemcpy( const msg = msg: { const msg = try sema.errMsg(src, "non-matching copy lengths", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(dest_src, msg, "length {} here", .{ + try sema.errNote(dest_src, msg, "length {f} here", .{ dest_len_val.fmtValueSema(pt, sema), }); - try sema.errNote(src_src, msg, "length {} here", .{ + try sema.errNote(src_src, msg, "length {f} here", .{ src_len_val.fmtValueSema(pt, sema), }); break :msg msg; @@ -25635,7 +25641,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void return sema.failWithOwnedErrorMsg(block, msg: { const msg = try sema.errMsg(src, "unknown @memset length", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(dest_src, msg, "destination type '{}' provides no length", .{ + try sema.errNote(dest_src, msg, "destination type '{f}' provides no length", .{ dest_ptr_ty.fmt(pt), }); break :msg msg; @@ -25815,7 +25821,7 @@ fn zirCUndef( const src = block.builtinCallArgSrc(extra.node, 0); const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cUndef_macro_name }); - try block.c_import_buf.?.writer().print("#undef {s}\n", .{name}); + try block.c_import_buf.?.print("#undef {s}\n", .{name}); return .void_value; } @@ -25828,7 +25834,7 @@ fn zirCInclude( const src = block.builtinCallArgSrc(extra.node, 0); const name = try sema.resolveConstString(block, src, extra.operand, .{ .simple = .operand_cInclude_file_name }); - try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name}); + try block.c_import_buf.?.print("#include <{s}>\n", .{name}); return .void_value; } @@ -25847,9 +25853,9 @@ fn zirCDefine( const rhs = try sema.resolveInst(extra.rhs); if (sema.typeOf(rhs).zigTypeTag(zcu) != .void) { const value = try sema.resolveConstString(block, val_src, extra.rhs, .{ .simple = .operand_cDefine_macro_value }); - try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); + try block.c_import_buf.?.print("#define {s} {s}\n", .{ name, value }); } else { - try block.c_import_buf.?.writer().print("#define {s}\n", .{name}); + try block.c_import_buf.?.print("#define {s}\n", .{name}); } return .void_value; } @@ -26067,7 +26073,7 @@ fn zirBuiltinExtern( } if (!try sema.validateExternType(ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(pt)}); + const msg = try sema.errMsg(ty_src, "extern symbol cannot have type '{f}'", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, ty_src, ty, .other); break :msg msg; @@ -26307,7 +26313,7 @@ pub fn validateVarType( if (is_extern) { if (!try sema.validateExternType(var_ty, .other)) { const msg = msg: { - const msg = try sema.errMsg(src, "extern variable cannot have type '{}'", .{var_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "extern variable cannot have type '{f}'", .{var_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, src, var_ty, .other); break :msg msg; @@ -26319,7 +26325,7 @@ pub fn validateVarType( return sema.fail( block, src, - "non-extern variable with opaque type '{}'", + "non-extern variable with opaque type '{f}'", .{var_ty.fmt(pt)}, ); } @@ -26328,7 +26334,7 @@ pub fn validateVarType( if (!try var_ty.comptimeOnlySema(pt)) return; const msg = msg: { - const msg = try sema.errMsg(src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "variable of type '{f}' must be const or comptime", .{var_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsComptime(msg, src, var_ty); @@ -26378,7 +26384,7 @@ fn explainWhyTypeIsComptimeInner( => return, .@"fn" => { - try sema.errNote(src_loc, msg, "use '*const {}' for a function pointer type", .{ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)}); }, .type => { @@ -26394,7 +26400,7 @@ fn explainWhyTypeIsComptimeInner( => return, .@"opaque" => { - try sema.errNote(src_loc, msg, "opaque type '{}' has undefined size", .{ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "opaque type '{f}' has undefined size", .{ty.fmt(pt)}); }, .array, .vector => { @@ -26581,7 +26587,7 @@ fn explainWhyTypeIsNotExtern( if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") { try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{}); } else if (try ty.comptimeOnlySema(pt)) { - try sema.errNote(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "pointer to comptime-only type '{f}'", .{pointee_ty.fmt(pt)}); try sema.explainWhyTypeIsComptime(msg, src_loc, ty); } try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other); @@ -26609,7 +26615,7 @@ fn explainWhyTypeIsNotExtern( }, .@"enum" => { const tag_ty = ty.intTagType(zcu); - try sema.errNote(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(pt)}); + try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)}); try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); }, .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), @@ -27045,7 +27051,7 @@ fn fieldVal( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27069,7 +27075,7 @@ fn fieldVal( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27089,7 +27095,7 @@ fn fieldVal( switch (ip.indexToKey(child_type.toIntern())) { .error_set_type => |error_set_type| blk: { if (error_set_type.nameIndex(ip, field_name) != null) break :blk; - return sema.fail(block, src, "no error named '{}' in '{}'", .{ + return sema.fail(block, src, "no error named '{f}' in '{f}'", .{ field_name.fmt(ip), child_type.fmt(pt), }); }, @@ -27144,7 +27150,7 @@ fn fieldVal( return sema.failWithBadMemberAccess(block, child_type, src, field_name); }, else => return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "type '{}' has no members", .{child_type.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' has no members", .{child_type.fmt(pt)}); errdefer msg.destroy(sema.gpa); if (child_type.isSlice(zcu)) try sema.errNote(src, msg, "slice values have 'len' and 'ptr' members", .{}); if (child_type.zigTypeTag(zcu) == .array) try sema.errNote(src, msg, "array values have 'len' member", .{}); @@ -27190,7 +27196,7 @@ fn fieldPtr( const object_ptr_ty = sema.typeOf(object_ptr); const object_ty = switch (object_ptr_ty.zigTypeTag(zcu)) { .pointer => object_ptr_ty.childType(zcu), - else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(pt)}), + else => return sema.fail(block, object_ptr_src, "expected pointer, found '{f}'", .{object_ptr_ty.fmt(pt)}), }; // Zig allows dereferencing a single pointer during field lookup. Note that @@ -27243,7 +27249,7 @@ fn fieldPtr( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27298,7 +27304,7 @@ fn fieldPtr( return sema.fail( block, field_name_src, - "no member named '{}' in '{}'", + "no member named '{f}' in '{f}'", .{ field_name.fmt(ip), object_ty.fmt(pt) }, ); } @@ -27321,7 +27327,7 @@ fn fieldPtr( if (error_set_type.nameIndex(ip, field_name) != null) { break :blk; } - return sema.fail(block, src, "no error named '{}' in '{}'", .{ + return sema.fail(block, src, "no error named '{f}' in '{f}'", .{ field_name.fmt(ip), child_type.fmt(pt), }); }, @@ -27375,7 +27381,7 @@ fn fieldPtr( } return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); }, - else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(pt)}), + else => return sema.fail(block, src, "type '{f}' has no members", .{child_type.fmt(pt)}), } }, .@"struct" => { @@ -27430,7 +27436,7 @@ fn fieldCallBind( const inner_ty = if (raw_ptr_ty.zigTypeTag(zcu) == .pointer and (raw_ptr_ty.ptrSize(zcu) == .one or raw_ptr_ty.ptrSize(zcu) == .c)) raw_ptr_ty.childType(zcu) else - return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(pt)}); + return sema.fail(block, raw_ptr_src, "expected single pointer, found '{f}'", .{raw_ptr_ty.fmt(pt)}); // Optionally dereference a second pointer to get the concrete type. const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one; @@ -27549,7 +27555,7 @@ fn fieldCallBind( }; const msg = msg: { - const msg = try sema.errMsg(src, "no field or member function named '{}' in '{}'", .{ + const msg = try sema.errMsg(src, "no field or member function named '{f}' in '{f}'", .{ field_name.fmt(ip), concrete_ty.fmt(pt), }); @@ -27559,7 +27565,7 @@ fn fieldCallBind( try sema.errNote( zcu.navSrcLoc(nav_index), msg, - "'{}' is not a member function", + "'{f}' is not a member function", .{field_name.fmt(ip)}, ); } @@ -27627,7 +27633,7 @@ fn namespaceLookup( if (try sema.lookupInNamespace(block, namespace, decl_name)) |lookup| { if (!lookup.accessible) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "'{}' is not marked 'pub'", .{ + const msg = try sema.errMsg(src, "'{f}' is not marked 'pub'", .{ decl_name.fmt(&zcu.intern_pool), }); errdefer msg.destroy(gpa); @@ -27865,12 +27871,12 @@ fn tupleFieldIndex( assert(!field_name.eqlSlice("len", ip)); if (field_name.toUnsigned(ip)) |field_index| { if (field_index < tuple_ty.structFieldCount(pt.zcu)) return field_index; - return sema.fail(block, field_name_src, "index '{}' out of bounds of tuple '{}'", .{ + return sema.fail(block, field_name_src, "index '{f}' out of bounds of tuple '{f}'", .{ field_name.fmt(ip), tuple_ty.fmt(pt), }); } - return sema.fail(block, field_name_src, "no field named '{}' in tuple '{}'", .{ + return sema.fail(block, field_name_src, "no field named '{f}' in tuple '{f}'", .{ field_name.fmt(ip), tuple_ty.fmt(pt), }); } @@ -27957,7 +27963,7 @@ fn unionFieldPtr( const msg = try sema.errMsg(src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, union_ty); @@ -27991,7 +27997,7 @@ fn unionFieldPtr( const msg = msg: { const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu); - const msg = try sema.errMsg(src, "access of union field '{}' while field '{}' is active", .{ + const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ field_name.fmt(ip), active_field_name.fmt(ip), }); @@ -28059,7 +28065,7 @@ fn unionFieldVal( const msg = msg: { const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu); - const msg = try sema.errMsg(src, "access of union field '{}' while field '{}' is active", .{ + const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ field_name.fmt(ip), active_field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); @@ -28117,7 +28123,7 @@ fn elemPtr( const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(zcu)) { .pointer => indexable_ptr_ty.childType(zcu), - else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(pt)}), + else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}), }; try sema.checkIndexable(block, src, indexable_ty); @@ -28288,7 +28294,7 @@ fn validateRuntimeElemAccess( const msg = msg: { const msg = try sema.errMsg( elem_index_src, - "values of type '{}' must be comptime-known, but index value is runtime-known", + "values of type '{f}' must be comptime-known, but index value is runtime-known", .{parent_ty.fmt(sema.pt)}, ); errdefer msg.destroy(sema.gpa); @@ -28304,7 +28310,7 @@ fn validateRuntimeElemAccess( const target = zcu.getTarget(); const as = parent_ty.ptrAddressSpace(zcu); if (target_util.arePointersLogical(target, as)) { - return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{}'", .{parent_ty.fmt(pt)}); + return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{f}'", .{parent_ty.fmt(pt)}); } } } @@ -29000,7 +29006,7 @@ fn coerceExtra( return sema.fail( block, inst_src, - "array literal requires address-of operator (&) to coerce to slice type '{}'", + "array literal requires address-of operator (&) to coerce to slice type '{f}'", .{dest_ty.fmt(pt)}, ); } @@ -29027,7 +29033,7 @@ fn coerceExtra( // pointer to tuple to slice if (!dest_info.flags.is_const) { const err_msg = err_msg: { - const err_msg = try sema.errMsg(inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(pt)}); + const err_msg = try sema.errMsg(inst_src, "cannot cast pointer to tuple to '{f}'", .{dest_ty.fmt(pt)}); errdefer err_msg.destroy(sema.gpa); try sema.errNote(dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{}); break :err_msg err_msg; @@ -29082,7 +29088,7 @@ fn coerceExtra( // comptime-known integer to other number if (!(try sema.intFitsInType(val, dest_ty, null))) { if (!opts.report_err) return error.NotCoercible; - return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }); + return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }); } return switch (zcu.intern_pool.indexToKey(val.toIntern())) { .undef => try pt.undefRef(dest_ty), @@ -29124,7 +29130,7 @@ fn coerceExtra( return sema.fail( block, inst_src, - "type '{}' cannot represent float value '{}'", + "type '{f}' cannot represent float value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }, ); } @@ -29157,7 +29163,7 @@ fn coerceExtra( // return sema.fail( // block, // inst_src, - // "type '{}' cannot represent integer value '{}'", + // "type '{f}' cannot represent integer value '{}'", // .{ dest_ty.fmt(pt), val }, // ); //} @@ -29171,7 +29177,7 @@ fn coerceExtra( const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); const string = zcu.intern_pool.indexToKey(val.toIntern()).enum_literal; const field_index = dest_ty.enumFieldIndex(string, zcu) orelse { - return sema.fail(block, inst_src, "no field named '{}' in enum '{}'", .{ + return sema.fail(block, inst_src, "no field named '{f}' in enum '{f}'", .{ string.fmt(&zcu.intern_pool), dest_ty.fmt(pt), }); }; @@ -29320,11 +29326,11 @@ fn coerceExtra( } const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) }); + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt) }); errdefer msg.destroy(sema.gpa); if (!can_coerce_to) { - try sema.errNote(inst_src, msg, "cannot coerce to '{}'", .{dest_ty.fmt(pt)}); + try sema.errNote(inst_src, msg, "cannot coerce to '{f}'", .{dest_ty.fmt(pt)}); } // E!T to T @@ -29513,13 +29519,13 @@ const InMemoryCoercionResult = union(enum) { break; }, .comptime_int_not_coercible => |int| { - try sema.errNote(src, msg, "type '{}' cannot represent value '{}'", .{ + try sema.errNote(src, msg, "type '{f}' cannot represent value '{f}'", .{ int.wanted.fmt(pt), int.actual.fmtValueSema(pt, sema), }); break; }, .error_union_payload => |pair| { - try sema.errNote(src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ + try sema.errNote(src, msg, "error union payload '{f}' cannot cast into error union payload '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29532,18 +29538,18 @@ const InMemoryCoercionResult = union(enum) { }, .array_sentinel => |sentinel| { if (sentinel.actual.toIntern() != .unreachable_value) { - try sema.errNote(src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ + try sema.errNote(src, msg, "array sentinel '{f}' cannot cast into array sentinel '{f}'", .{ sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema), }); } else { - try sema.errNote(src, msg, "destination array requires '{}' sentinel", .{ + try sema.errNote(src, msg, "destination array requires '{f}' sentinel", .{ sentinel.wanted.fmtValueSema(pt, sema), }); } break; }, .array_elem => |pair| { - try sema.errNote(src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ + try sema.errNote(src, msg, "array element type '{f}' cannot cast into array element type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29555,19 +29561,19 @@ const InMemoryCoercionResult = union(enum) { break; }, .vector_elem => |pair| { - try sema.errNote(src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ + try sema.errNote(src, msg, "vector element type '{f}' cannot cast into vector element type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; }, .optional_shape => |pair| { - try sema.errNote(src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ + try sema.errNote(src, msg, "optional type child '{f}' cannot cast into optional type child '{f}'", .{ pair.actual.optionalChild(pt.zcu).fmt(pt), pair.wanted.optionalChild(pt.zcu).fmt(pt), }); break; }, .optional_child => |pair| { - try sema.errNote(src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ + try sema.errNote(src, msg, "optional type child '{f}' cannot cast into optional type child '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29578,7 +29584,7 @@ const InMemoryCoercionResult = union(enum) { }, .missing_error => |missing_errors| { for (missing_errors) |err| { - try sema.errNote(src, msg, "'error.{}' not a member of destination error set", .{err.fmt(&pt.zcu.intern_pool)}); + try sema.errNote(src, msg, "'error.{f}' not a member of destination error set", .{err.fmt(&pt.zcu.intern_pool)}); } break; }, @@ -29631,7 +29637,7 @@ const InMemoryCoercionResult = union(enum) { break; }, .fn_param => |param| { - try sema.errNote(src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ + try sema.errNote(src, msg, "parameter {d} '{f}' cannot cast into '{f}'", .{ param.index, param.actual.fmt(pt), param.wanted.fmt(pt), }); cur = param.child; @@ -29641,13 +29647,13 @@ const InMemoryCoercionResult = union(enum) { break; }, .fn_return_type => |pair| { - try sema.errNote(src, msg, "return type '{}' cannot cast into return type '{}'", .{ + try sema.errNote(src, msg, "return type '{f}' cannot cast into return type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; }, .ptr_child => |pair| { - try sema.errNote(src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ + try sema.errNote(src, msg, "pointer type child '{f}' cannot cast into pointer type child '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); cur = pair.child; @@ -29658,11 +29664,11 @@ const InMemoryCoercionResult = union(enum) { }, .ptr_sentinel => |sentinel| { if (sentinel.actual.toIntern() != .unreachable_value) { - try sema.errNote(src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ + try sema.errNote(src, msg, "pointer sentinel '{f}' cannot cast into pointer sentinel '{f}'", .{ sentinel.actual.fmtValueSema(pt, sema), sentinel.wanted.fmtValueSema(pt, sema), }); } else { - try sema.errNote(src, msg, "destination pointer requires '{}' sentinel", .{ + try sema.errNote(src, msg, "destination pointer requires '{f}' sentinel", .{ sentinel.wanted.fmtValueSema(pt, sema), }); } @@ -29676,11 +29682,11 @@ const InMemoryCoercionResult = union(enum) { const wanted_allow_zero = pair.wanted.ptrAllowsZero(pt.zcu); const actual_allow_zero = pair.actual.ptrAllowsZero(pt.zcu); if (actual_allow_zero and !wanted_allow_zero) { - try sema.errNote(src, msg, "'{}' could have null values which are illegal in type '{}'", .{ + try sema.errNote(src, msg, "'{f}' could have null values which are illegal in type '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); } else { - try sema.errNote(src, msg, "mutable '{}' would allow illegal null values stored to type '{}'", .{ + try sema.errNote(src, msg, "mutable '{f}' would allow illegal null values stored to type '{f}'", .{ pair.wanted.fmt(pt), pair.actual.fmt(pt), }); } @@ -29692,7 +29698,7 @@ const InMemoryCoercionResult = union(enum) { if (actual_const and !wanted_const) { try sema.errNote(src, msg, "cast discards const qualifier", .{}); } else { - try sema.errNote(src, msg, "mutable '{}' would allow illegal const pointers stored to type '{}'", .{ + try sema.errNote(src, msg, "mutable '{f}' would allow illegal const pointers stored to type '{f}'", .{ pair.wanted.fmt(pt), pair.actual.fmt(pt), }); } @@ -29704,7 +29710,7 @@ const InMemoryCoercionResult = union(enum) { if (actual_volatile and !wanted_volatile) { try sema.errNote(src, msg, "cast discards volatile qualifier", .{}); } else { - try sema.errNote(src, msg, "mutable '{}' would allow illegal volatile pointers stored to type '{}'", .{ + try sema.errNote(src, msg, "mutable '{f}' would allow illegal volatile pointers stored to type '{f}'", .{ pair.wanted.fmt(pt), pair.actual.fmt(pt), }); } @@ -29730,13 +29736,13 @@ const InMemoryCoercionResult = union(enum) { break; }, .double_ptr_to_anyopaque => |pair| { - try sema.errNote(src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{ + try sema.errNote(src, msg, "cannot implicitly cast double pointer '{f}' to anyopaque pointer '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); break; }, .slice_to_anyopaque => |pair| { - try sema.errNote(src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{ + try sema.errNote(src, msg, "cannot implicitly cast slice '{f}' to anyopaque pointer '{f}'", .{ pair.actual.fmt(pt), pair.wanted.fmt(pt), }); try sema.errNote(src, msg, "consider using '.ptr'", .{}); @@ -30510,7 +30516,7 @@ fn coerceVarArgParam( const coerced_ty = sema.typeOf(coerced); if (!try sema.validateExternType(coerced_ty, .param_ty)) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(pt)}); + const msg = try sema.errMsg(inst_src, "cannot pass '{f}' to variadic function", .{coerced_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, inst_src, coerced_ty, .param_ty); @@ -30613,7 +30619,7 @@ fn storePtr2( // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer. if (try elem_ty.comptimeOnlySema(pt)) { return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(src, "cannot store comptime-only type '{}' at runtime", .{elem_ty.fmt(pt)}); + const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(ptr_src, msg, "operation is runtime due to this pointer", .{}); break :msg msg; @@ -30646,7 +30652,7 @@ fn storePtr2( }); return; } - return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ + return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{ ptr_ty.fmt(pt), }); } @@ -30815,19 +30821,19 @@ fn storePtrVal( .{}, ), .undef => return sema.failWithUseOfUndef(block, src), - .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}), + .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {f}", .{err_name.fmt(ip)}), .null_payload => return sema.fail(block, src, "attempt to use null value", .{}), .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}), .needed_well_defined => |ty| return sema.fail( block, src, - "comptime dereference requires '{}' to have a well-defined layout", + "comptime dereference requires '{f}' to have a well-defined layout", .{ty.fmt(pt)}, ), .out_of_bounds => |ty| return sema.fail( block, src, - "dereference of '{}' exceeds bounds of containing decl of type '{}'", + "dereference of '{f}' exceeds bounds of containing decl of type '{f}'", .{ ptr_ty.fmt(pt), ty.fmt(pt) }, ), .exceeds_host_size => return sema.fail(block, src, "bit-pointer target exceeds host size", .{}), @@ -30853,7 +30859,7 @@ fn bitCast( const old_bits = old_ty.bitSize(zcu); if (old_bits != dest_bits) { - return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{ + return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{f}' has {d} bits but source type '{f}' has {d} bits", .{ dest_ty.fmt(pt), dest_bits, old_ty.fmt(pt), @@ -30971,7 +30977,7 @@ fn coerceCompatiblePtrs( const inst_ty = sema.typeOf(inst); if (try sema.resolveValue(inst)) |val| { if (!val.isUndef(zcu) and val.isNull(zcu) and !dest_ty.isAllowzeroPtr(zcu)) { - return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(pt)}); + return sema.fail(block, inst_src, "null pointer casted to type '{f}'", .{dest_ty.fmt(pt)}); } // The comptime Value representation is compatible with both types. return Air.internedToRef( @@ -31017,7 +31023,7 @@ fn coerceEnumToUnion( const tag_ty = union_ty.unionTagType(zcu) orelse { const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ union_ty.fmt(pt), inst_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31031,7 +31037,7 @@ fn coerceEnumToUnion( const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src); if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| { const field_index = union_ty.unionTagFieldIndex(val, pt.zcu) orelse { - return sema.fail(block, inst_src, "union '{}' has no tag with value '{}'", .{ + return sema.fail(block, inst_src, "union '{f}' has no tag with value '{f}'", .{ union_ty.fmt(pt), val.fmtValueSema(pt, sema), }); }; @@ -31045,7 +31051,7 @@ fn coerceEnumToUnion( errdefer msg.destroy(sema.gpa); const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, union_ty); @@ -31056,13 +31062,13 @@ fn coerceEnumToUnion( const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { const msg = msg: { const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; - const msg = try sema.errMsg(inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{ + const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{ inst_ty.fmt(pt), union_ty.fmt(pt), field_ty.fmt(pt), field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ field_name.fmt(ip), }); try sema.addDeclaredHereNote(msg, union_ty); @@ -31078,7 +31084,7 @@ fn coerceEnumToUnion( if (tag_ty.isNonexhaustiveEnum(zcu)) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{ + const msg = try sema.errMsg(inst_src, "runtime coercion to union '{f}' from non-exhaustive enum", .{ union_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31097,7 +31103,7 @@ fn coerceEnumToUnion( if (Type.fromInterned(field_ty).zigTypeTag(zcu) == .noreturn) { const err_msg = msg orelse try sema.errMsg( inst_src, - "runtime coercion from enum '{}' to union '{}' which has a 'noreturn' field", + "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field", .{ tag_ty.fmt(pt), union_ty.fmt(pt) }, ); msg = err_msg; @@ -31120,7 +31126,7 @@ fn coerceEnumToUnion( const msg = msg: { const msg = try sema.errMsg( inst_src, - "runtime coercion from enum '{}' to union '{}' which has non-void fields", + "runtime coercion from enum '{f}' to union '{f}' which has non-void fields", .{ tag_ty.fmt(pt), union_ty.fmt(pt) }, ); errdefer msg.destroy(sema.gpa); @@ -31129,7 +31135,7 @@ fn coerceEnumToUnion( const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); if (!(try field_ty.hasRuntimeBitsSema(pt))) continue; - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{ + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{ field_name.fmt(ip), field_ty.fmt(pt), }); @@ -31170,7 +31176,7 @@ fn coerceArrayLike( const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(zcu)); if (dest_len != inst_len) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31258,7 +31264,7 @@ fn coerceTupleToArray( if (dest_len != inst_len) { const msg = msg: { - const msg = try sema.errMsg(inst_src, "expected type '{}', found '{}'", .{ + const msg = try sema.errMsg(inst_src, "expected type '{f}', found '{f}'", .{ dest_ty.fmt(pt), inst_ty.fmt(pt), }); errdefer msg.destroy(sema.gpa); @@ -31734,10 +31740,10 @@ fn analyzeLoad( const ptr_ty = sema.typeOf(ptr); const elem_ty = switch (ptr_ty.zigTypeTag(zcu)) { .pointer => ptr_ty.childType(zcu), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(pt)}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}), }; if (elem_ty.zigTypeTag(zcu) == .@"opaque") { - return sema.fail(block, ptr_src, "cannot load opaque type '{}'", .{elem_ty.fmt(pt)}); + return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}); } if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| { @@ -31758,7 +31764,7 @@ fn analyzeLoad( const bin_op = sema.getTmpAir().extraData(Air.Bin, ty_pl.payload).data; return block.addBinOp(.ptr_elem_val, bin_op.lhs, bin_op.rhs); } - return sema.fail(block, ptr_src, "unable to determine vector element index of type '{}'", .{ + return sema.fail(block, ptr_src, "unable to determine vector element index of type '{f}'", .{ ptr_ty.fmt(pt), }); } @@ -32046,7 +32052,7 @@ fn analyzeSlice( const ptr_ptr_ty = sema.typeOf(ptr_ptr); const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(zcu)) { .pointer => ptr_ptr_ty.childType(zcu), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(pt)}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ptr_ty.fmt(pt)}), }; var array_ty = ptr_ptr_child_ty; @@ -32095,7 +32101,7 @@ fn analyzeSlice( try sema.errNote( start_src, msg, - "expected '{}', found '{}'", + "expected '{f}', found '{f}'", .{ Value.zero_comptime_int.fmtValueSema(pt, sema), start_value.fmtValueSema(pt, sema), @@ -32111,7 +32117,7 @@ fn analyzeSlice( try sema.errNote( end_src, msg, - "expected '{}', found '{}'", + "expected '{f}', found '{f}'", .{ Value.one_comptime_int.fmtValueSema(pt, sema), end_value.fmtValueSema(pt, sema), @@ -32126,7 +32132,7 @@ fn analyzeSlice( return sema.fail( block, end_src, - "end index {} out of bounds for slice of single-item pointer", + "end index {f} out of bounds for slice of single-item pointer", .{end_value.fmtValueSema(pt, sema)}, ); } @@ -32173,7 +32179,7 @@ fn analyzeSlice( elem_ty = ptr_ptr_child_ty.childType(zcu); }, }, - else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(pt)}), + else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}), } const ptr = if (slice_ty.isSlice(zcu)) @@ -32220,7 +32226,7 @@ fn analyzeSlice( return sema.fail( block, end_src, - "end index {} out of bounds for array of length {}{s}", + "end index {f} out of bounds for array of length {f}{s}", .{ end_val.fmtValueSema(pt, sema), len_val.fmtValueSema(pt, sema), @@ -32265,7 +32271,7 @@ fn analyzeSlice( return sema.fail( block, end_src, - "end index {} out of bounds for slice of length {d}{s}", + "end index {f} out of bounds for slice of length {d}{s}", .{ end_val.fmtValueSema(pt, sema), try slice_val.sliceLen(pt), @@ -32324,7 +32330,7 @@ fn analyzeSlice( return sema.fail( block, start_src, - "start index {} is larger than end index {}", + "start index {f} is larger than end index {f}", .{ start_val.fmtValueSema(pt, sema), end_val.fmtValueSema(pt, sema), @@ -32348,13 +32354,13 @@ fn analyzeSlice( .needed_well_defined => |ty| return sema.fail( block, src, - "comptime dereference requires '{}' to have a well-defined layout", + "comptime dereference requires '{f}' to have a well-defined layout", .{ty.fmt(pt)}, ), .out_of_bounds => |ty| return sema.fail( block, end_src, - "slice end index {d} exceeds bounds of containing decl of type '{}'", + "slice end index {d} exceeds bounds of containing decl of type '{f}'", .{ end_int, ty.fmt(pt) }, ), }; @@ -32363,7 +32369,7 @@ fn analyzeSlice( const msg = msg: { const msg = try sema.errMsg(src, "value in memory does not match slice sentinel", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(src, msg, "expected '{}', found '{}'", .{ + try sema.errNote(src, msg, "expected '{f}', found '{f}'", .{ expected_sentinel.fmtValueSema(pt, sema), actual_sentinel.fmtValueSema(pt, sema), }); @@ -33251,7 +33257,7 @@ const PeerResolveResult = union(enum) { }; }, .field_error => |field_error| { - const fmt = "struct field '{}' has conflicting types"; + const fmt = "struct field '{f}' has conflicting types"; const args = .{field_error.field_name.fmt(&pt.zcu.intern_pool)}; if (opt_msg) |msg| { try sema.errNote(src, msg, fmt, args); @@ -33282,7 +33288,7 @@ const PeerResolveResult = union(enum) { candidate_srcs.resolve(block, conflict_idx[1]), }; - const fmt = "incompatible types: '{}' and '{}'"; + const fmt = "incompatible types: '{f}' and '{f}'"; const args = .{ conflict_tys[0].fmt(pt), conflict_tys[1].fmt(pt), @@ -33296,8 +33302,8 @@ const PeerResolveResult = union(enum) { break :msg msg; }; - if (conflict_srcs[0]) |src_loc| try sema.errNote(src_loc, msg, "type '{}' here", .{conflict_tys[0].fmt(pt)}); - if (conflict_srcs[1]) |src_loc| try sema.errNote(src_loc, msg, "type '{}' here", .{conflict_tys[1].fmt(pt)}); + if (conflict_srcs[0]) |src_loc| try sema.errNote(src_loc, msg, "type '{f}' here", .{conflict_tys[0].fmt(pt)}); + if (conflict_srcs[1]) |src_loc| try sema.errNote(src_loc, msg, "type '{f}' here", .{conflict_tys[1].fmt(pt)}); // No child error break; @@ -34609,7 +34615,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { if (struct_type.setLayoutWip(ip)) { const msg = try sema.errMsg( ty.srcLoc(zcu), - "struct '{}' depends on itself", + "struct '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -34828,13 +34834,13 @@ fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ const zcu = pt.zcu; if (!backing_int_ty.isInt(zcu)) { - return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(pt)}); + return sema.fail(block, src, "expected backing integer type, found '{f}'", .{backing_int_ty.fmt(pt)}); } if (backing_int_ty.bitSize(zcu) != fields_bit_sum) { return sema.fail( block, src, - "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}", + "backing integer type '{f}' has bit size {} but the struct fields have a total bit size of {}", .{ backing_int_ty.fmt(pt), backing_int_ty.bitSize(zcu), fields_bit_sum }, ); } @@ -34844,7 +34850,7 @@ fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { const pt = sema.pt; if (!ty.isIndexable(pt.zcu)) { const msg = msg: { - const msg = try sema.errMsg(src, "type '{}' does not support indexing", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' does not support indexing", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "operand must be an array, slice, tuple, or vector", .{}); break :msg msg; @@ -34868,7 +34874,7 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void } } const msg = msg: { - const msg = try sema.errMsg(src, "type '{}' is not an indexable pointer", .{ty.fmt(pt)}); + const msg = try sema.errMsg(src, "type '{f}' is not an indexable pointer", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "operand must be a slice, a many pointer or a pointer to an array", .{}); break :msg msg; @@ -34936,7 +34942,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { .field_types_wip, .layout_wip => { const msg = try sema.errMsg( ty.srcLoc(pt.zcu), - "union '{}' depends on itself", + "union '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35124,7 +35130,7 @@ pub fn resolveStructFieldTypes( if (struct_type.setFieldTypesWip(ip)) { const msg = try sema.errMsg( Type.fromInterned(ty).srcLoc(zcu), - "struct '{}' depends on itself", + "struct '{f}' depends on itself", .{Type.fromInterned(ty).fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35153,7 +35159,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { if (struct_type.setInitsWip(ip)) { const msg = try sema.errMsg( ty.srcLoc(zcu), - "struct '{}' depends on itself", + "struct '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35179,7 +35185,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load .field_types_wip => { const msg = try sema.errMsg( ty.srcLoc(zcu), - "union '{}' depends on itself", + "union '{f}' depends on itself", .{ty.fmt(pt)}, ); return sema.failWithOwnedErrorMsg(null, msg); @@ -35549,7 +35555,7 @@ fn structFields( switch (struct_type.layout) { .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field); @@ -35561,7 +35567,7 @@ fn structFields( }, .@"packed" => if (!try sema.validatePackedType(field_ty)) { const msg = msg: { - const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); @@ -35808,7 +35814,7 @@ fn unionFields( // The provided type is an integer type and we must construct the enum tag type here. int_tag_ty = provided_ty; if (int_tag_ty.zigTypeTag(zcu) != .int and int_tag_ty.zigTypeTag(zcu) != .comptime_int) { - return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(pt)}); + return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{f}'", .{int_tag_ty.fmt(pt)}); } if (fields_len > 0) { @@ -35817,7 +35823,7 @@ fn unionFields( const msg = msg: { const msg = try sema.errMsg(tag_ty_src, "specified integer tag type cannot represent every field", .{}); errdefer msg.destroy(sema.gpa); - try sema.errNote(tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{ + try sema.errNote(tag_ty_src, msg, "type '{f}' cannot fit values in range 0...{d}", .{ int_tag_ty.fmt(pt), fields_len - 1, }); @@ -35832,7 +35838,7 @@ fn unionFields( // The provided type is the enum tag type. const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) { .enum_type => ip.loadEnumType(provided_ty.toIntern()), - else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(pt)}), + else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{f}'", .{provided_ty.fmt(pt)}), }; union_type.setTagType(ip, provided_ty.toIntern()); // The fields of the union must match the enum exactly. @@ -35929,7 +35935,7 @@ fn unionFields( if (result.overflow) return sema.fail( &block_scope, value_src, - "enumeration value '{}' too large for type '{}'", + "enumeration value '{f}' too large for type '{f}'", .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) }, ); last_tag_val = result.val; @@ -35947,7 +35953,7 @@ fn unionFields( const msg = msg: { const msg = try sema.errMsg( value_src, - "enum tag value {} already taken", + "enum tag value {f} already taken", .{enum_tag_val.fmtValueSema(pt, sema)}, ); errdefer msg.destroy(gpa); @@ -35975,7 +35981,7 @@ fn unionFields( const tag_ty = union_type.tagTypeUnordered(ip); const tag_info = ip.loadEnumType(tag_ty); const enum_index = tag_info.nameIndex(ip, field_name) orelse { - return sema.fail(&block_scope, name_src, "no field named '{}' in enum '{}'", .{ + return sema.fail(&block_scope, name_src, "no field named '{f}' in enum '{f}'", .{ field_name.fmt(ip), Type.fromInterned(tag_ty).fmt(pt), }); }; @@ -35992,7 +35998,7 @@ fn unionFields( .base_node_inst = Type.fromInterned(tag_ty).typeDeclInstAllowGeneratedTag(zcu).?, .offset = .{ .container_field_name = enum_index }, }; - const msg = try sema.errMsg(name_src, "union field '{}' ordered differently than corresponding enum field", .{ + const msg = try sema.errMsg(name_src, "union field '{f}' ordered differently than corresponding enum field", .{ field_name.fmt(ip), }); errdefer msg.destroy(sema.gpa); @@ -36018,7 +36024,7 @@ fn unionFields( !try sema.validateExternType(field_ty, .union_field)) { const msg = msg: { - const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field); @@ -36029,7 +36035,7 @@ fn unionFields( return sema.failWithOwnedErrorMsg(&block_scope, msg); } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) { const msg = msg: { - const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(pt)}); + const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty); @@ -36065,7 +36071,7 @@ fn unionFields( for (tag_info.names.get(ip), 0..) |field_name, field_index| { if (explicit_tags_seen[field_index]) continue; - try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{}' missing, declared here", .{ + try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{f}' missing, declared here", .{ field_name.fmt(ip), }); } @@ -36101,7 +36107,7 @@ fn generateUnionTagTypeNumbered( const name = try ip.getOrPutStringFmt( gpa, pt.tid, - "@typeInfo({}).@\"union\".tag_type.?", + "@typeInfo({f}).@\"union\".tag_type.?", .{union_name.fmt(ip)}, .no_embedded_nulls, ); @@ -36137,7 +36143,7 @@ fn generateUnionTagTypeSimple( const name = try ip.getOrPutStringFmt( gpa, pt.tid, - "@typeInfo({}).@\"union\".tag_type.?", + "@typeInfo({f}).@\"union\".tag_type.?", .{union_name.fmt(ip)}, .no_embedded_nulls, ); @@ -36671,13 +36677,13 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr .needed_well_defined => |ty| return sema.fail( block, src, - "comptime dereference requires '{}' to have a well-defined layout", + "comptime dereference requires '{f}' to have a well-defined layout", .{ty.fmt(pt)}, ), .out_of_bounds => |ty| return sema.fail( block, src, - "dereference of '{}' exceeds bounds of containing decl of type '{}'", + "dereference of '{f}' exceeds bounds of containing decl of type '{f}'", .{ ptr_ty.fmt(pt), ty.fmt(pt) }, ), } @@ -36697,7 +36703,7 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value .success => |mv| return .{ .val = try mv.intern(pt, sema.arena) }, .runtime_load => return .runtime_load, .undef => return sema.failWithUseOfUndef(block, src), - .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {}", .{err_name.fmt(ip)}), + .err_payload => |err_name| return sema.fail(block, src, "attempt to unwrap error: {f}", .{err_name.fmt(ip)}), .null_payload => return sema.fail(block, src, "attempt to use null value", .{}), .inactive_union_field => return sema.fail(block, src, "access of inactive union field", .{}), .needed_well_defined => |ty| return .{ .needed_well_defined = ty }, @@ -36822,12 +36828,12 @@ fn intFromFloatScalar( const float = val.toFloat(f128, zcu); if (std.math.isNan(float)) { - return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{ + return sema.fail(block, src, "float value NaN cannot be stored in integer type '{f}'", .{ int_ty.fmt(pt), }); } if (std.math.isInf(float)) { - return sema.fail(block, src, "float value Inf cannot be stored in integer type '{}'", .{ + return sema.fail(block, src, "float value Inf cannot be stored in integer type '{f}'", .{ int_ty.fmt(pt), }); } @@ -36842,7 +36848,7 @@ fn intFromFloatScalar( .exact => return sema.fail( block, src, - "fractional component prevents float value '{}' from coercion to type '{}'", + "fractional component prevents float value '{f}' from coercion to type '{f}'", .{ val.fmtValueSema(pt, sema), int_ty.fmt(pt) }, ), .truncate => {}, @@ -36854,7 +36860,7 @@ fn intFromFloatScalar( const int_info = int_ty.intInfo(zcu); if (!big_int.toConst().fitsInTwosComp(int_info.signedness, int_info.bits)) { - return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ + return sema.fail(block, src, "float value '{f}' cannot be stored in integer type '{f}'", .{ val.fmtValueSema(pt, sema), int_ty.fmt(pt), }); } @@ -37186,9 +37192,9 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, var first_path: std.ArrayListUnmanaged(u8) = .empty; if (intermediate_value_count == 0) { - try first_path.writer(arena).print("{i}", .{start_value_name.fmt(ip)}); + try first_path.print(arena, "{fi}", .{start_value_name.fmt(ip)}); } else { - try first_path.writer(arena).print("v{}", .{intermediate_value_count - 1}); + try first_path.print(arena, "v{}", .{intermediate_value_count - 1}); } const comptime_ptr = try sema.notePathToComptimeAllocPtrInner(val, &first_path); @@ -37213,30 +37219,26 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, error.AnalysisFail => unreachable, }; - var second_path: std.ArrayListUnmanaged(u8) = .empty; + var second_path_aw: std.io.Writer.Allocating = .init(arena); + defer second_path_aw.deinit(); const inter_name = try std.fmt.allocPrint(arena, "v{d}", .{intermediate_value_count}); const deriv_start = @import("print_value.zig").printPtrDerivation( derivation, - second_path.writer(arena), + &second_path_aw.interface, pt, .lvalue, .{ .str = inter_name }, 20, - ) catch |err| switch (err) { - error.OutOfMemory => |e| return e, - error.AnalysisFail => unreachable, - error.ComptimeReturn => unreachable, - error.ComptimeBreak => unreachable, - }; + ) catch return error.OutOfMemory; switch (deriv_start) { .int, .nav_ptr => unreachable, .uav_ptr => |uav| { - try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items }); + try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() }); return .{ .new_val = .fromInterned(uav.val) }; }, .comptime_alloc_ptr => |cta_info| { - try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items }); + try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() }); const cta = sema.getComptimeAlloc(cta_info.idx); if (cta.is_const) { return .{ .new_val = cta_info.val }; @@ -37246,7 +37248,7 @@ fn notePathToComptimeAllocPtr(sema: *Sema, msg: *Zcu.ErrorMsg, src: LazySrcLoc, } }, .comptime_field_ptr => { - try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path.items }); + try sema.errNote(src, msg, "'{s}' points to '{s}', where", .{ first_path.items, second_path_aw.getWritten() }); try sema.errNote(src, msg, "'{s}' is a comptime field", .{inter_name}); return .done; }, @@ -37286,7 +37288,7 @@ fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayList const backing_enum = union_ty.unionTagTypeHypothetical(zcu); const field_idx = backing_enum.enumTagFieldIndex(.fromInterned(un.tag), zcu).?; const field_name = backing_enum.enumFieldName(field_idx, zcu); - try path.writer(arena).print(".{i}", .{field_name.fmt(ip)}); + try path.print(arena, ".{fi}", .{field_name.fmt(ip)}); return sema.notePathToComptimeAllocPtrInner(.fromInterned(un.val), path); }, .aggregate => |agg| { @@ -37301,17 +37303,17 @@ fn notePathToComptimeAllocPtrInner(sema: *Sema, val: Value, path: *std.ArrayList }; const agg_ty: Type = .fromInterned(agg.ty); switch (agg_ty.zigTypeTag(zcu)) { - .array, .vector => try path.writer(arena).print("[{d}]", .{elem_idx}), + .array, .vector => try path.print(arena, "[{d}]", .{elem_idx}), .pointer => switch (elem_idx) { Value.slice_ptr_index => try path.appendSlice(arena, ".ptr"), Value.slice_len_index => try path.appendSlice(arena, ".len"), else => unreachable, }, .@"struct" => if (agg_ty.isTuple(zcu)) { - try path.writer(arena).print("[{d}]", .{elem_idx}); + try path.print(arena, "[{d}]", .{elem_idx}); } else { const name = agg_ty.structFieldName(elem_idx, zcu).unwrap().?; - try path.writer(arena).print(".{i}", .{name.fmt(ip)}); + try path.print(arena, ".{fi}", .{name.fmt(ip)}); }, else => unreachable, } @@ -37588,7 +37590,7 @@ fn resolveDeclaredEnumInner( if (tag_type_ref != .none) { const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); if (ty.zigTypeTag(zcu) != .int and ty.zigTypeTag(zcu) != .comptime_int) { - return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(pt)}); + return sema.fail(block, tag_ty_src, "expected integer tag type, found '{f}'", .{ty.fmt(pt)}); } break :ty ty; } else if (fields_len == 0) { @@ -37642,7 +37644,7 @@ fn resolveDeclaredEnumInner( .offset = .{ .container_field_value = conflict.prev_field_idx }, }; const msg = msg: { - const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); + const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); errdefer msg.destroy(gpa); try sema.errNote(other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -37665,7 +37667,7 @@ fn resolveDeclaredEnumInner( .offset = .{ .container_field_value = conflict.prev_field_idx }, }; const msg = msg: { - const msg = try sema.errMsg(value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); + const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); errdefer msg.destroy(gpa); try sema.errNote(other_field_src, msg, "other occurrence here", .{}); break :msg msg; @@ -37682,7 +37684,7 @@ fn resolveDeclaredEnumInner( }; if (tag_overflow) { - const msg = try sema.errMsg(value_src, "enumeration value '{}' too large for type '{}'", .{ + const msg = try sema.errMsg(value_src, "enumeration value '{f}' too large for type '{f}'", .{ last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt), }); return sema.failWithOwnedErrorMsg(block, msg); diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig index 9bd876082f..43c98ebf97 100644 --- a/src/Sema/LowerZon.zig +++ b/src/Sema/LowerZon.zig @@ -661,7 +661,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse { return self.fail( node, - "enum {} has no member named '{}'", + "enum {f} has no member named '{f}'", .{ res_ty.fmt(self.sema.pt), std.zig.fmtId(field_name.get(self.file.zoir.?)), diff --git a/src/Type.zig b/src/Type.zig index 333e738b05..1a1f1d2b06 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -382,7 +382,9 @@ pub fn print(ty: Type, writer: anytype, pt: Zcu.PerThread) @TypeOf(writer).Error } } switch (fn_info.cc) { - .auto, .async, .naked, .@"inline" => try writer.print("callconv(.{}) ", .{std.zig.fmtId(@tagName(fn_info.cc))}), + .auto, .async, .naked, .@"inline" => try writer.print("callconv(.{f}) ", .{ + std.zig.fmtId(@tagName(fn_info.cc)), + }), else => try writer.print("callconv({any}) ", .{fn_info.cc}), } } diff --git a/src/Zcu.zig b/src/Zcu.zig index a815921cf0..3b54acc40b 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -2811,7 +2811,7 @@ comptime { } pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir { - return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file); + return loadZirCacheBody(gpa, try cache_file.deprecatedReader().readStruct(Zir.Header), cache_file); } pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir { diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 680af42f57..9b2477e093 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -341,7 +341,7 @@ fn loadZirZoirCache( }; // First we read the header to determine the lengths of arrays. - const header = cache_file.reader().readStruct(Header) catch |err| switch (err) { + const header = cache_file.deprecatedReader().readStruct(Header) catch |err| switch (err) { // This can happen if Zig bails out of this function between creating // the cached file and writing it. error.EndOfStream => return .invalid, @@ -477,11 +477,11 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { if (std.zig.srcHashEql(old_hash, new_hash)) { break :hash_changed; } - log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{ + log.debug("hash for (%{d} -> %{d}) changed: {x} -> {x}", .{ old_inst, new_inst, - std.fmt.fmtSliceHexLower(&old_hash), - std.fmt.fmtSliceHexLower(&new_hash), + &old_hash, + &new_hash, }); } // The source hash associated with this instruction changed - invalidate relevant dependencies. @@ -4378,7 +4378,7 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e if (build_options.enable_debug_extensions and comp.verbose_air) { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); stderr.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)}) catch {}; air.write(stderr, pt, liveness); stderr.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)}) catch {}; diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index 1b7d5ed3d4..080ab5e484 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -187,7 +187,7 @@ pub fn format( }, } - try writer.print(".{}", .{std.fmt.fmtSliceHexUpper(opc[0 .. opc.len - 1])}); + try writer.print(".{X}", .{opc[0 .. opc.len - 1]}); opc = opc[opc.len - 1 ..]; try writer.writeAll(".W"); diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index 8d07dce83a..ab3eeaa586 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -1205,9 +1205,9 @@ pub const Vex = struct { fn expectEqualHexStrings(expected: []const u8, given: []const u8, assembly: []const u8) !void { assert(expected.len > 0); if (std.mem.eql(u8, expected, given)) return; - const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(expected)}); + const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{expected}); defer testing.allocator.free(expected_fmt); - const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(given)}); + const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{given}); defer testing.allocator.free(given_fmt); const idx = std.mem.indexOfDiff(u8, expected_fmt, given_fmt).?; const padding = try testing.allocator.alloc(u8, idx + 5); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 5135095f69..40c5c234d3 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2486,7 +2486,7 @@ pub const Object = struct { var union_name_buf: ?[:0]const u8 = null; defer if (union_name_buf) |buf| gpa.free(buf); const union_name = if (layout.tag_size == 0) name else name: { - union_name_buf = try std.fmt.allocPrintZ(gpa, "{s}:Payload", .{name}); + union_name_buf = try std.fmt.allocPrintSentinel(gpa, "{s}:Payload", .{name}, 0); break :name union_name_buf.?; }; diff --git a/src/crash_report.zig b/src/crash_report.zig index 3958ac96ac..0704d08cb1 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -80,7 +80,7 @@ fn dumpStatusReport() !void { var fba = std.heap.FixedBufferAllocator.init(&crash_heap); const allocator = fba.allocator(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); const block: *Sema.Block = anal.block; const zcu = anal.sema.pt.zcu; @@ -271,7 +271,7 @@ const StackContext = union(enum) { debug.dumpStackTraceFromBase(context); }, .not_supported => { - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); stderr.writeAll("Stack trace not supported on this platform.\n") catch {}; }, } @@ -379,7 +379,7 @@ const PanicSwitch = struct { state.recover_stage = .release_mutex; - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); if (builtin.single_threaded) { stderr.print("panic: ", .{}) catch goTo(releaseMutex, .{state}); } else { @@ -406,7 +406,7 @@ const PanicSwitch = struct { recover(state, trace, stack, msg); state.recover_stage = .release_mutex; - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); stderr.writeAll("\nOriginal Error:\n") catch {}; goTo(reportStack, .{state}); } @@ -477,7 +477,7 @@ const PanicSwitch = struct { recover(state, trace, stack, msg); state.recover_stage = .silent_abort; - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); stderr.writeAll("Aborting...\n") catch {}; goTo(abort, .{}); } @@ -505,7 +505,7 @@ const PanicSwitch = struct { // lower the verbosity, and restore it at the end if we don't panic. state.recover_verbosity = .message_only; - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); stderr.writeAll("\nPanicked during a panic: ") catch {}; stderr.writeAll(msg) catch {}; stderr.writeAll("\nInner panic stack:\n") catch {}; @@ -519,7 +519,7 @@ const PanicSwitch = struct { .message_only => { state.recover_verbosity = .silent; - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); stderr.writeAll("\nPanicked while dumping inner panic stack: ") catch {}; stderr.writeAll(msg) catch {}; stderr.writeAll("\n") catch {}; diff --git a/src/fmt.zig b/src/fmt.zig index 20d40a3077..bbb02e0c34 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -60,7 +60,7 @@ pub fn run( const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.writeAll(usage_fmt); return process.cleanExit(); } else if (mem.eql(u8, arg, "--color")) { @@ -371,7 +371,7 @@ fn fmtPathFile( return; if (check_mode) { - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.print("{s}\n", .{file_path}); fmt.any_error = true; } else { @@ -380,7 +380,7 @@ fn fmtPathFile( try af.file.writeAll(fmt.out_buffer.items); try af.finish(); - const stdout = std.fs.File.stdout().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.print("{s}\n", .{file_path}); } } diff --git a/src/libs/libtsan.zig b/src/libs/libtsan.zig index de5a770e30..d17baf8fa1 100644 --- a/src/libs/libtsan.zig +++ b/src/libs/libtsan.zig @@ -268,7 +268,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo const skip_linker_dependencies = !target.os.tag.isDarwin(); const linker_allow_shlib_undefined = target.os.tag.isDarwin(); const install_name = if (target.os.tag.isDarwin()) - try std.fmt.allocPrintZ(arena, "@rpath/{s}", .{basename}) + try std.fmt.allocPrintSentinel(arena, "@rpath/{s}", .{basename}, 0) else null; // Workaround for https://github.com/llvm/llvm-project/issues/97627 diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index e2bcb19f08..1c2927eba0 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -306,7 +306,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { if (comp.verbose_cc) print: { std.debug.lockStdErr(); defer std.debug.unlockStdErr(); - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); nosuspend stderr.print("def file: {s}\n", .{def_file_path}) catch break :print; nosuspend stderr.print("include dir: {s}\n", .{include_dir}) catch break :print; nosuspend stderr.print("output path: {s}\n", .{def_final_path}) catch break :print; @@ -335,7 +335,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { // new scope to ensure definition file is written before passing the path to WriteImportLibrary const def_final_file = try o_dir.createFile(final_def_basename, .{ .truncate = true }); defer def_final_file.close(); - try pp.prettyPrintTokens(def_final_file.writer(), .result_only); + try pp.prettyPrintTokens(def_final_file.deprecatedWriter(), .result_only); } const lib_final_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename }); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index ea5d6a901c..ff71b0ca63 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -830,8 +830,8 @@ fn debugMem(allocator: Allocator, handle: std.process.Child.Id, pvaddr: std.os.w const buffer = try allocator.alloc(u8, code.len); defer allocator.free(buffer); const memread = try std.os.windows.ReadProcessMemory(handle, pvaddr, buffer); - log.debug("to write: {x}", .{std.fmt.fmtSliceHexLower(code)}); - log.debug("in memory: {x}", .{std.fmt.fmtSliceHexLower(memread)}); + log.debug("to write: {x}", .{code}); + log.debug("in memory: {x}", .{memread}); } fn writeMemProtected(handle: std.process.Child.Id, pvaddr: std.os.windows.LPVOID, code: []const u8) !void { diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 0d177bc21a..17cd2dc104 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -44,8 +44,8 @@ pub fn parse( pos += @sizeOf(elf.ar_hdr); if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) { - return diags.failParse(path, "invalid archive header delimiter: {s}", .{ - std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), + return diags.failParse(path, "invalid archive header delimiter: {f}", .{ + std.ascii.hexEscape(&hdr.ar_fmag, .lower), }); } @@ -288,7 +288,7 @@ pub const ArStrtab = struct { ) !void { _ = unused_fmt_string; _ = options; - try writer.print("{s}", .{std.fmt.fmtSliceEscapeLower(ar.buffer.items)}); + try writer.print("{f}", .{std.ascii.hexEscape(ar.buffer.items, .lower)}); } }; diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig index ad02d8d5d9..7f828b5431 100644 --- a/src/link/Elf/LinkerDefined.zig +++ b/src/link/Elf/LinkerDefined.zig @@ -147,9 +147,9 @@ pub fn initStartStopSymbols(self: *LinkerDefined, elf_file: *Elf) !void { for (slice.items(.shdr)) |shdr| { // TODO use getOrPut for incremental so that we don't create duplicates if (elf_file.getStartStopBasename(shdr)) |name| { - const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); + const start_name = try std.fmt.allocPrintSentinel(gpa, "__start_{s}", .{name}, 0); defer gpa.free(start_name); - const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); + const stop_name = try std.fmt.allocPrintSentinel(gpa, "__stop_{s}", .{name}, 0); defer gpa.free(stop_name); for (&[_][]const u8{ start_name, stop_name }) |nn| { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index f4b340a549..3f62b40e21 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -803,9 +803,9 @@ pub fn initRelaSections(self: *ZigObject, elf_file: *Elf) !void { const out_shndx = atom_ptr.output_section_index; const out_shdr = elf_file.sections.items(.shdr)[out_shndx]; if (out_shdr.sh_type == elf.SHT_NOBITS) continue; - const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{ + const rela_sect_name = try std.fmt.allocPrintSentinel(gpa, ".rela{s}", .{ elf_file.getShString(out_shdr.sh_name), - }); + }, 0); defer gpa.free(rela_sect_name); _ = elf_file.sectionByName(rela_sect_name) orelse try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), out_shndx); @@ -824,9 +824,9 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { const out_shndx = atom_ptr.output_section_index; const out_shdr = elf_file.sections.items(.shdr)[out_shndx]; if (out_shdr.sh_type == elf.SHT_NOBITS) continue; - const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{ + const rela_sect_name = try std.fmt.allocPrintSentinel(gpa, ".rela{s}", .{ elf_file.getShString(out_shdr.sh_name), - }); + }, 0); defer gpa.free(rela_sect_name); const out_rela_shndx = elf_file.sectionByName(rela_sect_name).?; const out_rela_shdr = &elf_file.sections.items(.shdr)[out_rela_shndx]; diff --git a/src/link/Elf/gc.zig b/src/link/Elf/gc.zig index 0f5b11f827..9ff9a75c79 100644 --- a/src/link/Elf/gc.zig +++ b/src/link/Elf/gc.zig @@ -163,7 +163,7 @@ fn prune(elf_file: *Elf) void { } pub fn dumpPrunedAtoms(elf_file: *Elf) !void { - const stderr = std.fs.File.stderr().writer(); + const stderr = std.fs.File.stderr().deprecatedWriter(); for (elf_file.objects.items) |index| { const file = elf_file.file(index).?; for (file.atoms()) |atom_index| { diff --git a/src/link/LdScript.zig b/src/link/LdScript.zig index ed5dbc4681..534f9766bb 100644 --- a/src/link/LdScript.zig +++ b/src/link/LdScript.zig @@ -41,8 +41,8 @@ pub fn parse( try line_col.append(gpa, .{ .line = line, .column = column }); switch (tok.id) { .invalid => { - return diags.failParse(path, "invalid token in LD script: '{s}' ({d}:{d})", .{ - std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column, + return diags.failParse(path, "invalid token in LD script: '{f}' ({d}:{d})", .{ + std.ascii.hexEscape(tok.get(data), .lower), line, column, }); }, .new_line => { diff --git a/src/link/Lld.zig b/src/link/Lld.zig index caf9da1ed2..6eddba2b53 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -933,9 +933,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { .fast, .uuid, .sha1, .md5 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ @tagName(base.build_id), })), - .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ - std.fmt.fmtSliceHexLower(hs.toSlice()), - })), + .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{x}", .{hs.toSlice()})), } try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{elf.image_base})); @@ -1511,9 +1509,7 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { .fast, .uuid, .sha1 => try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{ @tagName(base.build_id), })), - .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{ - std.fmt.fmtSliceHexLower(hs.toSlice()), - })), + .hexstring => |hs| try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{x}", .{hs.toSlice()})), .md5 => {}, } @@ -1667,7 +1663,7 @@ fn spawnLld( log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) }); { defer rsp_file.close(); - var rsp_buf = std.io.bufferedWriter(rsp_file.writer()); + var rsp_buf = std.io.bufferedWriter(rsp_file.deprecatedWriter()); const rsp_writer = rsp_buf.writer(); for (argv[2..]) |arg| { try rsp_writer.writeByte('"'); diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index 82818aa697..e7403c37d4 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -29,8 +29,8 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File pos += @sizeOf(ar_hdr); if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { - return diags.failParse(path, "invalid header delimiter: expected '{s}', found '{s}'", .{ - std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), + return diags.failParse(path, "invalid header delimiter: expected '{f}', found '{f}'", .{ + std.ascii.hexEscape(ARFMAG, .lower), std.ascii.hexEscape(&hdr.ar_fmag, .lower), }); } diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index ec9d07aabc..a569b52cb9 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -308,7 +308,7 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void { } else nlists.len; if (nlist_start == nlist_end or nlists[nlist_start].nlist.n_value > sect.addr) { - const name = try std.fmt.allocPrintZ(allocator, "{s}${s}$begin", .{ sect.segName(), sect.sectName() }); + const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$begin", .{ sect.segName(), sect.sectName() }, 0); defer allocator.free(name); const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr; const atom_index = try self.addAtom(allocator, .{ @@ -364,7 +364,7 @@ fn initSubsections(self: *Object, allocator: Allocator, nlists: anytype) !void { // which cannot be contained in any non-zero atom (since then this atom // would exceed section boundaries). In order to facilitate this behaviour, // we create a dummy zero-sized atom at section end (addr + size). - const name = try std.fmt.allocPrintZ(allocator, "{s}${s}$end", .{ sect.segName(), sect.sectName() }); + const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}$end", .{ sect.segName(), sect.sectName() }, 0); defer allocator.free(name); const atom_index = try self.addAtom(allocator, .{ .name = try self.addString(allocator, name), @@ -394,7 +394,7 @@ fn initSections(self: *Object, allocator: Allocator, nlists: anytype) !void { if (isFixedSizeLiteral(sect)) continue; if (isPtrLiteral(sect)) continue; - const name = try std.fmt.allocPrintZ(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() }); + const name = try std.fmt.allocPrintSentinel(allocator, "{s}${s}", .{ sect.segName(), sect.sectName() }, 0); defer allocator.free(name); const atom_index = try self.addAtom(allocator, .{ @@ -462,7 +462,7 @@ fn initCstringLiterals(self: *Object, allocator: Allocator, file: File.Handle, m } end += 1; - const name = try std.fmt.allocPrintZ(allocator, "l._str{d}", .{count}); + const name = try std.fmt.allocPrintSentinel(allocator, "l._str{d}", .{count}, 0); defer allocator.free(name); const name_str = try self.addString(allocator, name); @@ -529,7 +529,7 @@ fn initFixedSizeLiterals(self: *Object, allocator: Allocator, macho_file: *MachO pos += rec_size; count += 1; }) { - const name = try std.fmt.allocPrintZ(allocator, "l._literal{d}", .{count}); + const name = try std.fmt.allocPrintSentinel(allocator, "l._literal{d}", .{count}, 0); defer allocator.free(name); const name_str = try self.addString(allocator, name); @@ -587,7 +587,7 @@ fn initPointerLiterals(self: *Object, allocator: Allocator, macho_file: *MachO) for (0..num_ptrs) |i| { const pos: u32 = @as(u32, @intCast(i)) * rec_size; - const name = try std.fmt.allocPrintZ(allocator, "l._ptr{d}", .{i}); + const name = try std.fmt.allocPrintSentinel(allocator, "l._ptr{d}", .{i}, 0); defer allocator.free(name); const name_str = try self.addString(allocator, name); @@ -1558,7 +1558,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { const nlist = &self.symtab.items(.nlist)[nlist_idx]; const nlist_atom = &self.symtab.items(.atom)[nlist_idx]; - const name = try std.fmt.allocPrintZ(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)}); + const name = try std.fmt.allocPrintSentinel(gpa, "__DATA$__common${s}", .{sym.getName(macho_file)}, 0); defer gpa.free(name); const alignment = (nlist.n_desc >> 8) & 0x0f; diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 97c1a0ad54..df0be97ba6 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -959,7 +959,7 @@ fn updateNavCode( sym.out_n_sect = sect_index; atom.out_n_sect = sect_index; - const sym_name = try std.fmt.allocPrintZ(gpa, "_{s}", .{nav.fqn.toSlice(ip)}); + const sym_name = try std.fmt.allocPrintSentinel(gpa, "_{s}", .{nav.fqn.toSlice(ip)}, 0); defer gpa.free(sym_name); sym.name = try self.addString(gpa, sym_name); atom.setAlive(true); diff --git a/src/link/MachO/dyld_info/Trie.zig b/src/link/MachO/dyld_info/Trie.zig index b45651eb67..8224dc8424 100644 --- a/src/link/MachO/dyld_info/Trie.zig +++ b/src/link/MachO/dyld_info/Trie.zig @@ -336,9 +336,9 @@ const Edge = struct { fn expectEqualHexStrings(expected: []const u8, given: []const u8) !void { assert(expected.len > 0); if (mem.eql(u8, expected, given)) return; - const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(expected)}); + const expected_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{expected}); defer testing.allocator.free(expected_fmt); - const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{std.fmt.fmtSliceHexLower(given)}); + const given_fmt = try std.fmt.allocPrint(testing.allocator, "{x}", .{given}); defer testing.allocator.free(given_fmt); const idx = mem.indexOfDiff(u8, expected_fmt, given_fmt).?; const padding = try testing.allocator.alloc(u8, idx + 5); diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 60f5971e40..7bd9f89a42 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -1035,20 +1035,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { var id: [16]u8 = undefined; std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); var uuid: [36]u8 = undefined; - _ = try std.fmt.bufPrint(&uuid, "{s}-{s}-{s}-{s}-{s}", .{ - std.fmt.fmtSliceHexLower(id[0..4]), - std.fmt.fmtSliceHexLower(id[4..6]), - std.fmt.fmtSliceHexLower(id[6..8]), - std.fmt.fmtSliceHexLower(id[8..10]), - std.fmt.fmtSliceHexLower(id[10..]), + _ = try std.fmt.bufPrint(&uuid, "{x}-{x}-{x}-{x}-{x}", .{ + id[0..4], id[4..6], id[6..8], id[8..10], id[10..], }); try emitBuildIdSection(gpa, binary_bytes, &uuid); }, .hexstring => |hs| { var buffer: [32 * 2]u8 = undefined; - const str = std.fmt.bufPrint(&buffer, "{s}", .{ - std.fmt.fmtSliceHexLower(hs.toSlice()), - }) catch unreachable; + const str = std.fmt.bufPrint(&buffer, "{x}", .{hs.toSlice()}) catch unreachable; try emitBuildIdSection(gpa, binary_bytes, str); }, else => |mode| { diff --git a/src/link/tapi/parse.zig b/src/link/tapi/parse.zig index f6556dd5dd..28ef2642a9 100644 --- a/src/link/tapi/parse.zig +++ b/src/link/tapi/parse.zig @@ -57,14 +57,9 @@ pub const Node = struct { } } - pub fn format( - self: *const Node, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { + pub fn format(self: *const Node, writer: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { switch (self.tag) { - inline else => |tag| return @as(*tag.Type(), @fieldParentPtr("base", self)).format(fmt, options, writer), + inline else => |tag| return @as(*tag.Type(), @fieldParentPtr("base", self)).format(writer, fmt), } } @@ -86,14 +81,8 @@ pub const Node = struct { } } - pub fn format( - self: *const Doc, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; - _ = fmt; + pub fn format(self: *const Doc, writer: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); if (self.directive) |id| { try std.fmt.format(writer, "{{ ", .{}); const directive = self.base.tree.getRaw(id, id); @@ -133,14 +122,8 @@ pub const Node = struct { self.values.deinit(allocator); } - pub fn format( - self: *const Map, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; - _ = fmt; + pub fn format(self: *const Map, writer: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); try std.fmt.format(writer, "{{ ", .{}); for (self.values.items) |entry| { const key = self.base.tree.getRaw(entry.key, entry.key); @@ -172,14 +155,8 @@ pub const Node = struct { self.values.deinit(allocator); } - pub fn format( - self: *const List, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; - _ = fmt; + pub fn format(self: *const List, writer: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); try std.fmt.format(writer, "[ ", .{}); for (self.values.items) |node| { try std.fmt.format(writer, "{}, ", .{node}); @@ -203,14 +180,8 @@ pub const Node = struct { self.string_value.deinit(allocator); } - pub fn format( - self: *const Value, - comptime fmt: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; - _ = fmt; + pub fn format(self: *const Value, writer: *std.io.Writer, comptime fmt: []const u8) std.io.Writer.Error!void { + comptime assert(fmt.len == 0); const raw = self.base.tree.getRaw(self.base.start, self.base.end); return std.fmt.format(writer, "{s}", .{raw}); } diff --git a/src/main.zig b/src/main.zig index 38af88a0f1..a843366901 100644 --- a/src/main.zig +++ b/src/main.zig @@ -340,7 +340,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { } else if (mem.eql(u8, cmd, "targets")) { dev.check(.targets_command); const host = std.zig.resolveTargetQueryOrFatal(.{}); - const stdout = fs.File.stdout().writer(); + const stdout = fs.File.stdout().deprecatedWriter(); return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, &host); } else if (mem.eql(u8, cmd, "version")) { dev.check(.version_command); @@ -352,7 +352,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { } else if (mem.eql(u8, cmd, "env")) { dev.check(.env_command); verifyLibcxxCorrectlyLinked(); - return @import("print_env.zig").cmdEnv(arena, cmd_args, fs.File.stdout().writer()); + return @import("print_env.zig").cmdEnv(arena, cmd_args, fs.File.stdout().deprecatedWriter()); } else if (mem.eql(u8, cmd, "reduce")) { return jitCmd(gpa, arena, cmd_args, .{ .cmd_name = "reduce", @@ -3333,9 +3333,8 @@ fn buildOutputType( var bin_digest: Cache.BinDigest = undefined; hasher.final(&bin_digest); - const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{s}-stdin{s}", .{ - std.fmt.fmtSliceHexLower(&bin_digest), - ext.canonicalName(target), + const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-stdin{s}", .{ + &bin_digest, ext.canonicalName(target), }); try dirs.local_cache.handle.rename(dump_path, sub_path); @@ -6110,7 +6109,7 @@ fn cmdAstCheck( const stdout = fs.File.stdout(); const fmtIntSizeBin = std.fmt.fmtIntSizeBin; // zig fmt: off - try stdout.writer().print( + try stdout.deprecatedWriter().print( \\# Source bytes: {} \\# Tokens: {} ({}) \\# AST Nodes: {} ({}) @@ -6186,7 +6185,7 @@ fn cmdDetectCpu(args: []const []const u8) !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = fs.File.stdout().writer(); + const stdout = fs.File.stdout().deprecatedWriter(); try stdout.writeAll(detect_cpu_usage); return cleanExit(); } else if (mem.eql(u8, arg, "--llvm")) { @@ -6279,7 +6278,7 @@ fn detectNativeCpuWithLLVM( } fn printCpu(cpu: std.Target.Cpu) !void { - var bw = io.bufferedWriter(fs.File.stdout().writer()); + var bw = io.bufferedWriter(fs.File.stdout().deprecatedWriter()); const stdout = bw.writer(); if (cpu.model.llvm_name) |llvm_name| { @@ -6328,7 +6327,7 @@ fn cmdDumpLlvmInts( const dl = tm.createTargetDataLayout(); const context = llvm.Context.create(); - var bw = io.bufferedWriter(fs.File.stdout().writer()); + var bw = io.bufferedWriter(fs.File.stdout().deprecatedWriter()); const stdout = bw.writer(); for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| { @@ -6371,7 +6370,7 @@ fn cmdDumpZir( const stdout = fs.File.stdout(); const fmtIntSizeBin = std.fmt.fmtIntSizeBin; // zig fmt: off - try stdout.writer().print( + try stdout.deprecatedWriter().print( \\# Total ZIR bytes: {} \\# Instructions: {d} ({}) \\# String Table Bytes: {} @@ -6444,7 +6443,7 @@ fn cmdChangelist( var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty; try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map); - var bw = io.bufferedWriter(fs.File.stdout().writer()); + var bw = io.bufferedWriter(fs.File.stdout().deprecatedWriter()); const stdout = bw.writer(); { try stdout.print("Instruction mappings:\n", .{}); @@ -6794,7 +6793,7 @@ fn cmdFetch( const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = fs.File.stdout().writer(); + const stdout = fs.File.stdout().deprecatedWriter(); try stdout.writeAll(usage_fetch); return cleanExit(); } else if (mem.eql(u8, arg, "--global-cache-dir")) { @@ -6908,7 +6907,7 @@ fn cmdFetch( const name = switch (save) { .no => { - try fs.File.stdout().writer().print("{s}\n", .{package_hash_slice}); + try fs.File.stdout().deprecatedWriter().print("{s}\n", .{package_hash_slice}); return cleanExit(); }, .yes, .exact => |name| name: { @@ -6973,16 +6972,16 @@ fn cmdFetch( const new_node_init = try std.fmt.allocPrint(arena, \\.{{ - \\ .url = "{}", - \\ .hash = "{}", + \\ .url = "{f}", + \\ .hash = "{f}", \\ }} , .{ - std.zig.fmtEscapes(saved_path_or_url), - std.zig.fmtEscapes(package_hash_slice), + std.zig.fmtString(saved_path_or_url), + std.zig.fmtString(package_hash_slice), }); - const new_node_text = try std.fmt.allocPrint(arena, ".{p_} = {s},\n", .{ - std.zig.fmtId(name), new_node_init, + const new_node_text = try std.fmt.allocPrint(arena, ".{f} = {s},\n", .{ + std.zig.fmtIdPU(name), new_node_init, }); const dependencies_init = try std.fmt.allocPrint(arena, ".{{\n {s} }}", .{ @@ -7008,13 +7007,13 @@ fn cmdFetch( const location_replace = try std.fmt.allocPrint( arena, - "\"{}\"", - .{std.zig.fmtEscapes(saved_path_or_url)}, + "\"{f}\"", + .{std.zig.fmtString(saved_path_or_url)}, ); const hash_replace = try std.fmt.allocPrint( arena, - "\"{}\"", - .{std.zig.fmtEscapes(package_hash_slice)}, + "\"{f}\"", + .{std.zig.fmtString(package_hash_slice)}, ); warn("overwriting existing dependency named '{s}'", .{name}); diff --git a/src/print_value.zig b/src/print_value.zig index 0bd5bcee23..c509d1087d 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -232,7 +232,7 @@ fn printAggregate( const len = ty.arrayLenIncludingSentinel(zcu); if (len == 0) break :string; const slice = bytes.toSlice(if (bytes.at(len - 1, ip) == 0) len - 1 else len, ip); - try writer.print("\"{}\"", .{std.zig.fmtEscapes(slice)}); + try writer.print("\"{f}\"", .{std.zig.fmtString(slice)}); if (!is_ref) try writer.writeAll(".*"); return; }, @@ -249,7 +249,7 @@ fn printAggregate( const elem_val = Value.fromInterned(aggregate.storage.values()[0]); if (elem_val.isUndef(zcu)) break :one_byte_str; const byte = elem_val.toUnsignedInt(zcu); - try writer.print("\"{}\"", .{std.zig.fmtEscapes(&.{@intCast(byte)})}); + try writer.print("\"{f}\"", .{std.zig.fmtString(&.{@intCast(byte)})}); if (!is_ref) try writer.writeAll(".*"); return; }, diff --git a/src/print_zir.zig b/src/print_zir.zig index c9e1a18d89..4e60e8a1f4 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -30,7 +30,7 @@ pub fn renderAsTextToFile( .recurse_blocks = true, }; - var raw_stream = std.io.bufferedWriter(fs_file.writer()); + var raw_stream = std.io.bufferedWriter(fs_file.deprecatedWriter()); const stream = raw_stream.writer(); const main_struct_inst: Zir.Inst.Index = .main_struct_inst; @@ -49,8 +49,8 @@ pub fn renderAsTextToFile( extra_index = item.end; const import_path = zir.nullTerminatedString(item.data.name); - try stream.print(" @import(\"{}\") ", .{ - std.zig.fmtEscapes(import_path), + try stream.print(" @import(\"{f}\") ", .{ + std.zig.fmtString(import_path), }); try writer.writeSrcTokAbs(stream, item.data.token); try stream.writeAll("\n"); @@ -789,7 +789,7 @@ const Writer = struct { ) (@TypeOf(stream).Error || error{OutOfMemory})!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str; const str = inst_data.get(self.code); - try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)}); + try stream.print("\"{f}\")", .{std.zig.fmtString(str)}); } fn writeSliceStart(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { @@ -932,8 +932,8 @@ const Writer = struct { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok; const extra = self.code.extraData(Zir.Inst.Param, inst_data.payload_index); const body = self.code.bodySlice(extra.end, extra.data.type.body_len); - try stream.print("\"{}\", ", .{ - std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)), + try stream.print("\"{f}\", ", .{ + std.zig.fmtString(self.code.nullTerminatedString(extra.data.name)), }); if (extra.data.type.is_generic) try stream.writeAll("[generic] "); @@ -1203,7 +1203,7 @@ const Writer = struct { try stream.writeAll(", "); } else { const asm_source = self.code.nullTerminatedString(extra.data.asm_source); - try stream.print("\"{}\", ", .{std.zig.fmtEscapes(asm_source)}); + try stream.print("\"{f}\", ", .{std.zig.fmtString(asm_source)}); } try stream.writeAll(", "); @@ -1220,8 +1220,8 @@ const Writer = struct { const name = self.code.nullTerminatedString(output.data.name); const constraint = self.code.nullTerminatedString(output.data.constraint); - try stream.print("output({p}, \"{}\", ", .{ - std.zig.fmtId(name), std.zig.fmtEscapes(constraint), + try stream.print("output({f}, \"{f}\", ", .{ + std.zig.fmtIdFlags(name, .{ .allow_primitive = true }), std.zig.fmtString(constraint), }); try self.writeFlag(stream, "->", is_type); try self.writeInstRef(stream, output.data.operand); @@ -1239,8 +1239,8 @@ const Writer = struct { const name = self.code.nullTerminatedString(input.data.name); const constraint = self.code.nullTerminatedString(input.data.constraint); - try stream.print("input({p}, \"{}\", ", .{ - std.zig.fmtId(name), std.zig.fmtEscapes(constraint), + try stream.print("input({f}, \"{f}\", ", .{ + std.zig.fmtIdFlags(name, .{ .allow_primitive = true }), std.zig.fmtString(constraint), }); try self.writeInstRef(stream, input.data.operand); try stream.writeAll(")"); @@ -1255,7 +1255,7 @@ const Writer = struct { const str_index = self.code.extra[extra_i]; extra_i += 1; const clobber = self.code.nullTerminatedString(@enumFromInt(str_index)); - try stream.print("{p}", .{std.zig.fmtId(clobber)}); + try stream.print("{f}", .{std.zig.fmtIdFlags(clobber, .{ .allow_primitive = true })}); if (i + 1 < clobbers_len) { try stream.writeAll(", "); } @@ -1299,7 +1299,7 @@ const Writer = struct { .field => { const field_name = self.code.nullTerminatedString(extra.data.field_name_start); try self.writeInstRef(stream, extra.data.obj_ptr); - try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)}); + try stream.print(", \"{f}\"", .{std.zig.fmtString(field_name)}); }, } try stream.writeAll(", ["); @@ -1388,7 +1388,7 @@ const Writer = struct { extra.data.fields_hash_3, }); - try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)}); + try stream.print("hash({x}) ", .{&fields_hash}); var extra_index: usize = extra.end; @@ -1519,7 +1519,7 @@ const Writer = struct { try self.writeFlag(stream, "comptime ", field.is_comptime); if (field.name != .empty) { const field_name = self.code.nullTerminatedString(field.name); - try stream.print("{p}: ", .{std.zig.fmtId(field_name)}); + try stream.print("{f}: ", .{std.zig.fmtIdFlags(field_name, .{ .allow_primitive = true })}); } else { try stream.print("@\"{d}\": ", .{i}); } @@ -1580,7 +1580,7 @@ const Writer = struct { extra.data.fields_hash_3, }); - try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)}); + try stream.print("hash({x}) ", .{&fields_hash}); var extra_index: usize = extra.end; @@ -1682,7 +1682,7 @@ const Writer = struct { extra_index += 1; try stream.writeByteNTimes(' ', self.indent); - try stream.print("{p}", .{std.zig.fmtId(field_name)}); + try stream.print("{f}", .{std.zig.fmtIdFlags(field_name, .{ .allow_primitive = true })}); if (has_type) { const field_type = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])); @@ -1731,7 +1731,7 @@ const Writer = struct { extra.data.fields_hash_3, }); - try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)}); + try stream.print("hash({x}) ", .{&fields_hash}); var extra_index: usize = extra.end; @@ -1816,7 +1816,7 @@ const Writer = struct { extra_index += 1; try stream.writeByteNTimes(' ', self.indent); - try stream.print("{p}", .{std.zig.fmtId(field_name)}); + try stream.print("{f}", .{std.zig.fmtIdFlags(field_name, .{ .allow_primitive = true })}); if (has_tag_value) { const tag_value_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index])); @@ -1921,7 +1921,7 @@ const Writer = struct { const name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]); const name = self.code.nullTerminatedString(name_index); try stream.writeByteNTimes(' ', self.indent); - try stream.print("{p},\n", .{std.zig.fmtId(name)}); + try stream.print("{f},\n", .{std.zig.fmtIdFlags(name, .{ .allow_primitive = true })}); } self.indent -= 2; @@ -2203,7 +2203,7 @@ const Writer = struct { const extra = self.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; const name = self.code.nullTerminatedString(extra.field_name_start); try self.writeInstRef(stream, extra.lhs); - try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)}); + try stream.print(", \"{f}\") ", .{std.zig.fmtString(name)}); try self.writeSrcNode(stream, inst_data.src_node); } @@ -2244,7 +2244,7 @@ const Writer = struct { ) (@TypeOf(stream).Error || error{OutOfMemory})!void { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_tok; const str = inst_data.get(self.code); - try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)}); + try stream.print("\"{f}\") ", .{std.zig.fmtString(str)}); try self.writeSrcTok(stream, inst_data.src_tok); } @@ -2252,7 +2252,7 @@ const Writer = struct { const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].str_op; const str = inst_data.getStr(self.code); try self.writeInstRef(stream, inst_data.operand); - try stream.print(", \"{}\")", .{std.zig.fmtEscapes(str)}); + try stream.print(", \"{f}\")", .{std.zig.fmtString(str)}); } fn writeFunc( @@ -2594,11 +2594,7 @@ const Writer = struct { }, } const src_hash = self.code.getAssociatedSrcHash(inst).?; - try stream.print(" line({d}) column({d}) hash({})", .{ - decl.src_line, - decl.src_column, - std.fmt.fmtSliceHexLower(&src_hash), - }); + try stream.print(" line({d}) column({d}) hash({x})", .{ decl.src_line, decl.src_column, &src_hash }); { if (decl.type_body) |b| { @@ -2694,11 +2690,11 @@ const Writer = struct { try stream.writeAll("load "); try self.writeInstIndex(stream, ptr_inst); }, - .decl_val => |str| try stream.print("decl_val \"{}\"", .{ - std.zig.fmtEscapes(self.code.nullTerminatedString(str)), + .decl_val => |str| try stream.print("decl_val \"{f}\"", .{ + std.zig.fmtString(self.code.nullTerminatedString(str)), }), - .decl_ref => |str| try stream.print("decl_ref \"{}\"", .{ - std.zig.fmtEscapes(self.code.nullTerminatedString(str)), + .decl_ref => |str| try stream.print("decl_ref \"{f}\"", .{ + std.zig.fmtString(self.code.nullTerminatedString(str)), }), } } @@ -2831,7 +2827,7 @@ const Writer = struct { const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data; try self.writeInstRef(stream, extra.res_ty); const import_path = self.code.nullTerminatedString(extra.path); - try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(import_path)}); + try stream.print(", \"{f}\") ", .{std.zig.fmtString(import_path)}); try self.writeSrcTok(stream, inst_data.src_tok); } }; diff --git a/src/print_zoir.zig b/src/print_zoir.zig index b6cc8fe4d9..526bfbb148 100644 --- a/src/print_zoir.zig +++ b/src/print_zoir.zig @@ -77,8 +77,8 @@ const PrintZon = struct { }, .float_literal => |x| try pz.w.print("float({d})", .{x}), .char_literal => |x| try pz.w.print("char({d})", .{x}), - .enum_literal => |x| try pz.w.print("enum_literal({p})", .{std.zig.fmtId(x.get(zoir))}), - .string_literal => |x| try pz.w.print("str(\"{}\")", .{std.zig.fmtEscapes(x)}), + .enum_literal => |x| try pz.w.print("enum_literal({f})", .{std.zig.fmtIdP(x.get(zoir))}), + .string_literal => |x| try pz.w.print("str(\"{f}\")", .{std.zig.fmtString(x)}), .empty_literal => try pz.w.writeAll("empty_literal(.{})"), .array_literal => |vals| { try pz.w.writeAll("array_literal({"); @@ -97,7 +97,7 @@ const PrintZon = struct { pz.indent += 1; for (s.names, 0..s.vals.len) |name, idx| { try pz.newline(); - try pz.w.print("[{p}] ", .{std.zig.fmtId(name.get(zoir))}); + try pz.w.print("[{f}] ", .{std.zig.fmtIdP(name.get(zoir))}); try pz.renderNode(s.vals.at(@intCast(idx))); try pz.w.writeByte(','); } diff --git a/src/translate_c.zig b/src/translate_c.zig index dda2ee8e2e..436e011ca6 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -357,7 +357,7 @@ fn transFileScopeAsm(c: *Context, scope: *Scope, file_scope_asm: *const clang.Fi var len: usize = undefined; const bytes_ptr = asm_string.getString_bytes_begin_size(&len); - const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])}); + const str = try std.fmt.allocPrint(c.arena, "\"{f}\"", .{std.zig.fmtString(bytes_ptr[0..len])}); const str_node = try Tag.string_literal.create(c.arena, str); const asm_node = try Tag.asm_simple.create(c.arena, str_node); @@ -2276,7 +2276,7 @@ fn transNarrowStringLiteral( var len: usize = undefined; const bytes_ptr = stmt.getString_bytes_begin_size(&len); - const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])}); + const str = try std.fmt.allocPrint(c.arena, "\"{f}\"", .{std.zig.fmtString(bytes_ptr[0..len])}); const node = try Tag.string_literal.create(c.arena, str); return maybeSuppressResult(c, result_used, node); } @@ -3338,7 +3338,7 @@ fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.Predefined fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node { return Tag.char_literal.create(c.arena, if (narrow) - try std.fmt.allocPrint(c.arena, "'{'}'", .{std.zig.fmtEscapes(&.{@as(u8, @intCast(val))})}) + try std.fmt.allocPrint(c.arena, "'{f}'", .{std.zig.fmtChar(&.{@as(u8, @intCast(val))})}) else try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val})); } @@ -5832,7 +5832,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { num += c - 'A' + 10; }, else => { - i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); + i += std.fmt.printInt(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); num = 0; if (c == '\\') state = .escape @@ -5858,7 +5858,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { }; num += c - '0'; } else { - i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); + i += std.fmt.printInt(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); num = 0; count = 0; if (c == '\\') @@ -5872,21 +5872,21 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 { } } if (state == .hex or state == .octal) - i += std.fmt.formatIntBuf(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); + i += std.fmt.printInt(bytes[i..], num, 16, .lower, std.fmt.FormatOptions{ .fill = '0', .width = 2 }); return bytes[0..i]; } -/// non-ASCII characters (c > 127) are also treated as non-printable by fmtSliceEscapeLower. +/// non-ASCII characters (c > 127) are also treated as non-printable by ascii.hexEscape. /// If a C string literal or char literal in a macro is not valid UTF-8, we need to escape /// non-ASCII characters so that the Zig source we output will itself be UTF-8. fn escapeUnprintables(ctx: *Context, m: *MacroCtx) ![]const u8 { const zigified = try zigifyEscapeSequences(ctx, m); if (std.unicode.utf8ValidateSlice(zigified)) return zigified; - const formatter = std.fmt.fmtSliceEscapeLower(zigified); - const encoded_size = @as(usize, @intCast(std.fmt.count("{s}", .{formatter}))); + const formatter = std.ascii.hexEscape(zigified, .lower); + const encoded_size = @as(usize, @intCast(std.fmt.count("{fs}", .{formatter}))); const output = try ctx.arena.alloc(u8, encoded_size); - return std.fmt.bufPrint(output, "{s}", .{formatter}) catch |err| switch (err) { + return std.fmt.bufPrint(output, "{fs}", .{formatter}) catch |err| switch (err) { error.NoSpaceLeft => unreachable, else => |e| return e, }; @@ -5905,7 +5905,7 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) { return Tag.char_literal.create(c.arena, try escapeUnprintables(c, m)); } else { - const str = try std.fmt.allocPrint(c.arena, "0x{s}", .{std.fmt.fmtSliceHexLower(slice[1 .. slice.len - 1])}); + const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]}); return Tag.integer_literal.create(c.arena, str); } }, diff --git a/test/behavior/union_with_members.zig b/test/behavior/union_with_members.zig index 70f1086276..e5e4669608 100644 --- a/test/behavior/union_with_members.zig +++ b/test/behavior/union_with_members.zig @@ -10,8 +10,8 @@ const ET = union(enum) { pub fn print(a: *const ET, buf: []u8) anyerror!usize { return switch (a.*) { - ET.SINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}), - ET.UINT => |x| fmt.formatIntBuf(buf, x, 10, .lower, fmt.FormatOptions{}), + ET.SINT => |x| fmt.printInt(buf, x, 10, .lower, fmt.FormatOptions{}), + ET.UINT => |x| fmt.printInt(buf, x, 10, .lower, fmt.FormatOptions{}), }; } }; diff --git a/test/link/elf.zig b/test/link/elf.zig index 14b70441ba..05a070e929 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -1316,7 +1316,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step { \\extern fn live_fn2() void; \\pub fn main() void { \\ const stdout = std.io.getStdOut(); - \\ stdout.writer().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable; + \\ stdout.deprecatedWriter().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable; \\ live_fn2(); \\} , @@ -1358,7 +1358,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step { \\extern fn live_fn2() void; \\pub fn main() void { \\ const stdout = std.io.getStdOut(); - \\ stdout.writer().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable; + \\ stdout.deprecatedWriter().print("{d} {d}\n", .{ live_var1, live_var2 }) catch unreachable; \\ live_fn2(); \\} , diff --git a/test/standalone/run_output_paths/create_file.zig b/test/standalone/run_output_paths/create_file.zig index 041ebc3e50..da949d4fc1 100644 --- a/test/standalone/run_output_paths/create_file.zig +++ b/test/standalone/run_output_paths/create_file.zig @@ -10,7 +10,7 @@ pub fn main() !void { dir_name, .{}); const file_name = args.next().?; const file = try dir.createFile(file_name, .{}); - try file.writer().print( + try file.deprecatedWriter().print( \\{s} \\{s} \\Hello, world! diff --git a/test/standalone/simple/brace_expansion.zig b/test/standalone/simple/brace_expansion.zig index facaf4a754..c98171eddc 100644 --- a/test/standalone/simple/brace_expansion.zig +++ b/test/standalone/simple/brace_expansion.zig @@ -228,7 +228,7 @@ pub fn main() !void { const stdin_file = io.getStdIn(); const stdout_file = io.getStdOut(); - const stdin = try stdin_file.reader().readAllAlloc(global_allocator, std.math.maxInt(usize)); + const stdin = try stdin_file.deprecatedReader().readAllAlloc(global_allocator, std.math.maxInt(usize)); defer global_allocator.free(stdin); var result_buf = ArrayList(u8).init(global_allocator); diff --git a/test/standalone/windows_argv/fuzz.zig b/test/standalone/windows_argv/fuzz.zig index 6d08c1bf84..bbe956c365 100644 --- a/test/standalone/windows_argv/fuzz.zig +++ b/test/standalone/windows_argv/fuzz.zig @@ -58,7 +58,7 @@ pub fn main() !void { std.debug.print(">>> found discrepancy <<<\n", .{}); const cmd_line_wtf8 = try std.unicode.wtf16LeToWtf8Alloc(allocator, cmd_line_w); defer allocator.free(cmd_line_wtf8); - std.debug.print("\"{}\"\n\n", .{std.zig.fmtEscapes(cmd_line_wtf8)}); + std.debug.print("\"{f}\"\n\n", .{std.zig.fmtString(cmd_line_wtf8)}); errors += 1; } diff --git a/test/standalone/windows_argv/lib.zig b/test/standalone/windows_argv/lib.zig index 074273ae21..d41ad95313 100644 --- a/test/standalone/windows_argv/lib.zig +++ b/test/standalone/windows_argv/lib.zig @@ -27,8 +27,8 @@ fn testArgv(expected_args: []const [*:0]const u16) !void { wtf8_buf.clearRetainingCapacity(); try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(expected_arg)); if (!std.mem.eql(u8, wtf8_buf.items, arg_wtf8)) { - std.debug.print("{}: expected: \"{}\"\n", .{ i, std.zig.fmtEscapes(wtf8_buf.items) }); - std.debug.print("{}: actual: \"{}\"\n", .{ i, std.zig.fmtEscapes(arg_wtf8) }); + std.debug.print("{}: expected: \"{f}\"\n", .{ i, std.zig.fmtString(wtf8_buf.items) }); + std.debug.print("{}: actual: \"{f}\"\n", .{ i, std.zig.fmtString(arg_wtf8) }); eql = false; } } @@ -36,22 +36,22 @@ fn testArgv(expected_args: []const [*:0]const u16) !void { for (expected_args[min_len..], min_len..) |arg, i| { wtf8_buf.clearRetainingCapacity(); try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(arg)); - std.debug.print("{}: expected: \"{}\"\n", .{ i, std.zig.fmtEscapes(wtf8_buf.items) }); + std.debug.print("{}: expected: \"{f}\"\n", .{ i, std.zig.fmtString(wtf8_buf.items) }); } for (args[min_len..], min_len..) |arg, i| { - std.debug.print("{}: actual: \"{}\"\n", .{ i, std.zig.fmtEscapes(arg) }); + std.debug.print("{}: actual: \"{f}\"\n", .{ i, std.zig.fmtString(arg) }); } const peb = std.os.windows.peb(); const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer); wtf8_buf.clearRetainingCapacity(); try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(lpCmdLine)); - std.debug.print("command line: \"{}\"\n", .{std.zig.fmtEscapes(wtf8_buf.items)}); + std.debug.print("command line: \"{f}\"\n", .{std.zig.fmtString(wtf8_buf.items)}); std.debug.print("expected argv:\n", .{}); std.debug.print("&.{{\n", .{}); for (expected_args) |arg| { wtf8_buf.clearRetainingCapacity(); try std.unicode.wtf16LeToWtf8ArrayList(&wtf8_buf, std.mem.span(arg)); - std.debug.print(" \"{}\",\n", .{std.zig.fmtEscapes(wtf8_buf.items)}); + std.debug.print(" \"{f}\",\n", .{std.zig.fmtString(wtf8_buf.items)}); } std.debug.print("}}\n", .{}); return error.ArgvMismatch; diff --git a/test/tests.zig b/test/tests.zig index 9068d65012..872bc6d548 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2753,7 +2753,7 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void { run.addArg(b.graph.zig_exe); run.addFileArg(b.path("test/incremental/").path(b, entry.path)); - run.addArgs(&.{ "--zig-lib-dir", b.fmt("{}", .{b.graph.zig_lib_directory}) }); + run.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) }); run.addCheck(.{ .expect_term = .{ .Exited = 0 } });